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.
- checksums.yaml +7 -0
- data/LICENSE +675 -0
- data/README.md +174 -0
- data/bundler.d/monitoring.rb +2 -0
- data/lib/smart_proxy_monitoring/configuration_loader.rb +8 -0
- data/lib/smart_proxy_monitoring/dependency_injection.rb +8 -0
- data/lib/smart_proxy_monitoring/monitoring_api.rb +77 -0
- data/lib/smart_proxy_monitoring/monitoring_http_config.ru +5 -0
- data/lib/smart_proxy_monitoring/monitoring_plugin.rb +19 -0
- data/lib/smart_proxy_monitoring/version.rb +5 -0
- data/lib/smart_proxy_monitoring.rb +4 -0
- data/lib/smart_proxy_monitoring_common/monitoring_common.rb +6 -0
- data/lib/smart_proxy_monitoring_icinga2/icinga2_api_observer.rb +66 -0
- data/lib/smart_proxy_monitoring_icinga2/icinga2_client.rb +127 -0
- data/lib/smart_proxy_monitoring_icinga2/icinga2_initial_importer.rb +109 -0
- data/lib/smart_proxy_monitoring_icinga2/icinga2_result_uploader.rb +97 -0
- data/lib/smart_proxy_monitoring_icinga2/icinga2_upload_queue.rb +9 -0
- data/lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_common.rb +21 -0
- data/lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_main.rb +68 -0
- data/lib/smart_proxy_monitoring_icinga2/monitoring_icinga2_plugin.rb +16 -0
- data/lib/smart_proxy_monitoring_icinga2/plugin_configuration.rb +28 -0
- data/lib/smart_proxy_monitoring_icinga2.rb +2 -0
- data/settings.d/monitoring.yml.example +11 -0
- data/settings.d/monitoring_icinga2.yml.example +17 -0
- metadata +142 -0
data/README.md
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
# Smart Proxy - Monitoring
|
2
|
+
|
3
|
+
This plug-in adds support for Monitoring to Foreman's Smart Proxy.
|
4
|
+
It requires also the Foreman Monitoring plug-in.
|
5
|
+
|
6
|
+
# Installation
|
7
|
+
|
8
|
+
Please see the Foreman manual for appropriate instructions:
|
9
|
+
|
10
|
+
* [Foreman: How to Install a Plugin](http://theforeman.org/manuals/latest/index.html#6.Plugins)
|
11
|
+
|
12
|
+
The gem name is `smart_proxy_monitoring`.
|
13
|
+
|
14
|
+
RPM users can install the `rubygem-smart_proxy_monitoring` packages.
|
15
|
+
|
16
|
+
This plug-in has not been packaged for Debian, yet.
|
17
|
+
|
18
|
+
# Configuration
|
19
|
+
|
20
|
+
The plug-in requires some configuration on the Monitoring server and the Smart Proxy.
|
21
|
+
For now the only supported Monitoring solution is Icinga 2.
|
22
|
+
|
23
|
+
## Icinga 2
|
24
|
+
|
25
|
+
The Smart Proxy connects to the Icinga 2 API using an API User with password or
|
26
|
+
certificate to get Monitoring information. It requires at least Icinga 2 version 2.5.
|
27
|
+
|
28
|
+
The Icinga project provides detailed [documentation on Icinga 2](http://docs.icinga.org/icinga2/).
|
29
|
+
The required steps for connecting the Smart Proxy and Icinga 2 will be found below.
|
30
|
+
|
31
|
+
### Monitoring Server
|
32
|
+
|
33
|
+
On the Monitoring Server you have to enable the API and create API User.
|
34
|
+
|
35
|
+
For testing the fastest way to setup this will be the following commands.
|
36
|
+
|
37
|
+
```
|
38
|
+
# icinga2 api setup
|
39
|
+
# systemctl restart icinga2.service
|
40
|
+
```
|
41
|
+
|
42
|
+
This will create the certficates, enable the API feature and create and API User `root` with
|
43
|
+
a random password. The configuration of the API User will be located in `/etc/icinga2/conf.d/api-users.conf`.
|
44
|
+
|
45
|
+
More detailed instructions:
|
46
|
+
|
47
|
+
To enable the API follow the next steps, if the API is already enabled skip this steps
|
48
|
+
and start by creating an API User. The API will already be enabled if you use the Icingaweb 2
|
49
|
+
Module Director for configuration, Icinga 2 as Agents or in a distributed or high-available
|
50
|
+
setup.
|
51
|
+
|
52
|
+
Before you can enable the API a CA and a host certificate are required, the instructions
|
53
|
+
will help you to setup Icinga 2's own CA. You can also use your Puppet's certificates or
|
54
|
+
any other CA.
|
55
|
+
|
56
|
+
To create Icinga 2's own CA run:
|
57
|
+
|
58
|
+
```
|
59
|
+
# icinga2 pki new-ca
|
60
|
+
```
|
61
|
+
|
62
|
+
Afterwards copy the CA certificate to Icinga 2's pki directory:
|
63
|
+
|
64
|
+
```
|
65
|
+
# cp /var/lib/icinga2/ca/ca.crt /etc/icinga2/pki/
|
66
|
+
```
|
67
|
+
|
68
|
+
To create a certificate request for the node run:
|
69
|
+
|
70
|
+
```
|
71
|
+
# icinga2 pki new-cert --cn $(hostname -f) --key /etc/icinga2/pki/$(hostname -f).key --csr /etc/icinga2/pki/$(hostname -f).csr
|
72
|
+
```
|
73
|
+
|
74
|
+
And then sign the certficate request to get a certificate by executing:
|
75
|
+
|
76
|
+
```
|
77
|
+
# icinga2 pki sign-csr --csr /etc/icinga2/pki/$(hostname -f).csr --cert /etc/icinga2/pki/$(hostname -f).crt
|
78
|
+
```
|
79
|
+
|
80
|
+
With the certificates created and placed in Icinga 2's pki directory you can enable the API feature.
|
81
|
+
|
82
|
+
```
|
83
|
+
# icinga2 feature enable api
|
84
|
+
# systemctl restart icinga2.service
|
85
|
+
```
|
86
|
+
|
87
|
+
To allow API connections you have to create an API User. You should name him according to the use case,
|
88
|
+
so instructions will create an user named `foreman`.
|
89
|
+
|
90
|
+
Password authentication is easier to setup, but certificate-based authentication is more secure.
|
91
|
+
|
92
|
+
Password authentication only requires you to create an API User object in a configuration file
|
93
|
+
read by Icinga 2.
|
94
|
+
|
95
|
+
```
|
96
|
+
# vi /etc/icinga2/conf.d/api-users.conf
|
97
|
+
object ApiUser "foreman" {
|
98
|
+
password = "foreman"
|
99
|
+
permissions = [ "*" ]
|
100
|
+
}
|
101
|
+
# systemctl reload icinga2.service
|
102
|
+
```
|
103
|
+
|
104
|
+
Certificate-based authentication requires the API User object and a signed certificate.
|
105
|
+
|
106
|
+
```
|
107
|
+
# vi /etc/icinga2/conf.d/api-users.conf
|
108
|
+
object ApiUser "foreman" {
|
109
|
+
client_cn = "foreman"
|
110
|
+
permissions = [ "*" ]
|
111
|
+
}
|
112
|
+
# systemctl reload icinga2.service
|
113
|
+
# icinga2 pki new-cert --cn foreman --key /etc/icinga2/pki/foreman.key --csr /etc/icinga2/pki/foreman.csr
|
114
|
+
# icinga2 pki sign-csr --csr /etc/icinga2/pki/foreman.csr --cert /etc/icinga2/pki/foreman.crt
|
115
|
+
```
|
116
|
+
|
117
|
+
### Smart Proxy
|
118
|
+
|
119
|
+
Ensure that the Monitoring module is enabled and uses the provider monitoring_icinga2.
|
120
|
+
It is the default provider so also no setting for use_provider is fine.
|
121
|
+
If you configured hosts in Icinga2 only with hostname instead of FQDN, you can add `:strip_domain` with
|
122
|
+
all the parts to strip, e.g. `.localdomain`.
|
123
|
+
|
124
|
+
```
|
125
|
+
# vi /etc/foreman-proxy/settings.d/monitoring.yaml
|
126
|
+
---
|
127
|
+
:enabled: true
|
128
|
+
:use_provider: monitoring_icinga2
|
129
|
+
```
|
130
|
+
|
131
|
+
Configure the provider with your server details and the API User information.
|
132
|
+
Typically you will have to change the server attribute, copy the CA certificate from the server (located
|
133
|
+
in /etc/icinga2/pki/) and provide the authentication details of the API User. If using the IP address
|
134
|
+
instead of the FQDN of the server, you will have to set verify_ssl to false.
|
135
|
+
|
136
|
+
```
|
137
|
+
# vi /etc/foreman-proxy/settings.d/monitoring_icinga2.yaml
|
138
|
+
---
|
139
|
+
:enabled: true
|
140
|
+
:server: icinga2.localdomain
|
141
|
+
:api_cacert: /usr/share/foreman-proxy/monitoring/ca.crt
|
142
|
+
:api_user: foreman
|
143
|
+
:api_usercert: /usr/share/foreman-proxy/monitoring/foreman.crt
|
144
|
+
:api_userkey: /usr/share/foreman-proxy/monitoring/foreman.key
|
145
|
+
#:api_password: foreman
|
146
|
+
:verify_ssl: true
|
147
|
+
```
|
148
|
+
|
149
|
+
|
150
|
+
# TODO
|
151
|
+
|
152
|
+
Monitoring:
|
153
|
+
* Add host creation and update
|
154
|
+
|
155
|
+
Provider Icinga2:
|
156
|
+
* Add endpoint and zone management for Icinga 2 as agent
|
157
|
+
|
158
|
+
# Copyright
|
159
|
+
|
160
|
+
Copyright (c) 2016 The Foreman developers
|
161
|
+
|
162
|
+
This program is free software: you can redistribute it and/or modify
|
163
|
+
it under the terms of the GNU General Public License as published by
|
164
|
+
the Free Software Foundation, either version 3 of the License, or
|
165
|
+
(at your option) any later version.
|
166
|
+
|
167
|
+
This program is distributed in the hope that it will be useful,
|
168
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
169
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
170
|
+
GNU General Public License for more details.
|
171
|
+
|
172
|
+
You should have received a copy of the GNU General Public License
|
173
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
174
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'smart_proxy_monitoring/monitoring_plugin'
|
3
|
+
|
4
|
+
module Proxy::Monitoring
|
5
|
+
class Api < ::Sinatra::Base
|
6
|
+
extend Proxy::Monitoring::DependencyInjection
|
7
|
+
inject_attr :monitoring_provider, :server
|
8
|
+
|
9
|
+
include ::Proxy::Log
|
10
|
+
helpers ::Proxy::Helpers
|
11
|
+
authorize_with_trusted_hosts
|
12
|
+
authorize_with_ssl_client
|
13
|
+
|
14
|
+
delete '/host/:host' do |host|
|
15
|
+
begin
|
16
|
+
validate_dns_name!(host)
|
17
|
+
host = strip_domain(host)
|
18
|
+
|
19
|
+
server.remove_host(host)
|
20
|
+
rescue Proxy::Monitoring::NotFound => e
|
21
|
+
log_halt 404, e
|
22
|
+
rescue Proxy::Monitoring::ConnectionError => e
|
23
|
+
log_halt 503, e
|
24
|
+
rescue Exception => e
|
25
|
+
log_halt 400, e
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/downtime/host/:host?' do |host|
|
30
|
+
author = params[:author] || 'foreman'
|
31
|
+
comment = params[:comment] || 'triggered by foreman'
|
32
|
+
start_time = params[:start_time] || Time.now.to_i
|
33
|
+
end_time = params[:end_time] || (Time.now.to_i + (24 * 3600))
|
34
|
+
|
35
|
+
begin
|
36
|
+
validate_dns_name!(host)
|
37
|
+
host = strip_domain(host)
|
38
|
+
|
39
|
+
server.set_downtime_host(host, author, comment, start_time, end_time)
|
40
|
+
rescue Proxy::Monitoring::NotFound => e
|
41
|
+
log_halt 404, e
|
42
|
+
rescue Proxy::Monitoring::ConnectionError => e
|
43
|
+
log_halt 503, e
|
44
|
+
rescue Exception => e
|
45
|
+
log_halt 400, e
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
delete '/downtime/host/:host?' do |host|
|
50
|
+
author = params[:author] || 'foreman'
|
51
|
+
comment = params[:comment] || 'triggered by foreman'
|
52
|
+
|
53
|
+
begin
|
54
|
+
validate_dns_name!(host)
|
55
|
+
host = strip_domain(host)
|
56
|
+
|
57
|
+
server.remove_downtime_host(host, author, comment)
|
58
|
+
rescue Proxy::Monitoring::NotFound => e
|
59
|
+
log_halt 404, e
|
60
|
+
rescue Proxy::Monitoring::ConnectionError => e
|
61
|
+
log_halt 503, e
|
62
|
+
rescue Exception => e
|
63
|
+
log_halt 400, e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_dns_name!(name)
|
68
|
+
raise Proxy::Monitoring::Error.new("Invalid DNS name #{name}") unless name =~ /^([a-zA-Z0-9]([-a-zA-Z0-9]+)?\.?)+$/
|
69
|
+
end
|
70
|
+
|
71
|
+
def strip_domain(name)
|
72
|
+
domain = Proxy::Monitoring::Plugin.settings.strip_domain
|
73
|
+
name.slice!(domain) unless domain.nil?
|
74
|
+
name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'smart_proxy_monitoring/version'
|
2
|
+
|
3
|
+
module Proxy::Monitoring
|
4
|
+
class NotFound < RuntimeError; end
|
5
|
+
class ConnectionError < RuntimeError; end
|
6
|
+
class Error < RuntimeError; end
|
7
|
+
|
8
|
+
class Plugin < ::Proxy::Plugin
|
9
|
+
plugin 'monitoring', Proxy::Monitoring::VERSION
|
10
|
+
|
11
|
+
uses_provider
|
12
|
+
default_settings use_provider: 'monitoring_icinga2'
|
13
|
+
|
14
|
+
http_rackup_path File.expand_path('monitoring_http_config.ru', File.expand_path('../', __FILE__))
|
15
|
+
https_rackup_path File.expand_path('monitoring_http_config.ru', File.expand_path('../', __FILE__))
|
16
|
+
|
17
|
+
load_classes ::Proxy::Monitoring::ConfigurationLoader
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'socket'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module ::Proxy::Monitoring::Icinga2
|
6
|
+
class Icinga2ApiObserver
|
7
|
+
include ::Proxy::Log
|
8
|
+
include ::Proxy::Monitoring::Icinga2::Common
|
9
|
+
|
10
|
+
attr_reader :semaphore
|
11
|
+
|
12
|
+
def initialize(queue)
|
13
|
+
@queue = queue.queue
|
14
|
+
@semaphore = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def monitor
|
18
|
+
loop do
|
19
|
+
logger.debug "Connecting to Icinga event monitoring api: #{Icinga2Client.baseurl}."
|
20
|
+
|
21
|
+
ssl_socket = Icinga2Client.events_socket('/events?queue=foreman&types=StateChange&types=AcknowledgementSet&types=AcknowledgementCleared&types=DowntimeTriggered&types=DowntimeRemoved')
|
22
|
+
|
23
|
+
logger.info 'Icinga event api monitoring started.'
|
24
|
+
|
25
|
+
while line = ssl_socket.gets
|
26
|
+
next unless line.chars.first == '{'
|
27
|
+
|
28
|
+
with_event_counter('Icinga2 Event API Monitor') do
|
29
|
+
begin
|
30
|
+
parsed = JSON.parse(line)
|
31
|
+
if @queue.size > 100_000
|
32
|
+
@queue.clear
|
33
|
+
logger.error 'Queue was full. Flushing. Events were lost.'
|
34
|
+
end
|
35
|
+
@queue.push(parsed)
|
36
|
+
rescue JSON::ParserError => e
|
37
|
+
logger.error "Icinga2 Event API Monitor: Malformed JSON: #{e.message}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
logger.info 'Icinga event api monitoring stopped.'
|
43
|
+
end
|
44
|
+
rescue Errno::ECONNREFUSED => e
|
45
|
+
logger.error "Icinga Event Stream: Connection refused. Retrying in 5 seconds. Reason: #{e.message}"
|
46
|
+
sleep 5
|
47
|
+
retry
|
48
|
+
rescue Exception => e
|
49
|
+
logger.error "Error while monitoring: #{e.message}\n#{e.backtrace.join("\n")}"
|
50
|
+
sleep 1
|
51
|
+
retry
|
52
|
+
ensure
|
53
|
+
ssl_socket.sysclose unless ssl_socket.nil?
|
54
|
+
end
|
55
|
+
|
56
|
+
def start
|
57
|
+
@thread = Thread.new { monitor }
|
58
|
+
@thread.abort_on_exception = true
|
59
|
+
@thread
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop
|
63
|
+
@thread.terminate unless @thread.nil?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
require 'rest-client'
|
4
|
+
require 'thread'
|
5
|
+
require 'socket'
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module ::Proxy::Monitoring::Icinga2
|
9
|
+
class Icinga2Client
|
10
|
+
class << self
|
11
|
+
def client(request_url)
|
12
|
+
headers = {
|
13
|
+
'Accept' => 'application/json'
|
14
|
+
}
|
15
|
+
|
16
|
+
options = {
|
17
|
+
headers: headers,
|
18
|
+
user: user,
|
19
|
+
ssl_ca_file: cacert,
|
20
|
+
verify_ssl: ssl
|
21
|
+
}
|
22
|
+
|
23
|
+
auth_options = if certificate_request?
|
24
|
+
{
|
25
|
+
ssl_client_cert: cert,
|
26
|
+
ssl_client_key: key
|
27
|
+
}
|
28
|
+
else
|
29
|
+
{
|
30
|
+
password: password
|
31
|
+
}
|
32
|
+
end
|
33
|
+
options.merge!(auth_options)
|
34
|
+
|
35
|
+
RestClient::Resource.new(
|
36
|
+
URI.encode([baseurl, request_url].join('')),
|
37
|
+
options
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def events_socket(endpoint)
|
42
|
+
uri = URI.parse([baseurl, endpoint].join(''))
|
43
|
+
socket = TCPSocket.new(uri.host, uri.port)
|
44
|
+
|
45
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
46
|
+
ssl_context.ca_file = cacert
|
47
|
+
|
48
|
+
if ssl
|
49
|
+
ssl_context.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
|
50
|
+
else
|
51
|
+
ssl_context.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
52
|
+
end
|
53
|
+
|
54
|
+
if certificate_request?
|
55
|
+
ssl_context.cert = cert
|
56
|
+
ssl_context.key = key
|
57
|
+
end
|
58
|
+
|
59
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
60
|
+
ssl_socket.sync_close = true
|
61
|
+
ssl_socket.connect
|
62
|
+
|
63
|
+
ssl_socket.write "POST #{uri.request_uri} HTTP/1.1\r\n"
|
64
|
+
ssl_socket.write "Accept: application/json\r\n"
|
65
|
+
unless certificate_request?
|
66
|
+
auth = Base64.encode64("#{user}:#{password}")
|
67
|
+
ssl_socket.write "Authorization: Basic #{auth}"
|
68
|
+
end
|
69
|
+
ssl_socket.write "\r\n"
|
70
|
+
|
71
|
+
ssl_socket
|
72
|
+
end
|
73
|
+
|
74
|
+
def get(url)
|
75
|
+
client(url).get
|
76
|
+
end
|
77
|
+
|
78
|
+
def post(url, data)
|
79
|
+
client(url).post(data)
|
80
|
+
end
|
81
|
+
|
82
|
+
def put(url)
|
83
|
+
client(url).put
|
84
|
+
end
|
85
|
+
|
86
|
+
def delete(url)
|
87
|
+
client(url).delete
|
88
|
+
end
|
89
|
+
|
90
|
+
def cert
|
91
|
+
file = Proxy::Monitoring::Icinga2::Plugin.settings.api_usercert
|
92
|
+
return unless !file.nil? && File.file?(file)
|
93
|
+
OpenSSL::X509::Certificate.new(File.read(file))
|
94
|
+
end
|
95
|
+
|
96
|
+
def key
|
97
|
+
file = Proxy::Monitoring::Icinga2::Plugin.settings.api_userkey
|
98
|
+
return unless !file.nil? && File.file?(file)
|
99
|
+
OpenSSL::PKey::RSA.new(File.read(file))
|
100
|
+
end
|
101
|
+
|
102
|
+
def cacert
|
103
|
+
Proxy::Monitoring::Icinga2::Plugin.settings.api_cacert
|
104
|
+
end
|
105
|
+
|
106
|
+
def user
|
107
|
+
Proxy::Monitoring::Icinga2::Plugin.settings.api_user
|
108
|
+
end
|
109
|
+
|
110
|
+
def password
|
111
|
+
Proxy::Monitoring::Icinga2::Plugin.settings.api_password
|
112
|
+
end
|
113
|
+
|
114
|
+
def ssl
|
115
|
+
Proxy::Monitoring::Icinga2::Plugin.settings.verify_ssl
|
116
|
+
end
|
117
|
+
|
118
|
+
def certificate_request?
|
119
|
+
cert && key
|
120
|
+
end
|
121
|
+
|
122
|
+
def baseurl
|
123
|
+
"https://#{Proxy::Monitoring::Icinga2::Plugin.settings.server}:#{Proxy::Monitoring::Icinga2::Plugin.settings.api_port}/v1"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'socket'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module ::Proxy::Monitoring::Icinga2
|
6
|
+
class Icinga2InitialImporter
|
7
|
+
include ::Proxy::Log
|
8
|
+
|
9
|
+
def initialize(queue)
|
10
|
+
@queue = queue.queue
|
11
|
+
end
|
12
|
+
|
13
|
+
def monitor
|
14
|
+
logger.debug 'Starting initial icinga import.'
|
15
|
+
|
16
|
+
around_action('Initial Host Import') do
|
17
|
+
import_hosts
|
18
|
+
end
|
19
|
+
|
20
|
+
around_action('Initial Services Import') do
|
21
|
+
import_services
|
22
|
+
end
|
23
|
+
|
24
|
+
around_action('Initial Downtimes Import') do
|
25
|
+
import_downtimes
|
26
|
+
end
|
27
|
+
|
28
|
+
logger.info 'Finished initial icinga import.'
|
29
|
+
rescue Exception => e
|
30
|
+
logger.error "Error during initial import: #{e.message}\n#{e.backtrace}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def import_hosts
|
34
|
+
results = Icinga2Client.get('/objects/hosts?attrs=name&attrs=last_check_result&attrs=acknowledgement')
|
35
|
+
results = JSON.parse(results)
|
36
|
+
results['results'].each do |result|
|
37
|
+
parsed = {
|
38
|
+
host: result['attrs']['name'],
|
39
|
+
result: result['attrs']['last_check_result']['state'],
|
40
|
+
timestamp: result['attrs']['last_check_result']['schedule_end'],
|
41
|
+
acknowledged: (result['attrs']['acknowledgement'] != 0),
|
42
|
+
initial: true,
|
43
|
+
type: '_parsed'
|
44
|
+
}
|
45
|
+
@queue.push(parsed)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def import_services
|
50
|
+
results = Icinga2Client.get('/objects/services?attrs=name&attrs=last_check_result&attrs=acknowledgement&attrs=host_name')
|
51
|
+
results = JSON.parse(results)
|
52
|
+
results['results'].each do |result|
|
53
|
+
parsed = {
|
54
|
+
host: result['attrs']['host_name'],
|
55
|
+
service: result['attrs']['name'],
|
56
|
+
result: result['attrs']['last_check_result']['state'],
|
57
|
+
timestamp: result['attrs']['last_check_result']['schedule_end'],
|
58
|
+
acknowledged: (result['attrs']['acknowledgement'] != 0),
|
59
|
+
initial: true,
|
60
|
+
type: '_parsed'
|
61
|
+
}
|
62
|
+
@queue.push(parsed)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def import_downtimes
|
67
|
+
results = Icinga2Client.get('/objects/downtimes?attrs=host_name&attrs=service_name&attrs=trigger_time')
|
68
|
+
results = JSON.parse(results)
|
69
|
+
results['results'].each do |result|
|
70
|
+
next unless result['attrs']['trigger_time'] != 0
|
71
|
+
parsed = {
|
72
|
+
host: result['attrs']['host_name'],
|
73
|
+
service: result['attrs']['service_name'],
|
74
|
+
downtime: true,
|
75
|
+
initial: true,
|
76
|
+
type: '_parsed'
|
77
|
+
}
|
78
|
+
@queue.push(parsed)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def start
|
83
|
+
@thread = Thread.new { monitor }
|
84
|
+
@thread.abort_on_exception = true
|
85
|
+
@thread
|
86
|
+
end
|
87
|
+
|
88
|
+
def stop
|
89
|
+
@thread.terminate unless @thread.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def around_action(task)
|
95
|
+
beginning_time = Time.now
|
96
|
+
logger.info "Starting Task: #{task}."
|
97
|
+
yield
|
98
|
+
end_time = Time.now
|
99
|
+
logger.info "Finished Task: #{task} in #{end_time - beginning_time} seconds."
|
100
|
+
rescue Errno::ECONNREFUSED => e
|
101
|
+
logger.error "Icinga Initial Importer: Connection refused in task #{task}. Reason: #{e.message}"
|
102
|
+
logger.error "Icinga Initial Importer: Restarting #{task} in 5 seconds."
|
103
|
+
sleep 5
|
104
|
+
retry
|
105
|
+
rescue JSON::ParserError => e
|
106
|
+
logger.error "Icinga Initial Importer: Failed to parse JSON: #{e.message}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|