grafana 0.8.2 → 1.0.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 (44) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +8 -3
  3. data/lib/grafana/admin.rb +39 -65
  4. data/lib/grafana/alerts.rb +334 -14
  5. data/lib/grafana/annotations.rb +284 -9
  6. data/lib/grafana/client.rb +38 -1
  7. data/lib/grafana/dashboard.rb +182 -39
  8. data/lib/grafana/dashboard_permissions.rb +132 -0
  9. data/lib/grafana/dashboard_versions.rb +101 -5
  10. data/lib/grafana/datasource.rb +93 -49
  11. data/lib/grafana/folder.rb +198 -0
  12. data/lib/grafana/folder_and_dashboard_search.rb +57 -0
  13. data/lib/grafana/folder_permissions.rb +155 -0
  14. data/lib/grafana/login.rb +41 -35
  15. data/lib/grafana/network.rb +128 -91
  16. data/lib/grafana/organization.rb +65 -34
  17. data/lib/grafana/organizations.rb +119 -175
  18. data/lib/grafana/playlist.rb +599 -0
  19. data/lib/grafana/preferences.rb +122 -0
  20. data/lib/grafana/tags.rb +19 -8
  21. data/lib/grafana/teams.rb +364 -0
  22. data/lib/grafana/tools.rb +44 -12
  23. data/lib/grafana/user.rb +78 -39
  24. data/lib/grafana/users.rb +104 -53
  25. data/lib/grafana/validator.rb +47 -2
  26. data/lib/grafana/version.rb +3 -3
  27. metadata +13 -38
  28. data/doc/Array.html +0 -200
  29. data/doc/Boolean.html +0 -122
  30. data/doc/FalseClass.html +0 -132
  31. data/doc/Grafana.html +0 -172
  32. data/doc/Hash.html +0 -212
  33. data/doc/Logging.html +0 -326
  34. data/doc/Object.html +0 -286
  35. data/doc/Time.html +0 -200
  36. data/doc/TrueClass.html +0 -132
  37. data/doc/_index.html +0 -380
  38. data/doc/class_list.html +0 -51
  39. data/doc/file.README.html +0 -117
  40. data/doc/file_list.html +0 -56
  41. data/doc/frames.html +0 -17
  42. data/doc/index.html +0 -117
  43. data/doc/method_list.html +0 -771
  44. data/doc/top-level-namespace.html +0 -112
@@ -1,39 +1,314 @@
1
1
 
2
2
  module Grafana
3
3
 
4
- # http://docs.grafana.org/http_api/annotations/
4
+ # This is the API documentation for the new Grafana Annotations feature released in Grafana 4.6.
5
+ # Annotations are saved in the Grafana database (sqlite, mysql or postgres).
6
+ #
7
+ # Annotations can be global annotations that can be shown on any dashboard by configuring an annotation
8
+ # data source - they are filtered by tags.
9
+ #
10
+ # Or they can be tied to a panel on a dashboard and are then only shown on that panel.
11
+ #
12
+ # original API Documentation can be found under: http://docs.grafana.org/http_api/annotations/
5
13
  #
6
14
  module Annotations
7
15
 
8
16
  # Find Annotations
9
17
  # http://docs.grafana.org/http_api/annotations/#find-annotations
