1
0
Fork 0

Add support for JSON dashboards

This patch adds the support for JSON dashboards and also provides the
support for remote dashboards.
This commit is contained in:
Guillaume Thouvenin 2016-11-08 11:55:55 +01:00
parent c4ddb9ebda
commit 2958bda057
5 changed files with 92 additions and 65 deletions

View File

@ -44,7 +44,9 @@ Server installed with PostgreSQL database
user: grafana
password: passwd
Server installed with default StackLight JSON dashboards
Server installed with default StackLight JSON dashboards. This will
be replaced by the possibility for a service to provide its own dashboard
using salt-mine.
.. code-block:: yaml

View File

@ -65,6 +65,7 @@ def present(name,
base_panels_from_pillar=None,
base_rows_from_pillar=None,
dashboard=None,
dashboard_format='yaml',
profile='grafana'):
'''
Ensure the grafana dashboard exists and is managed.
@ -84,19 +85,39 @@ def present(name,
dashboard
A dict that defines a dashboard that should be managed.
dashboard_format
You can use two formats for dashboards. You can use the JSON format
if you provide a complete dashboard in raw JSON or you can use the YAML
format (this is the default) and provide a description of the
dashboard in YAML.
profile
A pillar key or dict that contains grafana information
'''
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
base_dashboards_from_pillar = base_dashboards_from_pillar or []
base_panels_from_pillar = base_panels_from_pillar or []
base_rows_from_pillar = base_rows_from_pillar or []
dashboard = dashboard or {}
if isinstance(profile, six.string_types):
profile = __salt__['config.option'](profile)
if dashboard_format == 'json':
# In this case, a raw JSON of the full dashboard is provided.
response = _update(dashboard, profile)
if response.get('status') == 'success':
ret['comment'] = 'Dashboard {0} created.'.format(name)
ret['changes']['new'] = 'Dashboard {0} created.'.format(name)
else:
ret['result'] = False
ret['comment'] = ("Failed to create dashboard {0}, "
"response={1}").format(name, response)
return ret
base_dashboards_from_pillar = base_dashboards_from_pillar or []
base_panels_from_pillar = base_panels_from_pillar or []
base_rows_from_pillar = base_rows_from_pillar or []
# Add pillar keys for default configuration
base_dashboards_from_pillar = ([_DEFAULT_DASHBOARD_PILLAR] +
base_dashboards_from_pillar)
@ -439,18 +460,12 @@ def _delete(url, profile):
'''Delete a specific dashboard.'''
request_url = "{0}/api/dashboards/{1}".format(profile.get('grafana_url'),
url)
if profile.get('grafana_token', False):
response = requests.delete(
request_url,
headers=_get_headers(profile),
timeout=profile.get('grafana_timeout'),
)
else:
response = requests.delete(
request_url,
auth=_get_auth(profile),
timeout=profile.get('grafana_timeout'),
)
response = requests.delete(
request_url,
auth=_get_auth(profile),
headers=_get_headers(profile),
timeout=profile.get('grafana_timeout'),
)
data = response.json()
return data
@ -461,30 +476,28 @@ def _update(dashboard, profile):
'dashboard': dashboard,
'overwrite': True
}
request_url = "{0}/api/dashboards/db".format(profile.get('grafana_url'))
if profile.get('grafana_token', False):
response = requests.post(
request_url,
headers=_get_headers(profile),
json=payload
)
else:
response = requests.post(
request_url,
auth=_get_auth(profile),
json=payload
)
response = requests.post(
"{0}/api/dashboards/db".format(profile.get('grafana_url')),
auth=_get_auth(profile),
headers=_get_headers(profile),
json=payload
)
return response.json()
def _get_headers(profile):
return {
'Accept': 'application/json',
'Authorization': 'Bearer {0}'.format(profile['grafana_token'])
}
headers = {'Content-type': 'application/json'}
if profile.get('grafana_token', False):
headers['Authorization'] = 'Bearer {0}'.format(profile['grafana_token'])
return headers
def _get_auth(profile):
if profile.get('grafana_token', False):
return None
return requests.auth.HTTPBasicAuth(
profile['grafana_user'],
profile['grafana_password']

View File

@ -36,52 +36,56 @@ grafana_client_datasource_{{ datasource_name }}:
{%- if client.remote_data.engine == 'salt_mine' %}
{%- for node_name, node_grains in salt['mine.get']('*', 'grains.items').iteritems() %}
{%- if node_grains.grafana is defined %}
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=node_grains.grafana.get('dashboard', {})) %}
{%- endif %}
{%- if node_grains.grafana is defined %}
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=node_grains.grafana.get('dashboard', {})) %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- if client.dashboard is defined %}
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=client.dashboard) %}
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=client.dashboard) %}
{%- endif %}
{%- for dashboard_name, dashboard in raw_dict.iteritems() %}
{%- set rows = [] %}
{%- for row_name, row in dashboard.get('row', {}).iteritems() %}
{%- set panels = [] %}
{%- for panel_name, panel in row.get('panel', {}).iteritems() %}
{%- set targets = [] %}
{%- for target_name, target in panel.get('target', {}).iteritems() %}
{%- do targets.extend([target]) %}
{%- endfor %}
{%- do panel.update({'targets': targets}) %}
{%- do panels.extend([panel]) %}
{%- endfor %}
{%- do row.update({'panels': panels}) %}
{%- do rows.extend([row]) %}
{%- endfor %}
{%- do dashboard.update({'rows': rows}) %}
{%- do final_dict.update({dashboard_name: dashboard}) %}
{%- if dashboard.get('format', 'yaml')|lower == 'yaml' %}
# Dashboards in JSON format are considered as blob
{%- set rows = [] %}
{%- for row_name, row in dashboard.get('row', {}).iteritems() %}
{%- set panels = [] %}
{%- for panel_name, panel in row.get('panel', {}).iteritems() %}
{%- set targets = [] %}
{%- for target_name, target in panel.get('target', {}).iteritems() %}
{%- do targets.extend([target]) %}
{%- endfor %}
{%- do panel.update({'targets': targets}) %}
{%- do panels.extend([panel]) %}
{%- endfor %}
{%- do row.update({'panels': panels}) %}
{%- do rows.extend([row]) %}
{%- endfor %}
{%- do dashboard.update({'rows': rows}) %}
{%- endif %}
{%- do final_dict.update({dashboard_name: dashboard}) %}
{%- endfor %}
{%- for dashboard_name, dashboard in final_dict.iteritems() %}
{%- if dashboard.get('enabled', True) %}
{%- if dashboard.get('enabled', True) %}
grafana_client_dashboard_{{ dashboard_name }}:
grafana3_dashboard.present:
- name: {{ dashboard_name }}
{%- if dashboard.get('format', 'yaml')|lower == 'json' %}
{%- import_json dashboard.template as dash %}
- dashboard: {{ dash|json }}
- dashboard_format: json
{%- else %}
- dashboard: {{ dashboard }}
{%- else %}
{%- endif %}
{%- else %}
grafana_client_dashboard_{{ dashboard_name }}:
grafana3_dashboard.absent:
- name: {{ dashboard_name }}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}

View File

@ -13,6 +13,7 @@ grafana_grains_dir:
{# Loading the other service support metadata for localhost #}
{%- for service_name, service in pillar.iteritems() %}
{%- if service.get('_support', {}).get('grafana', {}).get('enabled', False) %}
{%- macro load_grains_file(grains_fragment_file) %}{% include grains_fragment_file ignore missing %}{% endmacro %}
@ -20,6 +21,7 @@ grafana_grains_dir:
{%- set grains_yaml = load_grains_file(grains_fragment_file)|load_yaml %}
{%- set service_grains = salt['grains.filter_by']({'default': service_grains}, merge=grains_yaml) %}
{%- endif %}
{%- endfor %}
grafana_grain:

View File

@ -0,0 +1,6 @@
applications:
- grafana
parameters:
grafana:
collector:
enabled: true