feat: more work on the edges table

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam 2024-05-17 15:30:10 +02:00
parent 807125d8cc
commit 7490c55a1d
8 changed files with 206 additions and 12 deletions

View File

@ -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 {

View File

@ -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 <Typography paragraph>Loading...</Typography>;
}
const { stats } = useStatsForEntity(entity);
const content = () => {
if (!stats?.incoming.length && !stats?.outgoing.length) {
return (
<Typography paragraph>
@ -46,6 +43,7 @@ export const DependenciesCard = () => {
</Typography>
);
}
return <OctopusGraph stats={stats} entity={entity} />;
};

View File

@ -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 (
<Card className={styles.gridItemCard}>
<CardHeader title="Mesh Edges" className={styles.header} />
<Divider />
<CardContent className={styles.gridItemCardContent}>
<Typography paragraph>
This service doesn't look like it's tagged with the right service,
or linkerd is not injected.
</Typography>
</CardContent>
</Card>
);
}
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 (
<Card className={styles.gridItemCard}>
<CardHeader title="Mesh Edges" className={styles.header} />
<Divider />
<CardContent className={styles.gridItemCardContent}>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Direction</TableCell>
<TableCell align="right">Name</TableCell>
<TableCell align="right">RPS</TableCell>
<TableCell align="right">S/R</TableCell>
<TableCell align="right">TLS</TableCell>
</TableRow>
</TableHead>
<TableBody>
{edges.map(row => (
<TableRow key={row.name}>
<TableCell component="th" scope="row">
<Chip
label={
row.direction === 'incoming' ? 'Incoming' : 'Outgoing'
}
color={
row.direction === 'incoming' ? 'primary' : 'secondary'
}
/>
</TableCell>
<TableCell align="right">
<EntityRefLink
entityRef={stringifyEntityRef({
kind: 'component',
name: row.name,
namespace: row.namespace,
})}
/>
</TableCell>
<TableCell align="right">{`${row.requestRate.toFixed(
2,
)}`}</TableCell>
<TableCell align="right">
{`${Math.round(row.successRate * 100)}%`}
</TableCell>
<TableCell align="right">
{row.secure ? (
<CheckCircle color="primary" />
) : (
<RemoveCircle color="secondary" />
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</CardContent>
</Card>
);
};

View File

@ -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 (
<Grid item xs={12}>
<Alert icon={<ErrorIcon fontSize="inherit" />} severity="error">
Looks like this component is not currently meshed with Linkerd
</Alert>
</Grid>
);
}
if (stats.current) {
if (stats?.current) {
if (stats.current.pods.meshedPodsPercentage === 0) {
return (
<Grid item xs={12}>

View File

@ -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,

View File

@ -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);

View File

@ -2,4 +2,5 @@ export {
linkerdPlugin,
LinkerdDependenciesCard,
LinkerdIsMeshedBanner,
LinkerdEdgesTable,
} from './plugin';

View File

@ -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),
},
}),
);