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
@@ -3,179 +3,208 @@ module Grafana
3
3
 
4
4
  module Network
5
5
 
6
+ # GET request
7
+ #
8
+ # @param endpoint [String]
9
+ #
6
10
  def get( endpoint )
7
-
8
11
  request( 'GET', endpoint )
9
12
  end
10
13
 
14
+ # POST request
15
+ #
16
+ # @param endpoint [String]
17
+ # @param data [Hash]
18
+ #
11
19
  def post( endpoint, data )
12
-
13
20
  request( 'POST', endpoint, data )
14
21
  end
15
22
 
23
+ # PUT request
24
+ #
25
+ # @param endpoint [String]
26
+ # @param data [Hash]
27
+ #
16
28
  def put( endpoint, data )
17
-
18
29
  request( 'PUT', endpoint, data )
19
30
  end
20
31
 
32
+ # PATCH request
33
+ #
34
+ # @param endpoint [String]
35
+ # @param data [Hash]
36
+ #
21
37
  def patch( endpoint, data )
22
-
23
38
  request( 'PATCH', endpoint, data )
24
39
  end
25
40
 
41
+ # DELETE request
42
+ #
43
+ # @param endpoint [String]
44
+ #
26
45
  def delete( endpoint )
27
-
28
46
  request( 'DELETE', endpoint )
29
47
  end
30
48
 
49
+
50
+ private
51
+ # helper function for all request methods
52
+ #
53
+ # @param method_type [String]
54
+ # @param endpoint [String]
55
+ # @param data [Hash]
56
+ #
57
+ # @example
58
+ #
59
+ #
60
+ # @return [Hash]
61
+ #
31
62
  def request( method_type = 'GET', endpoint = '/', data = {} )
32
63
 
33
- raise 'try first login()' if @api_instance.nil?
64
+ logger.debug( "request( method_type: #{method_type}, endpoint: #{endpoint}, data )" )
65
+
66
+ raise 'try first login()' if @api_instance.nil?
67
+
68
+ # login( username: @username, password: @password )
34
69
 
35
70
  response = nil
36
71
  response_code = 404
37
72
  response_body = ''
38
73
 
39
74
  begin
40
-
41
75
  case method_type.upcase
42
76
  when 'GET'
43
- response = @api_instance[endpoint].get( @headers )
77
+ response = @api_instance[endpoint].get( headers )
44
78
  when 'POST'
45
- response = @api_instance[endpoint].post( data, @headers )
79
+ response = @api_instance[endpoint].post( data, headers )
46
80
  when 'PATCH'
47
- response = @api_instance[endpoint].patch( data, @headers )
81
+ response = @api_instance[endpoint].patch( data, headers )
48
82
  when 'PUT'
49
- # response = @api_instance[endpoint].put( data, @headers )
50
- @api_instance[endpoint].put( data, @headers ) do |response, request, result|
51
83
 
52
- case response.code
84
+ # response = @api_instance[endpoint].put( data, headers )
85
+ @api_instance[endpoint].put( data, headers ) do |resp, _request, _result|
86
+
87
+ response_code = resp.code.to_i
88
+ response_body = resp.body
89
+ response_body = JSON.parse(response_body) if response_body.is_a?(String)
90
+
91
+ #logger.debug( "code : #{response_code}" )
92
+ #logger.debug( "message: #{response_body}" )
93
+
94
+ case response_code.to_i
53
95
  when 200
54
- response_body = response.body
55
- response_code = response.code.to_i
56
- response_body = JSON.parse(response_body) if response_body.is_a?(String)
57
-
58
- return {
59
- 'status' => response_code,
60
- 'message' => response_body.dig('message').nil? ? 'Successful' : response_body.dig('message')
61
- }
96
+ return { 'status' => response_code, 'message' => response_body.dig('message').nil? ? 'Successful' : response_body.dig('message') }
62
97
  when 400
63
- response_body = response.body
64
- response_code = response.code.to_i
65
98
  raise RestClient::BadRequest
99
+ when 412
100
+ status = response_body.dig('status')
101
+ message = response_body.dig('message')
102
+ message += " (#{status})" unless(status.nil?)
103
+ return { 'status' => response_code, 'message' => message }
104
+ when 422
105
+ logger.error('422')
106
+
107
+ response_body = response_body.first if(response_body.is_a?(Array))
108
+ # message_field_name = response_body.dig('fieldNames')
109
+
110
+ #status = response_code # response_body.dig('status')
111
+ message = response_body # .dig('message')
112
+ #message += " (#{status})" unless(status.nil?)
113
+
114
+ # [{fieldNames"=>["Id"], "classification"=>"RequiredError", "message"=>"Required"}]
115
+
116
+ logger.error(message)
117
+ return { 'status' => response_code, 'message' => message }
118
+ # #raise RestClient::UnprocessableEntity
66
119
  else
