grafana 0.8.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +8 -3
  3. data/lib/_logging.rb_ +55 -0
  4. data/lib/grafana.rb +1 -1
  5. data/lib/grafana/admin.rb +2 -1
  6. data/lib/grafana/alerts.rb +338 -14
  7. data/lib/grafana/annotations.rb +284 -9
  8. data/lib/grafana/auth.rb +150 -0
  9. data/lib/grafana/client.rb +81 -5
  10. data/lib/grafana/dashboard.rb +99 -7
  11. data/lib/grafana/dashboard_permissions.rb +132 -0
  12. data/lib/grafana/dashboard_versions.rb +101 -5
  13. data/lib/grafana/datasource.rb +34 -38
  14. data/lib/grafana/folder.rb +198 -0
  15. data/lib/grafana/folder_and_dashboard_search.rb +57 -0
  16. data/lib/grafana/folder_permissions.rb +155 -0
  17. data/lib/grafana/logging.rb +55 -0
  18. data/lib/grafana/login.rb +93 -49
  19. data/lib/grafana/network.rb +130 -101
  20. data/lib/grafana/organization.rb +2 -1
  21. data/lib/grafana/organizations.rb +15 -6
  22. data/lib/grafana/playlist.rb +594 -0
  23. data/lib/grafana/preferences.rb +122 -0
  24. data/lib/grafana/tags.rb +16 -0
  25. data/lib/grafana/teams.rb +364 -0
  26. data/lib/grafana/tools.rb +42 -9
  27. data/lib/grafana/user.rb +6 -2
  28. data/lib/grafana/users.rb +19 -11
  29. data/lib/grafana/validator.rb +47 -2
  30. data/lib/grafana/version.rb +3 -3
  31. metadata +16 -39
  32. data/doc/Array.html +0 -200
  33. data/doc/Boolean.html +0 -122
  34. data/doc/FalseClass.html +0 -132
  35. data/doc/Grafana.html +0 -172
  36. data/doc/Hash.html +0 -212
  37. data/doc/Logging.html +0 -326
  38. data/doc/Object.html +0 -286
  39. data/doc/Time.html +0 -200
  40. data/doc/TrueClass.html +0 -132
  41. data/doc/_index.html +0 -380
  42. data/doc/class_list.html +0 -51
  43. data/doc/file.README.html +0 -117
  44. data/doc/file_list.html +0 -56
  45. data/doc/frames.html +0 -17
  46. data/doc/index.html +0 -117
  47. data/doc/method_list.html +0 -747
  48. data/doc/top-level-namespace.html +0 -112
  49. data/lib/logging.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bcc9d3c645a3c12b1cc31d23c9f123b10369be5b
4
- data.tar.gz: 8f99154dd21e93476cd6a3163e32550ecdd2816a
2
+ SHA256:
3
+ metadata.gz: ee4ecb6c21184aee321f81b9d5a5681524da6cac47b736756e8b3b1a4c091eed
4
+ data.tar.gz: 267e82424dad92727eace6b546f2fd436235e51af5b471c806833e4eb3186efe
5
5
  SHA512:
6
- metadata.gz: abef29e0ae13c67c3cfcf09a5f79a9c7f16a850b8eb7cecb023ae9ded603d49d335dd7069b696d9493efbc60dff0fdcb9a8534b8563979d4689b10ce388b0374
7
- data.tar.gz: 560de8458cf0d3ef08cdfff425be1d3a7c435846df193931fbe1cf2bca1eedb6dda9b738d47952f27d3fdab26e48fef8cc543ffdc66b3037cdda3ed5bd104288
6
+ metadata.gz: 97d4a3aa5740c1992cf706fec3deae4690db5c68f05eb334b828dea74d6173fde86fbb3a53c2afe562d5a299e13a2c5450d4e27bcdf7dae96a146a8b3f2cb770
7
+ data.tar.gz: 5c231dad3f4552d8176b8b0a5653284b3792ec1058c958674a625e99b790d9e51f93eb240ca5f500c94e2cbff23159b2933fac13723cdaa0518b8f808f31176a
data/README.md CHANGED
@@ -26,11 +26,16 @@ TODO: Write usage instructions here
26
26
 
