ruby-grafana-reporter 0.1.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -245
  3. data/bin/ruby-grafana-reporter +3 -2
  4. data/lib/VERSION.rb +6 -3
  5. data/lib/grafana/abstract_datasource.rb +116 -0
  6. data/lib/grafana/dashboard.rb +75 -66
  7. data/lib/grafana/errors.rb +81 -61
  8. data/lib/grafana/grafana.rb +130 -131
  9. data/lib/grafana/grafana_alerts_datasource.rb +57 -0
  10. data/lib/grafana/grafana_annotations_datasource.rb +56 -0
  11. data/lib/grafana/grafana_property_datasource.rb +25 -0
  12. data/lib/grafana/graphite_datasource.rb +44 -0
  13. data/lib/grafana/image_rendering_datasource.rb +44 -0
  14. data/lib/grafana/panel.rb +47 -39
  15. data/lib/grafana/prometheus_datasource.rb +39 -0
  16. data/lib/grafana/sql_datasource.rb +65 -0
  17. data/lib/grafana/variable.rb +218 -259
  18. data/lib/grafana/webrequest.rb +71 -0
  19. data/lib/grafana_reporter/abstract_query.rb +401 -0
  20. data/lib/grafana_reporter/abstract_report.rb +163 -109
  21. data/lib/grafana_reporter/alerts_table_query.rb +44 -0
  22. data/lib/grafana_reporter/annotations_table_query.rb +43 -0
  23. data/lib/grafana_reporter/application/application.rb +162 -229
  24. data/lib/grafana_reporter/application/errors.rb +33 -30
  25. data/lib/grafana_reporter/application/webservice.rb +242 -0
  26. data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +90 -0
  27. data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +89 -0
  28. data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +76 -0
  29. data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +77 -0
  30. data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +72 -0
  31. data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +98 -0
  32. data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +93 -0
  33. data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +23 -0
  34. data/lib/grafana_reporter/asciidoctor/report.rb +172 -159
  35. data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +46 -0
  36. data/lib/grafana_reporter/asciidoctor/show_help_include_processor.rb +35 -0
  37. data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +92 -0
  38. data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +88 -0
  39. data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
  40. data/lib/grafana_reporter/configuration.rb +310 -326
  41. data/lib/grafana_reporter/console_configuration_wizard.rb +319 -0
  42. data/lib/grafana_reporter/demo_report_wizard.rb +87 -0
  43. data/lib/grafana_reporter/errors.rb +81 -38
  44. data/lib/grafana_reporter/help.rb +447 -0
  45. data/lib/grafana_reporter/logger/two_way_logger.rb +58 -52
  46. data/lib/grafana_reporter/panel_image_query.rb +29 -0
  47. data/lib/grafana_reporter/panel_property_query.rb +22 -0
  48. data/lib/grafana_reporter/query_value_query.rb +79 -0
  49. data/lib/grafana_reporter/report_webhook.rb +35 -0
  50. data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +29 -27
  51. metadata +48 -60
  52. data/lib/grafana/abstract_panel_query.rb +0 -20
  53. data/lib/grafana/abstract_query.rb +0 -127
  54. data/lib/grafana/abstract_sql_query.rb +0 -42
  55. data/lib/grafana/panel_image_query.rb +0 -49
  56. data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +0 -99
  57. data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -96
  58. data/lib/grafana_reporter/asciidoctor/errors.rb +0 -37
  59. data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +0 -86
  60. data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +0 -86
  61. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +0 -67
  62. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +0 -65
  63. data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +0 -58
  64. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +0 -75
  65. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +0 -70
  66. data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +0 -18
  67. data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +0 -41
  68. data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +0 -202
  69. data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +0 -67
  70. data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +0 -65
  71. data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +0 -57
  72. data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -32
  73. data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -23
  74. data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -43
  75. data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -36
  76. data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -309
  77. data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -34
  78. data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +0 -32
