icinga_result 1.0.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 +7 -0
- data/.gitignore +1 -0
- data/README.md +67 -0
- data/bin/icinga-result +50 -0
- data/icinga_result.gemspec +20 -0
- data/lib/icinga_result/check_result.rb +21 -0
- data/lib/icinga_result/client.rb +94 -0
- data/lib/icinga_result/host.rb +31 -0
- data/lib/icinga_result/service.rb +32 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6b3f8edc6cbfc3b679867e29752536699a43d51b30e0141dc02e9c660866cb47
|
4
|
+
data.tar.gz: 838553a21e4cf234e53037d8de27e3e822b4b547a67e873fa60846213af8fc13
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7ea6f742dff6c491ec246741b04f7968027597e1a3dd690327f01776060ecf0d1c8bc20c5c0bb23e3b7ff28d3df923bdbe1ec1e2ae37f1d9705371fa49addf1c
|
7
|
+
data.tar.gz: 4b87e0c120f07e5e3e1ce79c79b2020379f29fdd91989209f90f45dcd6f40baa56cfc6e12e3b0ed929ef7dce6408800c7fcc5181736e12967f79146a231bc415
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Icinga Result Client
|
2
|
+
|
3
|
+
This gem provides a library and executable to send passive check results via API to Icinga2.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Require it in your Gemfile
|
8
|
+
```bash
|
9
|
+
gem 'icinga_result'
|
10
|
+
```
|
11
|
+
|
12
|
+
or install it directly via
|
13
|
+
```bash
|
14
|
+
gem install icinga_result
|
15
|
+
```
|
16
|
+
|
17
|
+
## Configuration
|
18
|
+
|
19
|
+
To use the gem you need a configuration file with an Icinga API host and user.
|
20
|
+
|
21
|
+
```yaml
|
22
|
+
---
|
23
|
+
username: your icinga username
|
24
|
+
password: your super secred icinga password
|
25
|
+
host: icinga.example.com
|
26
|
+
port: 5665
|
27
|
+
always_send_host_alive: false
|
28
|
+
```
|
29
|
+
|
30
|
+
"always_send_host_alive" sends the host alive signal every time a service result is delivered.
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
### Command line client
|
35
|
+
|
36
|
+
You can deliver status results simple by calling `icinga-result`. While it is sufficient to supply "name", "status" and "message" when the service exists, you should probably always give as much information as you can. The first time a check result is sent, it will probably fail (since the service does not exist yet). But it will automatically be created and when the check is run a second time, the result will be sent.
|
37
|
+
|
38
|
+
```
|
39
|
+
$ icinga-result --help
|
40
|
+
Usage: --help [options]
|
41
|
+
--service [NAME] Service name
|
42
|
+
--interval [INTERVAL] Server check interval
|
43
|
+
--description [DESCRIPTION] Service description
|
44
|
+
--status [STATUS] Status code for the check
|
45
|
+
--message [MESSAGE] Status message for the check
|
46
|
+
--performance-data [DATA] Performance data for the check
|
47
|
+
--host-alive Send host alive signal
|
48
|
+
```
|
49
|
+
|
50
|
+
### Library
|
51
|
+
|
52
|
+
When you implement your check in Ruby, you can call the library directly. A simple script might look like this:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
require 'icinga_result/client'
|
56
|
+
|
57
|
+
client = IcingaResult::Client.new
|
58
|
+
service = IcingaResult::Service.new('demo', interval: 3600, description: 'This is a demo check')
|
59
|
+
|
60
|
+
if my_special_check
|
61
|
+
result = IcingaResult::CheckResult.new(0, 'Ok')
|
62
|
+
else
|
63
|
+
result = IcingaResult::CheckResult.new(2, 'Special is borken!')
|
64
|
+
end
|
65
|
+
|
66
|
+
client.send(service, result)
|
67
|
+
```
|
data/bin/icinga-result
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'icinga_result/client'
|
5
|
+
|
6
|
+
@options = {
|
7
|
+
service: '',
|
8
|
+
interval: 3600,
|
9
|
+
description: '',
|
10
|
+
status: 0,
|
11
|
+
message: '',
|
12
|
+
performance_data: '',
|
13
|
+
host_alive: false
|
14
|
+
}
|
15
|
+
|
16
|
+
OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: #{ARGV[0]} [options]"
|
18
|
+
|
19
|
+
opts.on('--service [NAME]', 'Service name') do |name|
|
20
|
+
@options[:service] = name
|
21
|
+
end
|
22
|
+
opts.on('--interval [INTERVAL]', 'Server check interval') do |interval|
|
23
|
+
@options[:interval] = interval
|
24
|
+
end
|
25
|
+
opts.on('--description [DESCRIPTION]', 'Service description') do |description|
|
26
|
+
@options[:description] = description
|
27
|
+
end
|
28
|
+
opts.on('--status [STATUS]', 'Status code for the check') do |status|
|
29
|
+
@options[:status] = status
|
30
|
+
end
|
31
|
+
opts.on('--message [MESSAGE]', 'Status message for the check') do |message|
|
32
|
+
@options[:message] = message
|
33
|
+
end
|
34
|
+
opts.on('--performance-data [DATA]', 'Performance data for the check') do |data|
|
35
|
+
@options[:performance_data] = data
|
36
|
+
end
|
37
|
+
opts.on('--host-alive', 'Send host alive signal') do
|
38
|
+
@options[:host_alive] = true
|
39
|
+
end
|
40
|
+
end.parse!
|
41
|
+
|
42
|
+
client = IcingaResult::Client.new
|
43
|
+
|
44
|
+
client.send_host_alive if @options[:host_alive]
|
45
|
+
|
46
|
+
unless @options[:service].empty?
|
47
|
+
service = IcingaResult::Service.new(@options[:service], interval: @options[:interval], description: @options[:description])
|
48
|
+
result = IcingaResult::CheckResult.new(@options[:status], @status[:description])
|
49
|
+
client.send(service, result)
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'icinga_result'
|
6
|
+
spec.version = '1.0.0'
|
7
|
+
spec.authors = ['Gerrit Visscher']
|
8
|
+
spec.email = ['gerrit@visscher.de']
|
9
|
+
spec.summary = 'A library to send passive check results to icinga via the API'
|
10
|
+
spec.description = 'This library send checks result to Icinga2 via the http api. It provides an executable to send result from shell scripts'
|
11
|
+
spec.homepage = ''
|
12
|
+
spec.license = 'MIT'
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ['lib']
|
18
|
+
|
19
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module IcingaResult
|
2
|
+
# Contains the result of a check
|
3
|
+
class CheckResult
|
4
|
+
attr_accessor :status, :message, :performance_data
|
5
|
+
|
6
|
+
def initialize(status, message, performance_data = '')
|
7
|
+
@status = status
|
8
|
+
@message = message
|
9
|
+
@performance_data = performance_data
|
10
|
+
end
|
11
|
+
|
12
|
+
def data
|
13
|
+
data = {
|
14
|
+
'exit_status': @status,
|
15
|
+
'plugin_output': @message
|
16
|
+
}
|
17
|
+
data['performance_data'] = @performance_data if @performance_data && !@performance_data.empty?
|
18
|
+
data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require 'icinga_result/host'
|
6
|
+
require 'icinga_result/service'
|
7
|
+
require 'icinga_result/check_result'
|
8
|
+
|
9
|
+
module IcingaResult
|
10
|
+
# The Icinga2 API client
|
11
|
+
class Client
|
12
|
+
CONFIG_FILE = "#{ENV['HOME']}/.icinga_result.config.yml".freeze
|
13
|
+
|
14
|
+
attr_reader :username, :password, :host, :port
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
load_config
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_config
|
21
|
+
File.open(CONFIG_FILE, 'r') do |file|
|
22
|
+
data = YAML.safe_load(file.read)
|
23
|
+
@username = data['username']
|
24
|
+
@password = data['password']
|
25
|
+
@host = data['host']
|
26
|
+
@port = data['port']
|
27
|
+
@always_send = data['always_send_host_alive']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def send(service, check_result)
|
32
|
+
host = Host.new
|
33
|
+
send_result(host, service, check_result)
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_result(host, service, check_result)
|
37
|
+
response = api_post("/actions/process-check-result?service=#{host.name}!#{service.name}", check_result.data)
|
38
|
+
register_service(host, service) if response.code.to_i == 404
|
39
|
+
send_host_alive(host)
|
40
|
+
|
41
|
+
handle_errors(response)
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_host_alive(host = Host.new)
|
45
|
+
path = "/actions/process-check-result?host=#{host.name}"
|
46
|
+
data = { 'exit_status' => 0, 'plugin_output' => 'Host alive' }
|
47
|
+
response = api_post(path, data)
|
48
|
+
register_host(host) if response.code.to_i == 404
|
49
|
+
handle_errors(response)
|
50
|
+
response
|
51
|
+
end
|
52
|
+
|
53
|
+
def register_host(host)
|
54
|
+
response = api_put("/objects/hosts/#{host.name}", host.data)
|
55
|
+
handle_errors(response)
|
56
|
+
response
|
57
|
+
end
|
58
|
+
|
59
|
+
def register_service(host, service)
|
60
|
+
response = api_put("/objects/services/#{host.name}!#{service.name}", service.data)
|
61
|
+
register_host(host) if response.code.to_i == 404
|
62
|
+
handle_errors(response)
|
63
|
+
response
|
64
|
+
end
|
65
|
+
|
66
|
+
def handle_errors(response)
|
67
|
+
return if response.code.to_i >= 200 && response.code.to_i < 299
|
68
|
+
|
69
|
+
raise "Cannot send results to Icinga server: #{response.code} - #{response.message}: #{response.body}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def api_post(path, data)
|
73
|
+
http = Net::HTTP.new(@host, @port)
|
74
|
+
http.use_ssl = true
|
75
|
+
request = Net::HTTP::Post.new("/v1#{path}", {})
|
76
|
+
request.basic_auth @username, @password
|
77
|
+
request['Accept'] = 'application/json'
|
78
|
+
request.body = data.to_json
|
79
|
+
puts "Sending POST '#{request.body}' to /v1#{path}"
|
80
|
+
http.request(request)
|
81
|
+
end
|
82
|
+
|
83
|
+
def api_put(path, data)
|
84
|
+
http = Net::HTTP.new(@host, @port)
|
85
|
+
http.use_ssl = true
|
86
|
+
request = Net::HTTP::Put.new("/v1#{path}", {})
|
87
|
+
request['Accept'] = 'application/json'
|
88
|
+
request.basic_auth @username, @password
|
89
|
+
request.body = data.to_json
|
90
|
+
puts "Sending PUT '#{request.body}' to /v1#{path}"
|
91
|
+
http.request(request)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module IcingaResult
|
2
|
+
# Represents the current host (client)
|
3
|
+
class Host
|
4
|
+
DESCRIPTION_FILE = '/etc/description'.freeze
|
5
|
+
|
6
|
+
def name
|
7
|
+
@name ||= `hostname -f`.strip
|
8
|
+
end
|
9
|
+
|
10
|
+
def description
|
11
|
+
@description ||= read_description
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_description
|
15
|
+
return '' unless File.exist?(DESCRIPTION_FILE)
|
16
|
+
|
17
|
+
File.read(DESCRIPTION_FILE)
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
{
|
22
|
+
'templates': ['generic-host'],
|
23
|
+
'attrs': {
|
24
|
+
'check_command': 'passive',
|
25
|
+
'enable_active_checks': true,
|
26
|
+
'vars.description' => description
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module IcingaResult
|
2
|
+
# Represents an Icinga2 service object
|
3
|
+
class Service
|
4
|
+
attr_accessor :name, :interval, :description, :groups
|
5
|
+
|
6
|
+
DEFAULT_OPTONS = { interval: 3600, description: '', groups: [] }.freeze
|
7
|
+
|
8
|
+
def initialize(name, options = DEFAULT_OPTONS)
|
9
|
+
@name = name
|
10
|
+
@interval = options[:interval] || DEFAULT_OPTONS[:interval]
|
11
|
+
@description = options[:description] || DEFAULT_OPTONS[:description]
|
12
|
+
@groups = options[:groups] || DEFAULT_OPTONS[:groups]
|
13
|
+
end
|
14
|
+
|
15
|
+
def timeout
|
16
|
+
3 * @interval + 120
|
17
|
+
end
|
18
|
+
|
19
|
+
def data
|
20
|
+
{
|
21
|
+
'templates' => ['generic-service'],
|
22
|
+
'attrs' => {
|
23
|
+
'check_command' => 'passive',
|
24
|
+
'enable_active_checks' => true,
|
25
|
+
'check_interval' => timeout,
|
26
|
+
'vars.description' => @description,
|
27
|
+
'groups' => @groups
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: icinga_result
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerrit Visscher
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
description: This library send checks result to Icinga2 via the http api. It provides
|
28
|
+
an executable to send result from shell scripts
|
29
|
+
email:
|
30
|
+
- gerrit@visscher.de
|
31
|
+
executables:
|
32
|
+
- icinga-result
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- ".gitignore"
|
37
|
+
- README.md
|
38
|
+
- bin/icinga-result
|
39
|
+
- icinga_result.gemspec
|
40
|
+
- lib/icinga_result/check_result.rb
|
41
|
+
- lib/icinga_result/client.rb
|
42
|
+
- lib/icinga_result/host.rb
|
43
|
+
- lib/icinga_result/service.rb
|
44
|
+
homepage: ''
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubygems_version: 3.0.3
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: A library to send passive check results to icinga via the API
|
67
|
+
test_files: []
|