27
27
  ## Development
28
28
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
29
+ After checking out the repo, run `bin/setup` to install dependencies.
30
+ Then, run `rake rake` to run the tests.
31
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
32
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
33
+ To install this gem onto your local machine, run `bundle exec rake install`.
34
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
35
+ which will create a git tag for the version,
36
+ push git commits and tags and push the `.gem` file to [rubygems.org](https://rubygems.org/gems/grafana).
32
37
 
33
38
  ## Contributing
34
39
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/grafana.
40
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bodsch/grafana.
36
41
 
data/lib/_logging.rb_ ADDED
@@ -0,0 +1,55 @@
1
+
2
+ require 'logger'
3
+
4
+ # -------------------------------------------------------------------------------------------------
5
+
6
+ module Logging
7
+
8
+ def logger
9
+ @logger ||= Logging.logger_for( self.class.name )
10
+ end
11
+
12
+ # Use a hash class-ivar to cache a unique Logger per class:
13
+ @loggers = {}
14
+
15
+ class << self
16
+
17
+ def logger_for( classname )
18
+ @loggers[classname] ||= configure_logger_for( classname )
19
+ end
20
+
21
+ def configure_logger_for( classname )
22
+
23
+ log_level = ENV.fetch('LOG_LEVEL', 'INFO' )
24
+ level = log_level.dup
25
+
26
+ # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
27
+ log_level = case level.upcase
28
+ when 'DEBUG'
29
+ Logger::DEBUG # Low-level information for developers.
30
+ when 'INFO'
31
+ Logger::INFO # Generic (useful) information about system operation.
32
+ when 'WARN'
33
+ Logger::WARN # A warning.
34
+ when 'ERROR'
35
+ Logger::ERROR # A handleable error condition.
36
+ when 'FATAL'
37
+ Logger::FATAL # An unhandleable error that results in a program crash.
38
+ else
39
+ Logger::UNKNOWN # An unknown message that should always be logged.
40
+ end
41
+
42
+ $stdout.sync = true
43
+ logger = Logger.new($stdout)
44
+ logger.level = log_level
45
+ logger.datetime_format = "%Y-%m-%d %H:%M:%S %z"
46
+ logger.formatter = proc do |severity, datetime, progname, msg|
47
+ "[#{datetime.strftime( logger.datetime_format )}] #{severity.ljust(5)} #{msg}\n"
48
+ end
49
+
50
+ logger
51
+ end
52
+ end
53
+ end
54
+
55
+ # -------------------------------------------------------------------------------------------------
data/lib/grafana.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- require_relative 'logging'
2
+ # require_relative 'logging'
3
3
  require_relative 'monkey_patches.rb'
4
4
  require_relative 'grafana/client.rb'
5
5
 
data/lib/grafana/admin.rb CHANGED
@@ -142,7 +142,8 @@ module Grafana
142
142
  #
143
143
  def delete_user( user_id )
144
144
 
145
- raise ArgumentError.new(format('wrong type. user \'user_id\' must be an String (for an User name) or an Integer (for an User Id), given \'%s\'', user_id.class.to_s)) if( user_id.is_a?(String) && user_id.is_a?(Integer) )
145
+ raise ArgumentError.new(format('wrong type. user \'user_id\' must be an String (for an User name) or an Integer (for an User Id), given \'%s\'', user_id.class.to_s)) \
146
+ if( user_id.is_a?(String) && user_id.is_a?(Integer) )
146
147
  raise ArgumentError.new('missing \'user_id\'') if( user_id.size.zero? )
147
148
 
148
149
  if(user_id.is_a?(String))
@@ -1,38 +1,362 @@
1
1
 
2
2
  module Grafana
3
3
 
4
- # http://docs.grafana.org/http_api/alerting/
4
+ # You can use the Alerting API to get information about alerts and their states but this API cannot be used to modify the alert.
5
+ # To create new alerts or modify them you need to update the dashboard json that contains the alerts.
6
+ #
7
+ # This API can also be used to create, update and delete alert notifications.
8
+ #
9
+ # original API Documentation can be found under: http://docs.grafana.org/http_api/alerting/
5
10
  #
6
11
  module Alerts
7
12
 
8
13
  # Get alerts
14
+ #
15
+ # These parameters are used as querystring parameters. For example:
16
+ #
17
+ # @param [Hash] params
18
+ # @option params [Mixed] dashboard_id alerts for a specified dashboard.
19
+ # @option params [Integer] panel_id alerts for a specified panel on a dashboard.
20
+ # @option params [Integer] limit (10) response to x number of alerts.
21
+ # @option params [Integer] state (ALL,no_data, paused, alerting, ok, pending)
22
+ # @option params [Array] alerts with one or more of the following alert states: 'ALL', 'no_data', 'paused', 'alerting', 'ok', 'pending'.
23
+ ## To specify multiple states use the following format: ?state=paused&state=alerting
24
+ #
25
+ # @return [Array]
9
26
  # GET /api/alerts/
27
+ # curl -H 'Content-Type: application/json;charset=UTF-8' 'http://admin:admin@127.0.0.1:3030/api/alerts'
10
28
  #
29
+ def alerts( params )
30
+
31
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
32
+ # raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
33
+
34
+ dashboard_id = validate( params, required: false, var: 'dashboard_id' )
35
+ panel_id = validate( params, required: false, var: 'panel_id', type: Integer )
36
+ limit = validate( params, required: false, var: 'limit', type: Integer )
37
+ alert_array = validate( params, required: false, var: 'alerts', type: Array )
38
+ valid_alerts = %w[ALL no_data paused alerting ok pending].sort
39
+
40
+ unless( alert_array.nil? )
41
+ alert_array = alert_array.sort
42
+ # valid = alert_array & valid_alerts
43
+ invalid = alert_array - valid_alerts
44
+
45
+ raise ArgumentError.new(format('wrong alerts type. only %s allowed, given \'%s\'', valid_alerts.join(', '), alert_array.join(', '))) if( invalid.count != 0 )
46
+ end
47
+
48
+ if( dashboard_id.is_a?(String) )
49
+
50
+ dashboard = search_dashboards( query: dashboard_id )
51
+
52
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard_id) } if( dashboard.nil? || dashboard.dig('status').to_i != 200 )
53
+
54
+ dashboard = dashboard.dig('message').first unless( dashboard.nil? && dashboard.dig('status').to_i == 200 )
55
+ dashboard_id = dashboard.dig('id') unless( dashboard.nil? )
56
+
57
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard_id) } if( dashboard_id.nil? )
58
+ end
59
+
60
+ api = []
61
+ api << format( 'dashboardId=%s', dashboard_id ) unless( dashboard_id.nil? )
62
+ api << format( 'panelId=%s', panel_id ) unless( panel_id.nil? )
63
+ api << format( 'limit=%s', limit ) unless( limit.nil? )
64
+
65
+ unless( alert_array.nil? )
66
+ alert_array = alert_array.join( '&state=' ) if( alert_array.is_a?( Array ) )
67
+ api << format( 'state=%s', alert_array )
68
+ end
69
+ api = api.join( '&' )
70
+
71
+ endpoint = format( '/api/alerts/?%s' , api )
72
+
73
+ @logger.debug("Attempting to search for alerts (GET #{endpoint})") if @debug
74
+
75
+ get( endpoint )
76
+ end
77
+
11
78
  # Get one alert
