Skip to content

GrafanaDashboard syncing from url and replacing variables on the go #1760

@toporek3112

Description

@toporek3112

Is your feature request related to a problem? Please describe.
As platform engineers me and my collegues want to provide our customers with some standardized dashboards where our customers can only access their target cluster and namespace. For that we created a template dashboard which we store in git. Now we would like to create a kubernetes manifest GrafanaDashboard which takes in a url to the template dashboard json and substitutes some values on the go in the kubernetes manifest. Currently we have to create a seperate json file for each request where we need to change the query by hand. This is error prone and tidiouse if we want to update the "standardized" dashbaord

(If applicable)If your feature request solves a bug please provide a link to the community issue

Describe the solution you'd like
When I create a GrafanaDashboard I would like to be able to substitute some variables in the dashbaord.json. Example

      apiVersion: grafana.integreatly.org/v1beta1
      kind: GrafanaDashboard
      metadata:
        name: customer-dashboard.team-xyz
        namespace: monitoring
      spec:
        folder: Team-xyz
        instanceSelector:
          matchLabels:
            app.kubernetes.io/name: grafana-operator
        resyncPeriod: 10s
        url: https://raw.githubusercontent.com/blabla/dashbaord-template.json
        urlAuthorization:
          basicAuth:
            password:
              name: secret
              key: password
            username:
              name: secret
              key: username
         substituteVars:
           - varName1: "value1"
           - varName2: "value2"

Describe alternatives you've considered
Alternatives are to create a seperate dashboard.json and then a kubernetes manifest of GrafanaDashboard. With the approache described above we could have one central template and multiple GrafanaDashbaord's which synch with that one url and substitute variables on the go.

Additional context
n/a

Existing solutions
n/a

Would be a really nice feature to the operator. Please let me know what you think of this. BR.

Activity

added
enhancementNew feature or request
needs triageIndicates an issue or PR lacks a `triage/foo` label and requires one.
on Nov 14, 2024
KaiseerKenopsia

KaiseerKenopsia commented on Nov 19, 2024

@KaiseerKenopsia

Wouldn't a helm template be enough to solve your problem?

Put your vars into Values and then you can iterate over them with a 'range' loop, golang can iterate well over dicts and lists, so the differing-imported vars can have any yaml structure you want.


Go docs can be hard to understand sometimes so here is a 'range' example:
https://stackoverflow.com/questions/54156119/range-over-string-slice-in-golang-template

If you dig around the templates folder in helm chart, you'll be probably able to reverse engineer the rest

theSuess

theSuess commented on Nov 25, 2024

@theSuess
Collaborator

I've investigated this a bit and found a way to do this which is officially supported by Grafana (albeit, not very well documented).

By using the __inputs field in the Dashboard specification and the /api/dashboards/import endpoint, arbitrary variables can be replaced in a dashboard specification.

I'm open to adding this as a feature to the operator but would like to hear other opinions on this

added
triage/acceptedIndicates an issue or PR is ready to be actively worked on.
and removed
needs triageIndicates an issue or PR lacks a `triage/foo` label and requires one.
on Nov 25, 2024
Hipska

Hipska commented on Apr 3, 2025

@Hipska
Contributor

@theSuess I'm trying to create a dashboard from exported JSON which has constant type template vars, so the __inputs field looks like this:

  "__inputs": [
    {
      "name": "DS_GRW-DB",
      "label": "grw-db",
      "description": "",
      "type": "datasource",
      "pluginId": "graphite",
      "pluginName": "Graphite"
    },
    {
      "name": "VAR_ROLE",
      "type": "constant",
      "label": "role",
      "value": "{CPE,PBXPLUG}",
      "description": ""
    },
    {
      "name": "VAR_TENANT",
      "type": "constant",
      "label": "Tenant",
      "value": "000000",
      "description": ""
    }
  ],