10
- # GET /api/annotations?from=1506676478816&to=1507281278816&tags=tag1&tags=tag2&limit=100
11
- def find_annotation( params ); end
18
+ #
19
+ # @param [Hash] params
20
+ # @option params [Integer] from: epoch datetime in milliseconds. Optional.
21
+ # @option params [Integer] to: epoch datetime in milliseconds. Optional.
22
+ # @option params [Integer] limit: number. Optional - default is 10. Max limit for results returned.
23
+ # @option params [Integer] alert_id: number. Optional. Find annotations for a specified alert.
24
+ # @option params [Mixed] dashboard: number. Optional. Find annotations that are scoped to a specific dashboard
25
+ # @option params [Integer] panel_id: number. Optional. Find annotations that are scoped to a specific panel
26
+ # @option params [Array] tags: Optional. Use this to filter global annotations.
27
+ # Global annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel.
28
+ # To do an "AND" filtering with multiple tags, specify the tags parameter multiple times e.g.
29
+ #
30
+ # @example
31
+ # params = {
32
+ # limit: 5,
33
+ # tags: [ 'spec', 'test' ]
34
+ # }
35
+ # find_annotation( params )
36
+ #
37
+ # @return [Array]
38
+ #
39
+ def find_annotation( params )
40
+
41
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
42
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
43
+
44
+ dashboard = validate( params, required: false, var: 'dashboard' )
45
+ from = validate( params, required: false, var: 'from', type: Integer )
46
+ to = validate( params, required: false, var: 'to', type: Integer )
47
+ limit = validate( params, required: false, var: 'limit', type: Integer ) || 10
48
+ alert_id = validate( params, required: false, var: 'alert_id', type: Integer )
49
+ panel_id = validate( params, required: false, var: 'panel_id', type: Integer )
50
+ tags = validate( params, required: false, var: 'tags', type: Array )
51
+
52
+ if( dashboard.is_a?(String) )
53
+
54
+ dashboard = search_dashboards( query: dashboard )
55
+
56
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard) } if( dashboard.nil? || dashboard.dig('status').to_i != 200 )
57
+
58
+ dashboard = dashboard.dig('message').first unless( dashboard.nil? && dashboard.dig('status').to_i == 200 )
59
+ dashboard = dashboard.dig('id') unless( dashboard.nil? )
60
+
61
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard) } if( dashboard.nil? )
62
+ end
63
+
64
+ api = []
65
+ api << format( 'from=%s', from ) unless( from.nil? )
66
+ api << format( 'to=%s', to ) unless( to.nil? )
67
+ api << format( 'limit=%s', limit ) unless( limit.nil? )
68
+ api << format( 'alertId=%s', alert_id ) unless( alert_id.nil? )
69
+ api << format( 'panelId=%s', panel_id ) unless( panel_id.nil? )
70
+ api << format( 'dashboardId=%s', dashboard ) unless( dashboard.nil? )
71
+
72
+ unless( tags.nil? )
73
+ tags = tags.join( '&tags=' ) if( tags.is_a?( Array ) )
74
+ api << format( 'tags=%s', tags )
75
+ end
76
+ api = api.join( '&' )
77
+
78
+ endpoint = format( '/api/annotations/?%s' , api )
79
+
80
+ @logger.debug("Attempting to search for annotations (GET #{endpoint})") if @debug
81
+
82
+ get( endpoint )
83
+ end
12
84
 
13
85
  # Create Annotation
86
+ #
87
+ # Creates an annotation in the Grafana database.
88
+ # The dashboard_id and panel_id fields are optional.
89
+ # If they are not specified then a global annotation is created and can be queried in any dashboard that adds
90
+ # the Grafana annotations data source.
91
+ #
92
+ # When creating a region annotation the response will include both id and endId, if not only id.
93
+ #
14
94
  # http://docs.grafana.org/http_api/annotations/#create-annotation
15
95
  # POST /api/annotations
