Merge ~johnsca/charm-grafana:johnsca/feature/dashboard-import into ~prometheus-charmers/charm-grafana:master

Proposed by Cory Johns
Status: Merged
Approved by: Jeremy Lounder
Approved revision: 781d72730b8709066cd5d6c9c148956fdaaa9e0f
Merged at revision: 4cd46e4a696b27b3b4b4c77f6be95d96ce6bb1f8
Proposed branch: ~johnsca/charm-grafana:johnsca/feature/dashboard-import
Merge into: ~prometheus-charmers/charm-grafana:master
Diff against target: 247 lines (+71/-28)
13 files modified
actions.yaml (+2/-0)
actions/change-user-role (+1/-1)
actions/create-api-key (+1/-1)
actions/create-user (+1/-1)
actions/delete-user (+1/-1)
actions/get-admin-password (+1/-1)
actions/get-login-info (+30/-0)
actions/import-dashboard (+1/-21)
actions/set-user-password (+1/-1)
layer.yaml (+1/-1)
lib/charms/layer/grafana.py (+20/-0)
metadata.yaml (+2/-0)
reactive/grafana.py (+9/-0)
Reviewer Review Type Date Requested Status
Jeremy Lounder (community) Approve
Cory Johns (community) Needs Resubmitting
Stuart Bishop (community) Approve
Prometheus Charmers Pending
Review via email: mp+371002@code.launchpad.net

Commit message

Add relation for getting dashboards imported

Kubernetes has dashboards it needs loaded when monitoring is in use.
This adds a relation that it can use to provide those dashboards.

Also adds a new action to get all info for connecting.

The URL or port can be changed via config, so it's useful (and more
convenient) to get all info needed to connect to Grafana from a single
action. I added a new action for clarity and to maintain compatibility,
but this could potentially be folded into get-admin-password.

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Stuart Bishop (stub) wrote :

Code changes are all great. I think there is a bug on line 170 of the diff, but trivially fixed.

This is using proposed changes to charms.reactive I believe, for the request/response interface ? Has this landed, do we need to wait before landing this MP, or do we need to update requirements.txt to temporarily build with a charms.reactive fork?

review: Approve
Revision history for this message
Jeremy Lounder (jldev) wrote :

Comments inline.

Need to check on the build status of this branch, regarding Stuart's reactive question. I will circle back on this after the import_dashboard signature issue has been fixed.

review: Needs Fixing
Revision history for this message
Cory Johns (johnsca) wrote :

Review comments addressed.

The PR for charms.reactive is at: https://github.com/juju-solutions/charms.reactive/pull/215

I'd like to get that reviewed and merged prior to releasing this or the Prometheus2 charm. For reference, this is all in support of https://github.com/charmed-kubernetes/charm-kubernetes-master/pull/45

Revision history for this message
Cory Johns (johnsca) :
review: Needs Resubmitting
Revision history for this message
Cory Johns (johnsca) wrote :

1.3.0 of charms.reactive is released with the relevant change, as well as the interface layer PRs.

Revision history for this message
Jeremy Lounder (jldev) :
review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 4cd46e4a696b27b3b4b4c77f6be95d96ce6bb1f8

Revision history for this message
Kevin W Monroe (kwmonroe) wrote :

