2016-10-29 18:27:24 -04:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
'''
|
|
|
|
Manage Grafana v3.0 data sources
|
|
|
|
|
|
|
|
.. versionadded:: 2016.3.0
|
|
|
|
|
|
|
|
Token auth setup
|
|
|
|
|
|
|
|
.. code-block:: yaml
|
|
|
|
|
2016-11-03 05:40:29 -04:00
|
|
|
grafana_version: 3
|
2016-10-29 18:27:24 -04:00
|
|
|
grafana:
|
|
|
|
grafana_timeout: 5
|
|
|
|
grafana_token: qwertyuiop
|
|
|
|
grafana_url: 'https://url.com'
|
|
|
|
|
|
|
|
Basic auth setup
|
|
|
|
|
|
|
|
.. code-block:: yaml
|
|
|
|
|
2016-11-03 05:40:29 -04:00
|
|
|
grafana_version: 3
|
2016-10-29 18:27:24 -04:00
|
|
|
grafana:
|
|
|
|
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
|
|
|
|
|
2016-11-03 09:52:16 -04:00
|
|
|
import json
|
2016-10-29 18:27:24 -04:00
|
|
|
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,
|
|
|
|
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.).
|
|
|
|
|
2016-11-03 05:40:29 -04:00
|
|
|
access
|
|
|
|
Use proxy or direct. Default: proxy
|
|
|
|
|
2016-10-29 18:27:24 -04:00
|
|
|
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
|
|
|
|
|
2016-11-03 05:40:29 -04:00
|
|
|
database
|
|
|
|
Optional - database to use with the data source
|
|
|
|
|
2016-10-29 18:27:24 -04:00
|
|
|
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
|
2016-11-03 05:40:29 -04:00
|
|
|
Optional - Set data source as default. Default: False
|
2016-10-29 18:27:24 -04:00
|
|
|
'''
|
|
|
|
if isinstance(profile, string_types):
|
|
|
|
profile = __salt__['config.option'](profile)
|
|
|
|
|
|
|
|
ret = {'name': name, 'result': None, 'comment': None, 'changes': None}
|
|
|
|
datasource = _get_datasource(profile, name)
|
2016-11-03 05:40:29 -04:00
|
|
|
data = _get_json_data(name, type, url,
|
|
|
|
access=access,
|
|
|
|
user=user,
|
|
|
|
password=password,
|
|
|
|
database=database,
|
|
|
|
basic_auth=basic_auth,
|
|
|
|
basic_auth_user=basic_auth_user,
|
|
|
|
basic_auth_password=basic_auth_password,
|
|
|
|
is_default=is_default)
|
2016-10-29 18:27:24 -04:00
|
|
|
|
|
|
|
if datasource:
|
2016-11-03 09:52:16 -04:00
|
|
|
requests.put(
|
|
|
|
_get_url(profile, datasource['id']),
|
|
|
|
data=json.dumps(data),
|
|
|
|
auth=_get_auth(profile),
|
|
|
|
headers=_get_headers(profile),
|
|
|
|
timeout=profile.get('grafana_timeout', 3),
|
|
|
|
)
|
2016-10-29 18:27:24 -04:00
|
|
|
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:
|
2016-11-03 09:52:16 -04:00
|
|
|
requests.post(
|
|
|
|
'{0}/api/datasources'.format(profile['grafana_url']),
|
|
|
|
data=json.dumps(data),
|
|
|
|
auth=_get_auth(profile),
|
|
|
|
headers=_get_headers(profile),
|
|
|
|
timeout=profile.get('grafana_timeout', 3),
|
|
|
|
)
|
2016-10-29 18:27:24 -04:00
|
|
|
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
|
|
|
|
|
2016-11-03 09:52:16 -04:00
|
|
|
requests.delete(
|
|
|
|
_get_url(profile, datasource['id']),
|
|
|
|
auth=_get_auth(profile),
|
|
|
|
headers=_get_headers(profile),
|
|
|
|
timeout=profile.get('grafana_timeout', 3),
|
|
|
|
)
|
2016-10-29 18:27:24 -04:00
|
|
|
|
|
|
|
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):
|
2016-11-03 09:52:16 -04:00
|
|
|
response = requests.get(
|
|
|
|
'{0}/api/datasources'.format(profile['grafana_url']),
|
|
|
|
auth=_get_auth(profile),
|
|
|
|
headers=_get_headers(profile),
|
|
|
|
timeout=profile.get('grafana_timeout', 3),
|
|
|
|
)
|
2016-10-29 18:27:24 -04:00
|
|
|
data = response.json()
|
|
|
|
for datasource in data:
|
|
|
|
if datasource['name'] == name:
|
|
|
|
return datasource
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def _get_headers(profile):
|
2016-11-03 09:52:16 -04:00
|
|
|
|
|
|
|
headers = {'Content-type': 'application/json'}
|
|
|
|
|
|
|
|
if profile.get('grafana_token', False):
|
|
|
|
headers['Authorization'] = 'Bearer {0}'.format(profile['grafana_token'])
|
|
|
|
|
|
|
|
return headers
|
2016-10-29 18:27:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
def _get_auth(profile):
|
2016-11-03 09:52:16 -04:00
|
|
|
if profile.get('grafana_token', False):
|
|
|
|
return None
|
|
|
|
|
2016-10-29 18:27:24 -04:00
|
|
|
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,
|
2016-11-03 05:40:29 -04:00
|
|
|
type_logo_url='public/app/plugins/datasource/influxdb/img/influxdb_logo.svg',
|
|
|
|
with_credentials=False):
|
2016-10-29 18:27:24 -04:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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]
|
2016-12-12 10:53:38 -05:00
|
|
|
# New versions of Grafana can introduce new keys that are not present
|
|
|
|
# in _get_json_data.
|
|
|
|
elif key in new and old[key] == new[key]:
|
2016-10-29 18:27:24 -04:00
|
|
|
del old[key]
|
|
|
|
del new[key]
|
|
|
|
return {'old': old, 'new': new}
|