# -*- coding: utf-8 -*- ''' Manage Grafana v3.0 data sources .. versionadded:: 2016.3.0 Token auth setup .. code-block:: yaml grafana: grafana_version: 3 grafana_timeout: 5 grafana_token: qwertyuiop grafana_url: 'https://url.com' Basic auth setup .. code-block:: yaml grafana: grafana_version: 3 grafana_timeout: 5 grafana_user: grafana grafana_password: qwertyuiop grafana_url: 'https://url.com' .. code-block:: yaml Ensure influxdb data source is present: grafana_datasource.present: - name: influxdb - type: influxdb - url: http://localhost:8086 - access: proxy - basic_auth: true - basic_auth_user: myuser - basic_auth_password: mypass - is_default: true ''' from __future__ import absolute_import import requests from salt.ext.six import string_types def __virtual__(): '''Only load if grafana v3.0 is configured.''' return __salt__['config.get']('grafana_version', 1) == 3 def present(name, type, url, access='proxy', user='', password='', database='', basic_auth=False, basic_auth_user='', basic_auth_password='', is_default=False, type_logo_url='public/app/plugins/datasource/graphite/img/graphite_logo.png', with_credentials=False, json_data=None, profile='grafana'): ''' Ensure that a data source is present. name Name of the data source. type Which type of data source it is ('graphite', 'influxdb' etc.). url The URL to the data source API. user Optional - user to authenticate with the data source password Optional - password to authenticate with the data source basic_auth Optional - set to True to use HTTP basic auth to authenticate with the data source. basic_auth_user Optional - HTTP basic auth username. basic_auth_password Optional - HTTP basic auth password. is_default Default: False ''' if isinstance(profile, string_types): profile = __salt__['config.option'](profile) ret = {'name': name, 'result': None, 'comment': None, 'changes': None} datasource = _get_datasource(profile, name) data = _get_json_data(name, type, url, access, user, password, database, basic_auth, basic_auth_user, basic_auth_password, is_default, json_data) if datasource: if profile.get('grafana_token', False): requests.put( _get_url(profile, datasource['id']), data, headers=_get_headers(profile), timeout=profile.get('grafana_timeout', 3), ) else: requests.put( _get_url(profile, datasource['id']), data, auth=_get_auth(profile), timeout=profile.get('grafana_timeout', 3), ) ret['result'] = True ret['changes'] = _diff(datasource, data) if ret['changes']['new'] or ret['changes']['old']: ret['comment'] = 'Data source {0} updated'.format(name) else: ret['changes'] = None ret['comment'] = 'Data source {0} already up-to-date'.format(name) else: requests.post( '{0}/api/datasources'.format(profile['grafana_url']), data, headers=_get_headers(profile), timeout=profile.get('grafana_timeout', 3), ) ret['result'] = True ret['comment'] = 'New data source {0} added'.format(name) ret['changes'] = data return ret def absent(name, profile='grafana'): ''' Ensure that a data source is present. name Name of the data source to remove. ''' if isinstance(profile, string_types): profile = __salt__['config.option'](profile) ret = {'result': None, 'comment': None, 'changes': None} datasource = _get_datasource(profile, name) if not datasource: ret['result'] = True ret['comment'] = 'Data source {0} already absent'.format(name) return ret if profile.get('grafana_token', False): requests.delete( _get_url(profile, datasource['id']), headers=_get_headers(profile), timeout=profile.get('grafana_timeout', 3), ) else: requests.delete( _get_url(profile, datasource['id']), auth=_get_auth(profile), timeout=profile.get('grafana_timeout', 3), ) ret['result'] = True ret['comment'] = 'Data source {0} was deleted'.format(name) return ret def _get_url(profile, datasource_id): return '{0}/api/datasources/{1}'.format( profile['grafana_url'], datasource_id ) def _get_datasource(profile, name): if profile.get('grafana_token', False): response = requests.get( '{0}/api/datasources'.format(profile['grafana_url']), headers=_get_headers(profile), timeout=profile.get('grafana_timeout', 3), ) else: response = requests.get( '{0}/api/datasources'.format(profile['grafana_url']), auth=_get_auth(profile), timeout=profile.get('grafana_timeout', 3), ) data = response.json() for datasource in data: if datasource['name'] == name: return datasource return None def _get_headers(profile): return { 'Accept': 'application/json', 'Authorization': 'Bearer {0}'.format(profile['grafana_token']) } def _get_auth(profile): return requests.auth.HTTPBasicAuth( profile['grafana_user'], profile['grafana_password'] ) def _get_json_data(name, type, url, access='proxy', user='', password='', database='', basic_auth=False, basic_auth_user='', basic_auth_password='', is_default=False, type_logo_url='public/app/plugins/datasource/graphite/img/graphite_logo.png', with_credentials=False, json_data=None): return { 'name': name, 'type': type, 'url': url, 'access': access, 'user': user, 'password': password, 'database': database, 'basicAuth': basic_auth, 'basicAuthUser': basic_auth_user, 'basicAuthPassword': basic_auth_password, 'isDefault': is_default, 'typeLogoUrl': type_logo_url, 'withCredentials': with_credentials, 'jsonData': json_data, } def _diff(old, new): old_keys = old.keys() old = old.copy() new = new.copy() for key in old_keys: if key == 'id' or key == 'orgId': del old[key] elif old[key] == new[key]: del old[key] del new[key] return {'old': old, 'new': new}