12
- # GET /api/alerts/:id
13
79
  #
14
- def alerts( id = nil ); end
80
+ # @param [Mixed] alert_id Alertname (String) or Alertid (Integer)
81
+ #
82
+ # @example
83
+ # alert( 1 )
84
+ # alert( 'foo' )
85
+ #
86
+ # @return [Hash]
87
+ #
88
+ # curl -H 'Content-Type: application/json;charset=UTF-8' 'http://admin:admin@127.0.0.1:3030/api/alerts/1'
89
+ #
90
+ def alert( alert_id )
15
91
 
16
- # Pause alert
17
- # POST /api/alerts/:id/pause
18
- def alert_pause( id ); end
92
+ if( alert_id.is_a?(String) && alert_id.is_a?(Integer) )
93
+ raise ArgumentError.new(format('wrong type. \'alert_id\' must be an String (for an Alert name) or an Integer (for an Alert Id), given \'%s\'', alert_id.class.to_s))
94
+ end
95
+ raise ArgumentError.new('missing \'alert_id\'') if( alert_id.size.zero? )
96
+
97
+ # if(alert_id.is_a?(String))
98
+ # data = alerts( alerts: 'all' ).select { |_k,v| v['name'] == alert_id }
99
+ # alert_id = data.keys.first if( data )
100
+ # end
101
+
102
+ # puts alert_id
103
+ # GET /api/alerts/:id
104
+
105
+ endpoint = format( '/api/alerts/%d' , alert_id )
106
+
107
+ # puts endpoint
108
+
109
+ @logger.debug("Attempting get alert id #{alert_id} (GET #{endpoint})") if @debug
110
+
111
+ get( endpoint )
112
+ end
113
+
114
+
115
+ # Pause single alert
116
+ #
117
+ # @param [Mixed] alert_id Alertname (String) or Alertid (Integer)
118
+ #
119
+ # @example
120
+ # alert_pause( 1 )
121
+ # alert_pause( 'foo' )
122
+ #
123
+ # @return [Hash]
124
+ #
125
+ def alert_pause( alert_id )
126
+
127
+ if( alert_id.is_a?(String) && alert_id.is_a?(Integer) )
128
+ raise ArgumentError.new(format('wrong type. \'alert_id\' must be an String (for an Alert name) or an Integer (for an Alert Id), given \'%s\'', alert_id.class.to_s))
129
+ end
130
+ raise ArgumentError.new('missing \'alert_id\'') if( alert_id.size.zero? )
131
+
132
+ if( alert_id.is_a?(String) )
133
+ data = alerts( alerts: 'all' ).select { |_k,v| v['name'] == alert_id }
134
+ alert_id = data.keys.first if( data )
135
+ end
136
+
137
+ endpoint = format( '/api/alerts/%d/pause', alert_id )
138
+
139
+ @logger.debug("Attempting pause alert id #{alert_id} (POST #{endpoint})") if @debug
140
+
141
+ # POST /api/alerts/:id/pause
142
+ # puts alert_id
143
+ post( endpoint )
144
+ end
19
145
 