16
- def create_annotation( params ); end
96
+ #
97
+ #
98
+ # @param [Hash] params
99
+ # @option params [Mixed] dashboard
100
+ # @option params [Integer] panel_id
101
+ # @option params [Integer] time:
102
+ # @option params [Integer] time_end:
103
+ # @option params [Boolean] region:
104
+ # @option params [Array] tags:
105
+ # @option params [String] text:
106
+ #
107
+ # @example
108
+ # params = {
109
+ # time: Time.now.to_i,
110
+ # tags: [ 'spec', 'test' ],
111
+ # text: 'test annotation'
112
+ # }
113
+ # create_annotation( params )
114
+ #
115
+ # @return [Hash]
116
+ #
117
+ def create_annotation( params )
118
+
119
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
120
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
121
+
122
+ dashboard = validate( params, required: false, var: 'dashboard' )
123
+ panel_id = validate( params, required: false, var: 'panel_id', type: Integer )
124
+ time = validate( params, required: false, var: 'time', type: Integer ) || Time.now.to_i
125
+ time_end = validate( params, required: false, var: 'time_end', type: Integer )
126
+ region = validate( params, required: false, var: 'region', type: Boolean )
127
+ tags = validate( params, required: true, var: 'tags', type: Array )
128
+ text = validate( params, required: true, var: 'text', type: String )
129
+
130
+ if( dashboard.is_a?(String) )
131
+
132
+ dashboard = search_dashboards( query: dashboard )
133
+
134
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard) } if( dashboard.nil? || dashboard.dig('status').to_i != 200 )
135
+
136
+ dashboard = dashboard.dig('message').first unless( dashboard.nil? && dashboard.dig('status').to_i == 200 )
137
+ dashboard = dashboard.dig('id') unless( dashboard.nil? )
138
+
139
+ return { 'status' => 404, 'message' => format( 'No Dashboard \'%s\' found', dashboard) } if( dashboard.nil? )
140
+ end
141
+
142
+ unless( time_end.nil? )
143
+ return { 'status' => 404, 'message' => format( '\'end_time\' can\'t be lower then \'time\'' ) } if( time_end < time )
144
+ end
145
+
146
+ endpoint = '/api/annotations'
147
+ payload = {
148
+ dashboardId: dashboard,
149
+ panelId: panel_id,
150
+ time: time,
151
+ timeEnd: time_end,
152
+ isRegion: region,
153
+ tags: tags,
154
+ text: text
155
+ }
156
+ payload.reject!{ |_k, v| v.nil? }
157
+
158
+ post(endpoint, payload.to_json)
159
+ end
17
160
 
18
161
  # Create Annotation in Graphite format
162
+ #
163
+ # Creates an annotation by using Graphite-compatible event format.
164
+ # The when and data fields are optional.
165
+ # If when is not specified then the current time will be used as annotation's timestamp.
166
+ # The tags field can also be in prior to Graphite 0.10.0 format (string with multiple tags being separated by a space).
167
+ #
19
168
  # http://docs.grafana.org/http_api/annotations/#create-annotation-in-graphite-format
20
169
  # POST /api/annotations/graphite
21
- def create_annotation_graphite( params ); end
170
+ #
171
+ # @param [Hash] params
172
+ # @option params [Integer] what
173
+ # @option params [Integer] when
174
+ # @option params [Array] tags
175
+ # @option params [String] data
176
+ #
177
+ # @example
178
+ # params = {
179
+ # what: 'spec test graphite annotation',
180
+ # when: Time.now.to_i,
181
+ # tags: [ 'spec', 'test' ],
182
+ # data: 'test annotation'
183
+ # }
184
+ # create_annotation_graphite( params )
185
+ #
186
+ # @return [Hash]
187
+ #
188
+ def create_annotation_graphite( params )
189
+
190
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
191
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
192
+
193
+ what = validate( params, required: true , var: 'what', type: String )
194
+ time_when = validate( params, required: false, var: 'when', type: Integer ) || Time.now.to_i
195
+ tags = validate( params, required: true , var: 'tags', type: Array )
196
+ data = validate( params, required: false, var: 'data', type: String )
197
+
198
+ endpoint = '/api/annotations/graphite'
199
+ payload = {
200
+ what: what,
201
+ when: time_when,
202
+ tags: tags,
203
+ data: data
204
+ }
205
+ payload.reject!{ |_k, v| v.nil? }
206
+
207
+ post(endpoint, payload.to_json)
208
+ end
22
209
 
23
210
  # Update Annotation
211
+ #
24
212
  # http://docs.grafana.org/http_api/annotations/#update-annotation
