diff --git a/src/common/seriesHelpers.ts b/src/common/seriesHelpers.ts index 32ae2e1..e9941f2 100644 --- a/src/common/seriesHelpers.ts +++ b/src/common/seriesHelpers.ts @@ -10,6 +10,11 @@ export function getSeriesValue(asyncData: any, name: string, pred: (value: any) return val ? val[`Value #${name}`] : 0 } +export function getSeriesLabelValue(asyncData: any, name: string, labelName: string, pred: (value: any) => boolean) { + const val = getSeries(asyncData, name, pred) + return val ? val[labelName] : [] +} + export function getAllSeries(asyncData: any, name: string, pred: (value: any) => boolean) { if (asyncData && asyncData.get(name)) { return asyncData.get(name).filter(pred) diff --git a/src/metrics/metrics.ts b/src/metrics/metrics.ts index 95e2a20..e193da3 100644 --- a/src/metrics/metrics.ts +++ b/src/metrics/metrics.ts @@ -25,6 +25,21 @@ export const Metrics = { uid: 'uid', } }, + kubePodStatusPhase: { + name: 'kube_pod_status_phase', + labels:{ + namespace: 'namespace', + pod: 'pod', + phase: 'phase', + } + }, + kubePodCreated: { + name: 'kube_pod_created', + labels:{ + namespace: 'namespace', + pod: 'pod', + } + }, kubePodContainerInfo: { name: 'kube_pod_container_info', labels:{ diff --git a/src/pages/Workloads/tabs/Pods/Pods.tsx b/src/pages/Workloads/tabs/Pods/Pods.tsx index c7b26e2..bc04547 100644 --- a/src/pages/Workloads/tabs/Pods/Pods.tsx +++ b/src/pages/Workloads/tabs/Pods/Pods.tsx @@ -8,7 +8,7 @@ import { VariableValueSelectors, SceneVariables, } from '@grafana/scenes'; -import { getAllSeries, getSeriesValue } from 'common/seriesHelpers'; +import { getAllSeries, getSeriesLabelValue, getSeriesValue } from 'common/seriesHelpers'; import { LabelFilters } from 'common/queryHelpers'; import { createNamespaceVariable } from 'common/variableHelpers'; import { Metrics } from 'metrics/metrics'; @@ -208,6 +208,29 @@ const columns: Array> = [ color: determineAlertsColor } }, + { + id: 'age', + header: 'AGE', + sortingConfig: { + enabled: true, + local: false, + type: 'value' + }, + cellType: 'formatted', + cellProps: { + format: 'dtdurations', + }, + accessor: (row: TableRow) => (Date.now() / 1000) - row.created + }, + { + id: 'status', + header: 'STATUS', + sortingConfig: { + enabled: true, + local: false, + type: 'value' + }, + }, { id: 'memory', header: 'MEMORY', @@ -318,6 +341,8 @@ const serieMatcherPredicate = (row: TableRow) => (value: any) => row.pod === val function asyncDataRowMapper(row: TableRow, asyncRowData: any) { + row.status = getSeriesLabelValue(asyncRowData, 'status', 'phase', serieMatcherPredicate(row)) + row.created = getSeriesValue(asyncRowData, 'created', serieMatcherPredicate(row)) const alerts = getAllSeries(asyncRowData, 'alerts', serieMatcherPredicate(row)) row.alerts = alerts; diff --git a/src/pages/Workloads/tabs/Pods/Queries.ts b/src/pages/Workloads/tabs/Pods/Queries.ts index fd964ba..724815e 100644 --- a/src/pages/Workloads/tabs/Pods/Queries.ts +++ b/src/pages/Workloads/tabs/Pods/Queries.ts @@ -108,6 +108,33 @@ function createAlertsQuery(cluster?: string, pods?: string) { ` } +function createCreatedQuery(cluster?: string, pods?: string) { + return `max( + ${Metrics.kubePodCreated.name}{ + ${pods ? `${Metrics.kubePodCreated.labels.pod}=~"${pods}",` : ''} + cluster="${cluster}" + } + ) by ( + ${Metrics.kubePodCreated.labels.pod}, + ${Metrics.kubePodCreated.labels.namespace}, + cluster + )` +} + +function createStatusQuery(cluster?: string, pods?: string) { + return `max( + ${Metrics.kubePodStatusPhase.name}{ + ${pods ? `${Metrics.kubePodStatusPhase.labels.pod}=~"${pods}",` : ''} + cluster="${cluster}" + } == 1 + ) by ( + ${Metrics.kubePodStatusPhase.labels.pod}, + ${Metrics.kubePodStatusPhase.labels.namespace}, + ${Metrics.kubePodStatusPhase.labels.phase}, + cluster + )` +} + export function createRootQuery( staticLabelFilters: LabelFilters, variableSet: SceneVariableSet | SceneVariables, @@ -132,6 +159,12 @@ export function createRootQuery( if (remoteSort) { sortFn = sorting.direction === 'asc' ? 'sort' : 'sort_desc' switch (sorting.columnId) { + case 'created': { + sortQuery = ` + * on (${onLabels}) group_right(${carryOverLabels}) + ${createCreatedQuery('$cluster')}` + break; + } case 'alerts': { sortQuery = ` * on (${onLabels}) group_right(${carryOverLabels}) @@ -256,6 +289,18 @@ export function createRowQueries(rows: TableRow[], sceneVariables: SceneVariable const cluster = resolveVariable(sceneVariables, 'cluster'); return [ + { + refId: 'status', + expr: createStatusQuery(cluster?.toString(), pods), + instant: true, + format: 'table' + }, + { + refId: 'created', + expr: createCreatedQuery(cluster?.toString(), pods), + instant: true, + format: 'table' + }, { refId: 'alerts', expr: createAlertsQuery(cluster?.toString(), pods), diff --git a/src/pages/Workloads/tabs/Pods/types.ts b/src/pages/Workloads/tabs/Pods/types.ts index 6304aaf..cb7b49c 100644 --- a/src/pages/Workloads/tabs/Pods/types.ts +++ b/src/pages/Workloads/tabs/Pods/types.ts @@ -12,6 +12,8 @@ export interface TableRow { node: string; host_ip: string; alerts: PodAlert[]; + created: number; + status: string; containers: { total: number; ready: number;