But the resulting dashboard in Grafana shows this:

  "templating": {
    "list": [
      {
        "current": {
          "text": "${VAR_ROLE}",
          "value": "${VAR_ROLE}"
        },
        "description": "",
        "hide": 2,
        "name": "role",
        "query": "${VAR_ROLE}",
        "skipUrlSync": true,
        "type": "constant"
      },
      {
        "current": {
          "text": "${VAR_TENANT}",
          "value": "${VAR_TENANT}"
        },
        "hide": 2,
        "label": "Tenant",
        "name": "tenant",
        "query": "${VAR_TENANT}",
        "skipUrlSync": true,
        "type": "constant"
      },

Instead of the expected

  "templating": {
    "list": [
      {
        "current": {
          "text": "{CPE,PBXPLUG}",
          "value": "{CPE,PBXPLUG}"
        },
        "description": "",
        "hide": 2,
        "name": "role",
        "query": "{CPE,PBXPLUG}",
        "skipUrlSync": true,
        "type": "constant"
      },
      {
        "current": {
          "text": "000000",
          "value": "000000"
        },
        "hide": 2,
        "label": "Tenant",
        "name": "tenant",
        "query": "000000",
        "skipUrlSync": true,
        "type": "constant"
      },

I'm not sure if this is a problem on Operator or Grafana side..

Hipska

Hipska commented on Apr 9, 2025

@Hipska
Contributor

So having a way to easily replace these vars based on the json __inputs or a new option in the spec (higher precedence) as suggested, would be very welcome!

jmendiara

jmendiara commented on May 15, 2025

@jmendiara

👍 +1 on supporting the constant type in the GrafanaDashboard spec — it's already a native Grafana feature.

Use case and example:

We can define a "constant" variable in a Dashboard.

Image

This allows $namespace to be used in queries without exposing the variable to users via the dashboard variable selector — a clear UX improvement.

UI image
Image

When exporting the dashboard externally, that constant variable (sic) is available in _inputs as VAR_**************

{
  "__inputs": [
    {
      "name": "DS_PROMETHEUS",
      "label": "Prometheus",
      "type": "datasource",
      "pluginId": "prometheus"
    },
    {
      "name": "VAR_NAMESPACE",
      "type": "constant",
      "label": "Namespace",
      "value": "my-namespace"
    }
  ],
  "templating": {
    "list": [
      {
        "name": "namespace",
        "type": "constant",
        "label": "Namespace",
        "query": "${VAR_NAMESPACE}",
        "hide": 2,
        "current": {
          "value": "${VAR_NAMESPACE}",
          "text": "${VAR_NAMESPACE}"
        },
        "options": [
          {
            "value": "${VAR_NAMESPACE}",
            "text": "${VAR_NAMESPACE}"
          }
        ]
      },
      {
        "name": "instance",
        "type": "query",
        "label": "instance",
        "datasource": {
          "type": "prometheus",
          "uid": "${DS_PROMETHEUS}"
        },
        "definition": "label_values(metric{namespace=\"$namespace\"},instance)",
        "query": {
          "query": "label_values(metric{namespace=\"$namespace\"},instance)",
          "refId": "PrometheusVariableQueryEditor-VariableQuery"
        },
        "refresh": 1
      }
    ]
  }
}

When importing this dashboard manually through the UI, we can define both the Prometheus data source and the Namespace constant.

Image

Suggested implementation:

Support a constants: field in the GrafanaDashboard spec, for example (Helm-style):

apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
spec:
  datasources:
    - inputName: DS_PROMETHEUS
      datasourceName: Prometheus
  constants:
    - inputName: VAR_NAMESPACE
      value: {{ .Release.Namespace }}
  instanceSelector:
    matchLabels:
      dashboards: grafana
  json: |
    ...

This would provide parity between dashboards imported via the UI and those deployed through the Operator.

Hipska

Hipska commented on Jun 4, 2025

@Hipska
Contributor

IMHO, if you name it inputs, it could even replace the current datasources setting.

apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
spec:
  inputs:
    - inputName: DS_PROMETHEUS
      value: Prometheus
    - inputName: VAR_NAMESPACE
      value: {{ .Release.Namespace }}
  instanceSelector:
    matchLabels:
      dashboards: grafana
  json: |
    ...

If the value for a constant is not set in the spec, the default value as defined in the JSON could be used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage/acceptedIndicates an issue or PR is ready to be actively worked on.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @Hipska@jmendiara@theSuess@toporek3112@KaiseerKenopsia

        Issue actions

          GrafanaDashboard syncing from url and replacing variables on the go · Issue #1760 · grafana/grafana-operator