blob: 3ac5338b69afb38d1af9f6bbb633779525b0b8e3 [file] [log] [blame]
Ales Komarek3f044b22016-10-30 00:27:24 +02001# -*- coding: utf-8 -*-
2'''
3Manage Grafana v3.0 data sources
4
5.. versionadded:: 2016.3.0
6
7Token auth setup
8
9.. code-block:: yaml
10
Guillaume Thouveninab102342016-11-03 10:40:29 +010011 grafana_version: 3
Ales Komarek3f044b22016-10-30 00:27:24 +020012 grafana:
Ales Komarek3f044b22016-10-30 00:27:24 +020013 grafana_timeout: 5
14 grafana_token: qwertyuiop
15 grafana_url: 'https://url.com'
16
17Basic auth setup
18
19.. code-block:: yaml
20
Guillaume Thouveninab102342016-11-03 10:40:29 +010021 grafana_version: 3
Ales Komarek3f044b22016-10-30 00:27:24 +020022 grafana:
Ales Komarek3f044b22016-10-30 00:27:24 +020023 grafana_timeout: 5
24 grafana_user: grafana
25 grafana_password: qwertyuiop
26 grafana_url: 'https://url.com'
27
28.. code-block:: yaml
29
30 Ensure influxdb data source is present:
31 grafana_datasource.present:
32 - name: influxdb
33 - type: influxdb
34 - url: http://localhost:8086
35 - access: proxy
36 - basic_auth: true
37 - basic_auth_user: myuser
38 - basic_auth_password: mypass
39 - is_default: true
40'''
41from __future__ import absolute_import
42
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +010043import json
Ales Komarek3f044b22016-10-30 00:27:24 +020044import requests
45
46from salt.ext.six import string_types
47
48
49def __virtual__():
50 '''Only load if grafana v3.0 is configured.'''
51 return __salt__['config.get']('grafana_version', 1) == 3
52
53
54def present(name,
55 type,
56 url,
57 access='proxy',
58 user='',
59 password='',
60 database='',
61 basic_auth=False,
62 basic_auth_user='',
63 basic_auth_password='',
64 is_default=False,
Ales Komarek3f044b22016-10-30 00:27:24 +020065 profile='grafana'):
66 '''
67 Ensure that a data source is present.
68
69 name
70 Name of the data source.
71
72 type
73 Which type of data source it is ('graphite', 'influxdb' etc.).
74
Guillaume Thouveninab102342016-11-03 10:40:29 +010075 access
76 Use proxy or direct. Default: proxy
77
Ales Komarek3f044b22016-10-30 00:27:24 +020078 url
79 The URL to the data source API.
80
81 user
82 Optional - user to authenticate with the data source
83
84 password
85 Optional - password to authenticate with the data source
86
Guillaume Thouveninab102342016-11-03 10:40:29 +010087 database
88 Optional - database to use with the data source
89
Ales Komarek3f044b22016-10-30 00:27:24 +020090 basic_auth
91 Optional - set to True to use HTTP basic auth to authenticate with the
92 data source.
93
94 basic_auth_user
95 Optional - HTTP basic auth username.
96
97 basic_auth_password
98 Optional - HTTP basic auth password.
99
100 is_default
Guillaume Thouveninab102342016-11-03 10:40:29 +0100101 Optional - Set data source as default. Default: False
Ales Komarek3f044b22016-10-30 00:27:24 +0200102 '''
103 if isinstance(profile, string_types):
104 profile = __salt__['config.option'](profile)
105
106 ret = {'name': name, 'result': None, 'comment': None, 'changes': None}
107 datasource = _get_datasource(profile, name)
Guillaume Thouveninab102342016-11-03 10:40:29 +0100108 data = _get_json_data(name, type, url,
109 access=access,
110 user=user,
111 password=password,
112 database=database,
113 basic_auth=basic_auth,
114 basic_auth_user=basic_auth_user,
115 basic_auth_password=basic_auth_password,
116 is_default=is_default)
Ales Komarek3f044b22016-10-30 00:27:24 +0200117
118 if datasource:
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100119 requests.put(
120 _get_url(profile, datasource['id']),
121 data=json.dumps(data),
122 auth=_get_auth(profile),
123 headers=_get_headers(profile),
124 timeout=profile.get('grafana_timeout', 3),
125 )
Ales Komarek3f044b22016-10-30 00:27:24 +0200126 ret['result'] = True
127 ret['changes'] = _diff(datasource, data)
128 if ret['changes']['new'] or ret['changes']['old']:
129 ret['comment'] = 'Data source {0} updated'.format(name)
130 else:
131 ret['changes'] = None
132 ret['comment'] = 'Data source {0} already up-to-date'.format(name)
133 else:
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100134 requests.post(
135 '{0}/api/datasources'.format(profile['grafana_url']),
136 data=json.dumps(data),
137 auth=_get_auth(profile),
138 headers=_get_headers(profile),
139 timeout=profile.get('grafana_timeout', 3),
140 )
Ales Komarek3f044b22016-10-30 00:27:24 +0200141 ret['result'] = True
142 ret['comment'] = 'New data source {0} added'.format(name)
143 ret['changes'] = data
144
145 return ret
146
147
148def absent(name, profile='grafana'):
149 '''
150 Ensure that a data source is present.
151
152 name
153 Name of the data source to remove.
154 '''
155 if isinstance(profile, string_types):
156 profile = __salt__['config.option'](profile)
157
158 ret = {'result': None, 'comment': None, 'changes': None}
159 datasource = _get_datasource(profile, name)
160
161 if not datasource:
162 ret['result'] = True
163 ret['comment'] = 'Data source {0} already absent'.format(name)
164 return ret
165
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100166 requests.delete(
167 _get_url(profile, datasource['id']),
168 auth=_get_auth(profile),
169 headers=_get_headers(profile),
170 timeout=profile.get('grafana_timeout', 3),
171 )
Ales Komarek3f044b22016-10-30 00:27:24 +0200172
173 ret['result'] = True
174 ret['comment'] = 'Data source {0} was deleted'.format(name)
175
176 return ret
177
178
179def _get_url(profile, datasource_id):
180 return '{0}/api/datasources/{1}'.format(
181 profile['grafana_url'],
182 datasource_id
183 )
184
185
186def _get_datasource(profile, name):
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100187 response = requests.get(
188 '{0}/api/datasources'.format(profile['grafana_url']),
189 auth=_get_auth(profile),
190 headers=_get_headers(profile),
191 timeout=profile.get('grafana_timeout', 3),
192 )
Ales Komarek3f044b22016-10-30 00:27:24 +0200193 data = response.json()
194 for datasource in data:
195 if datasource['name'] == name:
196 return datasource
197 return None
198
199
200def _get_headers(profile):
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100201
202 headers = {'Content-type': 'application/json'}
203
204 if profile.get('grafana_token', False):
205 headers['Authorization'] = 'Bearer {0}'.format(profile['grafana_token'])
206
207 return headers
Ales Komarek3f044b22016-10-30 00:27:24 +0200208
209
210def _get_auth(profile):
Guillaume Thouvenine3e6e3f2016-11-03 14:52:16 +0100211 if profile.get('grafana_token', False):
212 return None
213
Ales Komarek3f044b22016-10-30 00:27:24 +0200214 return requests.auth.HTTPBasicAuth(
215 profile['grafana_user'],
216 profile['grafana_password']
217 )
218
219
220def _get_json_data(name,
221 type,
222 url,
223 access='proxy',
224 user='',
225 password='',
226 database='',
227 basic_auth=False,
228 basic_auth_user='',
229 basic_auth_password='',
230 is_default=False,
Guillaume Thouveninab102342016-11-03 10:40:29 +0100231 type_logo_url='public/app/plugins/datasource/influxdb/img/influxdb_logo.svg',
232 with_credentials=False):
Ales Komarek3f044b22016-10-30 00:27:24 +0200233 return {
234 'name': name,
235 'type': type,
236 'url': url,
237 'access': access,
238 'user': user,
239 'password': password,
240 'database': database,
241 'basicAuth': basic_auth,
242 'basicAuthUser': basic_auth_user,
243 'basicAuthPassword': basic_auth_password,
244 'isDefault': is_default,
245 'typeLogoUrl': type_logo_url,
246 'withCredentials': with_credentials,
Ales Komarek3f044b22016-10-30 00:27:24 +0200247 }
248
249
250def _diff(old, new):
251 old_keys = old.keys()
252 old = old.copy()
253 new = new.copy()
254 for key in old_keys:
255 if key == 'id' or key == 'orgId':
256 del old[key]
257 elif old[key] == new[key]:
258 del old[key]
259 del new[key]
260 return {'old': old, 'new': new}