From aeb745309d0dcea202dd8beb5726e73ecb6343f8 Mon Sep 17 00:00:00 2001 From: Tiit Hansen Date: Sat, 25 May 2024 11:21:39 +0300 Subject: [PATCH] feat: Allow datasource name pattern to be configured from app settings page Include datasource selection on every page where it is relevant --- README.md | 4 +- src/components/AppConfig/AppConfig.tsx | 91 ++++------ src/components/Routes/Routes.tsx | 5 + src/components/testIds.ts | 2 +- src/pages/Clusters/Clusters.tsx | 23 ++- src/pages/Clusters/tabs/Nodes/Nodes.tsx | 9 +- src/pages/Workloads/Workloads.tsx | 48 +++-- .../ContainersTable/ContainersTable.tsx | 9 +- .../Workloads/components/ResourceLabels.tsx | 8 +- src/pages/Workloads/pages/PodPage.tsx | 18 +- .../Workloads/tabs/CronJobs/CronJobs.tsx | 4 +- .../Workloads/tabs/DaemonSets/DaemonSets.tsx | 4 +- .../tabs/Deployments/Deployments.tsx | 9 +- src/pages/Workloads/tabs/Jobs/Jobs.tsx | 4 +- .../Workloads/tabs/Overview/Overview.tsx | 4 +- .../Workloads/tabs/Pods/PodExpandedRow.tsx | 4 +- src/pages/Workloads/tabs/Pods/Pods.tsx | 168 +++++++++--------- .../tabs/StatefulSets/StatefulSets.tsx | 4 +- src/pages/Workloads/variables.ts | 14 -- 19 files changed, 227 insertions(+), 205 deletions(-) delete mode 100644 src/pages/Workloads/variables.ts diff --git a/README.md b/README.md index a6c2faf..0a8202c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ This plugin relies on presence of default kube-state-metrics and node-exporter m ### Current limitations -* Datasource is not configurable yet and it is hardcoded with a name `prometheus`. * It expects the presence of `cluster` label on all the metrics. ### Screenshots @@ -46,4 +45,5 @@ If you have any feature requests, improvements or suggestions, please create an 2. Run `npm install` to install the dependencies. 3. Run `npm run dev` to start development server. 4. Run `docker-compose up` to start Grafana with the plugin. -5. Open Grafana at `http://localhost:3000/a/k8s-app/workloads`. +5. Navigate to `http://localhost:3000/plugins/k8s-app` and configure the plugins datasource. +6. Open Grafana at `http://localhost:3000/a/k8s-app/workloads`. diff --git a/src/components/AppConfig/AppConfig.tsx b/src/components/AppConfig/AppConfig.tsx index 8ad9e8e..c056f2c 100644 --- a/src/components/AppConfig/AppConfig.tsx +++ b/src/components/AppConfig/AppConfig.tsx @@ -1,5 +1,5 @@ import React, { useState, ChangeEvent } from 'react'; -import { Button, Field, Input, useStyles2, FieldSet, SecretInput } from '@grafana/ui'; +import { Button, Field, Input, useStyles2, FieldSet } from '@grafana/ui'; import { PluginConfigPageProps, AppPluginMeta, PluginMeta, GrafanaTheme2 } from '@grafana/data'; import { getBackendSrv, locationService } from '@grafana/runtime'; import { css } from '@emotion/css'; @@ -7,19 +7,20 @@ import { testIds } from '../testIds'; import { lastValueFrom } from 'rxjs'; export type JsonData = { - apiUrl?: string; - isApiKeySet?: boolean; + datasource?: string; + isclusterLabelEnabled?: boolean; + clusterLabel?: string; }; type State = { - // The URL to reach our custom API. - apiUrl: string; - // Tells us if the API key secret is set. - // Set to `true` ONLY if it has already been set and haven't been changed. - // (We unfortunately need an auxiliray variable for this, as `secureJsonData` is never exposed to the browser after it is set) - isApiKeySet: boolean; - // An secret key for our custom API. - apiKey: string; + // The regex pattern to match datasource + datasource: string; + + // Enable cluster label + isClusterLabelEnabled: boolean; + + // Cluster label name + clusterLabel: string; }; interface Props extends PluginConfigPageProps> {} @@ -28,29 +29,29 @@ export const AppConfig = ({ plugin }: Props) => { const s = useStyles2(getStyles); const { enabled, pinned, jsonData } = plugin.meta; const [state, setState] = useState({ - apiUrl: jsonData?.apiUrl || '', - apiKey: '', - isApiKeySet: Boolean(jsonData?.isApiKeySet), + datasource: jsonData?.datasource || 'prometheus', + isClusterLabelEnabled: true, + clusterLabel: jsonData?.clusterLabel || 'cluster', }); - const onResetApiKey = () => + const onChangeDatasource = (event: ChangeEvent) => { setState({ ...state, - apiKey: '', - isApiKeySet: false, + datasource: event.target.value.trim(), }); + }; - const onChangeApiKey = (event: ChangeEvent) => { + const onChangeClusterLabel = (event: ChangeEvent) => { setState({ ...state, - apiKey: event.target.value.trim(), - }); - }; + clusterLabel: event.target.value.trim(), + }) + } - const onChangeApiUrl = (event: ChangeEvent) => { + const onChangeClusterLabelEnabled = (event: ChangeEvent) => { setState({ ...state, - apiUrl: event.target.value.trim(), + isClusterLabelEnabled: Boolean(event.target.value.trim()), }); }; @@ -99,31 +100,17 @@ export const AppConfig = ({ plugin }: Props) => { {/* CUSTOM SETTINGS */} -
- {/* API Key */} - - - - +
{/* API Url */} - + @@ -136,21 +123,13 @@ export const AppConfig = ({ plugin }: Props) => { enabled, pinned, jsonData: { - apiUrl: state.apiUrl, - isApiKeySet: true, + datasource: state.datasource, }, - // This cannot be queried later by the frontend. - // We don't want to override it in case it was set previously and left untouched now. - secureJsonData: state.isApiKeySet - ? undefined - : { - apiKey: state.apiKey, - }, }) } - disabled={Boolean(!state.apiUrl || (!state.isApiKeySet && !state.apiKey))} + disabled={Boolean(!state.datasource)} > - Save API settings + Save
diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx index 0732f9f..9b6ccfb 100644 --- a/src/components/Routes/Routes.tsx +++ b/src/components/Routes/Routes.tsx @@ -4,8 +4,13 @@ import { Clusters } from '../../pages/Clusters'; import { Workloads } from '../../pages/Workloads'; import { prefixRoute } from '../../utils/utils.routing'; import { ROUTES } from '../../constants'; +import { usePluginProps } from 'utils/utils.plugin'; export const Routes = () => { + + const props = usePluginProps(); + console.log(props); + return ( diff --git a/src/components/testIds.ts b/src/components/testIds.ts index c17eb22..05d2116 100644 --- a/src/components/testIds.ts +++ b/src/components/testIds.ts @@ -1,7 +1,7 @@ export const testIds = { appConfig: { container: 'data-testid ac-container', - apiKey: 'data-testid ac-api-key', + datasource: 'data-testid ac-datasource', apiUrl: 'data-testid ac-api-url', submit: 'data-testid ac-submit-form', }, diff --git a/src/pages/Clusters/Clusters.tsx b/src/pages/Clusters/Clusters.tsx index c629598..aaddb99 100644 --- a/src/pages/Clusters/Clusters.tsx +++ b/src/pages/Clusters/Clusters.tsx @@ -5,27 +5,41 @@ import { SceneControlsSpacer, SceneTimePicker, SceneRefreshPicker, + SceneVariableSet, + DataSourceVariable, + VariableValueSelectors, } from '@grafana/scenes'; import { ROUTES } from '../../constants'; import React, { useMemo } from 'react'; import { prefixRoute } from 'utils/utils.routing'; import { getOverviewScene } from './tabs/Overview/Overview'; import { getNodesScene } from './tabs/Nodes/Nodes'; +import { usePluginProps } from 'utils/utils.plugin'; const timeRange = new SceneTimeRange({ from: 'now-1h', to: 'now', }); -function getScene() { - +function getScene({ datasource }: { datasource: string }) { return new SceneApp({ pages: [ new SceneAppPage({ title: 'Clusters', url: prefixRoute(`${ROUTES.Clusters}`), $timeRange: timeRange, + $variables: new SceneVariableSet({ + variables: [ + new DataSourceVariable({ + name: 'datasource', + label: 'Datasource', + pluginId: 'prometheus', + regex: datasource, + }), + ], + }), controls: [ + new VariableValueSelectors({}), new SceneControlsSpacer(), new SceneTimePicker({ isOnCanvas: true }), new SceneRefreshPicker({ @@ -52,7 +66,10 @@ function getScene() { } export const Clusters = () => { - const scene = useMemo(() => getScene(), []); + const props = usePluginProps(); + const scene = useMemo(() => getScene({ + datasource: props?.meta.jsonData?.datasource || 'prometheus', + }), [props?.meta.jsonData?.datasource]); return ; }; diff --git a/src/pages/Clusters/tabs/Nodes/Nodes.tsx b/src/pages/Clusters/tabs/Nodes/Nodes.tsx index cf14b9b..7ef1ccd 100644 --- a/src/pages/Clusters/tabs/Nodes/Nodes.tsx +++ b/src/pages/Clusters/tabs/Nodes/Nodes.tsx @@ -23,12 +23,13 @@ import { getSeriesValue } from 'pages/Workloads/seriesHelpers'; import { CellProps } from 'react-table'; import { NodeMemoryCell } from './NodeMemoryCell'; import { NodeCPUCell } from './NodeCPUCell'; +import { resolveVariable } from 'pages/Workloads/variableHelpers'; const clusterVariable = new QueryVariable({ name: 'cluster', label: 'Cluster', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -45,7 +46,7 @@ const searchVariable = new TextBoxVariable({ const nodesQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -171,9 +172,11 @@ class TableViz extends SceneObjectBase { return; } + const datasource = resolveVariable(sceneVariables, 'datasource'); + asyncQueryRunner({ datasource: { - uid: 'prometheus', + uid: datasource?.toString(), type: 'prometheus', }, diff --git a/src/pages/Workloads/Workloads.tsx b/src/pages/Workloads/Workloads.tsx index 389e9a4..3a34d87 100644 --- a/src/pages/Workloads/Workloads.tsx +++ b/src/pages/Workloads/Workloads.tsx @@ -7,6 +7,8 @@ import { SceneControlsSpacer, SceneTimePicker, SceneRefreshPicker, + DataSourceVariable, + QueryVariable, } from '@grafana/scenes'; import { ROUTES } from '../../constants'; import React, { useMemo } from 'react'; @@ -19,20 +21,37 @@ import { getPodPage } from './pages/PodPage'; import { getCronJobsScene } from './tabs/CronJobs/CronJobs'; import { getJobsScene } from './tabs/Jobs/Jobs'; import { getOverviewScene } from './tabs/Overview/Overview'; -import { clusterVariable } from './variables'; +import { usePluginProps } from 'utils/utils.plugin'; -const variables = new SceneVariableSet({ - variables: [ - clusterVariable, - ] -}) +function getScene({ datasource }: { datasource: string }) { -const timeRange = new SceneTimeRange({ - from: 'now-1h', - to: 'now', -}); + const variables = new SceneVariableSet({ + variables: [ + new DataSourceVariable({ + name: 'datasource', + label: 'Datasource', + pluginId: 'prometheus', + regex: datasource, + }), + new QueryVariable({ + name: 'cluster', + label: 'Cluster', + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + query: { + refId: 'cluster', + query: 'label_values(kube_namespace_labels, cluster)', + }, + }), + ], + }) -function getScene() { + const timeRange = new SceneTimeRange({ + from: 'now-1h', + to: 'now', + }); return new SceneApp({ pages: [ @@ -92,7 +111,7 @@ function getScene() { { routePath: prefixRoute(`${ROUTES.Workloads}/pods/:name`), getPage(routeMatch, parent) { - return getPodPage(routeMatch, parent, variables.clone(), timeRange.clone()); + return getPodPage(routeMatch, parent); } }, @@ -103,7 +122,10 @@ function getScene() { } export const Workloads = () => { - const scene = useMemo(() => getScene(), []); + const props = usePluginProps(); + const scene = useMemo(() => getScene({ + datasource: props?.meta.jsonData?.datasource || 'prometheus', + }), [props?.meta.jsonData?.datasource]); return ; }; diff --git a/src/pages/Workloads/components/ContainersTable/ContainersTable.tsx b/src/pages/Workloads/components/ContainersTable/ContainersTable.tsx index b34d665..f186073 100644 --- a/src/pages/Workloads/components/ContainersTable/ContainersTable.tsx +++ b/src/pages/Workloads/components/ContainersTable/ContainersTable.tsx @@ -23,12 +23,13 @@ import { RestartsCellBuilder } from '../../components/RestartsCell'; import { createRowQueries } from './Queries'; import { getSeriesValue } from 'pages/Workloads/seriesHelpers'; import { LabelFilters, asyncQueryRunner } from 'pages/Workloads/queryHelpers'; +import { resolveVariable } from 'pages/Workloads/variableHelpers'; const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -55,7 +56,7 @@ function createRootQuery(staticLabelFilters: LabelFilters, variableSet: SceneVar return new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -205,9 +206,11 @@ class TableViz extends SceneObjectBase { return; } + const datasource = resolveVariable(sceneVariables, 'datasource') + asyncQueryRunner({ datasource: { - uid: 'prometheus', + uid: datasource?.toString(), type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/components/ResourceLabels.tsx b/src/pages/Workloads/components/ResourceLabels.tsx index 3d7d2d2..33e9a98 100644 --- a/src/pages/Workloads/components/ResourceLabels.tsx +++ b/src/pages/Workloads/components/ResourceLabels.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { SceneComponentProps, SceneObjectBase, SceneObjectState, SceneQueryRunner, sceneGraph } from "@grafana/scenes"; import { LabelFilters, serializeLabelFilters } from '../queryHelpers'; -import { DataFrameView, GrafanaTheme2 } from '@grafana/data'; +import { DataFrameView, GrafanaTheme2, LoadingState } from '@grafana/data'; import { css } from '@emotion/css'; import { useStyles2 } from '@grafana/ui'; @@ -96,7 +96,9 @@ class ResourceLabels extends SceneObjectBase { const result: Label[] = []; - if (data) { + console.log(data) + + if (data && data.state === LoadingState.Done) { const df = new DataFrameView(data.series[0] || []) const frames = df.toArray() @@ -154,7 +156,7 @@ export function createResourceLabels(resourceKind: string, labelFilters: LabelFi key: `ResourceLabels-${resourceKind}`, $data: new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/pages/PodPage.tsx b/src/pages/Workloads/pages/PodPage.tsx index 7876c8f..bd6036b 100644 --- a/src/pages/Workloads/pages/PodPage.tsx +++ b/src/pages/Workloads/pages/PodPage.tsx @@ -1,4 +1,4 @@ -import { EmbeddedScene, PanelBuilders, SceneAppPage, SceneAppPageLike, SceneControlsSpacer, SceneFlexItem, SceneFlexLayout, SceneGridItem, SceneGridLayout, SceneGridRow, SceneQueryRunner, SceneRefreshPicker, SceneRouteMatch, SceneTimePicker, SceneTimeRange, SceneVariableSet, VariableValueSelectors } from "@grafana/scenes"; +import { EmbeddedScene, PanelBuilders, SceneAppPage, SceneAppPageLike, SceneControlsSpacer, SceneFlexItem, SceneFlexLayout, SceneQueryRunner, SceneRefreshPicker, SceneRouteMatch, SceneTimePicker, SceneTimeRange, SceneVariableSet, VariableValueSelectors, sceneGraph } from "@grafana/scenes"; import { ROUTES } from "../../../constants"; import { prefixRoute } from "utils/utils.routing"; import { GraphTransform } from "@grafana/schema"; @@ -12,7 +12,7 @@ function getMemoryPanel(pod: string) { .setUnit('bytes') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -63,7 +63,7 @@ function getCPUPanel(pod: string) { .setTitle('CPU') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -108,7 +108,7 @@ function getNetworkPanel(pod: string) { .setUnit('bytes') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -167,7 +167,7 @@ function getCPUThrottling(pod: string) { .setUnit('percent') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -211,6 +211,7 @@ function getCPUThrottling(pod: string) { function getScene(pod: string) { return new EmbeddedScene({ controls: [ + new VariableValueSelectors({}), new SceneControlsSpacer(), new SceneTimePicker({ isOnCanvas: true }), new SceneRefreshPicker({ @@ -272,13 +273,14 @@ function getScene(pod: string) { }) } -export function getPodPage(routeMatch: SceneRouteMatch, parent: SceneAppPageLike, variables: SceneVariableSet, timeRange: SceneTimeRange) { +export function getPodPage(routeMatch: SceneRouteMatch, parent: SceneAppPageLike) { return new SceneAppPage({ title: `Pod - ${routeMatch.params.name}`, titleIcon: 'dashboard', - $variables: variables, - $timeRange: timeRange, + $variables: sceneGraph.getVariables(parent).clone(), + $timeRange: sceneGraph.getTimeRange(parent).clone(), url: prefixRoute(`${ROUTES.Workloads}/pods/${routeMatch.params.name}`), getScene: () => getScene(routeMatch.params.name), + getParentPage: () => parent, }) } diff --git a/src/pages/Workloads/tabs/CronJobs/CronJobs.tsx b/src/pages/Workloads/tabs/CronJobs/CronJobs.tsx index 8e7e9dc..d04f10d 100644 --- a/src/pages/Workloads/tabs/CronJobs/CronJobs.tsx +++ b/src/pages/Workloads/tabs/CronJobs/CronJobs.tsx @@ -21,7 +21,7 @@ const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -42,7 +42,7 @@ const searchVariable = new TextBoxVariable({ const cronJobsQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/tabs/DaemonSets/DaemonSets.tsx b/src/pages/Workloads/tabs/DaemonSets/DaemonSets.tsx index c335be0..ce769eb 100644 --- a/src/pages/Workloads/tabs/DaemonSets/DaemonSets.tsx +++ b/src/pages/Workloads/tabs/DaemonSets/DaemonSets.tsx @@ -22,7 +22,7 @@ const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -43,7 +43,7 @@ const searchVariable = new TextBoxVariable({ const daemonSetsQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/tabs/Deployments/Deployments.tsx b/src/pages/Workloads/tabs/Deployments/Deployments.tsx index 696d12a..15a647d 100644 --- a/src/pages/Workloads/tabs/Deployments/Deployments.tsx +++ b/src/pages/Workloads/tabs/Deployments/Deployments.tsx @@ -23,12 +23,13 @@ import { asyncQueryRunner } from 'pages/Workloads/queryHelpers'; import { getSeriesValue } from 'pages/Workloads/seriesHelpers'; import { buildExpandedRowScene } from './DeploymentExpandedRow'; import { LinkCell } from 'pages/Workloads/components/LinkCell'; +import { resolveVariable } from 'pages/Workloads/variableHelpers'; const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -49,7 +50,7 @@ const searchVariable = new TextBoxVariable({ const deploymentsQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -175,9 +176,11 @@ class TableViz extends SceneObjectBase { return; } + const datasource = resolveVariable(sceneVariables, 'datasource') + asyncQueryRunner({ datasource: { - uid: 'prometheus', + uid: datasource?.toString(), type: 'prometheus', }, diff --git a/src/pages/Workloads/tabs/Jobs/Jobs.tsx b/src/pages/Workloads/tabs/Jobs/Jobs.tsx index 274d19c..ad34323 100644 --- a/src/pages/Workloads/tabs/Jobs/Jobs.tsx +++ b/src/pages/Workloads/tabs/Jobs/Jobs.tsx @@ -21,7 +21,7 @@ const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -42,7 +42,7 @@ const searchVariable = new TextBoxVariable({ const jobsQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/tabs/Overview/Overview.tsx b/src/pages/Workloads/tabs/Overview/Overview.tsx index df000dc..2282c3f 100644 --- a/src/pages/Workloads/tabs/Overview/Overview.tsx +++ b/src/pages/Workloads/tabs/Overview/Overview.tsx @@ -11,7 +11,7 @@ export const getOverviewScene = () => { .setTitle('Nodes') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -31,7 +31,7 @@ export const getOverviewScene = () => { .setTitle('Pods') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/tabs/Pods/PodExpandedRow.tsx b/src/pages/Workloads/tabs/Pods/PodExpandedRow.tsx index 86b9284..edd816b 100644 --- a/src/pages/Workloads/tabs/Pods/PodExpandedRow.tsx +++ b/src/pages/Workloads/tabs/Pods/PodExpandedRow.tsx @@ -15,7 +15,7 @@ export function buildExpandedRowScene(handler: string) { .setUnit('bytes') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -61,7 +61,7 @@ export function buildExpandedRowScene(handler: string) { .setTitle('CPU') .setData(new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/tabs/Pods/Pods.tsx b/src/pages/Workloads/tabs/Pods/Pods.tsx index a39534f..5f6898a 100644 --- a/src/pages/Workloads/tabs/Pods/Pods.tsx +++ b/src/pages/Workloads/tabs/Pods/Pods.tsx @@ -26,80 +26,81 @@ import { LinkCell } from 'pages/Workloads/components/LinkCell'; import { buildExpandedRowScene } from './PodExpandedRow'; import { getSeriesValue } from 'pages/Workloads/seriesHelpers'; import { LabelFilters, asyncQueryRunner } from 'pages/Workloads/queryHelpers'; - -const namespaceVariable = new QueryVariable({ - name: 'namespace', - label: 'Namespace', - datasource: { - uid: 'prometheus', - type: 'prometheus', - }, - query: { - refId: 'namespace', - query: 'label_values(kube_namespace_labels{cluster="$cluster"}, namespace)', - }, - defaultToAll: true, - allValue: '.*', - includeAll: true, - isMulti: true, -}); - -const nodeVariable = new QueryVariable({ - name: 'node', - label: 'Node', - datasource: { - uid: 'prometheus', - type: 'prometheus', - }, - query: { - refId: 'namespace', - query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace"}, node)', - }, - defaultToAll: true, - allValue: '.*', - includeAll: true, - isMulti: true, -}); - -const ownerKindVariable = new QueryVariable({ - name: 'ownerKind', - label: 'Owner kind', - datasource: { - uid: 'prometheus', - type: 'prometheus', - }, - query: { - refId: 'kind', - query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace"}, created_by_kind)', - }, - defaultToAll: true, - allValue: '.*', - includeAll: true, - isMulti: true, -}); - -const ownerNameVariable = new QueryVariable({ - name: 'ownerName', - label: 'Owner name', - datasource: { - uid: 'prometheus', - type: 'prometheus', - }, - query: { - refId: 'name', - query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace", created_by_kind=~"$ownerKind"}, created_by_name)', - }, - defaultToAll: true, - allValue: '.*', - includeAll: true, - isMulti: true, -}); - -const searchVariable = new TextBoxVariable({ - name: 'search', - label: 'Search', - value: '', -}); +import { resolveVariable } from 'pages/Workloads/variableHelpers'; + +function createVariables() { + return [ + new QueryVariable({ + name: 'namespace', + label: 'Namespace', + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + query: { + refId: 'namespace', + query: 'label_values(kube_namespace_labels{cluster="$cluster"}, namespace)', + }, + defaultToAll: true, + allValue: '.*', + includeAll: true, + isMulti: true, + }), + new QueryVariable({ + name: 'node', + label: 'Node', + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + query: { + refId: 'namespace', + query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace"}, node)', + }, + defaultToAll: true, + allValue: '.*', + includeAll: true, + isMulti: true, + }), + new QueryVariable({ + name: 'ownerKind', + label: 'Owner kind', + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + query: { + refId: 'kind', + query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace"}, created_by_kind)', + }, + defaultToAll: true, + allValue: '.*', + includeAll: true, + isMulti: true, + }), + new QueryVariable({ + name: 'ownerName', + label: 'Owner name', + datasource: { + uid: '$datasource', + type: 'prometheus', + }, + query: { + refId: 'name', + query: 'label_values(kube_pod_info{cluster="$cluster", namespace=~"$namespace", created_by_kind=~"$ownerKind"}, created_by_name)', + }, + defaultToAll: true, + allValue: '.*', + includeAll: true, + isMulti: true, + }), + new TextBoxVariable({ + name: 'search', + label: 'Search', + value: '', + }) + ] +} function createRootQuery(staticLabelFilters: LabelFilters, variableSet: SceneVariableSet) { @@ -114,7 +115,7 @@ function createRootQuery(staticLabelFilters: LabelFilters, variableSet: SceneVar return new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ @@ -278,12 +279,13 @@ class TableViz extends SceneObjectBase { return; } + const datasourceVariable = resolveVariable(sceneVariables, 'datasource') + asyncQueryRunner({ datasource: { - uid: 'prometheus', + uid: datasourceVariable?.toString(), type: 'prometheus', }, - queries: [ ...createRowQueries(ids, sceneVariables), ], @@ -307,7 +309,9 @@ class TableViz extends SceneObjectBase { }; } -export const getPodsScene = (staticLabelFilters: LabelFilters, showVariableControls: boolean, createVariables: boolean) => { +const vars = createVariables() + +export const getPodsScene = (staticLabelFilters: LabelFilters, showVariableControls: boolean, shouldCreateVariables: boolean) => { const controls = [] if (showVariableControls) { @@ -315,12 +319,8 @@ export const getPodsScene = (staticLabelFilters: LabelFilters, showVariableContr } const variables = [] - if (createVariables) { - variables.push(namespaceVariable) - variables.push(nodeVariable) - variables.push(ownerKindVariable) - variables.push(ownerNameVariable) - variables.push(searchVariable) + if (shouldCreateVariables) { + variables.push(...vars) } const variableSet = new SceneVariableSet({ diff --git a/src/pages/Workloads/tabs/StatefulSets/StatefulSets.tsx b/src/pages/Workloads/tabs/StatefulSets/StatefulSets.tsx index 8f5f905..2b1491d 100644 --- a/src/pages/Workloads/tabs/StatefulSets/StatefulSets.tsx +++ b/src/pages/Workloads/tabs/StatefulSets/StatefulSets.tsx @@ -22,7 +22,7 @@ const namespaceVariable = new QueryVariable({ name: 'namespace', label: 'Namespace', datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, query: { @@ -43,7 +43,7 @@ const searchVariable = new TextBoxVariable({ const statefulSetsQueryRunner = new SceneQueryRunner({ datasource: { - uid: 'prometheus', + uid: '$datasource', type: 'prometheus', }, queries: [ diff --git a/src/pages/Workloads/variables.ts b/src/pages/Workloads/variables.ts deleted file mode 100644 index 5f3d8fb..0000000 --- a/src/pages/Workloads/variables.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { QueryVariable } from "@grafana/scenes"; - -export const clusterVariable = new QueryVariable({ - name: 'cluster', - label: 'Cluster', - datasource: { - uid: 'prometheus', - type: 'prometheus', - }, - query: { - refId: 'cluster', - query: 'label_values(kube_namespace_labels, cluster)', - } -});