67
- # logger.error( response.code )
68
- # logger.error( response.body )
69
-
70
- body = JSON.parse(response.body) if(response_body.is_a?(String))
71
- return {
72
- 'status' => response_code,
73
- 'message' => body.dig('message')
74
- }
120
+ # logger.error( response_code )
121
+ # logger.error( response_body )
122
+ return { 'status' => response_code, 'message' => response_body.dig('message') }
75
123
  # response.return! # (request, result)
76
124
  end
77
125
  end
78
126
 
79
127
  when 'DELETE'
80
- response = @api_instance[endpoint].delete( @headers )
128
+
129
+ @api_instance[endpoint].delete( headers ) do |resp, _request, _result|
130
+
131
+ response_code = resp.code.to_i
132
+ response_body = resp.body
133
+ response_body = JSON.parse(response_body) if response_body.is_a?(String)
134
+
135
+ #logger.debug( "code : #{response_code}" )
136
+ #logger.debug( "message: #{response_body}" )
137
+
138
+ case response_code.to_i
139
+ when 200
140
+ return { 'status' => response_code, 'message' => response_body.dig('message').nil? ? 'Successful' : response_body.dig('message') }
141
+ when 404
142
+ return { 'status' => response_code, 'message' => response_body.dig('message').nil? ? 'Successful' : response_body.dig('message') }
143
+ else
144
+ # logger.error( response_code )
145
+ # logger.error( response_body )
146
+ return { 'status' => response_code, 'message' => response_body.dig('message') }
147
+ end
148
+
149
+ end
150
+
81
151
  else
82
- @logger.error( "Error: #{__method__} is not a valid request method." )
152
+ logger.error( "Error: #{__method__} is not a valid request method." )
83
153
  return false
84
154
  end
85
155
 
156
+ # logger.debug( "response: #{response} (#{response.class})" )
157
+
86
158
  response_code = response.code.to_i
87
159
  response_body = response.body
88
160
  response_headers = response.headers
89
161
 
90
- if( @debug )
91
- logger.debug("response_code : #{response_code}" )
92
- logger.debug("response_body : #{response_body}" )
93
- logger.debug("response_headers : #{response_headers}" )
94
- end
95
-
96
162
  if( ( response_code >= 200 && response_code <= 299 ) || ( response_code >= 400 && response_code <= 499 ) )
97
163
 
98
- result = JSON.parse( response_body )
99
-
100
- if( result.is_a?(Array) )
101
- r_result= {
102
- 'status' => response_code,
103
- 'message' => result
104
- }
105
- return r_result
164
+ if( response_body =~ /^\[.*\]$/ || response_body =~ /^\{.*\}$/ )
165
+ result = JSON.parse( response_body )
166
+ return { 'status' => response_code, 'message' => result } if( result.is_a?(Array) )
167
+ else
168
+ return { 'status' => response_code, 'message' => response_body }
106
169
  end
107
170
 
108
- result_status = result.dig('status') if( result.is_a?( Hash ) )
109
-
171
+ result_status = result.dig('status') if( result.is_a?( Hash ) )
110
172
  result['message'] = result_status unless( result_status.nil? )
111
173
  result['status'] = response_code
112
174
 
113
175
  return result
114
176
  else
115
-
116
- @logger.error( "#{__method__} #{method_type.upcase} on #{endpoint} failed: HTTP #{response.code} - #{response_body}" )
117
- @logger.error( @headers )
118
- @logger.error( JSON.pretty_generate( response_headers ) )
177
+ logger.error( "#{__method__} #{method_type.upcase} on #{endpoint} failed: HTTP #{response.code} - #{response_body}" )
178
+ logger.error( headers )
179
+ logger.error( JSON.pretty_generate( response_headers ) )
119
180
 
120
181
  return JSON.parse( response_body )
121
182
  end
122
183
 
123
184
  rescue RestClient::BadRequest
124
-
125
185
  response_body = JSON.parse(response_body) if response_body.is_a?(String)
126
-
127
- return {
128
- 'status' => 400,
129
- 'message' => response_body.dig('message').nil? ? 'Bad Request' : response_body.dig('message')
130
- }
131
-
186
+ return { 'status' => 400, 'message' => response_body.dig('message').nil? ? 'Bad Request' : response_body.dig('message') }
132
187
  rescue RestClient::Unauthorized
