Skip to content

Commit 9862973

Browse files
author
Kautilya Tripathi
committed
prometheus: Add chart for PVC
This adds charts for pvc disk usage and capacity. Signed-off-by: Kautilya Tripathi <[email protected]>
1 parent 469d0d1 commit 9862973

File tree

2 files changed

+195
-1
lines changed

2 files changed

+195
-1
lines changed

prometheus/src/common.tsx

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,127 @@ export function GenericMetricsChart(props: {
194194
);
195195
}
196196

197+
export function DiskMetricsChart(props: {
198+
usageQuery?: string;
199+
capacityQuery?: string;
200+
}) {
201+
enum prometheusState {
202+
UNKNOWN,
203+
LOADING,
204+
ERROR,
205+
INSTALLED,
206+
}
207+
208+
const classes = useStyles();
209+
const pluginSettings = usePluginSettings();
210+
const [refresh, setRefresh] = useState<boolean>(true);
211+
212+
const [prometheusInfo, setPrometheusInfo] = useState<{
213+
podName: string;
214+
podNamespace: string;
215+
} | null>(null);
216+
const [state, setState] = useState<prometheusState>(prometheusState.LOADING);
217+
218+
useEffect(() => {
219+
(async () => {
220+
try {
221+
const [isInstalled, podName, namespace] = await isPrometheusInstalled();
222+
if (isInstalled) {
223+
setPrometheusInfo({ podName, podNamespace: namespace });
224+
setState(prometheusState.INSTALLED);
225+
} else {
226+
setPrometheusInfo(null);
227+
setState(prometheusState.UNKNOWN);
228+
}
229+
} catch (e) {
230+
setState(prometheusState.ERROR);
231+
return;
232+
}
233+
})();
234+
}, []);
235+
236+
if (!pluginSettings.isVisible) {
237+
return null;
238+
}
239+
240+
return (
241+
<SectionBox>
242+
<Box
243+
display="flex"
244+
justifyContent="space-around"
245+
alignItems="center"
246+
style={{ marginBottom: '0.5rem', margin: '0 auto', width: '0%' }}
247+
248+
>
249+
{state === prometheusState.INSTALLED
250+
? [
251+
<Box>Disk</Box>,
252+
<Box pl={2}>
253+
<IconButton
254+
onClick={() => {
255+
setRefresh(refresh => !refresh);
256+
}}
257+
size="Big"
258+
>
259+
{refresh ? <Icon icon="mdi:pause" /> : <Icon icon="mdi:play" />}
260+
</IconButton>
261+
</Box>,
262+
]
263+
: []}
264+
</Box>
265+
266+
{prometheusInfo ? (
267+
<Box style={{ justifyContent: 'center', display: 'flex', height: '40vh', width: '80%', margin: '0 auto'}}>
268+
<DiskChart
269+
usageQuery={props.usageQuery}
270+
capacityQuery={props.capacityQuery}
271+
autoRefresh={refresh}
272+
prometheusPrefix={`${prometheusInfo.podNamespace}/pods/${prometheusInfo.podName}`}
273+
/>
274+
</Box>
275+
) : state === prometheusState.LOADING ? (
276+
<Box m={2}>
277+
<Loader title="Loading Prometheus Info" />
278+
</Box>
279+
) : state === prometheusState.ERROR ? (
280+
<Box m={2}>
281+
<Alert severity="warning">Error fetching prometheus Info</Alert>
282+
</Box>
283+
) : (
284+
<Grid
285+
container
286+
spacing={2}
287+
direction="column"
288+
justifyContent="center"
289+
alignItems="center"
290+
className={classes.skeletonBox}
291+
>
292+
<Grid item>
293+
<Typography variant="h5">Install Prometheus for accessing metrics charts</Typography>
294+
</Grid>
295+
<Grid item>
296+
<Typography>
297+
<Link href={learnMoreLink} target="_blank">
298+
Learn more about enabling advanced charts.
299+
</Link>
300+
</Typography>
301+
</Grid>
302+
<Grid item>
303+
<Button
304+
className={classes.dismissButton}
305+
size="small"
306+
variant="contained"
307+
onClick={() => pluginSettings.setIsVisible(false)}
308+
>
309+
Dismiss
310+
</Button>
311+
</Grid>
312+
</Grid>
313+
)}
314+
</SectionBox>
315+
);
316+
}
317+
197318
function createTickTimestampFormatter() {
198319
let prevRenderedTimestamp = null;
199320

@@ -442,6 +563,70 @@ export function NetworkChart(props: {
442563
);
443564
}
444565

566+
export function DiskChart(props: {
567+
usageQuery: string;
568+
capacityQuery: string;
569+
prometheusPrefix: string;
570+
autoRefresh: boolean;
571+
}) {
572+
const xTickFormatter = createTickTimestampFormatter();
573+
const theme = useTheme();
574+
575+
return (
576+
<Chart
577+
plots={[
578+
{
579+
query: props.usageQuery,
580+
name: 'usage',
581+
strokeColor: '#CDC300',
582+
fillColor: '#FFF178',
583+
dataProcessor: dataProcessor,
584+
},
585+
{
586+
query: props.capacityQuery,
587+
name: 'capacity',
588+
strokeColor: '#006B58',
589+
fillColor: '#98F6DC',
590+
dataProcessor: dataProcessor,
591+
},
592+
]}
593+
xAxisProps={{
594+
dataKey: 'timestamp',
595+
tickLine: false,
596+
tick: props => {
597+
const value = xTickFormatter(props.payload.value);
598+
return (
599+
value !== '' && (
600+
<g
601+
transform={`translate(${props.x},${props.y})`}
602+
fill={theme.palette.chartStyles.labelColor}
603+
>
604+
<text x={0} y={10} dy={0} textAnchor="middle">
605+
{value}
606+
</text>
607+
</g>
608+
)
609+
);
610+
},
611+
}}
612+
yAxisProps={{
613+
domain: ['dataMin', 'auto'],
614+
tick: ({ x, y, payload }) => (
615+
<g transform={`translate(${x},${y})`} fill={theme.palette.chartStyles.labelColor}>
616+
<text x={-35} y={0} dy={0} textAnchor="middle">
617+
{formatBytes(payload.value)}
618+
</text>
619+
</g>
620+
),
621+
width: 80,
622+
}}
623+
fetchMetrics={fetchMetrics}
624+
CustomTooltip={CustomTooltipFormatBytes}
625+
{...props}
626+
/>
627+
);
628+
}
629+
445630
export function FilesystemChart(props: {
446631
readQuery: string;
447632
writeQuery: string;

prometheus/src/index.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
registerDetailsViewHeaderActionsProcessor,
55
registerDetailsViewSectionsProcessor,
66
} from '@kinvolk/headlamp-plugin/lib';
7-
import { GenericMetricsChart } from './common';
7+
import { DiskMetricsChart, GenericMetricsChart } from './common';
88
import { ChartEnabledKinds } from './util';
99
import VisibilityButton from './VisibilityButton';
1010

@@ -38,6 +38,15 @@ function PrometheusMetrics(resource: DetailsViewSectionProps) {
3838
/>
3939
);
4040
}
41+
42+
if (resource.kind === 'PersistentVolumeClaim') {
43+
return (
44+
<DiskMetricsChart
45+
usageQuery={`sum(kubelet_volume_stats_used_bytes{namespace='${resource.jsonData.metadata.namespace}',persistentvolumeclaim='${resource.jsonData.metadata.name}'}) by (persistentvolumeclaim, namespace)`}
46+
capacityQuery={`sum(kubelet_volume_stats_capacity_bytes{namespace='${resource.jsonData.metadata.namespace}',persistentvolumeclaim='${resource.jsonData.metadata.name}'}) by (persistentvolumeclaim, namespace)`}
47+
/>
48+
);
49+
}
4150
}
4251

4352
registerDetailsViewSectionsProcessor(function addSubheaderSection(resource, sections) {

0 commit comments

Comments
 (0)