blob: a66836bb880145cbd761eec3ee6637cbd0a65cd1 [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
11 grafana:
12 grafana_version: 3
13 grafana_timeout: 5
14 grafana_token: qwertyuiop
15 grafana_url: 'https://url.com'
16
17Basic auth setup
18
19.. code-block:: yaml
20
21 grafana:
22 grafana_version: 3
23 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
43import requests
44
45from salt.ext.six import string_types
46
47
48def __virtual__():
49 '''Only load if grafana v3.0 is configured.'''
50 return __salt__['config.get']('grafana_version', 1) == 3
51
52
53def present(name,
54 type,
55 url,
56 access='proxy',
57 user='',
58 password='',
59 database='',
60 basic_auth=False,
61 basic_auth_user='',
62 basic_auth_password='',
63 is_default=False,
64 type_logo_url='public/app/plugins/datasource/graphite/img/graphite_logo.png',
65 with_credentials=False,
66 json_data=None,
67 profile='grafana'):
68 '''
69 Ensure that a data source is present.
70
71 name
72 Name of the data source.
73
74 type
75 Which type of data source it is ('graphite', 'influxdb' etc.).
76
77 url
78 The URL to the data source API.
79
80 user
81 Optional - user to authenticate with the data source
82
83 password
84 Optional - password to authenticate with the data source
85
86 basic_auth
87 Optional - set to True to use HTTP basic auth to authenticate with the
88 data source.
89
90 basic_auth_user
91 Optional - HTTP basic auth username.
92
93 basic_auth_password
94 Optional - HTTP basic auth password.
95
96 is_default
97 Default: False
98 '''
99 if isinstance(profile, string_types):
100 profile = __salt__['config.option'](profile)
101
102 ret = {'name': name, 'result': None, 'comment': None, 'changes': None}
103 datasource = _get_datasource(profile, name)
104 data = _get_json_data(name, type, url, access, user, password, database,
105 basic_auth, basic_auth_user, basic_auth_password, is_default, json_data)
106
107 if datasource:
108 if profile.get('grafana_token', False):
109 requests.put(
110 _get_url(profile, datasource['id']),
111 data,
112 headers=_get_headers(profile),
113 timeout=profile.get('grafana_timeout', 3),
114 )
115 else:
116 requests.put(
117 _get_url(profile, datasource['id']),
118 data,
119 auth=_get_auth(profile),
120 timeout=profile.get('grafana_timeout', 3),
121 )
122 ret['result'] = True
123 ret['changes'] = _diff(datasource, data)
124 if ret['changes']['new'] or ret['changes']['old']:
125 ret['comment'] = 'Data source {0} updated'.format(name)
126 else:
127 ret['changes'] = None
128 ret['comment'] = 'Data source {0} already up-to-date'.format(name)
129 else:
130 requests.post(
131 '{0}/api/datasources'.format(profile['grafana_url']),
132 data,
133 headers=_get_headers(profile),
134 timeout=profile.get('grafana_timeout', 3),
135 )
136 ret['result'] = True
137 ret['comment'] = 'New data source {0} added'.format(name)
138 ret['changes'] = data
139
140 return ret
141
142
143def absent(name, profile='grafana'):
144 '''
145 Ensure that a data source is present.
146
147 name
148 Name of the data source to remove.
149 '''
150 if isinstance(profile, string_types):
151 profile = __salt__['config.option'](profile)
152
153 ret = {'result': None, 'comment': None, 'changes': None}
154 datasource = _get_datasource(profile, name)
155
156 if not datasource:
157 ret['result'] = True
158 ret['comment'] = 'Data source {0} already absent'.format(name)
159 return ret
160
161 if profile.get('grafana_token', False):
162 requests.delete(
163 _get_url(profile, datasource['id']),
164 headers=_get_headers(profile),
165 timeout=profile.get('grafana_timeout', 3),
166 )
167 else:
168 requests.delete(
169 _get_url(profile, datasource['id']),
170 auth=_get_auth(profile),
171 timeout=profile.get('grafana_timeout', 3),
172 )
173
174 ret['result'] = True
175 ret['comment'] = 'Data source {0} was deleted'.format(name)
176
177 return ret
178
179
180def _get_url(profile, datasource_id):
181 return '{0}/api/datasources/{1}'.format(
182 profile['grafana_url'],
183 datasource_id
184 )
185
186
187def _get_datasource(profile, name):
188 if profile.get('grafana_token', False):
189 response = requests.get(
190 '{0}/api/datasources'.format(profile['grafana_url']),
191 headers=_get_headers(profile),
192 timeout=profile.get('grafana_timeout', 3),
193 )
194 else:
195 response = requests.get(
196 '{0}/api/datasources'.format(profile['grafana_url']),
197 auth=_get_auth(profile),
198 timeout=profile.get('grafana_timeout', 3),
199 )
200 data = response.json()
201 for datasource in data:
202 if datasource['name'] == name:
203 return datasource
204 return None
205
206
207def _get_headers(profile):
208 return {
209 'Accept': 'application/json',
210 'Authorization': 'Bearer {0}'.format(profile['grafana_token'])
211 }
212
213
214def _get_auth(profile):
215 return requests.auth.HTTPBasicAuth(
216 profile['grafana_user'],
217 profile['grafana_password']
218 )
219
220
221def _get_json_data(name,
222 type,
223 url,
224 access='proxy',
225 user='',
226 password='',
227 database='',
228 basic_auth=False,
229 basic_auth_user='',
230 basic_auth_password='',
231 is_default=False,
232 type_logo_url='public/app/plugins/datasource/graphite/img/graphite_logo.png',
233 with_credentials=False,
234 json_data=None):
235 return {
236 'name': name,
237 'type': type,
238 'url': url,
239 'access': access,
240 'user': user,
241 'password': password,
242 'database': database,
243 'basicAuth': basic_auth,
244 'basicAuthUser': basic_auth_user,
245 'basicAuthPassword': basic_auth_password,
246 'isDefault': is_default,
247 'typeLogoUrl': type_logo_url,
248 'withCredentials': with_credentials,
249 'jsonData': json_data,
250 }
251
252
253def _diff(old, new):
254 old_keys = old.keys()
255 old = old.copy()
256 new = new.copy()
257 for key in old_keys:
258 if key == 'id' or key == 'orgId':
259 del old[key]
260 elif old[key] == new[key]:
261 del old[key]
262 del new[key]
263 return {'old': old, 'new': new}