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.
- checksums.yaml +5 -5
- data/README.md +8 -3
- data/lib/_logging.rb_ +55 -0
- data/lib/grafana.rb +1 -1
- data/lib/grafana/admin.rb +2 -1
- data/lib/grafana/alerts.rb +338 -14
- data/lib/grafana/annotations.rb +284 -9
- data/lib/grafana/auth.rb +150 -0
- data/lib/grafana/client.rb +81 -5
- data/lib/grafana/dashboard.rb +99 -7
- data/lib/grafana/dashboard_permissions.rb +132 -0
- data/lib/grafana/dashboard_versions.rb +101 -5
- data/lib/grafana/datasource.rb +34 -38
- data/lib/grafana/folder.rb +198 -0
- data/lib/grafana/folder_and_dashboard_search.rb +57 -0
- data/lib/grafana/folder_permissions.rb +155 -0
- data/lib/grafana/logging.rb +55 -0
- data/lib/grafana/login.rb +93 -49
- data/lib/grafana/network.rb +130 -101
- data/lib/grafana/organization.rb +2 -1
- data/lib/grafana/organizations.rb +15 -6
- data/lib/grafana/playlist.rb +594 -0
- data/lib/grafana/preferences.rb +122 -0
- data/lib/grafana/tags.rb +16 -0
- data/lib/grafana/teams.rb +364 -0
- data/lib/grafana/tools.rb +42 -9
- data/lib/grafana/user.rb +6 -2
- data/lib/grafana/users.rb +19 -11
- data/lib/grafana/validator.rb +47 -2
- data/lib/grafana/version.rb +3 -3
- metadata +16 -39
- data/doc/Array.html +0 -200
- data/doc/Boolean.html +0 -122
- data/doc/FalseClass.html +0 -132
- data/doc/Grafana.html +0 -172
- data/doc/Hash.html +0 -212
- data/doc/Logging.html +0 -326
- data/doc/Object.html +0 -286
- data/doc/Time.html +0 -200
- data/doc/TrueClass.html +0 -132
- data/doc/_index.html +0 -380
- data/doc/class_list.html +0 -51
- data/doc/file.README.html +0 -117
- data/doc/file_list.html +0 -56
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -117
- data/doc/method_list.html +0 -747
- data/doc/top-level-namespace.html +0 -112
- data/lib/logging.rb +0 -35
data/lib/grafana/network.rb
CHANGED
@@ -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
|
-
|
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(
|
77
|
+
response = @api_instance[endpoint].get( headers )
|
44
78
|
when 'POST'
|
45
|
-
response = @api_instance[endpoint].post( data,
|
79
|
+
response = @api_instance[endpoint].post( data, headers )
|
46
80
|
when 'PATCH'
|
47
|
-
response = @api_instance[endpoint].patch( data,
|
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
|
-
|
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
|
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
|
-
#
|
68
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
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
|
-
|
117
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
164
|
-
}
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
logger.error( "Error: #{__method__} #{method_type.upcase} on #{endpoint} error: '#{
|
169
|
-
logger.error( data )
|
170
|
-
|
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
|
data/lib/grafana/organization.rb
CHANGED
@@ -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) }
|
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
|
-
|
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',
|
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
|
-
|
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
|
-
|
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 { |
|
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 = [
|
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
|