25
- # PUT /api/annotations/:id
26
- def update_annotation( params ); end
213
+ #
214
+ # @param [Hash] params
215
+ # @option params [Integer] annotation
216
+ # @option params [Integer] time
217
+ # @option params [Integer] time_end
218
+ # @option params [Boolean] region
219
+ # @option params [Array] tags
220
+ # @option params [String] text
221
+ #
222
+ # @example
223
+ # params = {
224
+ # annotation: 1,
225
+ # tags: [ 'deployment' ],
226
+ # text: 'git tag #1234'
227
+ # }
228
+ # update_annotation( params )
229
+ #
230
+ # @return [Hash]
231
+ #
232
+ def update_annotation( params )
233
+
234
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
235
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
236
+
237
+ annotation_id = validate( params, required: true, var: 'annotation', type: Integer )
238
+ time = validate( params, required: false, var: 'time', type: Integer )
239
+ time_end = validate( params, required: false, var: 'time_end', type: Integer )
240
+ region = validate( params, required: false, var: 'region', type: Boolean )
241
+ tags = validate( params, required: false, var: 'tags', type: Array )
242
+ text = validate( params, required: false, var: 'text', type: String )
243
+
244
+ unless( time_end.nil? )
245
+ return { 'status' => 404, 'message' => format( '\'end_time\' can\'t be lower then \'time\'' ) } if( time_end < time )
246
+ end
247
+
248
+ endpoint = format( '/api/annotations/%d', annotation_id)
249
+ payload = {
250
+ time: time,
251
+ timeEnd: time_end,
252
+ isRegion: region,
253
+ text: text,
254
+ tags: tags
255
+ }
256
+ payload.reject!{ |_k, v| v.nil? }
257
+
258
+ put(endpoint, payload.to_json)
259
+ end
27
260
 
28
261
  # Delete Annotation By Id
262
+ #
263
+ # Deletes the annotation that matches the specified id.
264
+ #
29
265
  # http://docs.grafana.org/http_api/annotations/#delete-annotation-by-id
30
266
  # DELETE /api/annotation/:id
31
- def delete_annotation( params ); end
267
+ #
268
+ # @param [Integer] annotation_id
269
+ #
270
+ # @example
271
+ # delete_annotation( 1 )
272
+ #
273
+ # @return [Hash]
274
+ #
275
+ def delete_annotation( annotation_id )
276
+
277
+ raise ArgumentError.new(format('wrong type. user \'annotation_id\' must be an Integer, given \'%s\'', annotation_id.class.to_s)) unless( annotation_id.is_a?(Integer) )
278
+ raise ArgumentError.new('missing \'annotation_id\'') if( annotation_id.size.zero? )
279
+ raise ArgumentError.new('\'annotation_id\' can not be 0') if( annotation_id.zero? )
280
+
281
+ endpoint = format( '/api/annotation/%d', annotation_id )
282
+
283
+ delete(endpoint)
284
+ end
32
285
 
33
286
  # Delete Annotation By RegionId
287
+ #
288
+ # Deletes the annotation that matches the specified region id.
289
+ # A region is an annotation that covers a timerange and has a start and end time.
290
+ # In the Grafana database, this is a stored as two annotations connected by a region id.
291
+ #
34
292
  # http://docs.grafana.org/http_api/annotations/#delete-annotation-by-regionid
35
293
  # DELETE /api/annotation/region/:id
36
- def delete_annotation_by_region( params ); end
294
+ #
295
+ # @param [Integer] region_id
296
+ #
297
+ # @example
298
+ # delete_annotation_by_region( 1 )
299
+ #
300
+ # @return [Hash]
301
+ #
302
+ def delete_annotation_by_region( region_id )
303
+
304
+ raise ArgumentError.new(format('wrong type. user \'region_id\' must be an Integer, given \'%s\'', region_id.class.to_s)) unless( region_id.is_a?(Integer) )
305
+ raise ArgumentError.new('missing \'region_id\'') if( region_id.size.zero? )
306
+ # raise ArgumentError.new('\'region_id\' can not be 0') if( region_id.zero? )
307
+
308
+ endpoint = format( '/api/annotation/region/%d', region_id )
309
+
310
+ delete(endpoint)
311
+ end
37
312
 
38
313
  end
39
314
 
@@ -12,14 +12,22 @@ require_relative 'network'
12
12
  require_relative 'tools'
13
13
  require_relative 'admin'
14
14
  require_relative 'annotations'
15
+ require_relative 'preferences'
15
16
  require_relative 'user'
16
17
  require_relative 'users'
18
+ require_relative 'teams'
17
19
  require_relative 'datasource'
18
20
  require_relative 'organization'
19
21
  require_relative 'organizations'
20
22
  require_relative 'dashboard'
21
23
  require_relative 'dashboard_versions'
