From c5b88ef2d27f1fc8100711401457c9b89279be0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 11 Oct 2026 09:44:28 +0200 Subject: [PATCH] mixin: make dashboard UID, title, description and tags configurable (#2672) Co-authored-by: Claude Signed-off-by: Claude --- contrib/mixin/README.md | 19 ++++++++++++++++++- contrib/mixin/config.libsonnet | 7 +++++++ .../dashboards/windows-exporter.libsonnet | 15 ++++++--------- contrib/mixin/tests/dashboard.test.jsonnet | 11 +++++++++++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/contrib/mixin/README.md b/contrib/mixin/README.md index 46c6b299..8e2f1108 100644 --- a/contrib/mixin/README.md +++ b/contrib/mixin/README.md @@ -258,7 +258,24 @@ queries, IDs, variables, annotations, transformations, and tab/row layout. `mise run check-dashboards` regenerates it and runs `git diff --exit-code`, displaying any drift. CI runs that check before the mixin tests. The dashboard uses its own variables for selectors; from `_config` it reads only `collectors`, -`enableFleetTab` and `enableOverviewTab`. +`enableFleetTab`, `enableOverviewTab` and the dashboard metadata below. + +### Metadata + +`dashboardUID`, `dashboardTitle`, `dashboardDescription` and `dashboardTags` +set the dashboard's UID (`metadata.name`), title, description and tags. Give a +customized dashboard its own UID so it can be imported next to the sample +dashboard instead of replacing it: + +```jsonnet +(import 'mixin.libsonnet') { + _config+:: { + dashboardUID: 'windows-compact', + dashboardTitle: 'Windows (compact)', + dashboardTags+: ['compact'], + }, +}.grafanaDashboards['windows-exporter.json'] +``` ### Collectors diff --git a/contrib/mixin/config.libsonnet b/contrib/mixin/config.libsonnet index e8ac85e3..af6bf25e 100644 --- a/contrib/mixin/config.libsonnet +++ b/contrib/mixin/config.libsonnet @@ -11,6 +11,13 @@ // Requires the time collector with its ntp subcollector enabled. enableTime: false, + // Grafana dashboard metadata. dashboardUID is the v2 metadata.name; change + // it to import the dashboard next to the sample one. + dashboardUID: 'Kdaassddw', + dashboardTitle: 'Windows Exporter', + dashboardDescription: 'Fleet overview and per-host details for Windows hosts monitored by windows_exporter.', + dashboardTags: ['prometheus', 'windows', 'windows_exporter'], + // Dashboard tabs that don't belong to a single collector. Turn them off // for a compact dashboard with only the collector tabs. enableFleetTab: true, diff --git a/contrib/mixin/dashboards/windows-exporter.libsonnet b/contrib/mixin/dashboards/windows-exporter.libsonnet index 746176ae..2d5b02f5 100644 --- a/contrib/mixin/dashboards/windows-exporter.libsonnet +++ b/contrib/mixin/dashboards/windows-exporter.libsonnet @@ -1,9 +1,10 @@ local b = import 'builders.libsonnet'; local dashboard = b.dashboard; -// config.collectors selects the collectors the dashboard renders, and +// config.collectors selects the collectors the dashboard renders, // config.enableFleetTab and config.enableOverviewTab the tabs across -// collectors, see config.libsonnet. +// collectors, and config.dashboard* its UID, title, description and tags, see +// config.libsonnet. function(config) local known = std.objectFields((import '../config.libsonnet')._config.collectors); local unknown = std.setDiff(std.objectFields(config.collectors), known); @@ -39,9 +40,9 @@ function(config) local panelNames = std.flattenArrays([std.objectFields(tab.elements) for tab in tabs]); assert std.length(panelNames) == std.length(std.set(panelNames)) : 'Panel IDs must be unique across tabs'; - dashboard.new('Kdaassddw', 'Windows Exporter') + dashboard.new(config.dashboardUID, config.dashboardTitle) + dashboard.spec.withCursorSync('Crosshair') - + dashboard.spec.withDescription('Fleet overview and per-host details for Windows hosts monitored by windows_exporter.') + + dashboard.spec.withDescription(config.dashboardDescription) + dashboard.spec.withEditable(true) + dashboard.spec.withLinks([ { @@ -59,11 +60,7 @@ function(config) ]) + dashboard.spec.withLiveNow(false) + dashboard.spec.withPreload(false) - + dashboard.spec.withTags([ - 'prometheus', - 'windows', - 'windows_exporter', - ]) + + dashboard.spec.withTags(config.dashboardTags) + dashboard.spec.withTimeSettings({ autoRefresh: '1m', autoRefreshIntervals: [ diff --git a/contrib/mixin/tests/dashboard.test.jsonnet b/contrib/mixin/tests/dashboard.test.jsonnet index 7aa33bbd..ef5236bd 100644 --- a/contrib/mixin/tests/dashboard.test.jsonnet +++ b/contrib/mixin/tests/dashboard.test.jsonnet @@ -44,6 +44,17 @@ local expect(name, want) = assert results[name] == want : name + ': got ' + std.manifestJson(results[name]); true; +local metadata = render(function(collectors) collectors, { + dashboardUID: 'custom-uid', + dashboardTitle: 'Custom title', + dashboardDescription: 'Custom description', + dashboardTags+: ['custom'], +}); +assert metadata.metadata.name == 'custom-uid' : 'metadata: got UID ' + metadata.metadata.name; +assert metadata.spec.title == 'Custom title' : 'metadata: got title ' + metadata.spec.title; +assert metadata.spec.description == 'Custom description' : 'metadata: got description ' + metadata.spec.description; +assert metadata.spec.tags == ['prometheus', 'windows', 'windows_exporter', 'custom'] : 'metadata: got tags ' + std.manifestJson(metadata.spec.tags); + assert std.length(std.objectFields(results.all)) == 15 : 'all: got ' + std.join(', ', std.objectFields(results.all)); assert expect('defaults', { CPU: ['Summary', 'Utilization', 'Scheduling', 'System calls and frequency'],