-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Basic table views for ingresses and services
- Loading branch information
1 parent
5a3349f
commit 62e5a98
Showing
13 changed files
with
470 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { | ||
SceneApp, | ||
SceneAppPage, | ||
VariableValueSelectors, | ||
SceneControlsSpacer, | ||
SceneTimePicker, | ||
SceneRefreshPicker, | ||
} from '@grafana/scenes'; | ||
import { ROUTES } from '../../constants'; | ||
import React, { useMemo } from 'react'; | ||
import { prefixRoute } from 'utils/utils.routing'; | ||
import { usePluginProps } from 'utils/utils.plugin'; | ||
import { createTimeRange, createTopLevelVariables } from '../../common/variableHelpers'; | ||
import { getIngressesScene } from './tabs/Ingresses/Ingresses'; | ||
import { getServicesScene } from './tabs/Services/Services'; | ||
|
||
function getScene({ datasource }: { datasource: string }) { | ||
|
||
const variables = createTopLevelVariables({ datasource }) | ||
const timeRange = createTimeRange() | ||
|
||
return new SceneApp({ | ||
pages: [ | ||
new SceneAppPage({ | ||
title: 'Network', | ||
url: prefixRoute(`${ROUTES.Network}`), | ||
$timeRange: timeRange, | ||
controls: [ | ||
new VariableValueSelectors({}), | ||
new SceneControlsSpacer(), | ||
new SceneTimePicker({ isOnCanvas: true }), | ||
new SceneRefreshPicker({ | ||
intervals: ['5s', '1m', '1h'], | ||
isOnCanvas: true, | ||
}), | ||
], | ||
$variables: variables, | ||
tabs: [ | ||
new SceneAppPage({ | ||
title: 'Ingresses', | ||
url: prefixRoute(`${ROUTES.Network}/ingresses`), | ||
getScene: getIngressesScene, | ||
}), | ||
new SceneAppPage({ | ||
title: 'Services', | ||
url: prefixRoute(`${ROUTES.Network}/services`), | ||
getScene: getServicesScene, | ||
}), | ||
], | ||
getScene: getIngressesScene, | ||
}), | ||
] | ||
}) | ||
} | ||
|
||
export const Network = () => { | ||
const props = usePluginProps(); | ||
const scene = useMemo(() => getScene({ | ||
datasource: props?.meta.jsonData?.datasource || 'prometheus', | ||
}), [props?.meta.jsonData?.datasource]); | ||
|
||
return <scene.Component model={scene} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './Network' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { | ||
EmbeddedScene, | ||
SceneFlexLayout, | ||
SceneFlexItem, | ||
SceneVariableSet, | ||
TextBoxVariable, | ||
VariableValueSelectors, | ||
} from '@grafana/scenes'; | ||
import { createNamespaceVariable } from 'common/variableHelpers'; | ||
import { IngressesQueryBuilder } from './Queries'; | ||
import { TableRow } from './types'; | ||
import { AsyncTable, Column } from 'components/AsyncTable'; | ||
import { SortingState } from 'common/sortingHelpers'; | ||
import { ROUTES } from '../../../../constants'; | ||
import { prefixRoute } from 'utils/utils.routing'; | ||
|
||
const columns: Array<Column<TableRow>> = [ | ||
{ | ||
id: 'ingress', | ||
header: 'INGRESS', | ||
cellType: 'link', | ||
cellProps: { | ||
urlBuilder: (row: TableRow) => prefixRoute(`${ROUTES.Network}/ingress/${row.namespace}/${row.ingress}`), | ||
}, | ||
sortingConfig: { | ||
enabled: true, | ||
type: 'label', | ||
local: true | ||
} | ||
}, | ||
{ | ||
id: 'namespace', | ||
header: 'NAMESPACE', | ||
cellType: 'link', | ||
cellProps: { | ||
urlBuilder: (row: TableRow) => prefixRoute(`${ROUTES.Clusters}/namespaces/${row.namespace}`), | ||
}, | ||
sortingConfig: { | ||
enabled: true, | ||
type: 'label', | ||
local: true | ||
} | ||
}, | ||
{ | ||
id: 'ingressclass', | ||
header: 'CLASS', | ||
sortingConfig: { | ||
enabled: true, | ||
type: 'value', | ||
local: false | ||
} | ||
}, | ||
{ | ||
id: 'controller', | ||
header: 'CONTROLLER', | ||
sortingConfig: { | ||
enabled: true, | ||
type: 'value', | ||
local: false | ||
} | ||
}, | ||
] | ||
|
||
function asyncDataRowMapper(row: TableRow, asyncRowData: Record<string, number[]>) { } | ||
|
||
function createRowId(row: TableRow) { | ||
return `${row.namespace}/${row.ingress}`; | ||
} | ||
|
||
export function getIngressesScene() { | ||
|
||
const variables = new SceneVariableSet({ | ||
variables: [ | ||
createNamespaceVariable(), | ||
new TextBoxVariable({ | ||
name: 'search', | ||
label: 'Search', | ||
value: '', | ||
}) | ||
], | ||
}); | ||
|
||
const defaultSorting: SortingState = { | ||
columnId: 'ingress', | ||
direction: 'asc', | ||
} | ||
|
||
const queryBuilder = new IngressesQueryBuilder(); | ||
|
||
return new EmbeddedScene({ | ||
$variables: variables, | ||
controls: [ | ||
new VariableValueSelectors({}) | ||
], | ||
body: new SceneFlexLayout({ | ||
children: [ | ||
new SceneFlexItem({ | ||
width: '100%', | ||
height: '100%', | ||
body: new AsyncTable<TableRow>({ | ||
columns: columns, | ||
$data: queryBuilder.rootQueryBuilder(variables, defaultSorting), | ||
createRowId: createRowId, | ||
queryBuilder: queryBuilder, | ||
asyncDataRowMapper: asyncDataRowMapper, | ||
sorting: defaultSorting, | ||
}), | ||
}), | ||
], | ||
}), | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { SceneVariableSet, SceneVariables, SceneQueryRunner } from "@grafana/scenes"; | ||
import { SortingState } from "common/sortingHelpers"; | ||
import { ColumnSortingConfig, QueryBuilder } from "components/AsyncTable"; | ||
import { TableRow } from "./types"; | ||
import { PromQL } from "common/promql"; | ||
import { Metrics } from "metrics/metrics"; | ||
|
||
export class IngressesQueryBuilder implements QueryBuilder<TableRow> { | ||
rootQueryBuilder(variables: SceneVariableSet | SceneVariables, sorting: SortingState, sortingConfig?: ColumnSortingConfig<TableRow> | undefined) { | ||
|
||
const baseQuery = PromQL.group( | ||
PromQL.parenthesis( | ||
PromQL.metric(Metrics.kubeIngressPath.name) | ||
.withLabelEquals('cluster', '$cluster') | ||
.withLabelMatches('namespace', '$namespace') | ||
// Get ingress class from kube_ingress_info based on ingress and namespace | ||
.multiply() | ||
.on([ | ||
'ingress', | ||
'namespace', | ||
]) | ||
.groupLeft( | ||
[ | ||
Metrics.kubeIngressInfo.labels.ingressClass, | ||
], | ||
PromQL.metric(Metrics.kubeIngressInfo.name) | ||
.withLabelEquals('cluster', '$cluster') | ||
) | ||
) | ||
// Get controller from kube_ingressclass_info based on ingress class | ||
.multiply() | ||
.on([ | ||
'ingressclass', | ||
]) | ||
.groupLeft( | ||
[ | ||
'controller', | ||
], | ||
PromQL.metric(Metrics.kubeIngressClassInfo.name) | ||
.withLabelEquals('cluster', '$cluster') | ||
) | ||
).by([ | ||
'namespace', | ||
'ingress', | ||
'ingressclass', | ||
'controller', | ||
]) | ||
|
||
return new SceneQueryRunner({ | ||
datasource: { | ||
uid: '$datasource', | ||
type: 'prometheus', | ||
}, | ||
queries: [ | ||
{ | ||
refId: 'ingresses', | ||
expr: baseQuery.stringify(), | ||
instant: true, | ||
format: 'table' | ||
}, | ||
], | ||
}) | ||
} | ||
|
||
rowQueryBuilder(rows: TableRow[], variables: SceneVariableSet | SceneVariables) { | ||
return [] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface TableRow { | ||
ingress: string; | ||
namespace: string; | ||
controller: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { SceneVariableSet, SceneVariables, SceneQueryRunner } from "@grafana/scenes"; | ||
import { SortingState } from "common/sortingHelpers"; | ||
import { ColumnSortingConfig, QueryBuilder } from "components/AsyncTable"; | ||
import { TableRow } from "./types"; | ||
import { PromQL } from "common/promql"; | ||
import { Metrics } from "metrics/metrics"; | ||
|
||
export class ServicesQueryBuilder implements QueryBuilder<TableRow> { | ||
rootQueryBuilder(variables: SceneVariableSet | SceneVariables, sorting: SortingState, sortingConfig?: ColumnSortingConfig<TableRow> | undefined) { | ||
|
||
const baseQuery = PromQL.group( | ||
PromQL.parenthesis( | ||
PromQL.metric(Metrics.kubeServiceInfo.name) | ||
.withLabelEquals('cluster', '$cluster') | ||
.withLabelMatches('namespace', '$namespace') | ||
// Get ingress class from kube_ingress_info based on ingress and namespace | ||
.multiply() | ||
.on([ | ||
'service', | ||
'namespace', | ||
]) | ||
.groupLeft( | ||
[ | ||
Metrics.kubeServiceSpecType.labels.type, | ||
], | ||
PromQL.metric(Metrics.kubeServiceSpecType.name) | ||
.withLabelEquals('cluster', '$cluster') | ||
) | ||
) | ||
).by([ | ||
'namespace', | ||
'service', | ||
'type', | ||
]) | ||
|
||
return new SceneQueryRunner({ | ||
datasource: { | ||
uid: '$datasource', | ||
type: 'prometheus', | ||
}, | ||
queries: [ | ||
{ | ||
refId: 'services', | ||
expr: baseQuery.stringify(), | ||
instant: true, | ||
format: 'table' | ||
}, | ||
], | ||
}) | ||
} | ||
|
||
rowQueryBuilder(rows: TableRow[], variables: SceneVariableSet | SceneVariables) { | ||
return [] | ||
} | ||
} |
Oops, something went wrong.