Add support for JSON dashboards
This patch adds the support for JSON dashboards and also provides the
support for remote dashboards.
diff --git a/README.rst b/README.rst
index fcbdef8..f806ffe 100644
--- a/README.rst
+++ b/README.rst
@@ -44,7 +44,9 @@
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
@@ -202,7 +204,7 @@
span: 6
editable: false
type: graph
- targets:
+ targets:
- refId: A
target: "support_prd.cfg01_iot_tcpcloud_eu.cpu.0.idle"
datasource: graphite01
diff --git a/_states/grafana3_dashboard.py b/_states/grafana3_dashboard.py
index 0087b2c..63090ab 100644
--- a/_states/grafana3_dashboard.py
+++ b/_states/grafana3_dashboard.py
@@ -65,6 +65,7 @@
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 @@
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 @@
'''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 @@
'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']
@@ -568,4 +581,4 @@
for k, v in six.iteritems(d):
if v:
ret[k] = v
- return ret
\ No newline at end of file
+ return ret
diff --git a/grafana/client.sls b/grafana/client.sls
index 47cef61..1275f1b 100644
--- a/grafana/client.sls
+++ b/grafana/client.sls
@@ -36,52 +36,56 @@
{%- 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 %}
diff --git a/grafana/collector.sls b/grafana/collector.sls
index b1f76b1..4532547 100644
--- a/grafana/collector.sls
+++ b/grafana/collector.sls
@@ -13,6 +13,7 @@
{# 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 @@
{%- 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:
diff --git a/metadata/service/collector.yml b/metadata/service/collector.yml
new file mode 100644
index 0000000..f788dd0
--- /dev/null
+++ b/metadata/service/collector.yml
@@ -0,0 +1,6 @@
+applications:
+- grafana
+parameters:
+ grafana:
+ collector:
+ enabled: true