24
+ require_relative 'dashboard_permissions'
22
25
  require_relative 'snapshot'
26
+ require_relative 'alerts'
27
+ require_relative 'folder'
28
+ require_relative 'folder_permissions'
29
+ require_relative 'folder_and_dashboard_search'
30
+ require_relative 'playlist'
23
31
 
24
32
  # -------------------------------------------------------------------------------------------------------------------
25
33
  #
@@ -46,14 +54,22 @@ module Grafana
46
54
  include Grafana::Tools
47
55
  include Grafana::Admin
48
56
  include Grafana::Annotations
57
+ include Grafana::Preferences
49
58
  include Grafana::User
50
59
  include Grafana::Users
60
+ include Grafana::Teams
51
61
  include Grafana::Datasource
52
62
  include Grafana::Organization
53
63
  include Grafana::Organizations
54
64
  include Grafana::Dashboard
55
65
  include Grafana::DashboardVersions
66
+ include Grafana::DashboardPermissions
56
67
  include Grafana::Snapshot
68
+ include Grafana::Alerts
69
+ include Grafana::Folder
70
+ include Grafana::FolderPermissions
71
+ include Grafana::FolderSearch
72
+ include Grafana::Playlist
57
73
 
58
74
  attr_accessor :debug
59
75
 
@@ -98,6 +114,8 @@ module Grafana
98
114
  @http_headers = settings.dig(:grafana, :http_headers) || {}
99
115
  @debug = settings.dig(:debug) || false
100
116
 
117
+ @headers = {}
118
+
101
119
  raise ArgumentError.new('missing \'host\'') if( host.nil? )
102
120
 
103
121
  raise ArgumentError.new(format('wrong type. \'port\' must be an Integer, given \'%s\'', port.class.to_s)) unless( port.is_a?(Integer) )
@@ -107,11 +125,30 @@ module Grafana
107
125
  raise ArgumentError.new(format('wrong type. \'open_timeout\' must be an Integer, given \'%s\'', @open_timeout.class.to_s)) unless( @open_timeout.is_a?(Integer) )
108
126
 
109
127
  protocoll = ssl == true ? 'https' : 'http'
110
- raise ArgumentError.new(format('wrong \'protocoll\'. only \'http\' or \'https\' allowed, given \'%s\'', protocoll)) if( %w[http https].include?(protocoll.downcase) == false )
111
128
 
112
129
  @url = format( '%s://%s:%d%s', protocoll, host, port, url_path )
113
130
  end
114
131
 
132
+ # Get Settings
133
+ #
134
+ # http://docs.grafana.org/http_api/other/#get-settings
135
+ #
136
+ def settings
137
+ endpoint = '/api/frontend/settings'
138
+ @logger.debug("Getting all settings (GET #{endpoint})") if @debug
139
+ get(endpoint)
140
+ end
141
+
142
+
143
+ def version
144
+ s = settings
145
+ @version = s.dig('buildInfo','version')
146
+ @major_version = @version.split('.').first.to_i
147
+
148
+ {version: @version, major_version: @major_version}
149
+ end
150
+
151
+
115
152
  def self.logger
116
153
  @@logger ||= defined?(Logging) ? Logging.logger : Logger.new(STDOUT)
117
154
  end
@@ -2,59 +2,186 @@
2
2
  module Grafana
3
3
 
4
4
  # http://docs.grafana.org/http_api/dashboard/
5
+
6
+ # The identifier (id) of a dashboard is an auto-incrementing numeric value and is only unique per Grafana install.
7
+ #
8
+ # The unique identifier (uid) of a dashboard can be used for uniquely identify a dashboard between multiple Grafana installs.
9
+ # It's automatically generated if not provided when creating a dashboard. The uid allows having consistent URL's for
10
+ # accessing dashboards and when syncing dashboards between multiple Grafana installs, see dashboard provisioning for
11
+ # more information. This means that changing the title of a dashboard will not break any bookmarked links to that dashboard.
12
+ #
13
+ # The uid can have a maximum length of 40 characters.
14
+ #
15
+ # Deprecated resources
16
+ # Please note that these resource have been deprecated and will be removed in a future release.
17
+ #
18
+ # - Get dashboard by slug
19
+ # - Delete dashboard by slug
20
+ #
21
+ #
5
22
  #