20
146
  # Get alert notifications
21
- # GET /api/alert-notifications
22
- def alert_notifications; end
147
+ #
148
+ # @example
149
+ # alert_notifications
150
+ #
151
+ # @return [Hash]
152
+ #
153
+ def alert_notifications
154
+ logger.debug('Getting alert notifications') if @debug
155
+ get('/api/alert-notifications')
156
+ end
157
+
158
+
159
+
160
+
161
+
23
162
 
24
163
  # Create alert notification
25
- # POST /api/alert-notifications
26
- def create_alert_notification( oarams ); end
164
+ #
165
+ # @param [Hash] params
166
+ # @option params [String] name short description - required
167
+ # @option params [String] type one of 'slack', 'pagerduty','email','webhook','kafka','hipchat',
168
+ # 'victorops','sensu','opsgenie','threema','pushover','telegram','line','prometheus-alertmanager' - required
169
+ # @option params [Boolean] default (false)
170
+ # @option params [Hash] settings
171
+ #
172
+ # @example
173
+ # params = {
174
+ # name: 'new alert notification',
175
+ # type: 'email',
176
+ # default: false,
177
+ # settings: {
178
+ # addresses: 'carl@grafana.com;dev@grafana.com'
179
+ # }
180
+ # }
181
+ # create_alert_notification( params )
182
+ #
183
+ # @return [Hash]
184
+ #
185
+ def create_alert_notification( params )
186
+
187
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
188
+ raise ArgumentError.new('missing params') if( params.size.zero? )
189
+
190
+ # TODO
191
+ # type are 'email'
192
+ # and the other possible values?
193
+ name = validate( params, required: true, var: 'name', type: String )
194
+ type = validate( params, required: true, var: 'type', type: String ) || 'email'
195
+ default = validate( params, required: false, var: 'default', type: Boolean ) || false
196
+ settings = validate( params, required: false, var: 'settings', type: Hash )
197
+
198
+ unless( type.nil? )
199
+ valid_types = %w[slack pagerduty email webhook kafka hipchat victorops sensu opsgenie threema pushover telegram line prometheus-alertmanager]
200
+ raise ArgumentError.new(format('wrong notification type. only %s allowed, given \%s\'', valid_types.join(', '), type)) if( valid_types.include?(type.downcase) == false )
201
+ end
202
+
203
+ # TODO
204
+ # check if the alert 'name' already created
205
+ return { 'status' => 404, 'message' => format( 'alert notification \'%s\' alread exists', name) } if( alert_notification?(name) )
206
+
207
+ # data = alert_notifications
208
+ # data = data.dig('message').first unless( data.nil? && data.dig('status').to_i == 200 )
209
+ # data = data.select { |k| k['name'] == name }
210
+ # return { 'status' => 404, 'message' => format( 'alert notification \'%s\' alread exists', name) } if( data )
211
+
212
+ payload = {
213
+ name: name,
214
+ type: type,
215
+ isDefault: default,
216
+ settings: settings
217
+ }
218
+ payload.reject!{ |_k, v| v.nil? }
219
+
220
+ endpoint = '/api/alert-notifications'
221
+
222
+ # puts endpoint
223
+ # puts payload
224
+
225
+ post(endpoint, payload.to_json)
226
+ end
27
227
 
