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,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the datasource interface to grafana alerts.
|
5
|
+
class GrafanaAlertsDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Hash with the following structure:
|
7
|
+
#
|
8
|
+
# {
|
9
|
+
# dashboardId: Dashboard ID as String or nil
|
10
|
+
# panelId: Panel ID as String or nil
|
11
|
+
# columns:
|
12
|
+
# limit:
|
13
|
+
# query:
|
14
|
+
# state:
|
15
|
+
# folderId:
|
16
|
+
# dashboardQuery:
|
17
|
+
# dashboardTag:
|
18
|
+
# }
|
19
|
+
# @see AbstractDatasource#request
|
20
|
+
def request(query_description)
|
21
|
+
webrequest = query_description[:prepared_request]
|
22
|
+
webrequest.relative_url = "/api/alerts#{url_parameters(query_description)}"
|
23
|
+
|
24
|
+
result = webrequest.execute(query_description[:timeout])
|
25
|
+
|
26
|
+
json = JSON.parse(result.body)
|
27
|
+
|
28
|
+
content = []
|
29
|
+
begin
|
30
|
+
json.each { |item| content << item.fetch_values(*query_description[:raw_query]['columns'].split(',')) }
|
31
|
+
rescue KeyError => e
|
32
|
+
raise MalformedAttributeContentError.new(e.message, 'columns', query_description[:raw_query]['columns'])
|
33
|
+
end
|
34
|
+
|
35
|
+
result = {}
|
36
|
+
result[:header] = [query_description[:raw_query]['columns'].split(',')]
|
37
|
+
result[:content] = content
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def url_parameters(query_desc)
|
45
|
+
url_vars = {}
|
46
|
+
url_vars.merge!(query_desc[:raw_query].select do |k, _v|
|
47
|
+
k =~ /^(?:limit|dashboardId|panelId|query|state|folderId|dashboardQuery|dashboardTag)/
|
48
|
+
end)
|
49
|
+
url_vars['from'] = query_desc[:from] if query_desc[:from]
|
50
|
+
url_vars['to'] = query_desc[:to] if query_desc[:to]
|
51
|
+
url_params = URI.encode_www_form(url_vars.map { |k, v| [k, v.to_s] })
|
52
|
+
return '' if url_params.empty?
|
53
|
+
|
54
|
+
"?#{url_params}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the datasource interface to grafana annotations.
|
5
|
+
class GrafanaAnnotationsDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Hash with the following structure:
|
7
|
+
#
|
8
|
+
# {
|
9
|
+
# dashboardId: Dashboard ID as String or nil
|
10
|
+
# panelId: Panel ID as String or nil
|
11
|
+
# columns:
|
12
|
+
# limit:
|
13
|
+
# alertId:
|
14
|
+
# userId:
|
15
|
+
# type:
|
16
|
+
# tags:
|
17
|
+
# }
|
18
|
+
# @see AbstractDatasource#request
|
19
|
+
def request(query_description)
|
20
|
+
webrequest = query_description[:prepared_request]
|
21
|
+
webrequest.relative_url = "/api/annotations#{url_parameters(query_description)}"
|
22
|
+
|
23
|
+
result = webrequest.execute(query_description[:timeout])
|
24
|
+
|
25
|
+
json = JSON.parse(result.body)
|
26
|
+
|
27
|
+
content = []
|
28
|
+
begin
|
29
|
+
json.each { |item| content << item.fetch_values(*query_description[:raw_query]['columns'].split(',')) }
|
30
|
+
rescue KeyError => e
|
31
|
+
raise MalformedAttributeContentError.new(e.message, 'columns', query_description[:raw_query]['columns'])
|
32
|
+
end
|
33
|
+
|
34
|
+
result = {}
|
35
|
+
result[:header] = [query_description[:raw_query]['columns'].split(',')]
|
36
|
+
result[:content] = content
|
37
|
+
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def url_parameters(query_desc)
|
44
|
+
url_vars = {}
|
45
|
+
url_vars.merge!(query_desc[:raw_query].select do |k, _v|
|
46
|
+
k =~ /^(?:limit|alertId|dashboardId|panelId|userId|type|tags)/
|
47
|
+
end)
|
48
|
+
url_vars['from'] = query_desc[:from] if query_desc[:from]
|
49
|
+
url_vars['to'] = query_desc[:to] if query_desc[:to]
|
50
|
+
url_params = URI.encode_www_form(url_vars.map { |k, v| [k, v.to_s] })
|
51
|
+
return '' if url_params.empty?
|
52
|
+
|
53
|
+
"?#{url_params}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the datasource interface to grafana model properties.
|
5
|
+
class GrafanaPropertyDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Hash with the following structure:
|
7
|
+
#
|
8
|
+
# {
|
9
|
+
# property_name: Name of the queried property as String
|
10
|
+
# panel: {Panel} object to query
|
11
|
+
# }
|
12
|
+
# @see AbstractDatasource#request
|
13
|
+
def request(query_description)
|
14
|
+
raise MissingSqlQueryError if query_description[:raw_query].nil?
|
15
|
+
|
16
|
+
panel = query_description[:raw_query][:panel]
|
17
|
+
property_name = query_description[:raw_query][:property_name]
|
18
|
+
|
19
|
+
{
|
20
|
+
header: [query_description[:raw_query][:property_name]],
|
21
|
+
content: [replace_variables(panel.field(property_name), query_description[:variables])]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the interface to graphite datasources.
|
5
|
+
class GraphiteDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Graphite query as String
|
7
|
+
# @see AbstractDatasource#request
|
8
|
+
def request(query_description)
|
9
|
+
raise MissingSqlQueryError if query_description[:raw_query].nil?
|
10
|
+
|
11
|
+
request = {
|
12
|
+
body: URI.encode_www_form('from': DateTime.strptime(query_description[:from], '%Q').strftime('%H:%M_%Y%m%d'),
|
13
|
+
'until': DateTime.strptime(query_description[:to], '%Q').strftime('%H:%M_%Y%m%d'),
|
14
|
+
'format': 'json',
|
15
|
+
'target': replace_variables(query_description[:raw_query], query_description[:variables])),
|
16
|
+
content_type: 'application/x-www-form-urlencoded',
|
17
|
+
request: Net::HTTP::Post
|
18
|
+
}
|
19
|
+
|
20
|
+
webrequest = query_description[:prepared_request]
|
21
|
+
webrequest.relative_url = "/api/datasources/proxy/#{id}/render"
|
22
|
+
webrequest.options.merge!(request)
|
23
|
+
|
24
|
+
result = webrequest.execute(query_description[:timeout])
|
25
|
+
preformat_response(result.body)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @see AbstractDatasource#raw_query_from_panel_model
|
29
|
+
def raw_query_from_panel_model(panel_query_target)
|
30
|
+
panel_query_target['target']
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# @see AbstractDatasource#preformat_response
|
36
|
+
def preformat_response(response_body)
|
37
|
+
# TODO: support multiple metrics as return types
|
38
|
+
{
|
39
|
+
header: %w[value time],
|
40
|
+
content: JSON.parse(response_body).first['datapoints']
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the interface to image rendering datasources.
|
5
|
+
class ImageRenderingDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Hash with the following structure:
|
7
|
+
#
|
8
|
+
# {
|
9
|
+
# panel: {Panel} which shall be rendered
|
10
|
+
# }
|
11
|
+
# @see AbstractDatasource#request
|
12
|
+
def request(query_description)
|
13
|
+
webrequest = query_description[:prepared_request]
|
14
|
+
webrequest.relative_url = query_description[:raw_query][:panel].render_url + url_params(query_description)
|
15
|
+
webrequest.options.merge!({ accept: 'image/png' })
|
16
|
+
|
17
|
+
result = webrequest.execute
|
18
|
+
|
19
|
+
{ header: ['image'], content: [result.body] }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def url_params(query_desc)
|
25
|
+
url_vars = query_desc[:variables].select { |k, _v| k =~ /^(?:timeout|height|width|theme|fullscreen|var-.+)$/ }
|
26
|
+
url_vars = default_vars.merge(url_vars)
|
27
|
+
url_vars['from'] = Variable.new(query_desc[:from])
|
28
|
+
url_vars['to'] = Variable.new(query_desc[:to])
|
29
|
+
result = URI.encode_www_form(url_vars.map { |k, v| [k, v.raw_value.to_s] })
|
30
|
+
|
31
|
+
return '' if result.empty?
|
32
|
+
|
33
|
+
"&#{result}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_vars
|
37
|
+
{
|
38
|
+
'fullscreen' => Variable.new(true),
|
39
|
+
'theme' => Variable.new('light'),
|
40
|
+
'timeout' => Variable.new(60)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/grafana/panel.rb
CHANGED
@@ -5,6 +5,7 @@ module Grafana
|
|
5
5
|
class Panel
|
6
6
|
# @return [Dashboard] parent {Dashboard} object
|
7
7
|
attr_reader :dashboard
|
8
|
+
attr_reader :model
|
8
9
|
|
9
10
|
# @param model [Hash] converted JSON Hash of the panel
|
10
11
|
# @param dashboard [Dashboard] parent {Dashboard} object
|
@@ -25,12 +26,17 @@ module Grafana
|
|
25
26
|
@model['id']
|
26
27
|
end
|
27
28
|
|
28
|
-
# @return [
|
29
|
+
# @return [Datasource] datasource object specified for the current panel
|
30
|
+
def datasource
|
31
|
+
dashboard.grafana.datasource_by_name(@model['datasource'])
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String] query string for the requested query letter
|
29
35
|
def query(query_letter)
|
30
36
|
query_item = @model['targets'].select { |item| item['refId'].to_s == query_letter.to_s }.first
|
31
|
-
raise QueryLetterDoesNotExistError.new(query_letter, self)
|
37
|
+
raise QueryLetterDoesNotExistError.new(query_letter, self) unless query_item
|
32
38
|
|
33
|
-
query_item
|
39
|
+
datasource.raw_query_from_panel_model(query_item)
|
34
40
|
end
|
35
41
|
|
36
42
|
# @return [String] relative rendering URL for the panel, to create an image out of it
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the interface to Prometheus datasources.
|
5
|
+
class PrometheusDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a Prometheus query as String
|
7
|
+
# @see AbstractDatasource#request
|
8
|
+
def request(query_description)
|
9
|
+
raise MissingSqlQueryError if query_description[:raw_query].nil?
|
10
|
+
|
11
|
+
url = "/api/datasources/proxy/#{id}/api/v1/query_range?"\
|
12
|
+
"start=#{query_description[:from]}&end=#{query_description[:to]}"\
|
13
|
+
"&query=#{replace_variables(query_description[:raw_query], query_description[:variables])}"
|
14
|
+
|
15
|
+
webrequest = query_description[:prepared_request]
|
16
|
+
webrequest.relative_url = url
|
17
|
+
webrequest.options.merge!({ request: Net::HTTP::Get })
|
18
|
+
|
19
|
+
result = webrequest.execute(query_description[:timeout])
|
20
|
+
preformat_response(result.body)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see AbstractDatasource#raw_query_from_panel_model
|
24
|
+
def raw_query_from_panel_model(panel_query_target)
|
25
|
+
panel_query_target['expr']
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# @see AbstractDatasource#preformat_response
|
31
|
+
def preformat_response(response_body)
|
32
|
+
# TODO: support multiple metrics as return types
|
33
|
+
{
|
34
|
+
header: %w[time value],
|
35
|
+
content: JSON.parse(response_body)['data']['result'].first['values']
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# Implements the interface to all SQL based datasources (tested with PostgreSQL and MariaDB/MySQL).
|
5
|
+
class SqlDatasource < AbstractDatasource
|
6
|
+
# +:raw_query+ needs to contain a SQL query as String in the respective database dialect
|
7
|
+
# @see AbstractDatasource#request
|
8
|
+
def request(query_description)
|
9
|
+
raise MissingSqlQueryError if query_description[:raw_query].nil?
|
10
|
+
|
11
|
+
sql = replace_variables(query_description[:raw_query], query_description[:variables])
|
12
|
+
request = {
|
13
|
+
body: {
|
14
|
+
from: query_description[:from],
|
15
|
+
to: query_description[:to],
|
16
|
+
queries: [rawSql: prepare_sql(sql), datasourceId: id, format: 'table']
|
17
|
+
}.to_json,
|
18
|
+
request: Net::HTTP::Post
|
19
|
+
}
|
20
|
+
|
21
|
+
webrequest = query_description[:prepared_request]
|
22
|
+
webrequest.relative_url = '/api/tsdb/query'
|
23
|
+
webrequest.options.merge!(request)
|
24
|
+
|
25
|
+
result = webrequest.execute(query_description[:timeout])
|
26
|
+
preformat_response(result.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see AbstractDatasource#raw_query_from_panel_model
|
30
|
+
def raw_query_from_panel_model(panel_query_target)
|
31
|
+
panel_query_target['rawSql']
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def preformat_response(response_body)
|
37
|
+
results = {}
|
38
|
+
results.default = []
|
39
|
+
|
40
|
+
JSON.parse(response_body)['results'].each_value do |query_result|
|
41
|
+
if query_result.key?('error')
|
42
|
+
results[:header] = results[:header] << ['SQL Error']
|
43
|
+
results[:content] = [[query_result['error']]]
|
44
|
+
|
45
|
+
elsif query_result['tables']
|
46
|
+
query_result['tables'].each do |table|
|
47
|
+
results[:header] = results[:header] << table['columns'].map { |header| header['text'] }
|
48
|
+
results[:content] = table['rows']
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
results
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_sql(sql)
|
58
|
+
# remove comments in query
|
59
|
+
sql.gsub!(/--[^\r\n]*(?:[\r\n]+|$)/, ' ')
|
60
|
+
sql.gsub!(/\r\n/, ' ')
|
61
|
+
sql.gsub!(/\n/, ' ')
|
62
|
+
sql
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/grafana/variable.rb
CHANGED
@@ -10,6 +10,7 @@ module Grafana
|
|
10
10
|
class Variable
|
11
11
|
attr_reader :name, :text, :raw_value
|
12
12
|
|
13
|
+
# Translation table to support {https://momentjs.com/docs/#/displaying/}.
|
13
14
|
DATE_MATCHES = { 'M' => '%-m', 'MM' => '%m', 'MMM' => '%b', 'MMMM' => '%B',
|
14
15
|
'D' => '%-d', 'DD' => '%d', 'DDD' => '%-j', 'DDDD' => '%j',
|
15
16
|
'd' => '%w', 'ddd' => '%a', 'dddd' => '%A',
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grafana
|
4
|
+
# This class standardizes all webcalls. Key functionality is to properly support HTTPS calls as a base functionality.
|
5
|
+
class WebRequest
|
6
|
+
attr_accessor :relative_url, :options
|
7
|
+
|
8
|
+
@ssl_cert = nil
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :ssl_cert
|
12
|
+
end
|
13
|
+
|
14
|
+
# Initializes a specific HTTP request.
|
15
|
+
#
|
16
|
+
# Default (can be overridden, by specifying the options Hash):
|
17
|
+
# accept: 'application/json'
|
18
|
+
# request: Net::HTTP::Get
|
19
|
+
# content_type: 'application/json'
|
20
|
+
#
|
21
|
+
# @param base_url [String] URL which shall be queried
|
22
|
+
# @param options [Hash] options, which shall be merged to the request. Also allows `+logger+` option
|
23
|
+
def initialize(base_url, options = {})
|
24
|
+
@base_url = base_url
|
25
|
+
default_options = { accept: 'application/json', request: Net::HTTP::Get, content_type: 'application/json' }
|
26
|
+
@options = default_options.merge(options.reject { |k, _v| k == :logger && k == :relative_url })
|
27
|
+
@relative_url = options[:relative_url]
|
28
|
+
@logger = options[:logger] || Logger.new(nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Executes the HTTP request
|
32
|
+
#
|
33
|
+
# @param timeout [Integer] number of seconds to wait, before the http request is cancelled, defaults to 60 seconds
|
34
|
+
# @return [Response] HTTP response object
|
35
|
+
def execute(timeout = nil)
|
36
|
+
timeout ||= 60
|
37
|
+
|
38
|
+
uri = URI.parse("#{@base_url}#{@relative_url}")
|
39
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
40
|
+
configure_ssl if @base_url =~ /^https/
|
41
|
+
|
42
|
+
@http.read_timeout = timeout.to_i
|
43
|
+
|
44
|
+
request = @options[:request].new(uri.request_uri)
|
45
|
+
request['Accept'] = @options[:accept] if @options[:accept]
|
46
|
+
request['Content-Type'] = @options[:content_type] if @options[:content_type]
|
47
|
+
request['Authorization'] = @options[:authorization] if @options[:authorization]
|
48
|
+
request.body = @options[:body]
|
49
|
+
|
50
|
+
@logger.debug("Requesting #{uri} with '#{@options[:body]}' and timeout '#{timeout}'")
|
51
|
+
response = @http.request(request)
|
52
|
+
@logger.debug("Received response #{response}")
|
53
|
+
|
54
|
+
response
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def configure_ssl
|
60
|
+
@http.use_ssl = true
|
61
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
62
|
+
if self.class.ssl_cert && !File.exist?(self.class.ssl_cert)
|
63
|
+
@logger.warn('SSL certificate file does not exist.')
|
64
|
+
elsif self.class.ssl_cert
|
65
|
+
@http.cert_store = OpenSSL::X509::Store.new
|
66
|
+
@http.cert_store.set_default_paths
|
67
|
+
@http.cert_store.add_file(self.class.ssl_cert)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|