@@ -1,66 +1,75 @@
1
- module Grafana
2
- # Representation of one specific dashboard in a {Grafana} instance.
3
- class Dashboard
4
- # @return [Grafana] parent {Grafana} object
5
- attr_reader :grafana
6
- attr_reader :panels, :variables
7
-
8
- # @param model [Hash] converted JSON Hash of the grafana dashboard
9
- # @param grafana [Grafana] parent {Grafana} object
10
- def initialize(model, grafana)
11
- @grafana = grafana
12
- @model = model
13
-
14
- # read panels
15
- @panels = []
16
- if @model.key?('panels')
17
- @model['panels'].each do |panel|
18
- if panel.key?('panels')
19
- panel['panels'].each do |subpanel|
20
- @panels << Panel.new(subpanel, self)
21
- end
22
- else
23
- @panels << Panel.new(panel, self)
24
- end
25
- end
26
- end
27
-
28
- # store variables in array as objects of type Variable
29
- @variables = []
30
- return unless @model.key?('templating')
31
-
32
- list = @model['templating']['list']
33
- return unless list.is_a? Array
34
-
35
- list.each do |item|
36
- @variables << Variable.new(item)
37
- end
38
- end
39
-
40
- # @return [String] +from+ time configured in the dashboard.
41
- def from_time
42
- return @model['time']['from'] if @model['time']
43
-
44
- nil
45
- end
46
-
47
- # @return [String] +to+ time configured in the dashboard.
48
- def to_time
49
- @model['time']['to'] if @model['time']
50
- nil
51
- end
52
-
53
- # @return [String] dashboard UID
54
- def id
55
- @model['uid']
56
- end
57
-
58
- # @return [Panel] panel for the specified ID
59
- def panel(id)
60
- panels = @panels.select { |item| item.field('id') == id.to_i }
61
- raise PanelDoesNotExistError.new(id, self) if panels.empty?
62
-
63
- panels.first
64
- end
65
- end
66
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Grafana
4
+ # Representation of one specific dashboard in a {Grafana} instance.
5
+ class Dashboard
6
+ # @return [Grafana] parent {Grafana} object
7
+ attr_reader :grafana
8
+ attr_reader :panels, :variables
9
+
10
+ # @param model [Hash] converted JSON Hash of the grafana dashboard
11
+ # @param grafana [Grafana] parent {Grafana} object
12
+ def initialize(model, grafana)
13
+ @grafana = grafana
14
+ @model = model
15
+
16
+ init_panels
17
+ init_variables
18
+ end
19
+
20
+ # @return [String] +from+ time configured in the dashboard.
21
+ def from_time
22
+ return @model['time']['from'] if @model['time']
23
+
24
+ nil
25
+ end
26
+
27
+ # @return [String] +to+ time configured in the dashboard.
28
+ def to_time
29
+ @model['time']['to'] if @model['time']
30
+ nil
31
+ end
32
+
33
+ # @return [String] dashboard UID
34
+ def id
35
+ @model['uid']
36
+ end
37
+
38
+ # @return [Panel] panel for the specified ID
39
+ def panel(id)
40
+ panels = @panels.select { |item| item.field('id') == id.to_i }
41
+ raise PanelDoesNotExistError.new(id, self) if panels.empty?
42
+
43
+ panels.first
44
+ end
45
+
46
+ private
47
+
48
+ # store variables in array as objects of type Variable
49
+ def init_variables
50
+ @variables = []
51
+ return unless @model.key?('templating')
52
+
53
+ list = @model['templating']['list']
54
+ return unless list.is_a? Array
55
+
56
+ list.each { |item| @variables << Variable.new(item) }
57
+ end
58
+
59
+ # read panels
60
+ def init_panels
61
+ @panels = []
62
+ return unless @model.key?('panels')
63
+
64
+ @model['panels'].each do |panel|
65
+ if panel.key?('panels')
66
+ panel['panels'].each do |subpanel|
67
+ @panels << Panel.new(subpanel, self)
68
+ end
69
+ else
70
+ @panels << Panel.new(panel, self)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,61 +1,81 @@
1
- module Grafana
2
- # A top level alarm for all other errors in current module.
3
- class GrafanaError < StandardError
4
- def initialize(message)
5
- super("GrafanaError: #{message} (#{self.class})")
6
- end
7
- end
8
-
9
- # Raised if a given dashboard does not exist in a specific {Grafana} instance.
10
- class DashboardDoesNotExistError < GrafanaError
11
- # @param dashboard_uid [String] dashboard uid, which could not be found
12
- def initialize(dashboard_uid)
13
- super("The specified dashboard '#{dashboard_uid}' does not exist.")
14
- end
15
- end
16
-
17
- # Raised if a given panel does not exist on a specific {Dashboard} in the current {Grafana} instance.
18
- class PanelDoesNotExistError < GrafanaError
19
- # @param panel_id [String] panel id, which could not be found on the dashboard
20
- # @param dashboard [Dashboard] dashboard object on which the panel could not be found
21
- def initialize(panel_id, dashboard)
22
- super("The specified panel id '#{panel_id}' does not exist on the dashboard '#{dashboard.id}'.")
23
- end
24
- end
25
-
26
- # Raised if a given query letter does not exist on a specific {Panel}.
27
- class QueryLetterDoesNotExistError < GrafanaError
28
- # @param query_letter [String] query letter name, which could not be found on the panel
29
- # @param panel [Panel] panel object on which the query could not be found
30
- def initialize(query_letter, panel)
31
- super("The specified query '#{query_letter}' does not exist in the panel '#{panel.id}' in dashboard '#{panel.dashboard}'.")
32
- end
33
- end
34
-
35
- # Raised if a given datasource does not exist in a specific {Grafana} instance.
36
- class DatasourceDoesNotExistError < GrafanaError
37
- # @param field [String] specifies, how the datasource has been searched, e.g. 'id' or 'name'
38
- # @param datasource_identifier [String] identifier of the datasource, which could not be found, e.g. the specifiy id or name
39
- def initialize(field, datasource_identifier)
40
- super("Datasource with #{field} '#{datasource_identifier}' does not exist.")
41
- end
42
- end
43
-
44
- # Raised if a {Panel} could not be rendered as an image.
45
- #
46
- # Most likely this happens, because the image renderer is not configures properly in grafana,
47
- # or the panel rendering ran into a timeout.
48
- class ImageCouldNotBeRenderedError < GrafanaError
49
- # @param panel [Panel] panel object, which could not be rendered
50
- def initialize(panel)
51
- super("The specified panel '#{panel.id}' from dashboard '#{panel.dashboard.id} could not be rendered to an image.")
52
- end
53
- end
54
-
55
- # Raised if no SQL query is specified in a {AbstractSqlQuery} object.
56
- class MissingSqlQueryError < GrafanaError
57
- def initialize
58
- super('No SQL statement has been specified.')
59
- end
60
- end
61
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Grafana
4
+ # A top level alarm for all other errors in current module.
5
+ class GrafanaError < StandardError
6
+ def initialize(message)
7
+ super("GrafanaError: #{message} (#{self.class})")
8
+ end
9
+ end
10
+
11
+ # Raised if a given dashboard does not exist in a specific {Grafana} instance.
12
+ class DashboardDoesNotExistError < GrafanaError
13
+ # @param dashboard_uid [String] dashboard uid, which could not be found
14
+ def initialize(dashboard_uid)
15
+ super("The specified dashboard '#{dashboard_uid}' does not exist.")
16
+ end
17
+ end
18
+
19
+ # Raised if a given panel does not exist on a specific {Dashboard} in the current {Grafana} instance.
20
+ class PanelDoesNotExistError < GrafanaError
21
+ # @param panel_id [String] panel id, which could not be found on the dashboard
22
+ # @param dashboard [Dashboard] dashboard object on which the panel could not be found
23
+ def initialize(panel_id, dashboard)
24
+ super("The specified panel id '#{panel_id}' does not exist on the dashboard '#{dashboard.id}'.")
25
+ end
26
+ end
27
+
28
+ # Raised if a given query letter does not exist on a specific {Panel}.
29
+ class QueryLetterDoesNotExistError < GrafanaError
30
+ # @param query_letter [String] query letter name, which could not be found on the panel
31
+ # @param panel [Panel] panel object on which the query could not be found
32
+ def initialize(query_letter, panel)
33
+ super("The specified query '#{query_letter}' does not exist in the panel '#{panel.id}' "\
34
+ "in dashboard '#{panel.dashboard}'.")
35
+ end
36
+ end
37
+
38
+ # Raised if a given datasource does not exist in a specific {Grafana} instance.
39
+ class DatasourceDoesNotExistError < GrafanaError
40
+ # @param field [String] specifies, how the datasource has been searched, e.g. 'id' or 'name'
41
+ # @param datasource_identifier [String] identifier of the datasource, which could not be found,
42
+ # e.g. the specifiy id or name
43
+ def initialize(field, datasource_identifier)
44
+ super("Datasource with #{field} '#{datasource_identifier}' does not exist.")
45
+ end
46
+ end
47
+
48
+ # Raised if a {Panel} could not be rendered as an image.
49
+ #
50
+ # Most likely this happens, because the image renderer is not configures properly in grafana,
51
+ # or the panel rendering ran into a timeout.
52
+ class ImageCouldNotBeRenderedError < GrafanaError
53
+ # @param panel [Panel] panel object, which could not be rendered
54
+ def initialize(panel)
55
+ super("The specified panel '#{panel.id}' from dashboard '#{panel.dashboard.id} could not be "\
56
+ 'rendered to an image.')
57
+ end
58
+ end
59
+
60
+ # Raised if no SQL query is specified in a {AbstractSqlQuery} object.
61
+ class MissingSqlQueryError < GrafanaError
62
+ def initialize
63
+ super('No SQL statement has been specified.')
64
+ end
65
+ end
66
+
67
+ # Raised if a datasource shall be queried, which is not (yet) supported by the reporter
68
+ class DatasourceTypeNotSupportedError < GrafanaError
69
+ def initialize(name, type)
70
+ super("The configured datasource with name '#{name}' is of type '#{type}', which is currently "\
71
+ 'not supported by ruby-grafana-reporter. It will only be usable in panel image queries.')
72
+ end
73
+ end
74
+
75
+ # Raised if a datasource shall be queried, which is not (yet) supported by the reporter
76
+ class InvalidDatasourceQueryProvidedError < GrafanaError
77
+ def initialize(query)
78
+ super("The datasource query provided, does not look like a grafana datasource target (received: #{query}).")
79
+ end
80
+ end
81
+ end
@@ -1,131 +1,130 @@
1
- # Contains all objects for creating structured objects for interfacing grafana.
2
- #
3
- # The intention is, that these represent the business logic contained within grafana in an appropriate object model for the reporter to work with.
4
- #
5
- # For details, see also {https://grafana.com/docs/grafana/latest/http_api Grafana API}.
6
- module Grafana
7
- # Main class for handling the interaction with one specific Grafana instance.
8
- class Grafana
9
- # @param base_uri [String] full URI pointing to the specific grafana instance without trailing slash, e.g. +https://localhost:3000+.
10
- # @param key [String] API key for the grafana instance, if required
11
- # @param opts [Hash] additional options.
12
- # Currently supporting +:logger+ and +:datasources+.
13
- # +:datasources+ need to be an Hash with datasource name as key and datasource id as value.
14
- # If not specified, the datasources will be queried from the grafana interface.
15
- # Specifying +:datasources+> here can be used, so that the interface can be used without grafana Admin privileges.
16
- def initialize(base_uri, key = nil, opts = {})
17
- @base_uri = base_uri
18
- @key = key
19
- @dashboards = {}
20
- @logger = opts[:logger] || ::Logger.new(nil)
21
- @datasources = opts[:datasources]
22
- end
23
-
24
- # Used to test a connection to the grafana instance.
25
- #
26
- # Running this function also determines, if the API configured here has Admin or NON-Admin privileges,
27
- # or even fails on connecting to grafana.
28
- #
29
- # @return [String] +Admin+, +NON-Admin+ or +Failed+ is returned, depending on the test results
30
- def test_connection
31
- res = execute_http_request('/api/datasources')
32
- if res.is_a?(Net::HTTPOK)
33
- # we have admin rights
34
- @logger.info('Reporter is running with Admin privileges on grafana.')
35
- return 'Admin'
36
- else
37
- # check if we have lower rights
38
- res = execute_http_request('/api/dashboards/home')
39
- if res.is_a?(Net::HTTPOK)
40
- @logger.warn('Reporter is running with NON-Admin privileges on grafana. Make sure that necessary datasources are specified in CONFIG_FILE, otherwise operation will fail')
41
- return 'NON-Admin'
42
- end
43
- end
44
-
45
- 'Failed'
46
- end
47
-
48
- # Returns the ID of a datasource, which has been queried by the datasource name.
49
- #
50
- # @return [Integer] ID for the specified datasource name
51
- def datasource_id(datasource_name)
52
- id = datasources[datasource_name]
53
- raise DatasourceDoesNotExistError.new('name', datasource_name) unless id
54
-
55
- id
56
- end
57
-
58
- # Returns if the given datasource ID exists for the grafana instance.
59
- #
60
- # @return [Boolean] true if exists, false otherwise
61
- def datasource_id_exists?(datasource_id)
62
- datasources.value?(datasource_id)
63
- end
64
-
65
- # @param dashboard_uid [String] UID of the searched {Dashboard}
66
- # @return [Dashboard] dashboard object, if it has been found
67
- def dashboard(dashboard_uid)
68
- return @dashboards[dashboard_uid] unless @dashboards[dashboard_uid].nil?
69
-
70
- response = execute_http_request('/api/dashboards/uid/' + dashboard_uid)
71
- model = JSON.parse(response.body)['dashboard']
72
-
73
- raise DashboardDoesNotExistError, dashboard_uid if model.nil?
74
-
75
- # cache dashboard for reuse
76
- @dashboards[dashboard_uid] = Dashboard.new(model, self)
77
-
78
- @dashboards[dashboard_uid]
79
- end
80
-
81
- # Runs a specific HTTP request against the current grafana instance.
82
- #
83
- # Default (can be overridden, by specifying the options Hash):
84
- # accept: 'application/json'
85
- # request: Net::HTTP::Get
86
- # content_type: 'application/json'
87
- #
88
- # @param relative_uri [String] relative URL with a leading slash, which shall be queried
89
- # @param options [Hash] options, which shall be merged to the request.
90
- # @param timeout [Integer] number of seconds to wait, before the http request is cancelled, defaults to 60 seconds
91
- def execute_http_request(relative_uri, options = {}, timeout = nil)
92
- uri = URI.parse(@base_uri + relative_uri)
93
- default_options = { accept: 'application/json', request: Net::HTTP::Get, content_type: 'application/json' }
94
- options = default_options.merge(options)
95
-
96
- http = Net::HTTP.new(uri.host, uri.port)
97
- if @base_uri =~ /^https/
98
- http.use_ssl = true
99
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
100
- end
101
- http.read_timeout = timeout.to_i if timeout
102
-
103
- request = options[:request].new(uri.request_uri)
104
- request['Accept'] = options[:accept]
105
- request['Content-Type'] = options[:content_type]
106
- request['Authorization'] = 'Bearer ' + @key unless @key.nil?
107
- request.body = options[:body]
108
-
109
- @logger.debug("Requesting #{relative_uri} with '#{options[:body]}' and timeout '#{http.read_timeout}'")
110
- resp = http.request(request)
111
- resp
112
- end
113
-
114
- private
115
-
116
- def datasources
117
- if @datasources.nil?
118
- # load datasources from grafana directly, if allowed
119
- response = execute_http_request('/api/datasources')
120
- if response['message'].nil?
121
- json = JSON.parse(response.body)
122
- # only store needed values
123
- @datasources = json.map { |item| [item['name'], item['id']] }.to_h
124
- else
125
- @datasources = {}
126
- end
127
- end
128
- @datasources
129
- end
130
- end
131
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Contains all objects for creating structured objects for interfacing grafana.
4
+ #
5
+ # The intention is, that these represent the business logic contained within grafana
6
+ # in an appropriate object model for the reporter to work with.
7
+ #
8
+ # For details, see also {https://grafana.com/docs/grafana/latest/http_api Grafana API}.
9
+ module Grafana
10
+ # Main class for handling the interaction with one specific Grafana instance.
11
+ class Grafana
12
+ # @param base_uri [String] full URI pointing to the specific grafana instance without
13
+ # trailing slash, e.g. +https://localhost:3000+.
14
+ # @param key [String] API key for the grafana instance, if required
15
+ # @param opts [Hash] additional options.
16
+ # Currently supporting +:logger+.
17
+ def initialize(base_uri, key = nil, opts = {})
18
+ @base_uri = base_uri
19
+ @key = key
20
+ @dashboards = {}
21
+ @logger = opts[:logger] || ::Logger.new(nil)
22
+
23
+ initialize_datasources unless @base_uri.empty?
24
+ end
25
+
26
+ # Used to test a connection to the grafana instance.
27
+ #
28
+ # Running this function also determines, if the API configured here has Admin or NON-Admin privileges,
29
+ # or even fails on connecting to grafana.
30
+ #
31
+ # @return [String] +Admin+, +NON-Admin+ or +Failed+ is returned, depending on the test results
32
+ def test_connection
33
+ if prepare_request({ relative_url: '/api/datasources' }).execute.is_a?(Net::HTTPOK)
34
+ # we have admin rights
35
+ @logger.warn('Reporter is running with Admin privileges on grafana. This is a potential security risk.')
36
+ return 'Admin'
37
+ end
38
+ # check if we have lower rights
39
+ return 'Failed' unless prepare_request({ relative_url: '/api/dashboards/home' }).execute.is_a?(Net::HTTPOK)
40
+
41
+ @logger.info('Reporter is running with NON-Admin privileges on grafana.')
42
+ 'NON-Admin'
43
+ end
44
+
45
+ # Returns the datasource, which has been queried by the datasource name.
46
+ #
47
+ # @param datasource_name [String] name of the searched datasource
48
+ # @return [Datasource] Datasource for the specified datasource name
49
+ def datasource_by_name(datasource_name)
50
+ datasource_name = 'default' if datasource_name.to_s.empty?
51
+ raise DatasourceDoesNotExistError.new('name', datasource_name) unless @datasources[datasource_name]
52
+
53
+ @datasources[datasource_name]
54
+ end
55
+
56
+ # Returns the datasource, which has been queried by the datasource id.
57
+ #
58
+ # @param datasource_id [Integer] id of the searched datasource
59
+ # @return [Datasource] Datasource for the specified datasource id
60
+ def datasource_by_id(datasource_id)
61
+ datasource = @datasources.select { |_name, ds| ds.id == datasource_id.to_i }.values.first
62
+ raise DatasourceDoesNotExistError.new('id', datasource_id) unless datasource
63
+
64
+ datasource
65
+ end
66
+
67
+ # @return [Array] Array of dashboard uids within the current grafana object
68
+ def dashboard_ids
69
+ response = prepare_request({ relative_url: '/api/search' }).execute
70
+ return [] unless response.is_a?(Net::HTTPOK)
71
+
72
+ dashboards = JSON.parse(response.body)
73
+
74
+ dashboards.each do |dashboard|
75
+ @dashboards[dashboard['uid']] = nil unless @dashboards[dashboard['uid']]
76
+ end
77
+
78
+ @dashboards.keys
79
+ end
80
+
81
+ # @param dashboard_uid [String] UID of the searched {Dashboard}
82
+ # @return [Dashboard] dashboard object, if it has been found
83
+ def dashboard(dashboard_uid)
84
+ return @dashboards[dashboard_uid] unless @dashboards[dashboard_uid].nil?
85
+
86
+ response = prepare_request({ relative_url: "/api/dashboards/uid/#{dashboard_uid}" }).execute
87
+ raise DashboardDoesNotExistError, dashboard_uid unless response.is_a?(Net::HTTPOK)
88
+
89
+ # cache dashboard for reuse
90
+ model = JSON.parse(response.body)['dashboard']
91
+ @dashboards[dashboard_uid] = Dashboard.new(model, self)
92
+
93
+ @dashboards[dashboard_uid]
94
+ end
95
+
96
+ # Prepares a {WebRequest} object for the current {Grafana} instance, which may be enriched
97
+ # with further properties and can then run {WebRequest#execute}.
98
+ #
99
+ # @option options [Hash] :relative_url relative URL with a leading slash, which shall be queried
100
+ # @option options [Hash] :accept
101
+ # @option options [Hash] :body
102
+ # @option options [Hash] :content_type
103
+ # @return [WebRequest] webrequest prepared for execution
104
+ def prepare_request(options = {})
105
+ auth = @key ? { authorization: "Bearer #{@key}" } : {}
106
+ WebRequest.new(@base_uri, auth.merge({ logger: @logger }).merge(options))
107
+ end
108
+
109
+ private
110
+
111
+ def initialize_datasources
112
+ @datasources = {}
113
+
114
+ settings = prepare_request({ relative_url: '/api/frontend/settings' }).execute
115
+ return unless settings.is_a?(Net::HTTPOK)
116
+
117
+ json = JSON.parse(settings.body)
118
+ json['datasources'].select { |_k, v| v['id'].to_i.positive? }.each do |ds_name, ds_value|
119
+ begin
120
+ @datasources[ds_name] = AbstractDatasource.build_instance(ds_value)
121
+ rescue DatasourceTypeNotSupportedError => e
122
+ # an unsupported datasource type has been configured in the dashboard
123
+ # - no worries here
124
+ @logger.warn(e.message)
125
+ end
126
+ end
127
+ @datasources['default'] = @datasources[json['defaultDatasource']]
128
+ end
129
+ end
130
+ end