Skip to content

Commit 6c4f88c

Browse files
committed
feat(grafana_dashboard): allow dashboard input variables to be set
1 parent 2330479 commit 6c4f88c

File tree

6 files changed

+155
-3
lines changed

6 files changed

+155
-3
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
minor_changes:
3+
- grafana_dashboard - allow dashboard input variables to be set

plugins/modules/grafana_dashboard.py

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
default: '1'
8686
version_added: "1.0.0"
8787
type: str
88+
inputs:
89+
description:
90+
- Set replacement values for dashboard input variables
91+
- The dictionary key is the input name and the value is the input value
92+
version_added: "2.4.0"
93+
type: dict
8894
commit_message:
8995
description:
9096
- Set a commit message for the version history.
@@ -128,6 +134,15 @@
128134
folder: myteam
129135
dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
130136
137+
- name: Import Grafana dashboard Node Exporter Full and set value for an input
138+
community.grafana.grafana_dashboard:
139+
grafana_url: http://grafana.company.com
140+
grafana_api_key: "{{ grafana_api_key }}"
141+
dashboard_id: 1860
142+
dashboard_revision: 40
143+
inputs:
144+
DS_PROMETHEUS: DatasourceName
145+
131146
- name: Export dashboard
132147
community.grafana.grafana_dashboard:
133148
grafana_url: http://grafana.company.com
@@ -148,6 +163,7 @@
148163
sample: 000000063
149164
"""
150165

166+
import copy
151167
import json
152168
from ansible.module_utils.basic import AnsibleModule
153169
from ansible.module_utils.urls import fetch_url
@@ -342,6 +358,27 @@ def is_grafana_dashboard_changed(payload, dashboard):
342358
if "meta" in payload:
343359
del payload["meta"]
344360

361+
# remove elements which are stripped by the import api
362+
for key in ["__inputs", "__elements", "__requires"]:
363+
if key in dashboard["dashboard"]:
364+
del dashboard["dashboard"][key]
365+
if key in payload["dashboard"]:
366+
del payload["dashboard"][key]
367+
368+
if "inputs" in payload:
369+
# ignore inputs for compare
370+
dashboard["inputs"] = payload["inputs"]
371+
372+
# replace inputs in payload with actual values
373+
payload_string = json.dumps(payload)
374+
for input_var in payload["inputs"]:
375+
if "name" not in input_var or "value" not in input_var:
376+
continue
377+
payload_string = payload_string.replace(
378+
"${" + input_var["name"] + "}", input_var["value"]
379+
)
380+
payload = json.loads(payload_string)
381+
345382
# Ignore dashboard ids since real identifier is uuid
346383
if "id" in dashboard["dashboard"]:
347384
del dashboard["dashboard"]["id"]
@@ -394,6 +431,24 @@ def grafana_create_dashboard(module, data):
394431
if data.get("uid"):
395432
payload["dashboard"]["uid"] = data["uid"]
396433

434+
# set dashboard inputs
435+
api_endpoint = "db"
436+
if data["inputs"] is not None:
437+
inputs = []
438+
for input_var in copy.deepcopy(payload["dashboard"].get("__inputs", [])):
439+
if input_var.get("name") is None:
440+
continue
441+
if input_var["name"] in data["inputs"]:
442+
# user has overriden input value
443+
input_var["value"] = data["inputs"].get(input_var["name"])
444+
inputs.append(input_var)
445+
elif "value" in input_var:
446+
# use default value for input
447+
inputs.append(input_var)
448+
if len(inputs) >= 1:
449+
api_endpoint = "import"
450+
payload["inputs"] = inputs
451+
397452
result = {}
398453

399454
# test if the folder exists
@@ -429,7 +484,10 @@ def grafana_create_dashboard(module, data):
429484
)
430485

431486
if dashboard_exists is True:
432-
grafana_dashboard_changed = is_grafana_dashboard_changed(payload, dashboard)
487+
# pass a copy of payload so that the original isn't modified by this function
488+
grafana_dashboard_changed = is_grafana_dashboard_changed(
489+
copy.deepcopy(payload), dashboard
490+
)
433491

434492
if grafana_dashboard_changed:
435493
if module.check_mode:
@@ -447,7 +505,7 @@ def grafana_create_dashboard(module, data):
447505

448506
r, info = fetch_url(
449507
module,
450-
"%s/api/dashboards/db" % data["url"],
508+
"%s/api/dashboards/%s" % (data["url"], api_endpoint),
451509
data=json.dumps(payload),
452510
headers=headers,
453511
method="POST",
@@ -487,7 +545,7 @@ def grafana_create_dashboard(module, data):
487545

488546
r, info = fetch_url(
489547
module,
490-
"%s/api/dashboards/db" % data["url"],
548+
"%s/api/dashboards/%s" % (data["url"], api_endpoint),
491549
data=json.dumps(payload),
492550
headers=headers,
493551
method="POST",
@@ -641,6 +699,7 @@ def main():
641699
dashboard_revision=dict(type="str", default="1"),
642700
overwrite=dict(type="bool", default=False),
643701
commit_message=dict(type="str"),
702+
inputs=dict(type="dict"),
644703
)
645704
module = AnsibleModule(
646705
argument_spec=argument_spec,

roles/grafana/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Configure Grafana organizations, dashboards, folders, datasources, teams and use
8484
| dashboard_id | no |
8585
| dashboard_revision | no |
8686
| folder | no |
87+
| inputs | no |
8788
| org_id | no |
8889
| org_name | no |
8990
| overwrite | no |

roles/grafana/tasks/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@
329329
dashboard_revision: "{{ dashboard.dashboard_revision | default(omit) }}"
330330
folder: "{{ dashboard.folder | default(omit) }}"
331331
parent_folder: "{{ dashboard.parent_folder | default(omit) }}"
332+
inputs: "{{ dashboard.inputs | default(omit) }}"
332333
org_id: "{{ dashboard.org_id | default(omit) }}"
333334
org_name: "{{ dashboard.org_name | default(omit) }}"
334335
overwrite: "{{ dashboard.overwrite | default(omit) }}"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
- name: Create Dashboard with inputs | check mode | dashboard does not exist
3+
community.grafana.grafana_dashboard:
4+
state: present
5+
commit_message: Updated by ansible
6+
dashboard_id: "405"
7+
dashboard_revision: "8"
8+
inputs:
9+
DS_PROMETHEUS: Prometheus
10+
overwrite: true
11+
uid: "dfi"
12+
check_mode: true
13+
register: dfi_result1
14+
- ansible.builtin.assert:
15+
that:
16+
- dfi_result1.failed == false
17+
- dfi_result1.changed == true
18+
- dfi_result1.uid is not defined
19+
- dfi_result1.msg == 'Dashboard Node Exporter Server Metrics will be created'
20+
21+
- name: Create Dashboard with inputs | run mode | dashboard does not exist
22+
community.grafana.grafana_dashboard:
23+
state: present
24+
commit_message: Updated by ansible
25+
dashboard_id: "405"
26+
dashboard_revision: "8"
27+
inputs:
28+
DS_PROMETHEUS: Prometheus
29+
overwrite: true
30+
uid: "dfi"
31+
check_mode: false
32+
register: dfi_result2
33+
- ansible.builtin.assert:
34+
that:
35+
- dfi_result2.failed == false
36+
- dfi_result2.changed == true
37+
- dfi_result2.uid is truthy
38+
- dfi_result2.uid == 'dfi'
39+
- dfi_result2.msg == 'Dashboard Node Exporter Server Metrics created'
40+
41+
- name: Create Dashboard with inputs | check mode | dashboard exists
42+
community.grafana.grafana_dashboard:
43+
state: present
44+
commit_message: Updated by ansible
45+
dashboard_id: "405"
46+
dashboard_revision: "8"
47+
inputs:
48+
DS_PROMETHEUS: Prometheus
49+
overwrite: true
50+
uid: "dfi"
51+
check_mode: true
52+
register: dfi_result3
53+
- ansible.builtin.assert:
54+
that:
55+
- dfi_result3.failed == false
56+
- dfi_result3.changed == false
57+
- dfi_result3.uid is truthy
58+
- dfi_result3.uid == 'dfi'
59+
- dfi_result3.msg == 'Dashboard Node Exporter Server Metrics unchanged.'
60+
61+
- name: Create Dashboard with inputs | run mode | dashboard exists
62+
community.grafana.grafana_dashboard:
63+
state: present
64+
commit_message: Updated by ansible
65+
dashboard_id: "405"
66+
dashboard_revision: "8"
67+
inputs:
68+
DS_PROMETHEUS: Prometheus
69+
overwrite: true
70+
uid: "dfi"
71+
check_mode: false
72+
register: dfi_result4
73+
- ansible.builtin.assert:
74+
that:
75+
- dfi_result4.failed == false
76+
- dfi_result4.changed == false
77+
- dfi_result4.uid is truthy
78+
- dfi_result4.uid == 'dfi'
79+
- dfi_result4.msg == 'Dashboard Node Exporter Server Metrics unchanged.'
80+
81+
- ansible.builtin.include_tasks:
82+
file: delete-dashboard.yml
83+
vars:
84+
uid_to_delete: "{{ dfi_result4.uid }}"

tests/integration/targets/grafana_dashboard/tasks/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
ansible.builtin.include_tasks:
88
file: dashboard-from-id.yml
99

10+
- name: Create dashboard with inputs
11+
ansible.builtin.include_tasks:
12+
file: dashboard-inputs.yml
13+
1014
- name: Create dashboard from file and export
1115
ansible.builtin.include_tasks:
1216
file: dashboard-from-file-export.yml

0 commit comments

Comments
 (0)