smart_proxy_monitoring 0.0.1

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.
@@ -0,0 +1,97 @@
1
+ require 'thread'
2
+
3
+ module ::Proxy::Monitoring::Icinga2
4
+ class MonitoringResult < Proxy::HttpRequest::ForemanRequest
5
+ def push_result(result)
6
+ send_request(request_factory.create_post('api/monitoring_results', result))
7
+ end
8
+ end
9
+
10
+ class Icinga2ResultUploader
11
+ include ::Proxy::Log
12
+ include ::Proxy::Monitoring::Icinga2::Common
13
+
14
+ attr_reader :semaphore
15
+
16
+ def initialize(queue)
17
+ @queue = queue.queue
18
+ @semaphore = Mutex.new
19
+ end
20
+
21
+ def upload
22
+ while change = @queue.pop
23
+ with_event_counter('Icinga2 Result Uploader') do
24
+ symbolize_keys_deep!(change)
25
+
26
+ change[:timestamp] = change[:check_result][:schedule_end] if change.key?(:check_result)
27
+ if change.key?(:downtime) && change[:downtime].is_a?(Hash)
28
+ change[:host] = change[:downtime][:host_name] if change[:host].nil? || change[:host].empty?
29
+ change[:service] = change[:downtime][:service_name] if change[:service].nil? || change[:service].empty?
30
+ end
31
+
32
+ if change[:service].nil? || change[:service].empty?
33
+ change[:service] = 'Host Check'
34
+ end
35
+
36
+ case change[:type]
37
+ when 'StateChange'
38
+ transformed = { result: change[:check_result][:state] }
39
+ when 'AcknowledgementSet'
40
+ transformed = { acknowledged: true }
41
+ when 'AchnowledgementCleared'
42
+ transformed = { acknowledged: false }
43
+ when 'DowntimeTriggered'
44
+ transformed = { downtime: true }
45
+ when 'DowntimeRemoved'
46
+ transformed = { downtime: false }
47
+ when '_parsed'
48
+ transformed = change.dup.reject! { |k, _v| k == :type }
49
+ else
50
+ next
51
+ end
52
+ transformed.merge!(
53
+ host: change[:host],
54
+ service: change[:service],
55
+ timestamp: change[:timestamp]
56
+ )
57
+ begin
58
+ MonitoringResult.new.push_result(transformed.to_json)
59
+ rescue Errno::ECONNREFUSED => e
60
+ logger.error "Foreman refused connection when tried to upload monitoring result: #{e.message}"
61
+ sleep 10
62
+ rescue => e
63
+ logger.error "Error while uploading monitoring results to Foreman: #{e.message}"
64
+ sleep 1
65
+ retry
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def start
72
+ @thread = Thread.new { upload }
73
+ @thread.abort_on_exception = true
74
+ @thread
75
+ end
76
+
77
+ def stop
78
+ @thread.terminate unless @thread.nil?
79
+ end
80
+
81
+ private
82
+
83
+ def symbolize_keys_deep!(h)
84
+ h.keys.each do |k|
85
+ ks = k.to_sym
86
+ h[ks] = h.delete k
87
+ symbolize_keys_deep! h[ks] if h[ks].is_a? Hash
88
+ end
89
+ end
90
+
91
+ def add_domain(host)
92
+ domain = Proxy::Monitoring::Plugin.settings.strip_domain
93
+ host = "#{host}#{domain}" unless domain.nil?
94
+ host
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,9 @@
1
+ require 'thread'
2
+
3
+ module ::Proxy::Monitoring::Icinga2
4
+ class Icinga2UploadQueue
5
+ def queue
6
+ @queue ||= Queue.new
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module ::Proxy::Monitoring::Icinga2
2
+ module Common
3
+ private
4
+
5
+ def with_event_counter(log_prefix, interval_count = 100, interval_seconds = 60)
6
+ semaphore.synchronize do
7
+ @counter ||= 0
8
+ @timer ||= Time.now
9
+ if @counter >= interval_count || (Time.now - @timer) > interval_seconds
10
+ status = "#{log_prefix}: Observed #{@counter} events in the last #{(Time.now - @timer).round(2)} seconds."
11
+ status += " #{@queue.length} items queued. #{@queue.num_waiting} threads waiting." unless @queue.nil?
12
+ logger.info status
13
+ @timer = Time.now
14
+ @counter = 0
15
+ end
16
+ @counter += 1
17
+ end
18
+ yield
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,68 @@
1
+ module Proxy::Monitoring::Icinga2
2
+ class Provider < ::Proxy::Monitoring::Provider
3
+ include Proxy::Log
4
+ include Proxy::Util
5
+
6
+ def remove_host(host)
7
+ request_url = "/objects/hosts/#{host}?cascade=1"
8
+
9
+ result = with_errorhandling("Remove #{host}") do
10
+ Icinga2Client.delete(request_url)
11
+ end
12
+ result.to_json
13
+ end
14
+
15
+ def remove_downtime_host(host, author, comment)
16
+ request_url = "/actions/remove-downtime?type=Host&filter=host.name==\"#{host}\"\&\&author==\"#{author}\"\&\&comment=\"#{comment}\""
17
+ data = {}
18
+
19
+ result = with_errorhandling("Remove downtime from #{host}") do
20
+ Icinga2Client.post(request_url, data.to_json)
21
+ end
22
+ result.to_json
23
+ end
24
+
25
+ def set_downtime_host(host, author, comment, start_time, end_time)
26
+ request_url = "/actions/schedule-downtime?type=Host&filter=host.name==\"#{host}\""
27
+ data = {
28
+ 'author' => author,
29
+ 'comment' => comment,
30
+ 'start_time' => start_time,
31
+ 'end_time' => end_time,
32
+ 'duration' => 1000
33
+ }
34
+
35
+ result = with_errorhandling("Set downtime on #{host}") do
36
+ Icinga2Client.post(request_url, data.to_json)
37
+ end
38
+ result.to_json
39
+ end
40
+
41
+ private
42
+
43
+ def with_errorhandling(action)
44
+ response = yield
45
+ logger.debug "Monitoring - Action successful: #{action}"
46
+ result = JSON.parse(response.body)
47
+ unless result.key?('results')
48
+ logger.error "Invalid Icinga result or result with errors: #{result.inspect}"
49
+ raise Proxy::Monitoring::Error.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} returned an invalid result.")
50
+ end
51
+ unless result['results'].first
52
+ raise Proxy::Monitoring::NotFound.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} returned an empty result.")
53
+ end
54
+ if result['results'][0]['code'] != 200
55
+ raise Proxy::Monitoring::Error.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} returned an error: #{result['results'][0]['code']} #{result['results'][0]['status']}")
56
+ end
57
+ result
58
+ rescue JSON::ParserError => e
59
+ raise Proxy::Monitoring::Error.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} returned invalid JSON: '#{e.message}'")
60
+ rescue RestClient::Exception => e
61
+ raise Proxy::Monitoring::Error.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} returned an error: '#{e.response}'")
62
+ rescue Errno::ECONNREFUSED => e
63
+ raise Proxy::Monitoring::ConnectionError.new("Icinga server at #{::Proxy::Monitoring::Icinga2::Plugin.settings.server} is not responding")
64
+ rescue SocketError => e
65
+ raise Proxy::Monitoring::ConnectionError.new("Icinga server '#{::Proxy::Monitoring::Icinga2::Plugin.settings.server}' is unknown")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,16 @@
1
+ module ::Proxy::Monitoring::Icinga2
2
+ class Plugin < ::Proxy::Provider
3
+ plugin :monitoring_icinga2, ::Proxy::Monitoring::VERSION
4
+
5
+ default_settings server: 'localhost'
6
+ default_settings api_port: '5665'
7
+ default_settings verify_ssl: true
8
+
9
+ requires :monitoring, ::Proxy::Monitoring::VERSION
10
+
11
+ start_services :icinga2_initial_importer, :icinga2_api_observer, :icinga2_result_uploader
12
+
13
+ load_classes ::Proxy::Monitoring::Icinga2::PluginConfiguration
14
+ load_dependency_injection_wirings ::Proxy::Monitoring::Icinga2::PluginConfiguration
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ module ::Proxy::Monitoring::Icinga2
2
+ class PluginConfiguration
3
+ def load_classes
4
+ require 'smart_proxy_monitoring_common/monitoring_common'
5
+ require 'smart_proxy_monitoring_icinga2/monitoring_icinga2_main'
6
+ require 'smart_proxy_monitoring_icinga2/monitoring_icinga2_common'
7
+ require 'smart_proxy_monitoring_icinga2/icinga2_upload_queue'
8
+ require 'smart_proxy_monitoring_icinga2/icinga2_client'
9
+ require 'smart_proxy_monitoring_icinga2/icinga2_initial_importer'
10
+ require 'smart_proxy_monitoring_icinga2/icinga2_api_observer'
11
+ require 'smart_proxy_monitoring_icinga2/icinga2_result_uploader'
12
+ end
13
+
14
+ def load_dependency_injection_wirings(container_instance, settings)
15
+ container_instance.dependency :monitoring_provider, lambda { ::Proxy::Monitoring::Icinga2::Provider.new }
16
+ container_instance.singleton_dependency :icinga2_upload_queue, lambda { ::Proxy::Monitoring::Icinga2::Icinga2UploadQueue.new }
17
+ container_instance.singleton_dependency :icinga2_api_observer, (lambda do
18
+ ::Proxy::Monitoring::Icinga2::Icinga2ApiObserver.new(container_instance.get_dependency(:icinga2_upload_queue))
19
+ end)
20
+ container_instance.singleton_dependency :icinga2_result_uploader, (lambda do
21
+ ::Proxy::Monitoring::Icinga2::Icinga2ResultUploader.new(container_instance.get_dependency(:icinga2_upload_queue))
22
+ end)
23
+ container_instance.singleton_dependency :icinga2_initial_importer, (lambda do
24
+ ::Proxy::Monitoring::Icinga2::Icinga2InitialImporter.new(container_instance.get_dependency(:icinga2_upload_queue))
25
+ end)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ require 'smart_proxy_monitoring_icinga2/plugin_configuration'
2
+ require 'smart_proxy_monitoring_icinga2/monitoring_icinga2_plugin'
@@ -0,0 +1,11 @@
1
+ ---
2
+ # Collect Monitoring information
3
+ :enabled: true
4
+
5
+ # Valid providers:
6
+ # monitoring_icinga2 (Icinga 2 API, default)
7
+ #:use_provider: monitoring_icinga2
8
+
9
+ # Strip this part of the domain when communicating with the Monitoring server
10
+ # and add it when communicating with Foreman
11
+ # :strip_domain: .localdomain
@@ -0,0 +1,17 @@
1
+ ---
2
+ # Collect Monitoring information via Icinga 2 API
3
+ :enabled: true
4
+
5
+ # The FQDN or IP address of the Icinga 2 server (if using IP address also set verify_ssl to false)
6
+ :server: icinga2.localdomain
7
+ # The CA certificate used by Icinga 2 (typically located on the server at /etc/icinga2/pki/ca.crt)
8
+ :api_cacert: /usr/share/foreman-proxy/monitoring/ca.crt
9
+ # The name of API User
10
+ :api_user: foreman
11
+ # The certificate issued on the client_cn attribute of the API User and the corresponding key
12
+ :api_usercert: /usr/share/foreman-proxy/monitoring/foreman.crt
13
+ :api_userkey: /usr/share/foreman-proxy/monitoring/foreman.key
14
+ # The password from the password attribute of the API User (if not using certificates)
15
+ #:api_password: foreman
16
+ # SSL Verfification mode (boolean value)
17
+ :verify_ssl: true
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart_proxy_monitoring
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Timo Goebel
8
+ - Dirk Goetz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-08-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: mocha
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: test-unit
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: Monitoring plug-in for Foreman's smart proxy
85
+ email:
86
+ - timo.goebel@dm.de
87
+ - dirk.goetz@netways.de
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files:
91
+ - README.md
92
+ - LICENSE
93
+ files:
94
+ - LICENSE
95
+ - README.md
96
+ - bundler.d/monitoring.rb
97
+ - lib/smart_proxy_monitoring.rb
98
+ - lib/smart_proxy_monitoring/configuration_loader.rb
99
+ - lib/smart_proxy_monitoring/dependency_injection.rb
100
+ - lib/smart_proxy_monitoring/monitoring_api.rb
101
+ - lib/smart_proxy_monitoring/monitoring_http_config.ru
102
+ - lib/smart_proxy_monitoring/monitoring_plugin.rb
103
+ - lib/smart_proxy_monitoring/version.rb
104
+ - lib/smart_proxy_monitoring_common/monitoring_common.rb
105
+ - lib/smart_proxy_monitoring_icinga2.rb
106
+ - lib/smart_proxy_monitoring_icinga2/icinga2_api_observer.rb
107
+ - lib/smart_proxy_monitoring_icinga2/icinga2_client.rb
108
+ - lib/smart_proxy_monitoring_icinga2/icinga2_initial_importer.rb
109
+ - lib/smart_proxy_monitoring_icinga2/icinga2_result_uploader.rb
110
+ - lib/smart_proxy_monitoring_icinga2/icinga2_upload_queue.rb
111
+ - lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_common.rb
112
+ - lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_main.rb
113
+ - lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_plugin.rb
114
+ - lib/smart_proxy_monitoring_icinga2/plugin_configuration.rb
115
+ - settings.d/monitoring.yml.example
116
+ - settings.d/monitoring_icinga2.yml.example
117
+ homepage: http://github.com/theforeman/smart_proxy_monitoring
118
+ licenses:
119
+ - GPLv3
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.4.5
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Monitoring plug-in for Foreman's smart proxy
141
+ test_files: []
142
+ has_rdoc: