diff --git a/src/pages/Workloads/components/CPUUsagePanel.tsx b/src/pages/Workloads/components/CPUUsagePanel.tsx new file mode 100644 index 0000000..45350f7 --- /dev/null +++ b/src/pages/Workloads/components/CPUUsagePanel.tsx @@ -0,0 +1,84 @@ +import { PanelBuilders, SceneQueryRunner } from "@grafana/scenes" +import { LegendDisplayMode } from "@grafana/ui" +import { LabelFilters, serializeLabelFilters } from "common/queryHelpers" +import { Metrics } from "metrics/metrics" + +export function CPUUsagePanel(filters: LabelFilters) { + + const serializedFilters = serializeLabelFilters(filters) + + return PanelBuilders + .timeseries() + .setTitle('CPU') + .setData(new SceneQueryRunner({ + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + queries: [ + { + refId: 'cpu_usage', + expr: ` + max( + rate( + ${Metrics.containerCpuUsageSecondsTotal.name}{ + ${serializedFilters} + ${Metrics.containerCpuUsageSecondsTotal.labels.container}!="", + cluster="$cluster", + }[$__rate_interval] + ) + ) by ( + ${Metrics.containerCpuUsageSecondsTotal.labels.pod}, + ${Metrics.containerCpuUsageSecondsTotal.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Usage {{pod}} - {{container}}' + }, + { + refId: 'cpu_requests', + expr: ` + max( + ${Metrics.kubePodContainerResourceRequests.name}{ + ${Metrics.kubePodContainerResourceRequests.labels.resource}="cpu", + ${serializedFilters} + ${Metrics.kubePodContainerResourceRequests.labels.container}!="", + cluster="$cluster" + } + ) by ( + ${Metrics.kubePodContainerResourceRequests.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Requests {{container}}' + }, + { + refId: 'cpu_limit', + expr: ` + max( + ${Metrics.kubePodContainerResourceLimits.name}{ + ${Metrics.kubePodContainerResourceLimits.labels.resource}="cpu", + ${serializedFilters} + ${Metrics.kubePodContainerResourceLimits.labels.container}!="", + cluster="$cluster" + } + ) by ( + ${Metrics.kubePodContainerResourceLimits.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Limits {{container}}' + } + ], + })) + .setOverrides((builder) => { + builder.matchFieldsByQuery('cpu_requests') + .overrideCustomFieldConfig('lineStyle', { fill: 'dash', dash: [5, 5] }) + .overrideCustomFieldConfig('fillOpacity', 10) + builder.matchFieldsByQuery('cpu_limit') + .overrideCustomFieldConfig('lineStyle', { fill: 'dash', dash: [20, 5] }) + .overrideCustomFieldConfig('fillOpacity', 10) + }) + .setOption('legend', { displayMode: LegendDisplayMode.Table }) + .build() +} diff --git a/src/pages/Workloads/components/MemoryUsagePanel.tsx b/src/pages/Workloads/components/MemoryUsagePanel.tsx new file mode 100644 index 0000000..e954fd5 --- /dev/null +++ b/src/pages/Workloads/components/MemoryUsagePanel.tsx @@ -0,0 +1,83 @@ +import { PanelBuilders, SceneQueryRunner } from "@grafana/scenes" +import { LegendDisplayMode } from "@grafana/schema" +import { LabelFilters, serializeLabelFilters } from "common/queryHelpers" +import { Metrics } from "metrics/metrics" + +export function MemoryUsagePanel(filters: LabelFilters) { + + const serializedFilters = serializeLabelFilters(filters) + + return PanelBuilders + .timeseries() + .setTitle('Memory') + .setUnit('bytes') + .setData(new SceneQueryRunner({ + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + queries: [ + { + refId: 'memory_usage', + expr: ` + max( + ${Metrics.containerMemoryWorkingSetBytes.name}{ + ${serializedFilters} + ${Metrics.containerMemoryWorkingSetBytes.labels.container}!="", + cluster="$cluster", + } + ) by ( + ${Metrics.containerMemoryWorkingSetBytes.labels.pod}, + ${Metrics.containerMemoryWorkingSetBytes.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Usage {{pod}} - {{container}}' + }, + { + refId: 'memory_requests', + expr: ` + max( + ${Metrics.kubePodContainerResourceRequests.name}{ + ${Metrics.kubePodContainerResourceRequests.labels.resource}="memory", + ${serializedFilters} + ${Metrics.kubePodContainerResourceRequests.labels.container}!="", + cluster="$cluster" + } + ) by ( + ${Metrics.kubePodContainerResourceRequests.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Requests {{container}}' + }, + { + refId: 'memory_limit', + expr: ` + max( + ${Metrics.kubePodContainerResourceLimits.name}{ + ${Metrics.kubePodContainerResourceLimits.labels.resource}="memory", + ${serializedFilters} + ${Metrics.kubePodContainerResourceLimits.labels.container}!="", + cluster="$cluster" + } + ) by ( + ${Metrics.kubePodContainerResourceLimits.labels.container} + )`, + instant: false, + timeseries: true, + legendFormat: 'Limits {{container}}' + } + ], + })) + .setOverrides((builder) => { + builder.matchFieldsByQuery('memory_requests') + .overrideCustomFieldConfig('lineStyle', { fill: 'dash', dash: [5, 5] }) + .overrideCustomFieldConfig('fillOpacity', 10) + builder.matchFieldsByQuery('memory_limit') + .overrideCustomFieldConfig('lineStyle', { fill: 'dash', dash: [20, 5] }) + .overrideCustomFieldConfig('fillOpacity', 10) + }) + .setOption('legend', { displayMode: LegendDisplayMode.Table }) + .build() +} diff --git a/src/pages/Workloads/pages/DeploymentPage.tsx b/src/pages/Workloads/pages/DeploymentPage.tsx index bf1883f..3ae888b 100644 --- a/src/pages/Workloads/pages/DeploymentPage.tsx +++ b/src/pages/Workloads/pages/DeploymentPage.tsx @@ -7,6 +7,9 @@ import { createResourceLabels } from "../components/ResourceLabels"; import { getPodsScene } from "../tabs/Pods/Pods"; import { LabelFilters } from "../../../common/queryHelpers"; import { Metrics } from "metrics/metrics"; +import Heading from "components/Heading"; +import { CPUUsagePanel } from "../components/CPUUsagePanel"; +import { MemoryUsagePanel } from "../components/MemoryUsagePanel"; function getPods(deployment: string) { const staticLabelFilters: LabelFilters = [ @@ -112,11 +115,38 @@ function getScene(deployment: string) { }) ] }), + new SceneFlexLayout({ + direction: 'row', + children: [ + new Heading({ title: 'Resource Usage Overview'}) + ] + }), + new SceneFlexLayout({ + direction: 'row', + minHeight: 400, + children: [ + CPUUsagePanel([{ + label: 'pod', + op: '=~', + value: `${deployment}.*` + }]), + MemoryUsagePanel([{ + label: 'pod', + op: '=~', + value: `${deployment}.*` + }]), + ] + }), + new SceneFlexLayout({ + direction: 'row', + children: [ + new Heading({ title: 'Pods'}) + ] + }), new SceneFlexLayout({ direction: 'row', children: [ new SceneFlexItem({ - height: 'auto', width: '100%', body: getPods(deployment), }),