133
-
134
- return {
135
- 'status' => 401,
136
- 'message' => format('Not authorized to connect \'%s/%s\' - wrong username or password?', @url, endpoint)
137
- }
188
+ return { 'status' => 401, 'message' => format('Not authorized to connect \'%s/%s\' - wrong username or password?', @url, endpoint) }
138
189
  rescue RestClient::Forbidden
139
-
140
- return {
141
- 'status' => 403,
142
- 'message' => format('The operation is forbidden \'%s/%s\'', @url, endpoint)
143
- }
144
-
190
+ return { 'status' => 403, 'message' => format('The operation is forbidden \'%s/%s\'', @url, endpoint) }
145
191
  rescue RestClient::NotFound
146
-
147
- return {
148
- 'status' => 404,
149
- 'message' => 'Not Found'
150
- }
151
-
192
+ return { 'status' => 404, 'message' => 'Not Found' }
152
193
  rescue RestClient::Conflict
153
-
154
- return {
155
- 'status' => 409,
156
- 'message' => 'Conflict with the current state of the target resource'
157
- }
158
-
194
+ return { 'status' => 409, 'message' => 'Conflict with the current state of the target resource' }
159
195
  rescue RestClient::PreconditionFailed
160
-
161
- return {
162
- 'status' => 412,
163
- 'message' => 'Precondition failed. The Object probably already exists.'
164
- }
165
-
166
- rescue RestClient::ExceptionWithResponse => e
167
-
168
- logger.error( "Error: #{__method__} #{method_type.upcase} on #{endpoint} error: '#{e}'" )
169
- logger.error( data )
170
- logger.error( @headers )
171
- logger.error( JSON.pretty_generate( response_headers ) )
172
-
173
- return false
174
-
196
+ return { 'status' => 412, 'message' => 'Precondition failed. The Object probably already exists.' }
197
+ rescue RestClient::PreconditionFailed
198
+ return { 'status' => 412, 'message' => 'Precondition failed. The Object probably already exists.' }
199
+ rescue RestClient::ExceptionWithResponse => error
200
+ #logger.error( "Error: (RestClient::ExceptionWithResponse) #{__method__} #{method_type.upcase} on #{endpoint} error: '#{error}'" )
201
+ #logger.error( "query: #{data}" )
202
+ return { 'status' => 500, 'message' => "Internal Server Error: #{error}" }
203
+ rescue => error
204
+ #logger.error( "Error: #{__method__} #{method_type.upcase} on #{endpoint} error: '#{error}'" )
205
+ #logger.error( "query: #{data}" )
206
+ return { 'status' => 500, 'message' => "Internal Server Error: #{error}" }
175
207
  end
176
-
177
208
  end
178
-
179
209
  end
180
-
181
210
  end
@@ -103,7 +103,8 @@ module Grafana
103
103
 
104
104
  if( org.is_a?(Hash) && org.dig('status').to_i == 200 )
105
105
  org = org.dig('message')
106
- return { 'status' => 404, 'message' => format('User \'%s\' are already in the organisation', login_or_email) } if( org.select { |x| x.dig('email') == login_or_email || x.dig('login') == login_or_email }.count >= 1 )
106
+ return { 'status' => 404, 'message' => format('User \'%s\' are already in the organisation', login_or_email) } \
107
+ if( org.select { |x| x.dig('email') == login_or_email || x.dig('login') == login_or_email }.count >= 1 )
107
108
  end
108
109
 
109
110
  endpoint = '/api/org/users'
@@ -23,11 +23,14 @@ module Grafana
23
23
  #
24
24
  def organization( organisation_id )
25
25
 
26
- raise ArgumentError.new(format('wrong type. user \'organisation_id\' must be an String (for an Datasource name) or an Integer (for an Datasource Id), given \'%s\'', organisation_id.class.to_s)) if( organisation_id.is_a?(String) && organisation_id.is_a?(Integer) )
26
+ if( organisation_id.is_a?(String) && organisation_id.is_a?(Integer))
27
+ raise ArgumentError.new(format('wrong type. \'organisation_id\' must be an String (for an Datasource name) ' \
28
+ 'or an Integer (for an Datasource Id), given \'%s\'', organisation_id.class.to_s))
29
+ end
27
30
  raise ArgumentError.new('missing \'organisation_id\'') if( organisation_id.size.zero? )
28
31
 
29
32
  endpoint = format( '/api/orgs/%d', organisation_id ) if(organisation_id.is_a?(Integer))
30
- endpoint = format( '/api/orgs/name/%s', URI.escape( organisation_id ) ) if(organisation_id.is_a?(String))
33
+ endpoint = format( '/api/orgs/name/%s', ERB::Util.url_encode( organisation_id ) ) if(organisation_id.is_a?(String))
31
34
 