I released this to edge/beta in https://jaas.ai/u/prometheus-charmers/grafana/34 to ease our K8s LMA testing, but I didn't push to stable in case there was a more formal stable release process.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/actions.yaml b/actions.yaml
2index 5476855..b90282b 100644
3--- a/actions.yaml
4+++ b/actions.yaml
5@@ -14,6 +14,8 @@ import-dashboard:
6 additionalProperties: false
7 get-admin-password:
8 description: Retrieves the admin password, either auto generated or set in config
9+get-login-info:
10+ description: Retrieves all of the info needed to log into Grafana.
11 create-api-key:
12 description: Create an api key given a keyname and a keyrole out of Viewer, Editor, Read Only Editor or Admin
13 params:
14diff --git a/actions/change-user-role b/actions/change-user-role
15index f635c59..3e455f4 100755
16--- a/actions/change-user-role
17+++ b/actions/change-user-role
18@@ -12,7 +12,7 @@ from charmhelpers.core.hookenv import (
19 log,
20 )
21
22-from grafana_utils import get_admin_password
23+from charms.layer.grafana import get_admin_password
24
25 action = "change-user-role"
26
27diff --git a/actions/create-api-key b/actions/create-api-key
28index bdd054d..9deafd5 100755
29--- a/actions/create-api-key
30+++ b/actions/create-api-key
31@@ -11,7 +11,7 @@ from charmhelpers.core.hookenv import (
32 )
33 import sys
34
35-from grafana_utils import get_admin_password
36+from charms.layer.grafana import get_admin_password
37
38 passwd = get_admin_password()
39
40diff --git a/actions/create-user b/actions/create-user
41index 95d5167..7abd043 100755
42--- a/actions/create-user
43+++ b/actions/create-user
44@@ -12,7 +12,7 @@ from charmhelpers.core.hookenv import (
45 log,
46 )
47
48-from grafana_utils import get_admin_password
49+from charms.layer.grafana import get_admin_password
50
51 action = "create-user"
52
53diff --git a/actions/delete-user b/actions/delete-user
54index 7e57172..5b41d9f 100755
55--- a/actions/delete-user
56+++ b/actions/delete-user
57@@ -12,7 +12,7 @@ from charmhelpers.core.hookenv import (
58 log,
59 )
60
61-from grafana_utils import get_admin_password
62+from charms.layer.grafana import get_admin_password
63
64 action = "delete-user"
65
66diff --git a/actions/get-admin-password b/actions/get-admin-password
67index c345762..7b66f92 100755
68--- a/actions/get-admin-password
69+++ b/actions/get-admin-password
70@@ -1,7 +1,7 @@
71 #!/usr/local/sbin/charm-env python3
72 # Get admin password
73
74-from grafana_utils import get_admin_password
75+from charms.layer.grafana import get_admin_password
76 import sys
77
78 from charmhelpers.core.hookenv import (
79diff --git a/actions/get-login-info b/actions/get-login-info
80new file mode 100755
81index 0000000..d1c50bb
82--- /dev/null
83+++ b/actions/get-login-info
84@@ -0,0 +1,30 @@
85+#!/usr/local/sbin/charm-env python3
86+# Get admin password
87+
88+import sys
89+
90+from charmhelpers.core.hookenv import (
91+ action_fail,
92+ action_set,
93+ unit_get,
94+ config,
95+)
96+
97+from charms.layer.grafana import get_admin_password
98+
99+passwd = get_admin_password()
100+
101+if passwd is not None:
102+ cfg = config()
103+ action_set({
104+ "url": cfg['root_url'] % {
105+ 'protocol': 'http',
106+ 'domain': unit_get('public-address'),
107+ 'http_port': cfg['port'],
108+ },
109+ "username": "admin",
110+ "password": passwd,
111+ })
112+else:
113+ action_fail('Unable to retrieve password.')
114+ sys.exit(0)
115diff --git a/actions/import-dashboard b/actions/import-dashboard
116index e7c6c53..62c28c5 100755
117--- a/actions/import-dashboard
118+++ b/actions/import-dashboard
119@@ -1,7 +1,6 @@
120 #!/usr/local/sbin/charm-env python3
121 # Imports a json based dashboard into grafana
122
123-import requests
124 import json
125 import base64
126 import traceback
127@@ -14,26 +13,7 @@ from charmhelpers.core.hookenv import (
128 log,
129 )
130
131-from grafana_utils import get_admin_password
132-
133-
134-def import_dashboard(dashboard):
135- headers = {'Content-Type': 'application/json'}
136- import_url = 'http://localhost:{}/api/dashboards/db'.format(
137- config('port'))
138- passwd = get_admin_password()
139- if passwd is None:
140- action_fail('Unable to retrieve grafana password.')
141- return False
142- api_auth = ('admin', passwd)
143- r = requests.post(import_url, auth=api_auth, headers=headers,
144- data=json.dumps(dashboard))
145- if r.status_code == 200:
146- return True
147- else:
148- title = dashboard['dashboard']['title']
149- action_fail('Error importing dashboard: "{}"'.format(title))
150- return False
151+from charms.layer.grafana import import_dashboard
152
153
154 def import_file(path):
155diff --git a/actions/set-user-password b/actions/set-user-password
156index 7a8403d..1bc2c56 100755
157--- a/actions/set-user-password
158+++ b/actions/set-user-password
159@@ -12,7 +12,7 @@ from charmhelpers.core.hookenv import (
160 log,
161 )
162
163-from grafana_utils import get_admin_password
164+from charms.layer.grafana import get_admin_password
165
166 action = "set-user-password"
167
168diff --git a/layer.yaml b/layer.yaml
169index 0eb7b9b..df345e6 100644
170--- a/layer.yaml
171+++ b/layer.yaml
172@@ -1,3 +1,3 @@
173-includes: ['layer:basic', 'layer:snap', 'interface:nrpe-external-master', 'interface:grafana-source', 'interface:http']
174+includes: ['layer:basic', 'layer:snap', 'interface:nrpe-external-master', 'interface:grafana-source', 'interface:http', 'interface:grafana-dashboard']
175 ignore: ['.*.swp' ]
176 repo: https://git.launchpad.net/grafana-charm
177diff --git a/actions/grafana_utils.py b/lib/charms/layer/grafana.py
178similarity index 65%
179rename from actions/grafana_utils.py
180rename to lib/charms/layer/grafana.py
181index 54af925..b482203 100644
182--- a/actions/grafana_utils.py
183+++ b/lib/charms/layer/grafana.py
184@@ -1,5 +1,7 @@
185 #!/usr/bin/python3
186
187+import json
188+import requests
189 from charmhelpers.core.hookenv import (
190 config,
191 log,
192@@ -22,3 +24,21 @@ def get_admin_password():
193
194 return passwd
195
196+
197+def import_dashboard(dashboard, name=None):
198+ if name is None:
199+ name = dashboard['dashboard'].get('title') or 'Untitled'
200+ headers = {'Content-Type': 'application/json'}
201+ import_url = 'http://localhost:{}/api/dashboards/db'.format(
202+ config('port'))
203+ passwd = get_admin_password()
204+ if passwd is None:
205+ return (False, 'Unable to retrieve grafana password.')
206+ api_auth = ('admin', passwd)
207+ r = requests.post(import_url, auth=api_auth, headers=headers,
208+ data=json.dumps(dashboard))
209+ if r.status_code == 200:
210+ return (True, None)
211+ else:
212+ return (False, 'Error importing dashboard "{}": {}'.format(name,
213+ r.text))
214diff --git a/metadata.yaml b/metadata.yaml
215index 64dcbff..9476ae1 100644
216--- a/metadata.yaml
217+++ b/metadata.yaml
218@@ -21,3 +21,5 @@ provides:
219 requires:
220 grafana-source:
221 interface: grafana-source
222+ dashboards:
223+ interface: grafana-dashboard
224diff --git a/reactive/grafana.py b/reactive/grafana.py
225index 7d1c422..ba40c2f 100644
226--- a/reactive/grafana.py
227+++ b/reactive/grafana.py
228@@ -31,6 +31,7 @@ from charms.reactive import (
229 )
230
231 from charms.layer import snap
232+from charms.layer.grafana import import_dashboard
233
234 SVCNAME = {'snap': 'snap.grafana.grafana',
235 'apt': 'grafana-server'}
236@@ -712,3 +713,11 @@ def check_adminuser():
237 def hpwgen(passwd, salt):
238 hpasswd = pbkdf2.PBKDF2(passwd, salt, 10000, SHA256).hexread(50)
239 return hpasswd
240+
241+
242+@when('grafana.started',
243+ 'endpoint.dashboards.requests')
244+def import_dashboards(dashboards):
245+ for request in dashboards.new_requests:
246+ success, reason = import_dashboard(request.dashboard, request.name)
247+ request.respond(success, reason)

Subscribers

People subscribed via source and target branches