Grafana dashboard : added folder parameter + fix when uid is missing in json file (#63342)
Related: ansible/ansible#61685
This commit is contained in:
parent
7d9a0baa7f
commit
0b9c241822
1 changed files with 119 additions and 18 deletions
|
@ -49,6 +49,11 @@ options:
|
|||
- The Grafana Organisation ID where the dashboard will be imported / exported.
|
||||
- Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organisation..
|
||||
default: 1
|
||||
folder:
|
||||
description:
|
||||
- The Grafana folder where this dashboard will be imported to.
|
||||
default: General
|
||||
version_added: '2.10'
|
||||
state:
|
||||
description:
|
||||
- State of the dashboard.
|
||||
|
@ -139,6 +144,7 @@ import json
|
|||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url, url_argument_spec
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils._text import to_text
|
||||
|
||||
|
@ -195,16 +201,40 @@ def get_grafana_version(module, grafana_url, headers):
|
|||
return int(grafana_version)
|
||||
|
||||
|
||||
def grafana_folder_exists(module, grafana_url, folder_name, headers):
|
||||
# the 'General' folder is a special case, it's ID is always '0'
|
||||
if folder_name == 'General':
|
||||
return True, 0
|
||||
|
||||
try:
|
||||
r, info = fetch_url(module, '%s/api/folders' % grafana_url, headers=headers, method='GET')
|
||||
|
||||
if info['status'] != 200:
|
||||
raise GrafanaAPIException("Unable to query Grafana API for folders (name: %s): %d" % (folder_name, info['status']))
|
||||
|
||||
folders = json.loads(r.read())
|
||||
|
||||
for folder in folders:
|
||||
if folder['title'] == folder_name:
|
||||
return True, folder['id']
|
||||
except Exception as e:
|
||||
raise GrafanaAPIException(e)
|
||||
|
||||
return False, 0
|
||||
|
||||
|
||||
def grafana_dashboard_exists(module, grafana_url, uid, headers):
|
||||
dashboard_exists = False
|
||||
dashboard = {}
|
||||
|
||||
grafana_version = get_grafana_version(module, grafana_url, headers)
|
||||
|
||||
if grafana_version >= 5:
|
||||
r, info = fetch_url(module, '%s/api/dashboards/uid/%s' % (grafana_url, uid), headers=headers, method='GET')
|
||||
uri = '%s/api/dashboards/uid/%s' % (grafana_url, uid)
|
||||
else:
|
||||
r, info = fetch_url(module, '%s/api/dashboards/db/%s' % (grafana_url, uid), headers=headers, method='GET')
|
||||
uri = '%s/api/dashboards/db/%s' % (grafana_url, uid)
|
||||
|
||||
r, info = fetch_url(module, uri, headers=headers, method='GET')
|
||||
|
||||
if info['status'] == 200:
|
||||
dashboard_exists = True
|
||||
try:
|
||||
|
@ -219,6 +249,52 @@ def grafana_dashboard_exists(module, grafana_url, uid, headers):
|
|||
return dashboard_exists, dashboard
|
||||
|
||||
|
||||
def grafana_dashboard_search(module, grafana_url, folder_id, title, headers):
|
||||
|
||||
# search by title
|
||||
uri = '%s/api/search?%s' % (grafana_url, urlencode({
|
||||
'folderIds': folder_id,
|
||||
'query': title,
|
||||
'type': 'dash-db'
|
||||
}))
|
||||
r, info = fetch_url(module, uri, headers=headers, method='GET')
|
||||
|
||||
if info['status'] == 200:
|
||||
try:
|
||||
dashboards = json.loads(r.read())
|
||||
for d in dashboards:
|
||||
if d['title'] == title:
|
||||
return grafana_dashboard_exists(module, grafana_url, d['uid'], headers)
|
||||
except Exception as e:
|
||||
raise GrafanaAPIException(e)
|
||||
else:
|
||||
raise GrafanaAPIException('Unable to search dashboard %s : %s' % (title, info))
|
||||
|
||||
return False, None
|
||||
|
||||
|
||||
# for comparison, we sometimes need to ignore a few keys
|
||||
def grafana_dashboard_changed(payload, dashboard):
|
||||
# you don't need to set the version, but '0' is incremented to '1' by Grafana's API
|
||||
if payload['dashboard']['version'] == 0:
|
||||
del(payload['dashboard']['version'])
|
||||
del(dashboard['dashboard']['version'])
|
||||
|
||||
# the meta key is not part of the 'payload' ever
|
||||
if 'meta' in dashboard:
|
||||
del(dashboard['meta'])
|
||||
|
||||
# new dashboards don't require an id attribute (or, it can be 'null'), Grafana's API will generate it
|
||||
if payload['dashboard']['id'] is None:
|
||||
del(dashboard['dashboard']['id'])
|
||||
del(payload['dashboard']['id'])
|
||||
|
||||
if payload == dashboard:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def grafana_create_dashboard(module, data):
|
||||
|
||||
# define data payload for grafana API
|
||||
|
@ -251,24 +327,37 @@ def grafana_create_dashboard(module, data):
|
|||
else:
|
||||
uid = None
|
||||
|
||||
# test if dashboard already exists
|
||||
dashboard_exists, dashboard = grafana_dashboard_exists(module, data['grafana_url'], uid, headers=headers)
|
||||
|
||||
result = {}
|
||||
if dashboard_exists is True:
|
||||
if dashboard == payload:
|
||||
# unchanged
|
||||
|
||||
# test if the folder exists
|
||||
if grafana_version >= 5:
|
||||
folder_exists, folder_id = grafana_folder_exists(module, data['grafana_url'], data['folder'], headers)
|
||||
if folder_exists is False:
|
||||
result['msg'] = "Dashboard folder '%s' does not exist." % data['folder']
|
||||
result['uid'] = uid
|
||||
result['msg'] = "Dashboard %s unchanged." % uid
|
||||
result['changed'] = False
|
||||
else:
|
||||
return result
|
||||
|
||||
payload['folderId'] = folder_id
|
||||
|
||||
# test if dashboard already exists
|
||||
if uid:
|
||||
dashboard_exists, dashboard = grafana_dashboard_exists(
|
||||
module, data['grafana_url'], uid, headers=headers)
|
||||
else:
|
||||
dashboard_exists, dashboard = grafana_dashboard_search(
|
||||
module, data['grafana_url'], folder_id, payload['dashboard']['title'], headers=headers)
|
||||
|
||||
if dashboard_exists is True:
|
||||
if grafana_dashboard_changed(payload, dashboard):
|
||||
# update
|
||||
if 'overwrite' in data and data['overwrite']:
|
||||
payload['overwrite'] = True
|
||||
if 'message' in data and data['message']:
|
||||
payload['message'] = data['message']
|
||||
|
||||
r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'], data=json.dumps(payload), headers=headers, method='POST')
|
||||
r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'],
|
||||
data=json.dumps(payload), headers=headers, method='POST')
|
||||
if info['status'] == 200:
|
||||
if grafana_version >= 5:
|
||||
try:
|
||||
|
@ -277,16 +366,26 @@ def grafana_create_dashboard(module, data):
|
|||
except Exception as e:
|
||||
raise GrafanaAPIException(e)
|
||||
result['uid'] = uid
|
||||
result['msg'] = "Dashboard %s updated" % uid
|
||||
result['msg'] = "Dashboard %s updated" % payload['dashboard']['title']
|
||||
result['changed'] = True
|
||||
else:
|
||||
body = json.loads(info['body'])
|
||||
raise GrafanaAPIException('Unable to update the dashboard %s : %s' % (uid, body['message']))
|
||||
raise GrafanaAPIException('Unable to update the dashboard %s : %s (HTTP: %d)' %
|
||||
(uid, body['message'], info['status']))
|
||||
else:
|
||||
# unchanged
|
||||
result['uid'] = uid
|
||||
result['msg'] = "Dashboard %s unchanged." % payload['dashboard']['title']
|
||||
result['changed'] = False
|
||||
else:
|
||||
# create
|
||||
r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'], data=json.dumps(payload), headers=headers, method='POST')
|
||||
if folder_exists is True:
|
||||
payload['folderId'] = folder_id
|
||||
|
||||
r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'],
|
||||
data=json.dumps(payload), headers=headers, method='POST')
|
||||
if info['status'] == 200:
|
||||
result['msg'] = "Dashboard %s created" % uid
|
||||
result['msg'] = "Dashboard %s created" % payload['dashboard']['title']
|
||||
result['changed'] = True
|
||||
if grafana_version >= 5:
|
||||
try:
|
||||
|
@ -296,7 +395,8 @@ def grafana_create_dashboard(module, data):
|
|||
raise GrafanaAPIException(e)
|
||||
result['uid'] = uid
|
||||
else:
|
||||
raise GrafanaAPIException('Unable to create the new dashboard %s : %s - %s.' % (uid, info['status'], info))
|
||||
raise GrafanaAPIException('Unable to create the new dashboard %s : %s - %s.' %
|
||||
(payload['dashboard']['title'], info['status'], info))
|
||||
|
||||
return result
|
||||
|
||||
|
@ -394,6 +494,7 @@ def main():
|
|||
url_password=dict(aliases=['grafana_password'], default='admin', no_log=True),
|
||||
grafana_api_key=dict(type='str', no_log=True),
|
||||
org_id=dict(default=1, type='int'),
|
||||
folder=dict(type='str', default='General'),
|
||||
uid=dict(type='str'),
|
||||
slug=dict(type='str'),
|
||||
path=dict(type='str'),
|
||||
|
@ -423,7 +524,7 @@ def main():
|
|||
except GrafanaMalformedJson as e:
|
||||
module.fail_json(
|
||||
failed=True,
|
||||
msg="error : json file does not contain a meta section with a slug parameter, or you did not specify the slug parameter"
|
||||
msg="error : %s" % to_native(e)
|
||||
)
|
||||
return
|
||||
except GrafanaDeleteException as e:
|
||||
|
|
Loading…
Reference in a new issue