ruby-grafana-reporter 0.3.0 → 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.
- checksums.yaml +4 -4
- data/README.md +81 -71
- data/bin/ruby-grafana-reporter +5 -5
- data/lib/VERSION.rb +3 -2
- data/lib/grafana/abstract_datasource.rb +116 -0
- data/lib/grafana/dashboard.rb +1 -3
- data/lib/grafana/errors.rb +15 -0
- data/lib/grafana/grafana.rb +53 -56
- data/lib/grafana/grafana_alerts_datasource.rb +57 -0
- data/lib/grafana/grafana_annotations_datasource.rb +56 -0
- data/lib/grafana/grafana_property_datasource.rb +25 -0
- data/lib/grafana/graphite_datasource.rb +44 -0
- data/lib/grafana/image_rendering_datasource.rb +44 -0
- data/lib/grafana/panel.rb +9 -3
- data/lib/grafana/prometheus_datasource.rb +39 -0
- data/lib/grafana/sql_datasource.rb +65 -0
- data/lib/grafana/variable.rb +1 -0
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +401 -0
- data/lib/grafana_reporter/abstract_report.rb +54 -3
- data/lib/grafana_reporter/alerts_table_query.rb +44 -0
- data/lib/grafana_reporter/annotations_table_query.rb +43 -0
- data/lib/grafana_reporter/application/application.rb +12 -8
- data/lib/grafana_reporter/application/webservice.rb +18 -6
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +90 -0
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +89 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +76 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +77 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +72 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +98 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +93 -0
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +23 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +24 -31
- data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +46 -0
- data/lib/grafana_reporter/asciidoctor/show_help_include_processor.rb +35 -0
- data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +92 -0
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +88 -0
- data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
- data/lib/grafana_reporter/configuration.rb +12 -6
- data/lib/grafana_reporter/console_configuration_wizard.rb +115 -65
- data/lib/grafana_reporter/demo_report_wizard.rb +87 -0
- data/lib/grafana_reporter/errors.rb +33 -0
- data/lib/grafana_reporter/help.rb +447 -0
- data/lib/grafana_reporter/logger/two_way_logger.rb +1 -1
- data/lib/grafana_reporter/panel_image_query.rb +29 -0
- data/lib/grafana_reporter/panel_property_query.rb +22 -0
- data/lib/grafana_reporter/query_value_query.rb +79 -0
- data/lib/grafana_reporter/report_webhook.rb +35 -0
- data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +0 -3
- metadata +37 -35
- data/lib/grafana/abstract_panel_query.rb +0 -22
- data/lib/grafana/abstract_query.rb +0 -132
- data/lib/grafana/abstract_sql_query.rb +0 -51
- data/lib/grafana/panel_image_query.rb +0 -52
- data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +0 -101
- data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -96
- data/lib/grafana_reporter/asciidoctor/errors.rb +0 -40
- data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +0 -92
- data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +0 -91
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +0 -69
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +0 -68
- data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +0 -61
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +0 -78
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +0 -73
- data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +0 -20
- data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +0 -43
- data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +0 -30
- data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +0 -70
- data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +0 -66
- data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +0 -88
- data/lib/grafana_reporter/asciidoctor/help.rb +0 -435
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -36
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -28
- data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -44
- data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -40
- data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -312
- data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -42
- data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +0 -44
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_environment[]
|
7
|
+
#
|
8
|
+
# Shows all available variables, which are accessible during this run of the asciidoctor
|
9
|
+
# grafana reporter in a asciidoctor readable form.
|
10
|
+
#
|
11
|
+
# This processor is very helpful during report template design, to find out the available
|
12
|
+
# variables, that can be accessed.
|
13
|
+
#
|
14
|
+
# == Used document parameters
|
15
|
+
# All, to be listed as the available environment.
|
16
|
+
class ShowEnvironmentIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
17
|
+
include ProcessorMixin
|
18
|
+
|
19
|
+
# :nodoc:
|
20
|
+
def handles?(target)
|
21
|
+
target.start_with? 'grafana_environment'
|
22
|
+
end
|
23
|
+
|
24
|
+
# :nodoc:
|
25
|
+
def process(doc, reader, _target, _attrs)
|
26
|
+
# return if @report.cancel
|
27
|
+
@report.next_step
|
28
|
+
@report.logger.debug('Processing ShowEnvironmentIncludeProcessor')
|
29
|
+
|
30
|
+
vars = ['== Accessible Variables',
|
31
|
+
'|===']
|
32
|
+
doc.attributes.sort.each do |k, v|
|
33
|
+
vars << "| `+{#{k}}+` | #{v}"
|
34
|
+
end
|
35
|
+
vars << '|==='
|
36
|
+
|
37
|
+
reader.unshift_lines vars
|
38
|
+
end
|
39
|
+
|
40
|
+
# @see ProcessorMixin#build_demo_entry
|
41
|
+
def build_demo_entry(_panel)
|
42
|
+
'include::grafana_environment[]'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_help[]
|
7
|
+
#
|
8
|
+
# Shows all available options for the asciidoctor grafana reporter in a asciidoctor readable form.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# None
|
12
|
+
class ShowHelpIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
13
|
+
include ProcessorMixin
|
14
|
+
|
15
|
+
# :nodoc:
|
16
|
+
def handles?(target)
|
17
|
+
target.start_with? 'grafana_help'
|
18
|
+
end
|
19
|
+
|
20
|
+
# :nodoc:
|
21
|
+
def process(_doc, reader, _target, _attrs)
|
22
|
+
# return if @report.cancel
|
23
|
+
@report.next_step
|
24
|
+
@report.logger.debug('Processing ShowHelpIncludeProcessor')
|
25
|
+
|
26
|
+
reader.unshift_lines GrafanaReporter::Help.new.asciidoctor.split("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see ProcessorMixin#build_demo_entry
|
30
|
+
def build_demo_entry(_panel)
|
31
|
+
'include::grafana_help[]'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_sql_table:<datasource_id>[<options>]
|
7
|
+
#
|
8
|
+
# Returns the results of the SQL query as a asciidoctor table.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
12
|
+
#
|
13
|
+
# +from+ - 'from' time for the sql query
|
14
|
+
#
|
15
|
+
# +to+ - 'to' time for the sql query
|
16
|
+
#
|
17
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
18
|
+
# in the given SQL query.
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +sql+ - sql statement (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +from+ - 'from' time for the sql query
|
26
|
+
#
|
27
|
+
# +to+ - 'to' time for the sql query
|
28
|
+
#
|
29
|
+
# +format+ - see {QueryMixin#format_columns}
|
30
|
+
#
|
31
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
32
|
+
#
|
33
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
34
|
+
class SqlTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
35
|
+
include ProcessorMixin
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def handles?(target)
|
39
|
+
target.start_with? 'grafana_sql_table:'
|
40
|
+
end
|
41
|
+
|
42
|
+
# :nodoc:
|
43
|
+
def process(doc, reader, target, attrs)
|
44
|
+
return if @report.cancel
|
45
|
+
|
46
|
+
@report.next_step
|
47
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
48
|
+
attrs['result_type'] = 'sql_table'
|
49
|
+
@report.logger.debug("Processing SqlTableIncludeProcessor (instance: #{instance},"\
|
50
|
+
" datasource: #{target.split(':')[1]}, sql: #{attrs['sql']})")
|
51
|
+
|
52
|
+
begin
|
53
|
+
# catch properly if datasource could not be identified
|
54
|
+
query = QueryValueQuery.new(@report.grafana(instance))
|
55
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target.split(':')[1].to_i)
|
56
|
+
query.raw_query = attrs['sql']
|
57
|
+
query.merge_hash_variables(doc.attributes, attrs)
|
58
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
59
|
+
|
60
|
+
reader.unshift_lines query.execute
|
61
|
+
rescue GrafanaReporterError => e
|
62
|
+
@report.logger.error(e.message)
|
63
|
+
reader.unshift_line "|#{e.message}"
|
64
|
+
rescue StandardError => e
|
65
|
+
@report.logger.fatal(e.message)
|
66
|
+
reader.unshift_line "|#{e.message}"
|
67
|
+
end
|
68
|
+
|
69
|
+
reader
|
70
|
+
end
|
71
|
+
|
72
|
+
# @see ProcessorMixin#build_demo_entry
|
73
|
+
def build_demo_entry(panel)
|
74
|
+
return nil unless panel
|
75
|
+
return nil unless panel.model['type'].include?('table')
|
76
|
+
|
77
|
+
ref_id = nil
|
78
|
+
panel.model['targets'].each do |item|
|
79
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
80
|
+
ref_id = item['refId']
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return nil unless ref_id
|
85
|
+
|
86
|
+
"|===\ninclude::grafana_sql_table:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
87
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",filter_columns=\"time\","\
|
88
|
+
"dashboard=\"#{panel.dashboard.id}\",from=\"now-1h\",to=\"now\"]\n|==="
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# grafana_sql_value:<datasource_id>[<options>]
|
7
|
+
#
|
8
|
+
# Returns the first value of the resulting SQL query.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
12
|
+
#
|
13
|
+
# +from+ - 'from' time for the sql query
|
14
|
+
#
|
15
|
+
# +to+ - 'to' time for the sql query
|
16
|
+
#
|
17
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
18
|
+
# in the given SQL query.
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +sql+ - sql statement (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +from+ - 'from' time for the sql query
|
26
|
+
#
|
27
|
+
# +to+ - 'to' time for the sql query
|
28
|
+
#
|
29
|
+
# +format+ - see {QueryMixin#format_columns}
|
30
|
+
#
|
31
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
32
|
+
#
|
33
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
34
|
+
class SqlValueInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
35
|
+
include ProcessorMixin
|
36
|
+
use_dsl
|
37
|
+
|
38
|
+
named :grafana_sql_value
|
39
|
+
|
40
|
+
# @see GrafanaReporter::Asciidoctor::SqlFirstValueQuery
|
41
|
+
def process(parent, target, attrs)
|
42
|
+
return if @report.cancel
|
43
|
+
|
44
|
+
@report.next_step
|
45
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
46
|
+
attrs['result_type'] = 'sql_value'
|
47
|
+
@report.logger.debug("Processing SqlValueInlineMacro (instance: #{instance}, datasource: #{target},"\
|
48
|
+
" sql: #{attrs['sql']})")
|
49
|
+
|
50
|
+
begin
|
51
|
+
# catch properly if datasource could not be identified
|
52
|
+
query = QueryValueQuery.new(@report.grafana(instance))
|
53
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target)
|
54
|
+
query.raw_query = attrs['sql']
|
55
|
+
query.merge_hash_variables(parent.document.attributes, attrs)
|
56
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
57
|
+
|
58
|
+
create_inline(parent, :quoted, query.execute)
|
59
|
+
rescue GrafanaReporterError => e
|
60
|
+
@report.logger.error(e.message)
|
61
|
+
create_inline(parent, :quoted, e.message)
|
62
|
+
rescue StandardError => e
|
63
|
+
@report.logger.fatal(e.message)
|
64
|
+
create_inline(parent, :quoted, e.message)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @see ProcessorMixin#build_demo_entry
|
69
|
+
def build_demo_entry(panel)
|
70
|
+
return nil unless panel
|
71
|
+
return nil unless panel.model['type'] == 'singlestat'
|
72
|
+
|
73
|
+
ref_id = nil
|
74
|
+
panel.model['targets'].each do |item|
|
75
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
76
|
+
ref_id = item['refId']
|
77
|
+
break
|
78
|
+
end
|
79
|
+
end
|
80
|
+
return nil unless ref_id
|
81
|
+
|
82
|
+
"grafana_sql_value:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
83
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",from=\"now-1h\","\
|
84
|
+
'to="now"]'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'processor_mixin'
|
4
|
+
|
5
|
+
module GrafanaReporter
|
6
|
+
module Asciidoctor
|
7
|
+
# Implements the hook
|
8
|
+
# include::grafana_value_as_variable[<options>]
|
9
|
+
#
|
10
|
+
# Returns an attribute definition in asciidoctor format. This is needed if you want to refer to values of
|
11
|
+
# a grafana query within a variable in asciidoctor. As this works without this function for the
|
12
|
+
# `IncludeProcessor`s values, it will not work for all the other processors.
|
13
|
+
#
|
14
|
+
# This method is just a proxy for all other hooks and will forward parameters accordingly.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# include:grafana_value_as_variable[call="grafana_sql_value:1",variable_name="my_variable",sql="SELECT 'looks good'",<any_other_option>]
|
19
|
+
#
|
20
|
+
# This will call the {SqlValueInlineMacro} with `datasource_id` set to `1` and store the result in the
|
21
|
+
# variable. The resulting asciidoctor variable definition will be created as:
|
22
|
+
#
|
23
|
+
# :my_variable: looks good
|
24
|
+
#
|
25
|
+
# and can be refered to in your document easily as
|
26
|
+
#
|
27
|
+
# {my_variable}
|
28
|
+
#
|
29
|
+
# == Supported options
|
30
|
+
# +call+ - regular call to the reporter hook (*mandatory*)
|
31
|
+
#
|
32
|
+
# +variable_name+ - name of the variable, to which the result shall be assigned (*mandatory*)
|
33
|
+
class ValueAsVariableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
34
|
+
include ProcessorMixin
|
35
|
+
|
36
|
+
# :nodoc:
|
37
|
+
def handles?(target)
|
38
|
+
target.start_with? 'grafana_value_as_variable'
|
39
|
+
end
|
40
|
+
|
41
|
+
# :nodoc:
|
42
|
+
def process(doc, reader, target, attrs)
|
43
|
+
return if @report.cancel
|
44
|
+
|
45
|
+
# increase step for this processor as well as it is also counted in the step counter
|
46
|
+
@report.next_step
|
47
|
+
|
48
|
+
call_attr = attrs.delete('call')
|
49
|
+
call, target = call_attr.split(':') if call_attr
|
50
|
+
attribute = attrs.delete('variable_name')
|
51
|
+
@report.logger.debug("Processing ValueAsVariableIncludeProcessor (call: #{call}, target: #{target},"\
|
52
|
+
" variable_name: #{attribute}, attrs: #{attrs})")
|
53
|
+
if !call || !attribute
|
54
|
+
@report.logger.error('ValueAsVariableIncludeProcessor: Missing mandatory attribute \'call\' or '\
|
55
|
+
'\'variable_name\'.')
|
56
|
+
# increase counter, as error occured and no sub call is being processed
|
57
|
+
@report.next_step
|
58
|
+
return reader
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: remove dirty hack to allow the document as parameter for other processors
|
62
|
+
def doc.document
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# TODO: properly show error messages also in document
|
67
|
+
ext = doc.extensions.find_inline_macro_extension(call) if doc.extensions.inline_macros?
|
68
|
+
if !ext
|
69
|
+
@report.logger.error('ValueAsVariableIncludeProcessor: Could not find inline macro extension for '\
|
70
|
+
"'#{call}'.")
|
71
|
+
# increase counter, as error occured and no sub call is being processed
|
72
|
+
@report.next_step
|
73
|
+
else
|
74
|
+
@report.logger.debug('ValueAsVariableIncludeProcessor: Calling sub-method.')
|
75
|
+
item = ext.process_method.call(doc, target, attrs)
|
76
|
+
if !item.text.to_s.empty?
|
77
|
+
result = ":#{attribute}: #{item.text}"
|
78
|
+
@report.logger.debug("ValueAsVariableIncludeProcessor: Adding '#{result}' to document.")
|
79
|
+
reader.unshift_line(result)
|
80
|
+
else
|
81
|
+
@report.logger.debug("ValueAsVariableIncludeProcessor: Not adding variable '#{attribute}'"\
|
82
|
+
' as query result was empty.')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
reader
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -56,11 +56,6 @@ module GrafanaReporter
|
|
56
56
|
"#{templates_folder}#{get_config('default-document-attributes:var-template')}.adoc"
|
57
57
|
end
|
58
58
|
|
59
|
-
# @return [String] path to ssl certificate file, if manually specified, or nil
|
60
|
-
def ssl_cert
|
61
|
-
get_config('grafana-reporter:ssl-cert')
|
62
|
-
end
|
63
|
-
|
64
59
|
# @return [String] destination filename for the report in {MODE_SINGLE_RENDER}.
|
65
60
|
def to_file
|
66
61
|
return get_config('to_file') || true if mode == MODE_SINGLE_RENDER
|
@@ -209,6 +204,15 @@ module GrafanaReporter
|
|
209
204
|
@logger.level = Object.const_get("::Logger::Severity::#{debug_level}") if debug_level =~ /DEBUG|INFO|WARN|
|
210
205
|
ERROR|FATAL|UNKNOWN/x
|
211
206
|
self.report_class = Object.const_get(rep_class) if rep_class
|
207
|
+
::Grafana::WebRequest.ssl_cert = get_config('grafana-reporter:ssl-cert')
|
208
|
+
|
209
|
+
# register callbacks
|
210
|
+
callbacks = get_config('grafana-reporter:callbacks')
|
211
|
+
return unless callbacks
|
212
|
+
|
213
|
+
callbacks.each do |url, event|
|
214
|
+
AbstractReport.add_event_listener(event.to_sym, ReportWebhook.new(url))
|
215
|
+
end
|
212
216
|
end
|
213
217
|
|
214
218
|
def get_config(path)
|
@@ -283,6 +287,7 @@ module GrafanaReporter
|
|
283
287
|
}
|
284
288
|
],
|
285
289
|
'default-document-attributes' => [Hash, explicit ? 1 : 0],
|
290
|
+
'to_file' => [String, 0],
|
286
291
|
'grafana-reporter' =>
|
287
292
|
[
|
288
293
|
Hash, 1,
|
@@ -295,7 +300,8 @@ module GrafanaReporter
|
|
295
300
|
'reports-folder' => [String, explicit ? 1 : 0],
|
296
301
|
'report-retention' => [Integer, explicit ? 1 : 0],
|
297
302
|
'ssl-cert' => [String, 0],
|
298
|
-
'webservice-port' => [Integer, explicit ? 1 : 0]
|
303
|
+
'webservice-port' => [Integer, explicit ? 1 : 0],
|
304
|
+
'callbacks' => [Hash, 0, { nil => [String, 1] }]
|
299
305
|
}
|
300
306
|
]
|
301
307
|
}
|
@@ -1,14 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GrafanaReporter
|
4
|
+
# This class provides a console configuration wizard, to reduce the manual efforts that have
|
5
|
+
# to be spent for that action and to reduce mistakes as good as possible.
|
4
6
|
class ConsoleConfigurationWizard
|
5
7
|
# Provides a command line configuration wizard for setting up the necessary configuration
|
6
8
|
# file.
|
7
9
|
# TODO: refactor class
|
8
10
|
def start_wizard(config_file, console_config)
|
9
|
-
|
11
|
+
action = overwrite_or_use_config_file(config_file)
|
12
|
+
return if action == 'abort'
|
13
|
+
|
14
|
+
config = create_config_wizard(config_file, console_config) if action == 'overwrite'
|
15
|
+
config ||= Configuration.new
|
16
|
+
|
17
|
+
begin
|
18
|
+
config.config = YAML.load_file(config_file)
|
19
|
+
rescue StandardError => e
|
20
|
+
raise ConfigurationError, "Could not read config file '#{config_file}' (Error: #{e.message})\n"\
|
21
|
+
"Source:\n#{File.read(config_file)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
config.validate(true)
|
26
|
+
puts 'Configuration file validated successfully.'
|
27
|
+
rescue ConfigurationError => e
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
|
31
|
+
demo_report = create_demo_report(config)
|
32
|
+
|
33
|
+
demo_report ||= '<<your_report_name>>'
|
34
|
+
config_param = config_file == Application::Application::CONFIG_FILE ? '' : " -c #{config_file}"
|
35
|
+
program_call = "#{Gem.ruby} #{$PROGRAM_NAME}"
|
36
|
+
program_call = ENV['OCRA_EXECUTABLE'].gsub("#{Dir.pwd}/".gsub('/', '\\'), '') if ENV['OCRA_EXECUTABLE']
|
10
37
|
|
11
|
-
|
38
|
+
puts
|
39
|
+
puts 'Now everything is setup properly. Create your reports as required in the templates '\
|
40
|
+
'folder and run the reporter either standalone with e.g. the following command:'
|
41
|
+
puts
|
42
|
+
puts " #{program_call}#{config_param} -t #{demo_report} -o demo_report_with_help.pdf"
|
43
|
+
puts
|
44
|
+
puts 'or run it as a service using the following command:'
|
45
|
+
puts
|
46
|
+
puts " #{program_call}#{config_param}"
|
47
|
+
puts
|
48
|
+
puts "Open 'http://localhost:#{config.webserver_port}/render?var-template=#{demo_report}' in a webbrowser to"\
|
49
|
+
' test your configuration.'
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def create_config_wizard(config_file, console_config)
|
55
|
+
config = Configuration.new
|
12
56
|
|
13
57
|
puts 'This wizard will guide you through an initial configuration for'\
|
14
58
|
' the ruby-grafana-reporter. The configuration file will be created'\
|
@@ -34,6 +78,20 @@ grafana-reporter:
|
|
34
78
|
reports-folder: #{reports}
|
35
79
|
report-retention: #{retention}
|
36
80
|
webservice-port: #{port}
|
81
|
+
# you may want to configure the following webhook callbacks to get informed on certain events
|
82
|
+
# callbacks:
|
83
|
+
# all:
|
84
|
+
# - <<your_callback_url>>
|
85
|
+
# - ...
|
86
|
+
# on_before_create:
|
87
|
+
# - <<your_callback_url>>
|
88
|
+
# - ...
|
89
|
+
# on_after_cancel:
|
90
|
+
# - <<your_callback_url>>
|
91
|
+
# - ...
|
92
|
+
# on_after_finish:
|
93
|
+
# - <<your_callback_url>>
|
94
|
+
# - ...
|
37
95
|
|
38
96
|
default-document-attributes:
|
39
97
|
imagesdir: #{images}
|
@@ -47,65 +105,51 @@ default-document-attributes:
|
|
47
105
|
raise e
|
48
106
|
end
|
49
107
|
|
50
|
-
|
51
|
-
config.config = YAML.load_file(config_file)
|
52
|
-
rescue StandardError => e
|
53
|
-
raise ConfigurationError, "Could not read config file '#{config_file}' (Error: #{e.message})\n"\
|
54
|
-
"Source:\n#{File.read(config_file)}"
|
55
|
-
end
|
56
|
-
|
57
|
-
begin
|
58
|
-
config.validate(true)
|
59
|
-
puts 'Configuration file validated successfully.'
|
60
|
-
rescue ConfigurationError => e
|
61
|
-
raise e
|
62
|
-
end
|
63
|
-
|
64
|
-
demo_report = create_demo_report(config)
|
65
|
-
|
66
|
-
demo_report ||= '<<your_report_name>>'
|
67
|
-
config_param = config_file == Application::Application::CONFIG_FILE ? '' : " -c #{config_file}"
|
68
|
-
program_call = "#{Gem.ruby} #{$PROGRAM_NAME}"
|
69
|
-
program_call = ENV['OCRA_EXECUTABLE'].gsub("#{Dir.pwd}/".gsub('/', '\\'), '') if ENV['OCRA_EXECUTABLE']
|
70
|
-
|
71
|
-
puts
|
72
|
-
puts 'Now everything is setup properly. Create your reports as required in the templates '\
|
73
|
-
'folder and run the reporter either standalone with e.g. the following command:'
|
74
|
-
puts
|
75
|
-
puts " #{program_call}#{config_param} -t #{demo_report} -o demo_report_with_help.pdf"
|
76
|
-
puts
|
77
|
-
puts 'or run it as a service using the following command:'
|
78
|
-
puts
|
79
|
-
puts " #{program_call}#{config_param}"
|
80
|
-
puts
|
81
|
-
puts "Open 'http://localhost:#{config.webserver_port}/render?var-template=#{demo_report}' in a webbrowser to"\
|
82
|
-
' test your configuration.'
|
108
|
+
config
|
83
109
|
end
|
84
110
|
|
85
|
-
private
|
86
|
-
|
87
111
|
def create_demo_report(config)
|
88
112
|
unless Dir.exist?(config.templates_folder)
|
89
113
|
puts "Skip creation of DEMO template, as folder '#{config.templates_folder}' does not exist."
|
90
114
|
return nil
|
91
115
|
end
|
92
116
|
|
117
|
+
create = user_input('Shall I create a demo report for your new configuration file? Please note '\
|
118
|
+
'that this report might contain confidential information, depending on the '\
|
119
|
+
'confidentiality of the information stored in your dashboard.', 'yN')
|
120
|
+
return nil unless create =~ /^(?:y|Y)$/
|
121
|
+
|
93
122
|
demo_report = 'demo_report'
|
94
123
|
demo_report_file = "#{config.templates_folder}#{demo_report}.adoc"
|
95
124
|
|
96
|
-
#
|
125
|
+
# ask to overwrite file
|
97
126
|
if File.exist?(demo_report_file)
|
98
|
-
|
99
|
-
|
127
|
+
input = user_input("Demo template '#{demo_report_file}' does already exist. Do you want to "\
|
128
|
+
'overwrite it?', 'yN')
|
129
|
+
|
130
|
+
case input
|
131
|
+
when /^(?:y|Y)$/
|
132
|
+
puts 'Overwriting existing DEMO template.'
|
133
|
+
|
134
|
+
else
|
135
|
+
puts 'Skip creation of DEMO template.'
|
136
|
+
return demo_report
|
137
|
+
end
|
100
138
|
end
|
101
139
|
|
102
|
-
|
140
|
+
# TODO: move this to Asciidoctor::Report class
|
141
|
+
classes = [Asciidoctor::AlertsTableIncludeProcessor, Asciidoctor::AnnotationsTableIncludeProcessor,
|
142
|
+
Asciidoctor::PanelImageBlockMacro, Asciidoctor::PanelImageInlineMacro,
|
143
|
+
Asciidoctor::PanelPropertyInlineMacro, Asciidoctor::PanelQueryTableIncludeProcessor,
|
144
|
+
Asciidoctor::PanelQueryValueInlineMacro, Asciidoctor::SqlTableIncludeProcessor,
|
145
|
+
Asciidoctor::SqlValueInlineMacro, Asciidoctor::ShowHelpIncludeProcessor,
|
146
|
+
Asciidoctor::ShowEnvironmentIncludeProcessor]
|
103
147
|
|
104
|
-
|
148
|
+
grafana = ::Grafana::Grafana.new(config.grafana_host, config.grafana_api_key)
|
149
|
+
demo_report_content = DemoReportWizard.new(classes).build(grafana)
|
105
150
|
|
106
|
-
include::grafana_environment[])
|
107
151
|
begin
|
108
|
-
File.write(demo_report_file,
|
152
|
+
File.write(demo_report_file, demo_report_content, mode: 'w')
|
109
153
|
puts "DEMO template '#{demo_report_file}' successfully created."
|
110
154
|
rescue StandardError => e
|
111
155
|
puts e.message
|
@@ -123,10 +167,9 @@ include::grafana_environment[])
|
|
123
167
|
url ||= user_input('Specify grafana host', 'http://localhost:3000')
|
124
168
|
print "Testing connection to '#{url}' #{api_key ? '_with_' : '_without_'} API key..."
|
125
169
|
begin
|
126
|
-
# TODO: how to handle if ssl access if not working properly?
|
127
170
|
res = Grafana::Grafana.new(url,
|
128
171
|
api_key,
|
129
|
-
logger: config.logger
|
172
|
+
logger: config.logger).test_connection
|
130
173
|
rescue StandardError => e
|
131
174
|
puts
|
132
175
|
puts e.message
|
@@ -135,35 +178,39 @@ include::grafana_environment[])
|
|
135
178
|
|
136
179
|
case res
|
137
180
|
when 'Admin'
|
138
|
-
|
181
|
+
tmp = user_input('Access to grafana is permitted as Admin, which is a potential security risk.'\
|
182
|
+
' Do you want to use another [a]pi key, [r]e-enter url key or [i]gnore?', 'aRi')
|
139
183
|
|
140
|
-
|
141
|
-
print 'Access to grafana is permitted as NON-Admin. Do you want to use an [a]pi key,'\
|
142
|
-
' [r]e-enter api key or [i]gnore? [aRi]: '
|
143
|
-
|
144
|
-
case gets
|
184
|
+
case tmp
|
145
185
|
when /(?:i|I)$/
|
146
186
|
valid = true
|
147
187
|
|
148
|
-
# TODO: what is difference between 'a' and 'r'?
|
149
188
|
when /(?:a|A)$/
|
150
189
|
print 'Enter API key: '
|
151
|
-
api_key = gets.
|
190
|
+
api_key = gets.strip
|
152
191
|
|
153
|
-
|
192
|
+
else
|
193
|
+
url = nil
|
154
194
|
api_key = nil
|
155
195
|
|
156
196
|
end
|
157
197
|
|
158
|
-
|
198
|
+
when 'NON-Admin'
|
199
|
+
print 'Access to grafana is permitted as NON-Admin.'
|
200
|
+
valid = true
|
201
|
+
|
159
202
|
else
|
160
|
-
|
161
|
-
|
203
|
+
tmp = user_input("Grafana could not be accessed at '#{url}'. Do you want to use an [a]pi key,"\
|
204
|
+
' [r]e-enter url, or [i]gnore and proceed?', 'aRi')
|
162
205
|
|
163
|
-
case
|
206
|
+
case tmp
|
164
207
|
when /(?:i|I)$/
|
165
208
|
valid = true
|
166
209
|
|
210
|
+
when /(?:a|A)$/
|
211
|
+
print 'Enter API key: '
|
212
|
+
api_key = gets.strip
|
213
|
+
|
167
214
|
else
|
168
215
|
url = nil
|
169
216
|
api_key = nil
|
@@ -174,7 +221,7 @@ include::grafana_environment[])
|
|
174
221
|
end
|
175
222
|
%(grafana:
|
176
223
|
default:
|
177
|
-
host: #{url}#{api_key ? "\n api_key: #{api_key}" : ''}
|
224
|
+
host: #{url}#{api_key ? "\n api_key: #{api_key}" : ''}
|
178
225
|
)
|
179
226
|
end
|
180
227
|
|
@@ -254,16 +301,19 @@ include::grafana_environment[])
|
|
254
301
|
false
|
255
302
|
end
|
256
303
|
|
257
|
-
def
|
258
|
-
return
|
304
|
+
def overwrite_or_use_config_file(config_file)
|
305
|
+
return 'overwrite' unless File.exist?(config_file)
|
259
306
|
|
260
307
|
input = nil
|
261
308
|
until input
|
262
|
-
input = user_input("Configuration file '#{config_file}' already exists. Do you want to
|
263
|
-
|
309
|
+
input = user_input("Configuration file '#{config_file}' already exists. Do you want to [o]verwrite it, "\
|
310
|
+
'use it to for [d]emo report creation only, or [a]bort?', 'odA')
|
264
311
|
end
|
265
312
|
|
266
|
-
|
313
|
+
return 'demo_report' if input =~ /^(?:d|D)$/
|
314
|
+
return 'abort' if input =~ /^(?:A|a|odA)$/
|
315
|
+
|
316
|
+
'overwrite'
|
267
317
|
end
|
268
318
|
end
|
269
319
|
end
|