32
35
  @logger.debug("Attempting to get existing data source Id #{organisation_id} (GET #{endpoint})") if @debug
33
36
 
@@ -83,7 +86,10 @@ module Grafana
83
86
  #
84
87
  def organization_users( organization_id )
85
88
 
86
- raise ArgumentError.new(format('wrong type. user \'organization_id\' must be an String (for an Organisation name) or an Integer (for an Organisation Id), given \'%s\'', organization_id.class.to_s)) if( organization_id.is_a?(String) && organization_id.is_a?(Integer) )
89
+ if( organization_id.is_a?(String) && organization_id.is_a?(Integer))
90
+ raise ArgumentError.new(format('wrong type. \'organization_id\' must be an String (for an Organisation name) '\
91
+ 'or an Integer (for an Organisation Id), given \'%s\'', organization_id.class.to_s))
92
+ end
87
93
  raise ArgumentError.new('missing \'organization_id\'') if( organization_id.size.zero? )
88
94
 
89
95
  if(organization_id.is_a?(String))
@@ -266,7 +272,10 @@ module Grafana
266
272
  #
267
273
  def delete_organisation( organisation_id )
268
274
 
269
- raise ArgumentError.new(format('wrong type. user \'organisation_id\' must be an String (for an Datasource name) or an Integer (for an Datasource Id), given \'%s\'', organisation_id.class.to_s)) if( organisation_id.is_a?(String) && organisation_id.is_a?(Integer) )
275
+ if( organisation_id.is_a?(String) && organisation_id.is_a?(Integer) )
276
+ raise ArgumentError.new(format('wrong type. \'organisation_id\' must be an String (for an Organisation name) ' \
277
+ 'or an Integer (for an Organisation Id), given \'%s\'', organisation_id.class.to_s))
278
+ end
270
279
  raise ArgumentError.new('missing \'organisation_id\'') if( organisation_id.size.zero? )
271
280
 
272
281
  if(organisation_id.is_a?(String))
@@ -275,7 +284,7 @@ module Grafana
275
284
  data.each do |d|
276
285
  organisation_map[d.dig('id')] = d.dig('name')
277
286
  end
278
- organisation_id = organisation_map.select { |x,y| y == organisation_id }.keys.first if( organisation_map )
287
+ organisation_id = organisation_map.select { |_,y| y == organisation_id }.keys.first if( organisation_map )
279
288
  end
280
289
 
281
290
  return { 'status' => 404, 'message' => format( 'No Organisation \'%s\' found', organisation_id) } if( organisation_id.nil? )
@@ -308,7 +317,7 @@ module Grafana
308
317
  organization = validate( params, required: true, var: 'organization', type: String )
309
318
  login_or_email = validate( params, required: true, var: 'login_or_email', type: String )
310
319
  role = validate( params, required: true, var: 'role', type: String )
311
- valid_roles = ['Viewer', 'Editor', 'Read Only Editor', 'Admin']
320
+ valid_roles = %w[Viewer Editor "Read Only Editor" Admin]
312
321
 
313
322
  # https://stackoverflow.com/questions/9333952/case-insensitive-arrayinclude?answertab=votes#tab-top
314
323
  # Do this once, or each time the array changes