6
23
  module Dashboard
7
24
 
8
-
25
+ # http://docs.grafana.org/http_api/dashboard/#get-dashboard-by-slug
26
+ # - Deprecated starting from Grafana v5.0.
27
+ # Please update to use the new Get dashboard by uid resource instead
28
+ #
9
29
  # Get dashboard
10
- # GET /api/dashboards/db/:slug
30
+ #
31
+ # Will return the dashboard given the dashboard slug.
32
+ # Slug is the url friendly version of the dashboard title.
33
+ # If there exists multiple dashboards with the same slug, one of them will be returned in the response.
34
+ #
35
+ # @example
36
+ # dashboard('dashboard for many foo')
37
+ #
38
+ # @return [String]
39
+ #
11
40
  def dashboard( name )
12
41
 
13
42
  raise ArgumentError.new(format('wrong type. \'name\' must be an String, given \'%s\'', name.class.to_s)) unless( name.is_a?(String) )
14
43
  raise ArgumentError.new('missing name') if( name.size.zero? )
15
44
 
16
- # raise ArgumentError.new('name must be an String') unless( name.is_a?(String) )
45
+ # v, mv = version.values
46
+ #
47
+ # if( mv == 5)
48
+ # puts 'DEPRICATION WARNING'
49
+ # puts 'Grafana v5.0 use a new interal id/uid handling'
50
+ # puts 'This function works well with Grafana v4.x'
51
+ # end
17
52
 
18
53
  endpoint = format( '/api/dashboards/db/%s', slug(name) )
54
+ @logger.debug( "Attempting to get dashboard (GET #{endpoint})" ) if @debug
19
55
 
20
- @logger.debug( "Attempting to get dashboard (GET /api/dashboards/db/#{name})" ) if @debug
56
+ get( endpoint )
57
+ end
58
+
59
+ # http://docs.grafana.org/http_api/dashboard/#get-dashboard-by-uid
60
+ #
61
+ # GET /api/dashboards/uid/:uid
62
+ # Will return the dashboard given the dashboard unique identifier (uid).
63
+ #
64
+ # Get dashboard
65
+ #
66
+ # Will return the dashboard given the dashboard unique identifier (uid).
67
+ #
68
+ # @example
69
+ # dashboard('L42r6NWiz')
70
+ #
71
+ # @return [String]
72
+ #
73
+ def dashboard_by_uid( uid )
74
+
75
+ if( uid.is_a?(String) && uid.is_a?(Integer) )
76
+ raise ArgumentError.new(format('wrong type. dashboard \'uid\' must be an String (for an title name) or an Integer (for an Datasource Id), given \'%s\'', uid.class.to_s))
77
+ end
78
+ raise ArgumentError.new('missing \'uid\'') if( uid.size.zero? )
79
+
80
+ v, mv = version.values
81
+ return { 'status' => 404, 'message' => format( 'uid has been supported in Grafana since version 5. you use version %s', v) } if(mv < 5)
82
+
83
+ return { 'status' => 404, 'message' => format( 'The uid can have a maximum length of 40 characters, but it is %s characters long', uid.length) } if( uid.length > 40 )
84
+
85
+ endpoint = format( '/api/dashboards/uid/%s', uid )
86
+ @logger.debug( "Attempting to get dashboard (GET #{endpoint})" ) if @debug
21
87
 
22
88
  get( endpoint )
23
89
  end
24
90
 
25
91
  # Create / Update dashboard
