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.
@@ -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
@@ -0,0 +1 @@
1
+ *.gem
@@ -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
+ ```
@@ -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: []