28
228
  # Update alert notification
29
- # PUT /api/alert-notifications/1
30
- def update_alert_notification( params ); end
229
+ #
230
+ # @param [Hash] params
231
+ # @param [Mixed] alert_id Alertname (String) or Alertid (Integer) to change
232
+ # @option params [String] name short description - required
233
+ # @option params [String] type ('email') - required
234
+ # @option params [Boolean] default (false)
235
+ # @option params [Hash] settings
236
+ #
237
+ # @example
238
+ # params = {
239
+ # alert_id: 1
240
+ # name: 'new alert notification',
241
+ # type: 'email',
242
+ # default: false,
243
+ # settings: {
244
+ # addresses: 'carl@grafana.com;dev@grafana.com'
245
+ # }
246
+ # }
247
+ # update_alert_notification( params )
248
+ #
249
+ # params = {
250
+ # alert_id: 'new alert notification'
251
+ # name: 'new alert notification',
252
+ # type: 'email',
253
+ # default: false,
254
+ # settings: {
255
+ # addresses: 'carl@grafana.com;dev@grafana.com'
256
+ # }
257
+ # }
258
+ # update_alert_notification( params )
259
+ #
260
+ # @return [Hash]
261
+ #
262
+ def update_alert_notification( params )
263
+
264
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
265
+ raise ArgumentError.new('missing params') if( params.size.zero? )
266
+
267
+ # TODO
268
+ # type are 'email'
269
+ # and the other possible values?
270
+ alert_id = validate( params, required: true, var: 'alert_id' )
271
+ name = validate( params, required: true, var: 'name', type: String )
272
+ type = validate( params, required: true, var: 'type', type: String ) || 'email'
273
+ default = validate( params, required: false, var: 'default', type: Boolean ) || false
274
+ settings = validate( params, required: false, var: 'settings', type: Hash )
275
+
276
+ unless( type.nil? )
277
+ valid_types = %w[slack pagerduty email webhook kafka hipchat victorops sensu opsgenie threema pushover telegram line prometheus-alertmanager]
278
+ raise ArgumentError.new(format('wrong notification type. only %s allowed, given \%s\'', valid_types.join(', '), type)) if( valid_types.include?(type.downcase) == false )
279
+ end
280
+
281
+ if( alert_id.is_a?(String) && alert_id.is_a?(Integer) )
282
+ raise ArgumentError.new(format('wrong type. user \'alert_id\' must be an String (for an Alertname) or an Integer (for an Alert Id), given \'%s\'', alert_id.class.to_s))
283
+ end
284
+
285
+ alert_id = alert_notification_id(alert_id)
286
+ return { 'status' => 404, 'message' => format( 'alert notification \'%s\' not exists', name) } if( alert_id.nil? )
287
+
288
+ payload = {
289
+ id: alert_id,
290
+ name: name,
291
+ type: type,
292
+ isDefault: default,
293
+ settings: settings
294
+ }
295
+ payload.reject!{ |_k, v| v.nil? }
296
+
297
+ endpoint = format( '/api/alert-notifications/%d', alert_id )
298
+
299
+ put(endpoint, payload.to_json)
300
+ end
31
301
 