92
+ #
93
+ # Creates a new dashboard or updates an existing dashboard.
94
+ #
95
+ # @param [Hash] params
96
+ # @option params [Hash] dashboard The complete dashboard model
97
+ # - dashboard.id - id = null to create a new dashboard.
98
+ # - dashboard.uid - Optional unique identifier when creating a dashboard. uid = null will generate a new uid.
99
+ # - folderId - The id of the folder to save the dashboard in.
100
+ # - overwrite - Set to true if you want to overwrite existing dashboard with newer version, same dashboard title in folder or same dashboard uid.
101
+ # - message - Set a commit message for the version history.
102
+ # @option params [Boolean] overwrite (true)
103
+ #
104
+ # @example
105
+ # params = {
106
+ # dashboard: {
107
+ # id: null,
108
+ # uid: null,
109
+ # title: 'Production Overview',
110
+ # tags: [ 'templated' ],
111
+ # timezone": 'browser',
112
+ # rows: [
113
+ # {
114
+ # }
115
+ # ],
116
+ # 'schemaVersion': 6,
117
+ # 'version': 0
118
+ # },
119
+ # folderId: 0,
120
+ # overwrite: false,
121
+ # message: 'created by foo'
122
+ # }
123
+ # create_dashboard( params )
124
+ #
125
+ # @return [Hash]
126
+ #
26
127
  # POST /api/dashboards/db
27
128
  def create_dashboard( params )
28
129
 
29
- raise ArgumentError.new(format('wrong type. params must be an Hash, given %s', params.class.to_s ) ) unless( params.is_a?(Hash) )
30
-
31
- title = params.dig(:title)
32
- dashboard = params.dig(:dashboard)
130
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
131
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
33
132
 
34
- # raise ArgumentError.new('missing title') if( title.nil? )
35
- raise ArgumentError.new('missing dashboard') if( dashboard.nil? )
36
- raise ArgumentError.new(format('wrong type. dashboard must be an Hash, given %s', dashboard.class.to_s ) ) unless( dashboard.is_a?(Hash) )
133
+ dashboard = validate( params, required: true , var: 'dashboard', type: Hash )
134
+ overwrite = validate( params, required: false, var: 'overwrite', type: Boolean ) || true
135
+ folder_id = validate( params, required: false, var: 'folderId' )
136
+ message = validate( params, required: false, var: 'message', type: String )
37
137
 
38
- endpoint = '/api/dashboards/db'
39
- # title = slug(title)
40
-
41
- # dashboard = JSON.parse( dashboard ) if( dashboard.is_a?(String) )
42
138
  dashboard = regenerate_template_ids( dashboard )
43
139
 
44
- if( title.nil? )
45
- db = JSON.parse( dashboard ) if( dashboard.is_a?(String) )
46
- title = db.dig('dashboard','title')
140
+ unless(folder_id.nil?)
141
+ f_folder = folder(folder_id)
142
+ return { 'status' => 404, 'message' => format( 'No Folder \'%s\' found', folder_id) } if( f_folder.dig('status') != 200 )
143
+
144
+ folder_id = f_folder.dig('id')
47
145
  end
48
146
 
147
+ db = JSON.parse( dashboard ) if( dashboard.is_a?(String) )
148
+ title = db.dig('dashboard','title')
149
+ uid = db.dig('dashboard','uid')
150
+
151
+ return { 'status' => 404, 'message' => format( 'The template \'%s\' can\'t be create. The uid can have a maximum length of 40 characters, but it is %s characters long', title, uid.length) } if( ! uid.nil? && uid.length > 40 )
152
+
153
+ endpoint = '/api/dashboards/db'
154
+
155
+ payload = {
156
+ dashboard: db.dig('dashboard'),
157
+ overwrite: overwrite,
158
+ folderId: folder_id,
159
+ message: message
160
+ }
161
+ payload.reject!{ |_k, v| v.nil? }
162
+
49
163
  @logger.debug("Creating dashboard: #{title} (POST /api/dashboards/db)") if @debug
50
164
 
51
- post( endpoint, dashboard )
165
+ post( endpoint, payload.to_json )
52
166
  end
53
167
 
168
+ # http://docs.grafana.org/http_api/dashboard/#delete-dashboard-by-slug
169
+ # - Deprecated starting from Grafana v5.0.
170
+ # Please update to use the new Get dashboard by uid resource instead
171
+ #
54
172
  # Delete dashboard
55
- # DELETE /api/dashboards/db/:slug
173
+ # Will delete the dashboard given the specified slug. Slug is the url friendly version of the dashboard title.
174
+ #
175
+ # @example
176
+ # delete_dashboard('dashboard for many foo')
177
+ #
178
+ # @return [Hash]
179
+ #
56
180
  def delete_dashboard( name )
57
181
 
