grafana 0.8.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+