32
302
  # Delete alert notification
33
- # DELETE /api/alert-notifications/:notificationId
34
- def delete_alert_notification( id ); end
303
+ #
304
+ # @param [Mixed] alert_id Alertname (String) or Alertid (Integer)
305
+ #
306
+ # @example
307
+ # delete_alert_notification( 1 )
308
+ # delete_alert_notification( 'foo' )
309
+ #
310
+ # @return [Hash]
311
+ #
312
+ def delete_alert_notification( alert_id )
313
+
314
+ if( alert_id.is_a?(String) && alert_id.is_a?(Integer) )
315
+ raise ArgumentError.new(format('wrong type. user \'alert_id\' must be an String (for an Alert name) or an Integer (for an Alert Id), given \'%s\'', alert_id.class.to_s))
316
+ end
317
+ raise ArgumentError.new('missing \'alert_id\'') if( alert_id.size.zero? )
318
+
319
+ id = alert_notification_id(alert_id)
320
+ return { 'status' => 404, 'message' => format( 'alert notification \'%s\' not exists', alert_id) } if( id.nil? )
321
+
322
+ endpoint = format('/api/alert-notifications/%d', alert_id )
323
+ logger.debug( "Deleting alert id #{alert_id} (DELETE #{endpoint})" ) if @debug
324
+
325
+ delete( endpoint )
326
+ end
327
+
328
+
329
+ private
330
+ def alert_notification?( alert_id )
331
+
332
+ id = alert_notification_id(alert_id)
333
+
334
+ return true unless( id.nil? )
335
+
336
+ false
337
+ end
338
+
339
+ def alert_notification_id( alert_id )
340
+
341
+ data = alert_notifications
342
+ data = data.dig('message') unless( data.nil? && data.dig('status').to_i == 200 )
343
+
344
+ map = {}
345
+ data.each do |d|
346
+ map[d.dig('id')] = d.dig('name').downcase.split.join('_')
347
+ end
348
+
349
+ id = map.select { |key,_value| key == alert_id } if( map && alert_id.is_a?(Integer) )
350
+ id = map.select { |_key,value| value == alert_id.downcase.split.join('_') } if( map && alert_id.is_a?(String) )
351
+
352
+ id = id.keys.first unless(id.nil?)
353
+
354
+ return id if( id.is_a?(Integer) )
355
+
356
+ nil
357
+ end
35
358
 
36
359
  end
37
360
 
38
361
  end
362
+