182
+ raise ArgumentError.new(format('wrong type. \'name\' must be an String, given \'%s\'', name.class.to_s)) unless( name.is_a?(String) )
183
+ raise ArgumentError.new('missing name') if( name.size.zero? )
184
+
58
185
  endpoint = format( '/api/dashboards/db/%s', slug(name) )
59
186
 
60
187
  @logger.debug("Deleting dashboard #{slug(name)} (DELETE #{endpoint})") if @debug
@@ -63,7 +190,12 @@ module Grafana
63
190
  end
64
191
 
65
192
  # Gets the home dashboard
66
- # GET /api/dashboards/home
193
+ #
194
+ # @example
195
+ # home_dashboard
196
+ #
197
+ # @return [Hash]
198
+ #
67
199
  def home_dashboard
68
200
 
69
201
  endpoint = '/api/dashboards/home'
@@ -74,7 +206,12 @@ module Grafana
74
206
  end
75
207
 
76
208
  # Tags for Dashboard
77
- # GET /api/dashboards/tags
209
+ #
210
+ # @example
211
+ # dashboard_tags
212
+ #
213
+ # @return [Hash]
214
+ #
78
215
  def dashboard_tags
79
216
 
80
217
  endpoint = '/api/dashboards/tags'
@@ -85,29 +222,30 @@ module Grafana
85
222
  end
86
223
 
87
224
  # Search Dashboards
88
- # GET /api/search/
89
225
  #
90
- # searchDashboards( { :tags => host } )
91
- # searchDashboards( { :tags => [ host, 'tag1' ] } )
92
- # searchDashboards( { :tags => [ 'tag2' ] } )
93
- # searchDashboards( { :query => title } )
94
- # searchDashboards( { :starred => true } )
95
- def search_dashboards( params = {} )
226
+ # @example
227
+ # searchDashboards( tags: host )
228
+ # searchDashboards( tags: [ host, 'tag1' ] )
229
+ # searchDashboards( tags: [ 'tag2' ] )
230
+ # searchDashboards( query: title )
231
+ # searchDashboards( starred: true )
232
+ #
233
+ # @return [Hash]
234
+ #
235
+ def search_dashboards( params )
96
236
 
97
237
  raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
98
238
 
99
- query = params.dig(:query)
100
- starred = params.dig(:starred)
101
- tags = params.dig(:tags)
102
- api = []
239
+ query = validate( params, required: false, var: 'query', type: String )
240
+ starred = validate( params, required: false, var: 'starred', type: Boolean )
241
+ tags = validate( params, required: false, var: 'tags' )
103
242
 
104
- api << format( 'query=%s', CGI.escape( query ) ) unless query.nil?
243
+ api = []
244
+ api << format( 'query=%s', CGI.escape( query ) ) unless( query.nil? )
105
245
  api << format( 'starred=%s', starred ? 'true' : 'false' ) unless( starred.nil? )
106
246
 
107
247
  unless( tags.nil? )
108
-
109
248
  tags = tags.join( '&tag=' ) if( tags.is_a?( Array ) )
110
-
111
249
  api << format( 'tag=%s', tags )
112
250
  end
113
251
 
@@ -120,7 +258,13 @@ module Grafana
120
258
  get( endpoint )
121
259
  end
122
260
 
123
-
261
+ # import Dashboards from directory
262
+ #
263
+ # @example
264
+ # import_dashboards_from_directory( '/tmp/dashboards' )
265
+ #
266
+ # @return [Hash]
267
+ #
124
268
  def import_dashboards_from_directory( directory )
125
269
 
126
270
  raise ArgumentError.new('directory must be an String') unless( directory.is_a?(String) )
@@ -135,10 +279,9 @@ module Grafana
135
279
 
136
280
  dashboard = File.read( f )
137
281
  dashboard = JSON.parse( dashboard )
138
- title = dashboard.dig('dashboard','title') || f
139
282
 
140
283
  result[f.to_s] ||= {}
141
- result[f.to_s] = create_dashboard( title: title, dashboard: dashboard )
284
+ result[f.to_s] = create_dashboard( dashboard: dashboard )
142
285
  end
143
286
 
144
287
  result