grafana 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/_logging.rb_ +55 -0
- data/lib/grafana.rb +1 -1
- data/lib/grafana/alerts.rb +6 -2
- data/lib/grafana/annotations.rb +2 -2
- data/lib/grafana/auth.rb +150 -0
- data/lib/grafana/client.rb +50 -12
- data/lib/grafana/folder.rb +1 -1
- data/lib/grafana/logging.rb +55 -0
- data/lib/grafana/login.rb +54 -16
- data/lib/grafana/network.rb +6 -2
- data/lib/grafana/organizations.rb +1 -1
- data/lib/grafana/playlist.rb +72 -77
- data/lib/grafana/preferences.rb +2 -2
- data/lib/grafana/validator.rb +2 -2
- data/lib/grafana/version.rb +1 -1
- metadata +4 -2
- data/lib/logging.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee4ecb6c21184aee321f81b9d5a5681524da6cac47b736756e8b3b1a4c091eed
|
4
|
+
data.tar.gz: 267e82424dad92727eace6b546f2fd436235e51af5b471c806833e4eb3186efe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97d4a3aa5740c1992cf706fec3deae4690db5c68f05eb334b828dea74d6173fde86fbb3a53c2afe562d5a299e13a2c5450d4e27bcdf7dae96a146a8b3f2cb770
|
7
|
+
data.tar.gz: 5c231dad3f4552d8176b8b0a5653284b3792ec1058c958674a625e99b790d9e51f93eb240ca5f500c94e2cbff23159b2933fac13723cdaa0518b8f808f31176a
|
data/README.md
CHANGED
@@ -33,9 +33,9 @@ You can also run `bin/console` for an interactive prompt that will allow you to
|
|
33
33
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
34
34
|
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
|
35
35
|
which will create a git tag for the version,
|
36
|
-
push git commits and tags and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
36
|
+
push git commits and tags and push the `.gem` file to [rubygems.org](https://rubygems.org/gems/grafana).
|
37
37
|
|
38
38
|
## Contributing
|
39
39
|
|
40
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
40
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bodsch/grafana.
|
41
41
|
|
data/lib/_logging.rb_
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
# -------------------------------------------------------------------------------------------------
|
5
|
+
|
6
|
+
module Logging
|
7
|
+
|
8
|
+
def logger
|
9
|
+
@logger ||= Logging.logger_for( self.class.name )
|
10
|
+
end
|
11
|
+
|
12
|
+
# Use a hash class-ivar to cache a unique Logger per class:
|
13
|
+
@loggers = {}
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def logger_for( classname )
|
18
|
+
@loggers[classname] ||= configure_logger_for( classname )
|
19
|
+
end
|
20
|
+
|
21
|
+
def configure_logger_for( classname )
|
22
|
+
|
23
|
+
log_level = ENV.fetch('LOG_LEVEL', 'INFO' )
|
24
|
+
level = log_level.dup
|
25
|
+
|
26
|
+
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
|
27
|
+
log_level = case level.upcase
|
28
|
+
when 'DEBUG'
|
29
|
+
Logger::DEBUG # Low-level information for developers.
|
30
|
+
when 'INFO'
|
31
|
+
Logger::INFO # Generic (useful) information about system operation.
|
32
|
+
when 'WARN'
|
33
|
+
Logger::WARN # A warning.
|
34
|
+
when 'ERROR'
|
35
|
+
Logger::ERROR # A handleable error condition.
|
36
|
+
when 'FATAL'
|
37
|
+
Logger::FATAL # An unhandleable error that results in a program crash.
|
38
|
+
else
|
39
|
+
Logger::UNKNOWN # An unknown message that should always be logged.
|
40
|
+
end
|
41
|
+
|
42
|
+
$stdout.sync = true
|
43
|
+
logger = Logger.new($stdout)
|
44
|
+
logger.level = log_level
|
45
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S %z"
|
46
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
47
|
+
"[#{datetime.strftime( logger.datetime_format )}] #{severity.ljust(5)} #{msg}\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
logger
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# -------------------------------------------------------------------------------------------------
|
data/lib/grafana.rb
CHANGED
data/lib/grafana/alerts.rb
CHANGED
@@ -102,7 +102,6 @@ module Grafana
|
|
102
102
|
# puts alert_id
|
103
103
|
# GET /api/alerts/:id
|
104
104
|
|
105
|
-
|
106
105
|
endpoint = format( '/api/alerts/%d' , alert_id )
|
107
106
|
|
108
107
|
# puts endpoint
|
@@ -130,13 +129,18 @@ module Grafana
|
|
130
129
|
end
|
131
130
|
raise ArgumentError.new('missing \'alert_id\'') if( alert_id.size.zero? )
|
132
131
|
|
133
|
-
if(alert_id.is_a?(String))
|
132
|
+
if( alert_id.is_a?(String) )
|
134
133
|
data = alerts( alerts: 'all' ).select { |_k,v| v['name'] == alert_id }
|
135
134
|
alert_id = data.keys.first if( data )
|
136
135
|
end
|
137
136
|
|
137
|
+
endpoint = format( '/api/alerts/%d/pause', alert_id )
|
138
|
+
|
139
|
+
@logger.debug("Attempting pause alert id #{alert_id} (POST #{endpoint})") if @debug
|
140
|
+
|
138
141
|
# POST /api/alerts/:id/pause
|
139
142
|
# puts alert_id
|
143
|
+
post( endpoint )
|
140
144
|
end
|
141
145
|
|
142
146
|
# Get alert notifications
|
data/lib/grafana/annotations.rb
CHANGED
@@ -124,8 +124,8 @@ module Grafana
|
|
124
124
|
time = validate( params, required: false, var: 'time', type: Integer ) || Time.now.to_i
|
125
125
|
time_end = validate( params, required: false, var: 'time_end', type: Integer )
|
126
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 )
|
127
|
+
tags = validate( params, required: true , var: 'tags', type: Array )
|
128
|
+
text = validate( params, required: true , var: 'text', type: String )
|
129
129
|
|
130
130
|
if( dashboard.is_a?(String) )
|
131
131
|
|
data/lib/grafana/auth.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
|
2
|
+
module Grafana
|
3
|
+
|
4
|
+
# abstract base class for authentication API
|
5
|
+
#
|
6
|
+
# https://grafana.com/docs/grafana/latest/http_api/auth/
|
7
|
+
#
|
8
|
+
# Token
|
9
|
+
# - Currently you can authenticate via an API Token or via a Session cookie (acquired using regular login or oauth).
|
10
|
+
#
|
11
|
+
# Basic Auth
|
12
|
+
# - If basic auth is enabled (it is enabled by default) you can authenticate your HTTP request via standard
|
13
|
+
# basic auth. Basic auth will also authenticate LDAP users.
|
14
|
+
#
|
15
|
+
module Auth
|
16
|
+
|
17
|
+
# Auth HTTP resources / actions
|
18
|
+
# Api Keys
|
19
|
+
#
|
20
|
+
# GET /api/auth/keys
|
21
|
+
def api_keys
|
22
|
+
|
23
|
+
endpoint = '/api/auth/keys'
|
24
|
+
|
25
|
+
@logger.debug("Attempting to get all existing api keys (GET #{endpoint})") if @debug
|
26
|
+
|
27
|
+
get( endpoint )
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def api_key( api_id )
|
32
|
+
|
33
|
+
if( api_id.is_a?(String) && api_id.is_a?(Integer) )
|
34
|
+
raise ArgumentError.new(format('wrong type. API token \'api_id\' must be an String (for an API name) or an Integer (for an API Id), given \'%s\'', api_id.class.to_s))
|
35
|
+
end
|
36
|
+
raise ArgumentError.new('missing \'api_id\'') if( api_id.size.zero? )
|
37
|
+
|
38
|
+
if(api_id.is_a?(String))
|
39
|
+
keys = api_keys
|
40
|
+
keys = JSON.parse(keys) if(keys.is_a?(String))
|
41
|
+
|
42
|
+
# logger.debug(keys)
|
43
|
+
|
44
|
+
status = keys.dig('status')
|
45
|
+
return keys if( status != 200 )
|
46
|
+
|
47
|
+
u = keys.dig('message').detect { |v| v['id'] == api_id || v['name'] == api_id }
|
48
|
+
|
49
|
+
# logger.debug(u)
|
50
|
+
|
51
|
+
return { 'status' => 404, 'message' => format( 'No API token \'%s\' found', api_id ) } if( u.nil? )
|
52
|
+
|
53
|
+
# api_id = u.dig('id') unless(u.nil?)
|
54
|
+
end
|
55
|
+
|
56
|
+
{ 'status' => 200, 'message' => u }
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Create API Key
|
62
|
+
#
|
63
|
+
# POST /api/auth/keys
|
64
|
+
# https://grafana.com/docs/grafana/latest/http_api/auth/#create-api-key
|
65
|
+
#
|
66
|
+
# @param [Hash] params
|
67
|
+
# @option params [String] name The key name - (required)
|
68
|
+
# @option params [String] role Sets the access level/Grafana Role for the key. Can be one of the following values: Viewer, Editor or Admin. - (required)
|
69
|
+
# @option params [Integer] seconds_to_live Sets the key expiration in seconds.
|
70
|
+
# It is optional. If it is a positive number an expiration date for the key is set.
|
71
|
+
# If it is null, zero or is omitted completely (unless api_key_max_seconds_to_live configuration option is set) the key will never expire.
|
72
|
+
#
|
73
|
+
#
|
74
|
+
# @return [Hash]
|
75
|
+
#
|
76
|
+
# @example:
|
77
|
+
#
|
78
|
+
def create_api_key( params )
|
79
|
+
|
80
|
+
raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) )
|
81
|
+
raise ArgumentError.new('missing \'params\'') if( params.size.zero? )
|
82
|
+
|
83
|
+
name = validate( params, required: true, var: 'name' )
|
84
|
+
role = validate( params, required: true, var: 'role' )
|
85
|
+
seconds_to_live = validate( params, required: false, var: 'seconds_to_live', type: Integer )
|
86
|
+
|
87
|
+
valid_roles = %w[Viewer Editor Admin]
|
88
|
+
|
89
|
+
# https://stackoverflow.com/questions/9333952/case-insensitive-arrayinclude?answertab=votes#tab-top
|
90
|
+
# Do this once, or each time the array changes
|
91
|
+
downcased = Set.new valid_roles.map(&:downcase)
|
92
|
+
unless( downcased.include?( role.downcase ) )
|
93
|
+
return {
|
94
|
+
'status' => 404,
|
95
|
+
'login_or_email' => login_or_email,
|
96
|
+
'role' => role,
|
97
|
+
'message' => format( 'wrong role. Role must be one of %s, given \'%s\'', valid_roles.join(', '), role )
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
seconds_to_live = 86_400 if seconds_to_live.nil?
|
102
|
+
|
103
|
+
endpoint = '/api/auth/keys'
|
104
|
+
|
105
|
+
data = {
|
106
|
+
name: name,
|
107
|
+
role: role,
|
108
|
+
secondsToLive: seconds_to_live
|
109
|
+
}
|
110
|
+
|
111
|
+
data.reject!{ |_k, v| v.nil? }
|
112
|
+
|
113
|
+
payload = data.deep_string_keys
|
114
|
+
# payload = existing_ds.merge(payload).deep_symbolize_keys
|
115
|
+
|
116
|
+
@logger.debug("create API token (POST #{endpoint})") if @debug
|
117
|
+
|
118
|
+
post(endpoint, payload.to_json)
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# Delete API Key
|
123
|
+
#
|
124
|
+
# DELETE /api/auth/keys/:id
|
125
|
+
def delete_api_key( key_id )
|
126
|
+
|
127
|
+
if( key_id.is_a?(String) && key_id.is_a?(Integer) )
|
128
|
+
raise ArgumentError.new(format('wrong type. \'key_id\' must be an String (for an API Key name) or an Integer (for an API Key Id), given \'%s\'', key_id.class.to_s))
|
129
|
+
end
|
130
|
+
raise ArgumentError.new('missing \'key_id\'') if( key_id.size.zero? )
|
131
|
+
|
132
|
+
if(key_id.is_a?(String))
|
133
|
+
data = api_keys.select { |_k,v| v['name'] == key_id }
|
134
|
+
key_id = data.keys.first if( data )
|
135
|
+
end
|
136
|
+
|
137
|
+
return { 'status' => 404, 'message' => format( 'No API key \'%s\' found', key_id) } if( key_id.nil? )
|
138
|
+
|
139
|
+
raise format('API Key can not be 0') if( key_id.zero? )
|
140
|
+
|
141
|
+
endpoint = format('/api/auth/keys/%d', key_id)
|
142
|
+
logger.debug("Deleting API key #{key_id} (DELETE #{endpoint})") if @debug
|
143
|
+
|
144
|
+
delete(endpoint)
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
data/lib/grafana/client.rb
CHANGED
@@ -5,7 +5,9 @@ require 'rest-client'
|
|
5
5
|
require 'json'
|
6
6
|
require 'timeout'
|
7
7
|
|
8
|
+
require_relative 'logging'
|
8
9
|
require_relative 'version'
|
10
|
+
require_relative 'auth'
|
9
11
|
require_relative 'validator'
|
10
12
|
require_relative 'login'
|
11
13
|
require_relative 'network'
|
@@ -48,6 +50,7 @@ module Grafana
|
|
48
50
|
include Logging
|
49
51
|
|
50
52
|
include Grafana::Version
|
53
|
+
include Grafana::Auth
|
51
54
|
include Grafana::Validator
|
52
55
|
include Grafana::Login
|
53
56
|
include Grafana::Network
|
@@ -111,11 +114,18 @@ module Grafana
|
|
111
114
|
ssl = settings.dig(:grafana, :ssl) || false
|
112
115
|
@timeout = settings.dig(:grafana, :timeout) || 5
|
113
116
|
@open_timeout = settings.dig(:grafana, :open_timeout) || 5
|
114
|
-
@
|
117
|
+
@api_user = settings.dig(:grafana, :api, :user) || 'admin'
|
118
|
+
@api_password = settings.dig(:grafana, :api, :password)
|
119
|
+
@http_headers = settings.dig(:grafana, :http_headers) || { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
|
115
120
|
@debug = settings.dig(:debug) || false
|
116
|
-
|
121
|
+
@debug = false
|
117
122
|
@headers = {}
|
118
123
|
|
124
|
+
# Token Support for Grafana 6
|
125
|
+
@api_key = nil
|
126
|
+
@api_token_name = settings.dig(:grafana, :api, :token, :name ) || (0..10).to_a.map{|_a| rand(16).to_s(16)}.join
|
127
|
+
@api_token_lifetime = settings.dig(:grafana, :api, :token, :lifetime ) || 0
|
128
|
+
|
119
129
|
raise ArgumentError.new('missing \'host\'') if( host.nil? )
|
120
130
|
|
121
131
|
raise ArgumentError.new(format('wrong type. \'port\' must be an Integer, given \'%s\'', port.class.to_s)) unless( port.is_a?(Integer) )
|
@@ -129,6 +139,28 @@ module Grafana
|
|
129
139
|
@url = format( '%s://%s:%d%s', protocoll, host, port, url_path )
|
130
140
|
end
|
131
141
|
|
142
|
+
|
143
|
+
def create_instance
|
144
|
+
|
145
|
+
logger.debug( "create_instance" )
|
146
|
+
logger.debug( "@api_key: #{@api_key} #{@api_key.class}" )
|
147
|
+
|
148
|
+
params = { timeout: @timeout.to_i, open_timeout: @open_timeout.to_i, headers: @http_headers, verify_ssl: false }
|
149
|
+
params = { timeout: @timeout.to_i, open_timeout: @open_timeout.to_i, headers: @http_headers, verify_ssl: false, user: @api_user, password: @api_password } if( @api_key.nil? )
|
150
|
+
|
151
|
+
logger.debug( "url : #{@url}" )
|
152
|
+
logger.debug( "params: #{params}" )
|
153
|
+
|
154
|
+
begin
|
155
|
+
RestClient::Resource.new( @url, params )
|
156
|
+
rescue => error
|
157
|
+
logger.error( error ) # if @debug
|
158
|
+
logger.debug( e.backtrace.join("\n") ) #if @debug
|
159
|
+
false
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
|
132
164
|
# Get Settings
|
133
165
|
#
|
134
166
|
# http://docs.grafana.org/http_api/other/#get-settings
|
@@ -142,20 +174,26 @@ module Grafana
|
|
142
174
|
|
143
175
|
def version
|
144
176
|
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
177
|
|
178
|
+
status = s.dig('status')
|
179
|
+
if( status.to_i == 200 )
|
180
|
+
@version = s.dig('buildInfo','version')
|
181
|
+
@major_version = @version.split('.').first.to_i
|
151
182
|
|
152
|
-
|
153
|
-
|
183
|
+
{ version: @version, major_version: @major_version }
|
184
|
+
else
|
185
|
+
s
|
186
|
+
end
|
154
187
|
end
|
155
188
|
|
156
|
-
|
157
|
-
|
158
|
-
|
189
|
+
|
190
|
+
# def self.logger
|
191
|
+
# @@logger ||= defined?(Logging) ? Logging.logger : Logger.new(STDOUT)
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# def self.logger=(logger)
|
195
|
+
# @@logger = logger
|
196
|
+
# end
|
159
197
|
|
160
198
|
end
|
161
199
|
|
data/lib/grafana/folder.rb
CHANGED
@@ -99,7 +99,7 @@ module Grafana
|
|
99
99
|
|
100
100
|
endpoint = '/api/folders'
|
101
101
|
|
102
|
-
@logger.debug("create folder#{title} (GET #{endpoint})") if @debug
|
102
|
+
@logger.debug("create folder #{title} (GET #{endpoint})") if @debug
|
103
103
|
logger.debug(payload.to_json) if(@debug)
|
104
104
|
|
105
105
|
post( endpoint, payload.to_json )
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
# -------------------------------------------------------------------------------------------------
|
5
|
+
|
6
|
+
module Logging
|
7
|
+
|
8
|
+
def logger
|
9
|
+
@logger ||= Logging.logger_for( self.class.name )
|
10
|
+
end
|
11
|
+
|
12
|
+
# Use a hash class-ivar to cache a unique Logger per class:
|
13
|
+
@loggers = {}
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def logger_for( classname )
|
18
|
+
@loggers[classname] ||= configure_logger_for( classname )
|
19
|
+
end
|
20
|
+
|
21
|
+
def configure_logger_for( classname )
|
22
|
+
|
23
|
+
log_level = ENV.fetch('LOG_LEVEL', 'INFO' )
|
24
|
+
level = log_level.dup
|
25
|
+
|
26
|
+
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
|
27
|
+
log_level = case level.upcase
|
28
|
+
when 'DEBUG'
|
29
|
+
Logger::DEBUG # Low-level information for developers.
|
30
|
+
when 'INFO'
|
31
|
+
Logger::INFO # Generic (useful) information about system operation.
|
32
|
+
when 'WARN'
|
33
|
+
Logger::WARN # A warning.
|
34
|
+
when 'ERROR'
|
35
|
+
Logger::ERROR # A handleable error condition.
|
36
|
+
when 'FATAL'
|
37
|
+
Logger::FATAL # An unhandleable error that results in a program crash.
|
38
|
+
else
|
39
|
+
Logger::UNKNOWN # An unknown message that should always be logged.
|
40
|
+
end
|
41
|
+
|
42
|
+
$stdout.sync = true
|
43
|
+
logger = Logger.new($stdout)
|
44
|
+
logger.level = log_level
|
45
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S %z"
|
46
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
47
|
+
"[#{datetime.strftime( logger.datetime_format )}] #{severity.ljust(5)} #{msg}\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
logger
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# -------------------------------------------------------------------------------------------------
|
data/lib/grafana/login.rb
CHANGED
@@ -29,20 +29,27 @@ module Grafana
|
|
29
29
|
max_retries = validate( params, required: false, var: 'max_retries', type: Integer ) || 2
|
30
30
|
sleep_between_retries = validate( params, required: false, var: 'sleep_between_retries', type: Integer ) || 5
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
32
|
+
# raise 'no valid rest instance found' if( @api_instance.nil? )
|
33
|
+
|
34
|
+
# only useful for Grafana version < 6
|
35
|
+
#
|
36
|
+
if( @api_instance.nil? )
|
37
|
+
|
38
|
+
@api_user = username
|
39
|
+
@api_password = password
|
40
|
+
|
41
|
+
@api_instance = create_instance
|
42
|
+
|
43
|
+
return true if(@api_instance)
|
44
|
+
else
|
45
|
+
logger.debug('User session already initiated') if @debug
|
46
|
+
return true
|
44
47
|
end
|
45
48
|
|
49
|
+
logger.debug( "resource: #{@api_instance.inspect}")
|
50
|
+
|
51
|
+
false
|
52
|
+
|
46
53
|
request_data = { 'User' => username, 'Password' => password }
|
47
54
|
|
48
55
|
if( @api_instance )
|
@@ -51,13 +58,15 @@ module Grafana
|
|
51
58
|
@headers = {}
|
52
59
|
|
53
60
|
begin
|
54
|
-
logger.debug('Attempting to establish user session') if @debug
|
61
|
+
logger.debug('Attempting to establish user session') # if @debug
|
55
62
|
|
56
|
-
response = @api_instance['/login'].post(
|
63
|
+
response = @api_instance['/api/login'].post(
|
57
64
|
request_data.to_json,
|
58
65
|
content_type: 'application/json; charset=UTF-8'
|
59
66
|
)
|
60
67
|
|
68
|
+
logger.debug( "response #{response}")
|
69
|
+
|
61
70
|
response_cookies = response.cookies
|
62
71
|
response_code = response.code.to_i
|
63
72
|
|
@@ -131,11 +140,40 @@ module Grafana
|
|
131
140
|
# @return [Hash]
|
132
141
|
#
|
133
142
|
def ping_session
|
134
|
-
logger.debug( "Pinging current session (GET #{endpoint})" ) if @debug
|
135
143
|
endpoint = '/api/login/ping'
|
136
|
-
|
144
|
+
logger.debug( "Pinging current session (GET #{endpoint})" ) if @debug
|
145
|
+
|
146
|
+
begin
|
147
|
+
get( endpoint )
|
148
|
+
rescue => error
|
149
|
+
logger.error(e)
|
150
|
+
end
|
137
151
|
end
|
138
152
|
|
153
|
+
# Returns health information about Grafana
|
154
|
+
#
|
155
|
+
# @example
|
156
|
+
# health
|
157
|
+
#
|
158
|
+
# @return [Hash]
|
159
|
+
#
|
160
|
+
def health
|
161
|
+
endpoint = '/api/health'
|
162
|
+
logger.debug( "get health information (GET #{endpoint})" ) if @debug
|
163
|
+
|
164
|
+
result = get( endpoint )
|
165
|
+
|
166
|
+
if( result.is_a?(Hash) )
|
167
|
+
status = result.dig('status')
|
168
|
+
if( status.to_i == 200 )
|
169
|
+
message = result.dig('message')
|
170
|
+
r = message.gsub('=>', ':').gsub(':nil,', ':null,')
|
171
|
+
return { 'status' => status, 'message' => JSON.parse( r ) }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
result
|
176
|
+
end
|
139
177
|
|
140
178
|
def headers
|
141
179
|
@headers
|
data/lib/grafana/network.rb
CHANGED
@@ -61,9 +61,11 @@ module Grafana
|
|
61
61
|
#
|
62
62
|
def request( method_type = 'GET', endpoint = '/', data = {} )
|
63
63
|
|
64
|
+
logger.debug( "request( method_type: #{method_type}, endpoint: #{endpoint}, data )" )
|
65
|
+
|
64
66
|
raise 'try first login()' if @api_instance.nil?
|
65
67
|
|
66
|
-
login( username: @username, password: @password )
|
68
|
+
# login( username: @username, password: @password )
|
67
69
|
|
68
70
|
response = nil
|
69
71
|
response_code = 404
|
@@ -103,7 +105,7 @@ module Grafana
|
|
103
105
|
logger.error('422')
|
104
106
|
|
105
107
|
response_body = response_body.first if(response_body.is_a?(Array))
|
106
|
-
message_field_name = response_body.dig('fieldNames')
|
108
|
+
# message_field_name = response_body.dig('fieldNames')
|
107
109
|
|
108
110
|
#status = response_code # response_body.dig('status')
|
109
111
|
message = response_body # .dig('message')
|
@@ -151,6 +153,8 @@ module Grafana
|
|
151
153
|
return false
|
152
154
|
end
|
153
155
|
|
156
|
+
# logger.debug( "response: #{response} (#{response.class})" )
|
157
|
+
|
154
158
|
response_code = response.code.to_i
|
155
159
|
response_body = response.body
|
156
160
|
response_headers = response.headers
|
@@ -317,7 +317,7 @@ module Grafana
|
|
317
317
|
organization = validate( params, required: true, var: 'organization', type: String )
|
318
318
|
login_or_email = validate( params, required: true, var: 'login_or_email', type: String )
|
319
319
|
role = validate( params, required: true, var: 'role', type: String )
|
320
|
-
valid_roles = [
|
320
|
+
valid_roles = %w[Viewer Editor "Read Only Editor" Admin]
|
321
321
|
|
322
322
|
# https://stackoverflow.com/questions/9333952/case-insensitive-arrayinclude?answertab=votes#tab-top
|
323
323
|
# Do this once, or each time the array changes
|
data/lib/grafana/playlist.rb
CHANGED
@@ -122,17 +122,16 @@ module Grafana
|
|
122
122
|
d = data.dig('message')
|
123
123
|
data = d.select { |k| k['name'] == playlist_id }
|
124
124
|
|
125
|
-
return { 'status' => 404, 'message' => format( 'No Playlist \'%s\' found', playlist_id) } if( data.size
|
125
|
+
return { 'status' => 404, 'message' => format( 'No Playlist \'%s\' found', playlist_id) } if( data.size.zero? )
|
126
126
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
_d << playlist( k['id'] )
|
127
|
+
unless( data.empty? )
|
128
|
+
playlist_data = []
|
129
|
+
data.each_entry do |k|
|
130
|
+
playlist_data << playlist( k['id'] )
|
132
131
|
end
|
133
|
-
|
132
|
+
|
133
|
+
return { 'status' => status, 'playlists' => playlist_data }
|
134
134
|
end
|
135
|
-
# return { 'status' => 200, 'message' => data } if( data.size != 0 )
|
136
135
|
end
|
137
136
|
|
138
137
|
raise format('playlist id can not be 0') if( playlist_id.zero? )
|
@@ -145,7 +144,7 @@ module Grafana
|
|
145
144
|
|
146
145
|
return { 'status' => 404, 'message' => 'playlist is empty', 'items' => [] } if( result.dig('status') == 404 )
|
147
146
|
|
148
|
-
|
147
|
+
result
|
149
148
|
end
|
150
149
|
|
151
150
|
### Get Playlist items
|
@@ -192,24 +191,22 @@ module Grafana
|
|
192
191
|
end
|
193
192
|
raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
|
194
193
|
|
195
|
-
|
194
|
+
tmp_playlists = playlists
|
196
195
|
|
197
196
|
begin
|
198
|
-
status =
|
199
|
-
message =
|
197
|
+
status = tmp_playlists.dig('status').to_i
|
198
|
+
message = tmp_playlists.dig('message')
|
200
199
|
|
201
|
-
if( status
|
200
|
+
return tmp_playlists if( status != 200 )
|
202
201
|
|
203
|
-
|
204
|
-
|
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) )
|
205
204
|
|
206
|
-
|
207
|
-
|
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')
|
208
209
|
|
209
|
-
id = data.first.dig('id')
|
210
|
-
else
|
211
|
-
return _playlists
|
212
|
-
end
|
213
210
|
rescue
|
214
211
|
return { 'status' => 404, 'message' => 'No Playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
|
215
212
|
end
|
@@ -220,7 +217,7 @@ module Grafana
|
|
220
217
|
|
221
218
|
return { 'status' => 404, 'message' => 'playlist is empty' } if( result.dig('status') == 404 )
|
222
219
|
|
223
|
-
|
220
|
+
result
|
224
221
|
end
|
225
222
|
|
226
223
|
### Get Playlist dashboards
|
@@ -321,7 +318,7 @@ module Grafana
|
|
321
318
|
interval = validate( params, required: true , var: 'interval' , type: String )
|
322
319
|
items = validate( params, required: true , var: 'items' , type: Array )
|
323
320
|
|
324
|
-
return { 'status' => 404, 'message' => 'There are no elements for a playlist' } if(items.count
|
321
|
+
return { 'status' => 404, 'message' => 'There are no elements for a playlist' } if(items.count.zero?)
|
325
322
|
|
326
323
|
payload_items = create_playlist_items(items)
|
327
324
|
|
@@ -412,29 +409,28 @@ module Grafana
|
|
412
409
|
# organisation = validate( params, required: false, var: 'organisation' )
|
413
410
|
items = validate( params, required: false, var: 'items', type: Array )
|
414
411
|
|
415
|
-
|
412
|
+
tmp_playlists = playlists
|
416
413
|
|
417
414
|
data = []
|
418
415
|
|
419
416
|
begin
|
420
|
-
status =
|
421
|
-
message =
|
417
|
+
status = tmp_playlists.dig('status').to_i
|
418
|
+
message = tmp_playlists.dig('message')
|
422
419
|
|
423
|
-
if( status
|
424
|
-
|
425
|
-
|
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 )
|
426
427
|
|
427
|
-
return { 'status' => 404, 'message' => 'no playlist found' } if( !data.is_a?(Array) || data.count == 0 || status.to_i != 200 )
|
428
|
-
return { 'status' => 404, 'message' => format('found %d playlists with name %s', data.count, playlist_id ) } if( data.count > 1 && multi_result == false )
|
429
|
-
else
|
430
|
-
return _playlists
|
431
|
-
end
|
432
428
|
rescue
|
433
429
|
return { 'status' => 404, 'message' => 'no playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
|
434
430
|
end
|
435
431
|
|
436
432
|
playlist_id = data.first.dig('id')
|
437
|
-
playlist_name = data.first.dig('name')
|
433
|
+
# playlist_name = data.first.dig('name')
|
438
434
|
payload_items = create_playlist_items(items, playlist_id)
|
439
435
|
|
440
436
|
payload = {
|
@@ -479,24 +475,22 @@ module Grafana
|
|
479
475
|
end
|
480
476
|
raise ArgumentError.new('missing \'playlist_id\'') if( playlist_id.size.zero? )
|
481
477
|
|
482
|
-
|
478
|
+
tmp_playlists = playlists
|
483
479
|
|
484
480
|
data = []
|
485
481
|
|
486
482
|
begin
|
487
|
-
status =
|
488
|
-
message =
|
483
|
+
status = tmp_playlists.dig('status').to_i
|
484
|
+
message = tmp_playlists.dig('message')
|
489
485
|
|
490
|
-
if( status
|
486
|
+
return tmp_playlists if( status != 200 )
|
491
487
|
|
492
|
-
|
493
|
-
|
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 )
|
494
493
|
|
495
|
-
return { 'status' => 404, 'message' => 'no playlist found' } if( !data.is_a?(Array) || data.count == 0 || status.to_i != 200 )
|
496
|
-
return { 'status' => 404, 'message' => format('found %d playlists with name %s', data.count, playlist_id ) } if( data.count > 1 && multi_result == false )
|
497
|
-
else
|
498
|
-
return _playlists
|
499
|
-
end
|
500
494
|
rescue
|
501
495
|
return { 'status' => 404, 'message' => 'no playlists found' } if( playlists.nil? || playlists == false || playlists.dig('status').to_i != 200 )
|
502
496
|
end
|
@@ -515,7 +509,7 @@ module Grafana
|
|
515
509
|
end
|
516
510
|
end
|
517
511
|
|
518
|
-
return result
|
512
|
+
# return result
|
519
513
|
else
|
520
514
|
|
521
515
|
playlist_id = data.first.dig('id')
|
@@ -530,69 +524,70 @@ module Grafana
|
|
530
524
|
return { 'status' => 200, 'message' => 'playlist deleted' } if(r.dig('status').to_i == 404)
|
531
525
|
end
|
532
526
|
|
533
|
-
return result
|
527
|
+
# return result
|
534
528
|
end
|
535
529
|
|
530
|
+
result
|
536
531
|
end
|
537
532
|
|
538
533
|
|
539
534
|
private
|
540
|
-
def create_playlist_items( items,
|
535
|
+
def create_playlist_items( items, playlist_id = nil)
|
541
536
|
|
542
|
-
|
537
|
+
playlist_items = []
|
543
538
|
|
544
539
|
items.each do |r|
|
545
|
-
|
540
|
+
playlist_element = {}
|
546
541
|
|
547
542
|
if( r['name'] )
|
548
543
|
|
549
|
-
|
550
|
-
|
544
|
+
playlist_name = search_dashboards( query: r['name'] )
|
545
|
+
playlist_name_status = playlist_name.dig('status')
|
551
546
|
|
552
|
-
next unless(
|
547
|
+
next unless( playlist_name_status == 200 )
|
553
548
|
|
554
|
-
|
555
|
-
|
556
|
-
|
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')
|
557
552
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
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?)
|
562
557
|
|
563
558
|
elsif( r['id'] )
|
564
559
|
|
565
|
-
|
566
|
-
|
560
|
+
uid = dashboard_by_uid(r['id'])
|
561
|
+
uid_status = uid.dig('status')
|
567
562
|
|
568
|
-
next unless(
|
563
|
+
next unless( uid_status == 200 )
|
569
564
|
|
570
|
-
|
571
|
-
|
572
|
-
|
565
|
+
playlist_element[:type] = 'dashboard_by_id'
|
566
|
+
playlist_element[:value] = r['id']
|
567
|
+
playlist_element[:playlistId] = playlist_id unless(playlist_id.nil?)
|
573
568
|
|
574
569
|
elsif( r['tag'] )
|
575
570
|
|
576
|
-
|
577
|
-
|
571
|
+
tags = search_dashboards( tags: r['tag'] )
|
572
|
+
tags_status = tags.dig('status')
|
578
573
|
|
579
|
-
next unless(
|
574
|
+
next unless( tags_status == 200 )
|
580
575
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
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?)
|
585
580
|
|
586
581
|
else
|
587
582
|
next
|
588
583
|
end
|
589
584
|
|
590
|
-
|
585
|
+
playlist_element[:order] = r['order'] if(r['order'])
|
591
586
|
|
592
|
-
|
587
|
+
playlist_items << playlist_element if(playlist_element.count >= 4)
|
593
588
|
end
|
594
589
|
|
595
|
-
|
590
|
+
playlist_items
|
596
591
|
end
|
597
592
|
|
598
593
|
end
|
data/lib/grafana/preferences.rb
CHANGED
@@ -11,7 +11,7 @@ module Grafana
|
|
11
11
|
|
12
12
|
# Get Current User Prefs
|
13
13
|
# GET /api/user/preferences
|
14
|
-
def user_preferences
|
14
|
+
def user_preferences
|
15
15
|
|
16
16
|
v, mv = version.values
|
17
17
|
return { 'status' => 404, 'message' => format( 'folder has been supported in Grafana since version 5. you use version %s', v) } if(mv < 5)
|
@@ -43,7 +43,7 @@ module Grafana
|
|
43
43
|
|
44
44
|
# Get Current Org Prefs
|
45
45
|
# GET /api/org/preferences
|
46
|
-
def org_preferences
|
46
|
+
def org_preferences
|
47
47
|
|
48
48
|
v, mv = version.values
|
49
49
|
return { 'status' => 404, 'message' => format( 'folder has been supported in Grafana since version 5. you use version %s', v) } if(mv < 5)
|
data/lib/grafana/validator.rb
CHANGED
@@ -8,7 +8,7 @@ module Grafana
|
|
8
8
|
#
|
9
9
|
# @param params [Hash]
|
10
10
|
# @param options [Hash]
|
11
|
-
# @option options [Boolean]
|
11
|
+
# @option options [Boolean] required
|
12
12
|
# @option options [String] var
|
13
13
|
# @option options [Class] type
|
14
14
|
#
|
@@ -26,7 +26,7 @@ module Grafana
|
|
26
26
|
params = params.deep_symbolize_keys
|
27
27
|
variable = params.dig(var.to_sym)
|
28
28
|
|
29
|
-
raise ArgumentError.new(format('\'%s\' is
|
29
|
+
raise ArgumentError.new(format('\'%s\' is required and missing!', var)) if(variable.nil? && required == true )
|
30
30
|
|
31
31
|
unless( type.nil? )
|
32
32
|
clazz = Object.const_get(type.to_s)
|
data/lib/grafana/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grafana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bodo Schulz
|
@@ -215,10 +215,12 @@ extra_rdoc_files: []
|
|
215
215
|
files:
|
216
216
|
- LICENSE
|
217
217
|
- README.md
|
218
|
+
- lib/_logging.rb_
|
218
219
|
- lib/grafana.rb
|
219
220
|
- lib/grafana/admin.rb
|
220
221
|
- lib/grafana/alerts.rb
|
221
222
|
- lib/grafana/annotations.rb
|
223
|
+
- lib/grafana/auth.rb
|
222
224
|
- lib/grafana/client.rb
|
223
225
|
- lib/grafana/dashboard.rb
|
224
226
|
- lib/grafana/dashboard_permissions.rb
|
@@ -227,6 +229,7 @@ files:
|
|
227
229
|
- lib/grafana/folder.rb
|
228
230
|
- lib/grafana/folder_and_dashboard_search.rb
|
229
231
|
- lib/grafana/folder_permissions.rb
|
232
|
+
- lib/grafana/logging.rb
|
230
233
|
- lib/grafana/login.rb
|
231
234
|
- lib/grafana/network.rb
|
232
235
|
- lib/grafana/organization.rb
|
@@ -241,7 +244,6 @@ files:
|
|
241
244
|
- lib/grafana/users.rb
|
242
245
|
- lib/grafana/validator.rb
|
243
246
|
- lib/grafana/version.rb
|
244
|
-
- lib/logging.rb
|
245
247
|
- lib/monkey_patches.rb
|
246
248
|
homepage: http://github.com/bodsch/ruby-grafana
|
247
249
|
licenses:
|
data/lib/logging.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'logger'
|
3
|
-
|
4
|
-
# -------------------------------------------------------------------------------------------------
|
5
|
-
|
6
|
-
module Logging
|
7
|
-
|
8
|
-
def logger
|
9
|
-
@logger ||= Logging.logger_for( self.class.name )
|
10
|
-
end
|
11
|
-
|
12
|
-
# Use a hash class-ivar to cache a unique Logger per class:
|
13
|
-
@loggers = {}
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def logger_for( classname )
|
17
|
-
@loggers[classname] ||= configure_logger_for( classname )
|
18
|
-
end
|
19
|
-
|
20
|
-
def configure_logger_for( classname )
|
21
|
-
|
22
|
-
logger = Logger.new(STDOUT)
|
23
|
-
logger.progname = classname
|
24
|
-
logger.level = Logger::DEBUG
|
25
|
-
logger.datetime_format = '%Y-%m-%d %H:%M:%S::%3N'
|
26
|
-
logger.formatter = proc do |severity, datetime, progname, msg|
|
27
|
-
"[#{datetime.strftime( logger.datetime_format )}] #{severity.ljust(5)} : #{progname} - #{msg}\n"
|
28
|
-
end
|
29
|
-
|
30
|
-
logger
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# -------------------------------------------------------------------------------------------------
|