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:
parent
c4ddb9ebda
commit
2958bda057
5 changed files with 92 additions and 65 deletions
|
@ -44,7 +44,9 @@ Server installed with PostgreSQL database
|
||||||
user: grafana
|
user: grafana
|
||||||
password: passwd
|
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
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ def present(name,
|
||||||
base_panels_from_pillar=None,
|
base_panels_from_pillar=None,
|
||||||
base_rows_from_pillar=None,
|
base_rows_from_pillar=None,
|
||||||
dashboard=None,
|
dashboard=None,
|
||||||
|
dashboard_format='yaml',
|
||||||
profile='grafana'):
|
profile='grafana'):
|
||||||
'''
|
'''
|
||||||
Ensure the grafana dashboard exists and is managed.
|
Ensure the grafana dashboard exists and is managed.
|
||||||
|
@ -84,19 +85,39 @@ def present(name,
|
||||||
dashboard
|
dashboard
|
||||||
A dict that defines a dashboard that should be managed.
|
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
|
profile
|
||||||
A pillar key or dict that contains grafana information
|
A pillar key or dict that contains grafana information
|
||||||
'''
|
'''
|
||||||
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
|
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 {}
|
dashboard = dashboard or {}
|
||||||
|
|
||||||
if isinstance(profile, six.string_types):
|
if isinstance(profile, six.string_types):
|
||||||
profile = __salt__['config.option'](profile)
|
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
|
# Add pillar keys for default configuration
|
||||||
base_dashboards_from_pillar = ([_DEFAULT_DASHBOARD_PILLAR] +
|
base_dashboards_from_pillar = ([_DEFAULT_DASHBOARD_PILLAR] +
|
||||||
base_dashboards_from_pillar)
|
base_dashboards_from_pillar)
|
||||||
|
@ -439,18 +460,12 @@ def _delete(url, profile):
|
||||||
'''Delete a specific dashboard.'''
|
'''Delete a specific dashboard.'''
|
||||||
request_url = "{0}/api/dashboards/{1}".format(profile.get('grafana_url'),
|
request_url = "{0}/api/dashboards/{1}".format(profile.get('grafana_url'),
|
||||||
url)
|
url)
|
||||||
if profile.get('grafana_token', False):
|
response = requests.delete(
|
||||||
response = requests.delete(
|
request_url,
|
||||||
request_url,
|
auth=_get_auth(profile),
|
||||||
headers=_get_headers(profile),
|
headers=_get_headers(profile),
|
||||||
timeout=profile.get('grafana_timeout'),
|
timeout=profile.get('grafana_timeout'),
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
response = requests.delete(
|
|
||||||
request_url,
|
|
||||||
auth=_get_auth(profile),
|
|
||||||
timeout=profile.get('grafana_timeout'),
|
|
||||||
)
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -461,30 +476,28 @@ def _update(dashboard, profile):
|
||||||
'dashboard': dashboard,
|
'dashboard': dashboard,
|
||||||
'overwrite': True
|
'overwrite': True
|
||||||
}
|
}
|
||||||
request_url = "{0}/api/dashboards/db".format(profile.get('grafana_url'))
|
response = requests.post(
|
||||||
if profile.get('grafana_token', False):
|
"{0}/api/dashboards/db".format(profile.get('grafana_url')),
|
||||||
response = requests.post(
|
auth=_get_auth(profile),
|
||||||
request_url,
|
headers=_get_headers(profile),
|
||||||
headers=_get_headers(profile),
|
json=payload
|
||||||
json=payload
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
response = requests.post(
|
|
||||||
request_url,
|
|
||||||
auth=_get_auth(profile),
|
|
||||||
json=payload
|
|
||||||
)
|
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
def _get_headers(profile):
|
def _get_headers(profile):
|
||||||
return {
|
headers = {'Content-type': 'application/json'}
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': 'Bearer {0}'.format(profile['grafana_token'])
|
if profile.get('grafana_token', False):
|
||||||
}
|
headers['Authorization'] = 'Bearer {0}'.format(profile['grafana_token'])
|
||||||
|
|
||||||
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def _get_auth(profile):
|
def _get_auth(profile):
|
||||||
|
if profile.get('grafana_token', False):
|
||||||
|
return None
|
||||||
|
|
||||||
return requests.auth.HTTPBasicAuth(
|
return requests.auth.HTTPBasicAuth(
|
||||||
profile['grafana_user'],
|
profile['grafana_user'],
|
||||||
profile['grafana_password']
|
profile['grafana_password']
|
||||||
|
|
|
@ -36,52 +36,56 @@ grafana_client_datasource_{{ datasource_name }}:
|
||||||
|
|
||||||
{%- if client.remote_data.engine == 'salt_mine' %}
|
{%- if client.remote_data.engine == 'salt_mine' %}
|
||||||
{%- for node_name, node_grains in salt['mine.get']('*', 'grains.items').iteritems() %}
|
{%- for node_name, node_grains in salt['mine.get']('*', 'grains.items').iteritems() %}
|
||||||
{%- if node_grains.grafana is defined %}
|
{%- if node_grains.grafana is defined %}
|
||||||
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=node_grains.grafana.get('dashboard', {})) %}
|
{%- set raw_dict = salt['grains.filter_by']({'default': raw_dict}, merge=node_grains.grafana.get('dashboard', {})) %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
{%- if client.dashboard is defined %}
|
{%- 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 %}
|
{%- endif %}
|
||||||
|
|
||||||
{%- for dashboard_name, dashboard in raw_dict.iteritems() %}
|
{%- for dashboard_name, dashboard in raw_dict.iteritems() %}
|
||||||
{%- set rows = [] %}
|
{%- if dashboard.get('format', 'yaml')|lower == 'yaml' %}
|
||||||
{%- for row_name, row in dashboard.get('row', {}).iteritems() %}
|
# Dashboards in JSON format are considered as blob
|
||||||
{%- set panels = [] %}
|
{%- set rows = [] %}
|
||||||
{%- for panel_name, panel in row.get('panel', {}).iteritems() %}
|
{%- for row_name, row in dashboard.get('row', {}).iteritems() %}
|
||||||
{%- set targets = [] %}
|
{%- set panels = [] %}
|
||||||
{%- for target_name, target in panel.get('target', {}).iteritems() %}
|
{%- for panel_name, panel in row.get('panel', {}).iteritems() %}
|
||||||
{%- do targets.extend([target]) %}
|
{%- set targets = [] %}
|
||||||
{%- endfor %}
|
{%- for target_name, target in panel.get('target', {}).iteritems() %}
|
||||||
{%- do panel.update({'targets': targets}) %}
|
{%- do targets.extend([target]) %}
|
||||||
{%- do panels.extend([panel]) %}
|
{%- endfor %}
|
||||||
{%- endfor %}
|
{%- do panel.update({'targets': targets}) %}
|
||||||
{%- do row.update({'panels': panels}) %}
|
{%- do panels.extend([panel]) %}
|
||||||
{%- do rows.extend([row]) %}
|
{%- endfor %}
|
||||||
{%- endfor %}
|
{%- do row.update({'panels': panels}) %}
|
||||||
{%- do dashboard.update({'rows': rows}) %}
|
{%- do rows.extend([row]) %}
|
||||||
{%- do final_dict.update({dashboard_name: dashboard}) %}
|
{%- endfor %}
|
||||||
|
{%- do dashboard.update({'rows': rows}) %}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
{%- do final_dict.update({dashboard_name: dashboard}) %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
{%- for dashboard_name, dashboard in final_dict.iteritems() %}
|
{%- for dashboard_name, dashboard in final_dict.iteritems() %}
|
||||||
|
{%- if dashboard.get('enabled', True) %}
|
||||||
{%- if dashboard.get('enabled', True) %}
|
|
||||||
|
|
||||||
grafana_client_dashboard_{{ dashboard_name }}:
|
grafana_client_dashboard_{{ dashboard_name }}:
|
||||||
grafana3_dashboard.present:
|
grafana3_dashboard.present:
|
||||||
- name: {{ dashboard_name }}
|
- 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 }}
|
- dashboard: {{ dashboard }}
|
||||||
|
{%- endif %}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
|
||||||
grafana_client_dashboard_{{ dashboard_name }}:
|
grafana_client_dashboard_{{ dashboard_name }}:
|
||||||
grafana3_dashboard.absent:
|
grafana3_dashboard.absent:
|
||||||
- name: {{ dashboard_name }}
|
- name: {{ dashboard_name }}
|
||||||
|
{%- endif %}
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -13,6 +13,7 @@ grafana_grains_dir:
|
||||||
{# Loading the other service support metadata for localhost #}
|
{# Loading the other service support metadata for localhost #}
|
||||||
|
|
||||||
{%- for service_name, service in pillar.iteritems() %}
|
{%- 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 %}
|
{%- 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 grains_yaml = load_grains_file(grains_fragment_file)|load_yaml %}
|
||||||
{%- set service_grains = salt['grains.filter_by']({'default': service_grains}, merge=grains_yaml) %}
|
{%- set service_grains = salt['grains.filter_by']({'default': service_grains}, merge=grains_yaml) %}
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
grafana_grain:
|
grafana_grain:
|
||||||
|
|
6
metadata/service/collector.yml
Normal file
6
metadata/service/collector.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
applications:
|
||||||
|
- grafana
|
||||||
|
parameters:
|
||||||
|
grafana:
|
||||||
|
collector:
|
||||||
|
enabled: true
|
Loading…
Reference in a new issue