From 7490c55a1de528ca5928de3c22d43d1a159f16bb Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 17 May 2024 15:30:10 +0200 Subject: [PATCH] feat: more work on the edges table Signed-off-by: blam --- .../linkerd/plugins/linkerd/src/api/types.ts | 17 ++ .../src/components/DependenciesCard.tsx | 8 +- .../linkerd/src/components/EdgesTable.tsx | 162 +++++++++++++++++- .../linkerd/src/components/IsMeshedBanner.tsx | 14 +- .../components/OctopusGraph/OctopusGraph.tsx | 2 +- .../linkerd/src/hooks/useStatsForEntity.ts | 2 +- .../linkerd/plugins/linkerd/src/index.ts | 1 + .../linkerd/plugins/linkerd/src/plugin.ts | 12 ++ 8 files changed, 206 insertions(+), 12 deletions(-) diff --git a/workspaces/linkerd/plugins/linkerd/src/api/types.ts b/workspaces/linkerd/plugins/linkerd/src/api/types.ts index f405c8378..15088c01f 100644 --- a/workspaces/linkerd/plugins/linkerd/src/api/types.ts +++ b/workspaces/linkerd/plugins/linkerd/src/api/types.ts @@ -24,12 +24,29 @@ export interface Metric { }; } +export interface Edge { + src: { + namespace: string; + name: string; + type: MetricType; + }; + dst: { + namespace: string; + name: string; + type: MetricType; + }; + clientId: string; + serverId: string; + noIdentityMsg: string; +} + type MetricType = Partial<'deployment' | 'service' | 'authority' | 'pod'>; export interface DeploymentResponse { incoming: Metric[]; outgoing: Metric[]; current: Metric; + edges: Edge[]; } export interface L5dClient { diff --git a/workspaces/linkerd/plugins/linkerd/src/components/DependenciesCard.tsx b/workspaces/linkerd/plugins/linkerd/src/components/DependenciesCard.tsx index dac9a9c2f..8e41cd4c4 100644 --- a/workspaces/linkerd/plugins/linkerd/src/components/DependenciesCard.tsx +++ b/workspaces/linkerd/plugins/linkerd/src/components/DependenciesCard.tsx @@ -32,12 +32,9 @@ const useStyles = makeStyles({ export const DependenciesCard = () => { const styles = useStyles(); const { entity } = useEntity(); - const { stats, loading } = useStatsForEntity(entity); - const content = () => { - if (loading && !stats) { - return Loading...; - } + const { stats } = useStatsForEntity(entity); + const content = () => { if (!stats?.incoming.length && !stats?.outgoing.length) { return ( @@ -46,6 +43,7 @@ export const DependenciesCard = () => { ); } + return ; }; diff --git a/workspaces/linkerd/plugins/linkerd/src/components/EdgesTable.tsx b/workspaces/linkerd/plugins/linkerd/src/components/EdgesTable.tsx index f2e586711..4dcb3a357 100644 --- a/workspaces/linkerd/plugins/linkerd/src/components/EdgesTable.tsx +++ b/workspaces/linkerd/plugins/linkerd/src/components/EdgesTable.tsx @@ -1 +1,161 @@ -export const EdgesTable = () => {}; +import React from 'react'; +import { EntityRefLink, useEntity } from '@backstage/plugin-catalog-react'; +import { useStatsForEntity } from '../hooks/useStatsForEntity'; +import { + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Card, + CardContent, + CardHeader, + Divider, + Chip, + makeStyles, + Typography, +} from '@material-ui/core'; +import CheckCircle from '@material-ui/icons/CheckCircle'; +import RemoveCircle from '@material-ui/icons/RemoveCircle'; + +import { stringifyEntityRef } from '@backstage/catalog-model'; + +const useStyles = makeStyles({ + gridItemCard: { + display: 'flex', + flexDirection: 'column', + height: 'calc(100% - 10px)', // for pages without content header + marginBottom: '10px', + }, + + gridItemCardContent: { + flex: 1, + }, + header: { + padding: 16, + }, +}); + +export const EdgesTable = () => { + const { entity } = useEntity(); + const styles = useStyles(); + const { stats } = useStatsForEntity(entity); + + if (!stats) { + return ( + + + + + + This service doesn't look like it's tagged with the right service, + or linkerd is not injected. + + + + ); + } + + const incoming = + stats?.incoming?.map(edge => { + const matchedEdge = stats?.edges.find( + e => + e.dst.namespace === stats.current.namespace && + e.dst.name === stats.current.name && + e.dst.type === stats.current.type && + e.src.type === edge.type && + e.src.name === edge.name && + e.src.namespace === edge.namespace, + ); + + return { + ...edge, + direction: 'incoming', + secure: matchedEdge?.noIdentityMsg === '', + }; + }) ?? []; + + const outgoing = + stats?.outgoing?.map(edge => { + const matchedEdge = stats?.edges.find( + e => + e.src.namespace === stats.current.namespace && + e.src.name === stats.current.name && + e.src.type === stats.current.type && + e.dst.type === edge.type && + e.dst.name === edge.name && + e.dst.namespace === edge.namespace, + ); + + return { + ...edge, + direction: 'outgoing', + secure: matchedEdge?.noIdentityMsg === '', + }; + }) ?? []; + + const edges = [...incoming, ...outgoing] + .filter(f => f.type === 'deployment') + .sort((a, b) => a.name.localeCompare(b.name)); + + return ( + + + + + + + + + Direction + Name + RPS + S/R + TLS + + + + {edges.map(row => ( + + + + + + + + {`${row.requestRate.toFixed( + 2, + )}`} + + {`${Math.round(row.successRate * 100)}%`} + + + {row.secure ? ( + + ) : ( + + )} + + + ))} + +
+
+
+
+ ); +}; diff --git a/workspaces/linkerd/plugins/linkerd/src/components/IsMeshedBanner.tsx b/workspaces/linkerd/plugins/linkerd/src/components/IsMeshedBanner.tsx index 04a39353f..0c8520e73 100644 --- a/workspaces/linkerd/plugins/linkerd/src/components/IsMeshedBanner.tsx +++ b/workspaces/linkerd/plugins/linkerd/src/components/IsMeshedBanner.tsx @@ -9,13 +9,19 @@ import { useStatsForEntity } from '../hooks/useStatsForEntity'; export const IsMeshedBanner = () => { const { entity } = useEntity(); - const { stats, loading } = useStatsForEntity(entity); + const { stats } = useStatsForEntity(entity); - if (loading || !stats) { - return null; + if (!stats) { + return ( + + } severity="error"> + Looks like this component is not currently meshed with Linkerd + + + ); } - if (stats.current) { + if (stats?.current) { if (stats.current.pods.meshedPodsPercentage === 0) { return ( diff --git a/workspaces/linkerd/plugins/linkerd/src/components/OctopusGraph/OctopusGraph.tsx b/workspaces/linkerd/plugins/linkerd/src/components/OctopusGraph/OctopusGraph.tsx index 721836ec6..bccb678fe 100644 --- a/workspaces/linkerd/plugins/linkerd/src/components/OctopusGraph/OctopusGraph.tsx +++ b/workspaces/linkerd/plugins/linkerd/src/components/OctopusGraph/OctopusGraph.tsx @@ -1,7 +1,7 @@ import { DeploymentResponse } from '../../api/types'; import { Entity } from '@backstage/catalog-model'; import 'reactflow/dist/style.css'; -import React, { useCallback } from 'react'; +import React, { useCallback, useEffect } from 'react'; import ReactFlow, { useNodesState, useEdgesState, diff --git a/workspaces/linkerd/plugins/linkerd/src/hooks/useStatsForEntity.ts b/workspaces/linkerd/plugins/linkerd/src/hooks/useStatsForEntity.ts index 4b5dcbc3c..0de8914d7 100644 --- a/workspaces/linkerd/plugins/linkerd/src/hooks/useStatsForEntity.ts +++ b/workspaces/linkerd/plugins/linkerd/src/hooks/useStatsForEntity.ts @@ -10,7 +10,7 @@ export const useStatsForEntity = (entity: Entity) => { const [counter, setCounter] = useState(0); const { value, loading } = useAsync( () => l5d.getStatsForEntity(entity), - [counter], + [counter, entity], ); useInterval(() => { setCounter(counter + 1); diff --git a/workspaces/linkerd/plugins/linkerd/src/index.ts b/workspaces/linkerd/plugins/linkerd/src/index.ts index 9b5e34294..faef0c6a9 100644 --- a/workspaces/linkerd/plugins/linkerd/src/index.ts +++ b/workspaces/linkerd/plugins/linkerd/src/index.ts @@ -2,4 +2,5 @@ export { linkerdPlugin, LinkerdDependenciesCard, LinkerdIsMeshedBanner, + LinkerdEdgesTable, } from './plugin'; diff --git a/workspaces/linkerd/plugins/linkerd/src/plugin.ts b/workspaces/linkerd/plugins/linkerd/src/plugin.ts index cf058552e..ace3a5034 100644 --- a/workspaces/linkerd/plugins/linkerd/src/plugin.ts +++ b/workspaces/linkerd/plugins/linkerd/src/plugin.ts @@ -60,3 +60,15 @@ export const LinkerdIsMeshedBanner = linkerdPlugin.provide( }, }), ); + +/** + * @public + */ +export const LinkerdEdgesTable = linkerdPlugin.provide( + createComponentExtension({ + name: 'LinkerdEdgesTable', + component: { + lazy: () => import('./components/EdgesTable').then(m => m.EdgesTable), + }, + }), +);