@@ -0,0 +1,594 @@
1
+
2
+ module Grafana
3
+
4
+ # +++
5
+ # title = "Playlist HTTP API "
6
+ # description = "Playlist Admin HTTP API"
7
+ # keywords = ["grafana", "http", "documentation", "api", "playlist"]
8
+ # aliases = ["/http_api/playlist/"]
9
+ # type = "docs"
10
+ # [menu.docs]
11
+ # name = "Playlist"
12
+ # parent = "http_api"
13
+ # +++
14
+
15
+ # https://github.com/grafana/grafana/blob/1165d098b0d0ae705955f9d2ea104beea98ca6eb/pkg/api/dtos/playlist.go
16
+
17
+ module Playlist
18
+
19
+ ## Playlist API
20
+ #
21
+ ### Search Playlist
22
+ #
23
+ #`GET /api/playlists`
24
+ #
25
+ #Get all existing playlist for the current organization using pagination
26
+ #
27
+ #**Example Request**:
28
+ #
29
+ #```bash
30
+ #GET /api/playlists HTTP/1.1
31
+ #Accept: application/json
32
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
33
+ #```
34
+ #
35
+ # Querystring Parameters:
36
+ #
37
+ # These parameters are used as querystring parameters.
38
+ #
39
+ # - **query** - Limit response to playlist having a name like this value.
40
+ # - **limit** - Limit response to *X* number of playlist.
41
+ #
42
+ #**Example Response**:
43
+ #
44
+ #```json
45
+ #HTTP/1.1 200
46
+ #Content-Type: application/json
47
+ #[
48
+ # {
49
+ # "id": 1,
50
+ # "name": "my playlist",
51
+ # "interval": "5m"
52
+ # }
53
+ #]
54
+ #```
55
+ def playlists
56
+
57
+ endpoint = '/api/playlists'
58
+
59
+ @logger.debug("Attempting to get all existing playlists (GET #{endpoint})") if @debug
60
+
61
+ playlists = get( endpoint )
62
+
63
+ return { 'status' => 404, 'message' => 'No Playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
64
+
65
+ playlists
66
+ end
67
+
68
+ ### Get one playlist
69
+ #
70
+ #`GET /api/playlists/:id`
71
+ #
72
+ #**Example Request**:
73
+ #
74
+ #```bash
75
+ #GET /api/playlists/1 HTTP/1.1
76
+ #Accept: application/json
77
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
78
+ #```
79
+ #
80
+ #**Example Response**:
81
+ #
82
+ #```json
83
+ #HTTP/1.1 200
84
+ #Content-Type: application/json
85
+ #{
86
+ # "id" : 1,
87
+ # "name": "my playlist",
88
+ # "interval": "5m",
89
+ # "orgId": "my org",
90
+ # "items": [
91
+ # {
92
+ # "id": 1,
93
+ # "playlistId": 1,
94
+ # "type": "dashboard_by_id",
95
+ # "value": "3",
96
+ # "order": 1,
97
+ # "title":"my third dasboard"
98
+ # },
99
+ # {
100
+ # "id": 2,
101
+ # "playlistId": 1,
102
+ # "type": "dashboard_by_tag",
103
+ # "value": "myTag",
104
+ # "order": 2,
105
+ # "title":"my other dasboard"
106
+ # }
107
+ # ]
108
+ #}
109
+ #```
110
+
111
+ def playlist( playlist_id )
112
+
113
+ if( playlist_id.is_a?(String) && playlist_id.is_a?(Integer) )
114
+ raise ArgumentError.new(format('wrong type. \'playlist_id\' must be an String (for an Playlist name) or an Integer (for an Playlist Id), given \'%s\'', playlist_id.class.to_s))
115
+ end
116
+ raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
117
+
118
+ if(playlist_id.is_a?(String))
119
+
120
+ data = playlists
121
+ status = data.dig('status')
122
+ d = data.dig('message')
123
+ data = d.select { |k| k['name'] == playlist_id }
124
+
125
+ return { 'status' => 404, 'message' => format( 'No Playlist \'%s\' found', playlist_id) } if( data.size.zero? )
126
+
127
+ unless( data.empty? )
128
+ playlist_data = []
129
+ data.each_entry do |k|
130
+ playlist_data << playlist( k['id'] )
131
+ end
132
+
133
+ return { 'status' => status, 'playlists' => playlist_data }
134
+ end
135
+ end
136
+
137
+ raise format('playlist id can not be 0') if( playlist_id.zero? )
138
+
139
+ endpoint = format('/api/playlists/%d', playlist_id )
140
+
141
+ @logger.debug("Attempting to get existing playlist id #{playlist_id} (GET #{endpoint})") if @debug
142
+
143
+ result = get(endpoint)
144
+
145
+ return { 'status' => 404, 'message' => 'playlist is empty', 'items' => [] } if( result.dig('status') == 404 )
146
+
147
+ result
148
+ end
149
+
150
+ ### Get Playlist items
151
+
152
+ #`GET /api/playlists/:id/items`
153
+ #
154
+ #**Example Request**:
155
+ #
156
+ #```bash
157
+ #GET /api/playlists/1/items HTTP/1.1
158
+ #Accept: application/json
159
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
160
+ #```
161
+ #
162
+ #**Example Response**:
163
+ #
164
+ #```json
165
+ #HTTP/1.1 200
166
+ #Content-Type: application/json
167
+ #[
168
+ # {
169
+ # "id": 1,
170
+ # "playlistId": 1,
171
+ # "type": "dashboard_by_id",
172
+ # "value": "3",
173
+ # "order": 1,
174
+ # "title":"my third dasboard"
175
+ # },
176
+ # {
177
+ # "id": 2,
178
+ # "playlistId": 1,
179
+ # "type": "dashboard_by_tag",
180
+ # "value": "myTag",
181
+ # "order": 2,
182
+ # "title":"my other dasboard"
183
+ # }
184
+ #]
185
+ #```
186
+
187
+ def playlist_items( playlist_id, multi_result = false )
188
+
189
+ if( playlist_id.is_a?(String) && playlist_id.is_a?(Integer) )
190
+ raise ArgumentError.new(format('wrong type. \'playlist_id\' must be an String (for an playlist name) or an Integer (for an playlist Id), given \'%s\'', playlist_id.class.to_s))
191
+ end
192
+ raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
193
+
194
+ tmp_playlists = playlists
195
+
196
+ begin
197
+ status = tmp_playlists.dig('status').to_i
198
+ message = tmp_playlists.dig('message')
199
+
200
+ return tmp_playlists if( status != 200 )
201
+
202
+ data = message.select { |k| k['id'] == playlist_id } if( playlist_id.is_a?(Integer) )
203
+ data = message.select { |k| k['name'] == playlist_id } if( playlist_id.is_a?(String) )
204
+
205
+ return { 'status' => 404, 'message' => 'No Playlist found' } if( !data.is_a?(Array) || data.count.zero? || status.to_i != 200 )
206
+ return { 'status' => 404, 'message' => format('found %d playlists with name %s', data.count, playlist_id ) } if( data.count > 1 && multi_result == false )
207
+
208
+ id = data.first.dig('id')
209
+
210
+ rescue
211
+ return { 'status' => 404, 'message' => 'No Playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
212
+ end
213
+
214
+ endpoint = "/api/playlists/#{id}/items"
215
+
216
+ result = get( endpoint )
217
+
218
+ return { 'status' => 404, 'message' => 'playlist is empty' } if( result.dig('status') == 404 )
219
+
220
+ result
221
+ end
222
+
223
+ ### Get Playlist dashboards
224
+ #
225
+ #`GET /api/playlists/:id/dashboards`
226
+ #
227
+ #**Example Request**:
228
+ #
229
+ #```bash
230
+ #GET /api/playlists/1/dashboards HTTP/1.1
231
+ #Accept: application/json
232
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
233
+ #```
234
+ #
235
+ #**Example Response**:
236
+ #
237
+ #```json
238
+ #HTTP/1.1 200
239
+ #Content-Type: application/json
240
+ #[
241
+ # {
242
+ # "id": 3,
243
+ # "title": "my third dasboard",
244
+ # "order": 1,
245
+ # },
246
+ # {
247
+ # "id": 5,
248
+ # "title":"my other dasboard"
249
+ # "order": 2,
250
+ #
251
+ # }
252
+ #]
253
+ #```
254
+
255
+ def playlist_dashboards( playlist_id )
256
+
257
+ raise ArgumentError.new(format('wrong type. \'playlist_id\' must be an Integer, given \'%s\'', playlist_id.class)) unless( playlist_id.is_a?(Integer) )
258
+ raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
259
+
260
+ endpoint = format('/api/playlists/%s/dashboards', playlist_id)
261
+
262
+ @logger.debug( "Attempting to get playlist (GET #{endpoint})" ) if @debug
263
+ get(endpoint)
264
+ end
265
+
266
+ # Create a playlist
267
+
268
+ # `POST /api/playlists/`
269
+ #
270
+ #**Example Request**:
271
+ #
272
+ #```bash
273
+ #PUT /api/playlists/1 HTTP/1.1
274
+ #Accept: application/json
275
+ #Content-Type: application/json
276
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
277
+ # {
278
+ # "name": "my playlist",
279
+ # "interval": "5m",
280
+ # "items": [
281
+ # {
282
+ # "type": "dashboard_by_id",
283
+ # "value": "3",
284
+ # "order": 1,
285
+ # "title":"my third dasboard"
286
+ # },
287
+ # {
288
+ # "type": "dashboard_by_tag",
289
+ # "value": "myTag",
290
+ # "order": 2,
291
+ # "title":"my other dasboard"
292
+ # }
293
+ # ]
294
+ # }
295
+ #```
296
+ #
297
+ #**Example Response**:
298
+ #
299
+ #```json
300
+ #HTTP/1.1 200
301
+ #Content-Type: application/json
302
+ # {
303
+ # "id": 1,
304
+ # "name": "my playlist",
305
+ # "interval": "5m"
306
+ # }
307
+ #```
308
+
309
+ def create_playlist( params )
310
+
311
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
312
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
313
+
314
+ # v, mv = version.values
315
+ # return { 'status' => 404, 'message' => format( 'folder has been supported in Grafana since version 5. you use version %s', v) } if(mv < 5)
316
+
317
+ name = validate( params, required: true , var: 'name' , type: String )
318
+ interval = validate( params, required: true , var: 'interval' , type: String )
319
+ items = validate( params, required: true , var: 'items' , type: Array )
320
+
321
+ return { 'status' => 404, 'message' => 'There are no elements for a playlist' } if(items.count.zero?)
322
+
323
+ payload_items = create_playlist_items(items)
324
+
325
+ payload = {
326
+ name: name,
327
+ interval: interval,
328
+ items: payload_items
329
+ }
330
+ payload.reject!{ |_k, v| v.nil? }
331
+
332
+ endpoint = '/api/playlists'
333
+
334
+ post(endpoint, payload.to_json)
335
+ end
336
+
337
+ ### Update a playlist
338
+ #
339
+ #`PUT /api/playlists/:id`
340
+ #
341
+ #**Example Request**:
342
+ #
343
+ #```bash
344
+ #PUT /api/playlists/1 HTTP/1.1
345
+ #Accept: application/json
346
+ #Content-Type: application/json
347
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
348
+ # {
349
+ # "name": "my playlist",
350
+ # "interval": "5m",
351
+ # "items": [
352
+ # {
353
+ # "playlistId": 1,
354
+ # "type": "dashboard_by_id",
355
+ # "value": "3",
356
+ # "order": 1,
357
+ # "title":"my third dasboard"
358
+ # },
359
+ # {
360
+ # "playlistId": 1,
361
+ # "type": "dashboard_by_tag",
362
+ # "value": "myTag",
363
+ # "order": 2,
364
+ # "title":"my other dasboard"
365
+ # }
366
+ # ]
367
+ # }
368
+ #```
369
+ #
370
+ #**Example Response**:
371
+ #
372
+ #```json
373
+ #HTTP/1.1 200
374
+ #Content-Type: application/json
375
+ #{
376
+ # "id" : 1,
377
+ # "name": "my playlist",
378
+ # "interval": "5m",
379
+ # "orgId": "my org",
380
+ # "items": [
381
+ # {
382
+ # "id": 1,
383
+ # "playlistId": 1,
384
+ # "type": "dashboard_by_id",
385
+ # "value": "3",
386
+ # "order": 1,
387
+ # "title":"my third dasboard"
388
+ # },
389
+ # {
390
+ # "id": 2,
391
+ # "playlistId": 1,
392
+ # "type": "dashboard_by_tag",
393
+ # "value": "myTag",
394
+ # "order": 2,
395
+ # "title":"my other dasboard"
396
+ # }
397
+ # ]
398
+ #}
399
+ #```
400
+
401
+ def update_playlist( params )
402
+
403
+ raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
404
+ raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
405
+
406
+ playlist_id = validate( params, required: true , var: 'playlist' )
407
+ name = validate( params, required: false, var: 'name' )
408
+ interval = validate( params, required: false, var: 'interval', type: String )
409
+ # organisation = validate( params, required: false, var: 'organisation' )
410
+ items = validate( params, required: false, var: 'items', type: Array )
411
+
412
+ tmp_playlists = playlists
413
+
414
+ data = []
415
+
416
+ begin
417
+ status = tmp_playlists.dig('status').to_i
418
+ message = tmp_playlists.dig('message')
419
+
420
+ return tmp_playlists if( status != 200 )
421
+
422
+ data = message.select { |k| k['id'] == playlist_id } if( playlist_id.is_a?(Integer) )
423
+ data = message.select { |k| k['name'] == playlist_id } if( playlist_id.is_a?(String) )
424
+
425
+ return { 'status' => 404, 'message' => 'no playlist found' } if( !data.is_a?(Array) || data.count.zero? || status.to_i != 200 )
426
+ return { 'status' => 404, 'message' => format('found %d playlists with name %s', data.count, playlist_id ) } if( data.count > 1 && multi_result == false )
427
+
428
+ rescue
429
+ return { 'status' => 404, 'message' => 'no playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
430
+ end
431
+
432
+ playlist_id = data.first.dig('id')
433
+ # playlist_name = data.first.dig('name')
434
+ payload_items = create_playlist_items(items, playlist_id)
435
+
436
+ payload = {
437
+ id: playlist_id,
438
+ name: name,
439
+ interval: interval,
440
+ items: payload_items
441
+ }
442
+ payload.reject!{ |_k, v| v.nil? }
443
+
444
+ endpoint = format( '/api/playlists/%d', playlist_id )
445
+
446
+ put( endpoint, payload.to_json )
447
+
448
+ end
449
+
450
+
451
+ ### Delete a playlist
452
+ #
453
+ #`DELETE /api/playlists/:id`
454
+ #
455
+ #**Example Request**:
456
+ #
457
+ #```bash
458
+ #DELETE /api/playlists/1 HTTP/1.1
459
+ #Accept: application/json
460
+ #Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
461
+ #```
462
+ #
463
+ #**Example Response**:
464
+ #
465
+ #```json
466
+ #HTTP/1.1 200
467
+ #Content-Type: application/json
468
+ #{}
469
+ #```
470
+
471
+ def delete_playlist(playlist_id, multi_result = false )
472
+
473
+ if( playlist_id.is_a?(String) && playlist_id.is_a?(Integer) )
474
+ raise ArgumentError.new(format('wrong type. \'playlist_id\' must be an String (for an Playlist name) or an Integer (for an Playlist Id), given \'%s\'', playlist_id.class.to_s))
475
+ end
476
+ raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
477
+
478
+ tmp_playlists = playlists
479
+
480
+ data = []
481
+
482
+ begin
483
+ status = tmp_playlists.dig('status').to_i
484
+ message = tmp_playlists.dig('message')
485
+
486
+ return tmp_playlists if( status != 200 )
487
+
488
+ data = message.select { |k| k['id'] == playlist_id } if( playlist_id.is_a?(Integer) )
489
+ data = message.select { |k| k['name'] == playlist_id } if( playlist_id.is_a?(String) )
490
+
491
+ return { 'status' => 404, 'message' => 'no playlist found' } if( !data.is_a?(Array) || data.count.zero? || status.to_i != 200 )
492
+ return { 'status' => 404, 'message' => format('found %d playlists with name %s', data.count, playlist_id ) } if( data.count > 1 && multi_result == false )
493
+
494
+ rescue
495
+ return { 'status' => 404, 'message' => 'no playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
496
+ end
497
+
498
+ if( multi_result == true )
499
+
500
+ result = { 'status' => 0, 'message' => 'under development' }
501
+ data.each do |x|
502
+
503
+ endpoint = format( '/api/playlists/%d', x.dig('id') )
504
+
505
+ begin
506
+ result = delete( endpoint )
507
+ rescue => error
508
+ logger.error( "error: #{error}" )
509
+ end
510
+ end
511
+
512
+ # return result
513
+ else
514
+
515
+ playlist_id = data.first.dig('id')
516
+
517
+ endpoint = format( '/api/playlists/%d', playlist_id )
518
+
519
+ result = delete( endpoint )
520
+
521
+ if(result.dig('status').to_i == 500)
522
+ # check if the playlist exists
523
+ r = playlist( playlist_id )
524
+ return { 'status' => 200, 'message' => 'playlist deleted' } if(r.dig('status').to_i == 404)
525
+ end
526
+
527
+ # return result
528
+ end
529
+
530
+ result
531
+ end
532
+
533
+
534
+ private
535
+ def create_playlist_items( items, playlist_id = nil)
536
+
537
+ playlist_items = []
538
+
539
+ items.each do |r|
540
+ playlist_element = {}
541
+
542
+ if( r['name'] )
543
+
544
+ playlist_name = search_dashboards( query: r['name'] )
545
+ playlist_name_status = playlist_name.dig('status')
546
+
547
+ next unless( playlist_name_status == 200 )
548
+
549
+ playlist_name = playlist_name.dig('message')
550
+ playlist_name_id = playlist_name.first.dig('id')
551
+ playlist_name_title = playlist_name.first.dig('title')
552
+
553
+ playlist_element[:type] = 'dashboard_by_id'
554
+ playlist_element[:value] = playlist_name_id.to_s
555
+ playlist_element[:title] = playlist_name_title
556
+ playlist_element[:playlistId] = playlist_id unless(playlist_id.nil?)
557
+
558
+ elsif( r['id'] )
559
+
560
+ uid = dashboard_by_uid(r['id'])
561
+ uid_status = uid.dig('status')
562
+
563
+ next unless( uid_status == 200 )
564
+
565
+ playlist_element[:type] = 'dashboard_by_id'
566
+ playlist_element[:value] = r['id']
567
+ playlist_element[:playlistId] = playlist_id unless(playlist_id.nil?)
568
+
569
+ elsif( r['tag'] )
570
+
571
+ tags = search_dashboards( tags: r['tag'] )
572
+ tags_status = tags.dig('status')
573
+
574
+ next unless( tags_status == 200 )
575
+
576
+ playlist_element[:type] = 'dashboard_by_tag'
577
+ playlist_element[:value] = r['tag']
578
+ playlist_element[:title] = r['tag']
579
+ playlist_element[:playlistId] = playlist_id unless(playlist_id.nil?)
580
+
581
+ else
582
+ next
583
+ end
584
+
585
+ playlist_element[:order] = r['order'] if(r['order'])
586
+
587
+ playlist_items << playlist_element if(playlist_element.count >= 4)
588
+ end
589
+
590
+ playlist_items
591
+ end
592
+
593
+ end
594
+ end