├── .gitignore ├── .rspec ├── .rubocop.yml ├── .travis.yml ├── AUTHORS ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── config.reek ├── doc ├── downtimes.md ├── examples ├── hostgroups.md ├── hosts.md ├── notifications.md ├── servicegroups.md ├── services.md ├── statistics.md ├── usergroups.md └── users.md ├── examples ├── _blank.rb ├── cert-manager.sh ├── config.rb ├── downtimes.rb ├── hostgroups.rb ├── hosts.rb ├── informations.rb ├── notifications.rb ├── servicegroups.rb ├── services.rb ├── statistics.rb ├── test.rb ├── usergroups.rb └── users.rb ├── icinga2.gemspec ├── lib ├── icinga2.rb ├── icinga2 │ ├── actions.rb │ ├── client.rb │ ├── configuration_management.rb │ ├── converts.rb │ ├── downtimes.rb │ ├── hostgroups.rb │ ├── hosts.rb │ ├── network.rb │ ├── notifications.rb │ ├── servicegroups.rb │ ├── services.rb │ ├── statistics.rb │ ├── tools.rb │ ├── usergroups.rb │ ├── users.rb │ ├── validator.rb │ └── version.rb ├── logging.rb └── monkey_patches.rb └── spec ├── icinga2_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | 19 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.0 3 | 4 | AllCops: 5 | Exclude: 6 | - examples/* 7 | - spec/* 8 | 9 | # Disables "Use nested module/class definitions instead of compact style" warning 10 | ClassAndModuleChildren: 11 | Enabled: false 12 | 13 | # Increases "Class definition is too long" warning from 100 to 200 14 | Metrics/ClassLength: 15 | Max: 200 16 | 17 | # Increases "Method has too many lines" warning from 10 to 75 18 | Metrics/MethodLength: 19 | Max: 75 20 | 21 | # Increases "Module has too many lines" warning from 100 to 300 22 | Metrics/ModuleLength: 23 | Max: 300 24 | 25 | # Increases "Assignment Branch Condition size" warning from 15 to 80 26 | Metrics/AbcSize: 27 | Max: 80 28 | 29 | # Increases "Block has too many lines" warning from 25 to 190 30 | Metrics/BlockLength: 31 | Max: 190 32 | 33 | # Disables "Missing top-level class documentation comment" warning 34 | Documentation: 35 | Enabled: false 36 | 37 | # Increases "Line is too long" warning from 80 tp 200 38 | Metrics/LineLength: 39 | Max: 200 40 | Enabled: true 41 | 42 | CyclomaticComplexity: 43 | Enabled: false 44 | 45 | PerceivedComplexity: 46 | Enabled: false 47 | 48 | Style/Encoding: 49 | Enabled: false 50 | 51 | Style/RaiseArgs: 52 | EnforcedStyle: compact 53 | 54 | Layout: 55 | Enabled: False 56 | 57 | RescueWithoutErrorClass: 58 | Enabled: False 59 | 60 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # .travis.yml 2 | language: ruby 3 | 4 | sudo: required 5 | bundler_args: --retry=3 --jobs=3 6 | 7 | rvm: 8 | - 2.0 9 | - 2.1 10 | - 2.2 11 | - 2.3 12 | - 2.4 13 | - 2.5 14 | 15 | services: 16 | - docker 17 | 18 | before_install: 19 | - gem install bundler 20 | - gem update bundler 21 | - docker pull bodsch/docker-icinga2:2.8.1-master-r3 22 | - | 23 | docker run \ 24 | --rm \ 25 | --detach \ 26 | --publish=5665:5665 \ 27 | --env ICINGA_MASTER=icinga2 \ 28 | --env ICINGA_CLUSTER=true \ 29 | --env ICINGA_API_USERS=root:icinga \ 30 | --env DEMO_DATA=true \ 31 | --hostname=icinga2 \ 32 | bodsch/docker-icinga2:2.8.1-master-r3 33 | - sleep 10s 34 | - | 35 | docker run \ 36 | --rm \ 37 | --detach \ 38 | --env ICINGA2_MASTER=icinga2 \ 39 | --env ICINGA2_PARENT=icinga2 \ 40 | --env CERT_SERVICE_BA_USER=admin \ 41 | --env CERT_SERVICE_BA_PASSWORD=admin \ 42 | --env CERT_SERVICE_API_USER=root \ 43 | --env CERT_SERVICE_API_PASSWORD=icinga \ 44 | --env CERT_SERVICE_SERVER=icinga2 \ 45 | --env CERT_SERVICE_PORT=8080 \ 46 | --env CERT_SERVICE_PATH=/ \ 47 | --hostname=icinga2-satellite \ 48 | bodsch/docker-icinga2:2.8.1-satellite-r3 49 | - docker ps 50 | - sleep 25s 51 | 52 | script: bundle exec rspec spec 53 | 54 | fast_finish: true 55 | 56 | gemfile: 57 | - Gemfile 58 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Authors ordered by first contribution. 2 | 3 | Bodo Schulz - https://github.com/bodsch (bodo@boone-schulz.de) 4 | Andrei Skopenko - https://github.com/scopenco (andrei@skopenko.net) 5 | Shuliyey - https://github.com/Shuliyey () 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | If you want to contribute to a project and make it better, your help is very welcome. Contributing is also a great way to learn more about social coding on Github, new technologies and and their ecosystems and how to make constructive, helpful bug reports, feature requests and the noblest of all contributions: a good, clean pull request. 4 | 5 | ### How to make a clean pull request 6 | 7 | Look for a project's contribution instructions. If there are any, follow them. 8 | 9 | - Create a personal fork of the project on Github. 10 | - Clone the fork on your local machine. Your remote repo on Github is called `origin`. 11 | - Add the original repository as a remote called `upstream`. 12 | - If you created your fork a while ago be sure to pull upstream changes into your local repository. 13 | - Create a new branch to work on! Branch from `develop` if it exists, else from `master`. 14 | - Implement/fix your feature, comment your code. 15 | - Follow the code style of the project, including indentation. 16 | - If the project has tests run them! 17 | - Write or adapt tests as needed. 18 | - Add or change the documentation as needed. 19 | - Squash your commits into a single commit with git's [interactive rebase](https://help.github.com/articles/interactive-rebase). Create a new branch if necessary. 20 | - Push your branch to your fork on Github, the remote `origin`. 21 | - From your fork open a pull request in the correct branch. Target the project's `develop` branch if there is one, else go for `master`! 22 | - If the maintainer requests further changes just push them to your branch. The PR will be updated automatically. 23 | - Once the pull request is approved and merged you can pull the changes from `upstream` to your local repo and delete 24 | your extra branch(es). 25 | 26 | And last but not least: Always write your commit messages in the present tense. Your commit message should describe what the commit, when applied, does to the code – not what you did to the code. 27 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in icinga2.gemspec 4 | group :tools do 5 | gem 'rake' 6 | gem 'rake-notes' 7 | gem 'rspec' 8 | gem 'rspec_junit_formatter' 9 | gem 'rubocop' 10 | gem 'rubocop-checkstyle_formatter' 11 | gem 'rubycritic' 12 | end 13 | 14 | gemspec 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ruby-icinga2 2 | 3 | An enhanced ruby gem to communicate with Icinga2 API 4 | 5 | [![Gem Version](https://badge.fury.io/rb/icinga2.svg)](https://badge.fury.io/rb/icinga2) 6 | 7 | [![Build Status](https://travis-ci.org/bodsch/ruby-icinga2.svg)][travis] 8 | [![Gem Downloads](http://ruby-gem-downloads-badge.herokuapp.com/icinga2)][gem-downloads] 9 | [![total Downloads](http://ruby-gem-downloads-badge.herokuapp.com/icinga2?type=total&metric=true&label=downloads-total)][gem-downloads] 10 | [![Dependency Status](https://gemnasium.com/badges/github.com/bodsch/ruby-icinga2.svg)][gemnasium] 11 | 12 | 13 | [travis]: https://travis-ci.org/bodsch/ruby-icinga2 14 | [gem-downloads]: http://ruby-gem-downloads-badge.herokuapp.com/icinga2 15 | [gemnasium]: https://gemnasium.com/github.com/bodsch/ruby-icinga2 16 | 17 | ## Requirements 18 | 19 | * ruby version => 2.0 20 | * rest-client ~> 2.0 21 | * json ~> 2.1 22 | * openssl ~> 2.0 (only with ruby >= 2.3) 23 | * ruby_dig (only with ruby < 2.3) 24 | 25 | ## Install 26 | 27 | gem install icinga2 28 | 29 | ## Usage 30 | 31 | create an instance 32 | 33 | require 'icinga2' 34 | 35 | config = { 36 | icinga: { 37 | host: icinga_host, 38 | api: { 39 | port: icinga_api_port, 40 | username: icinga_api_user, 41 | password: icinga_api_pass 42 | } 43 | } 44 | } 45 | 46 | @icinga = Icinga2::Client.new( config ) 47 | 48 | ### Use the examples 49 | 50 | You can use the [Icinga Vagrant-Box](https://github.com/Icinga/icinga-vagrant) from the Icinga Team or 51 | my own [Docker Container](https://hub.docker.com/r/bodsch/docker-icinga2/) as Datasource. 52 | 53 | **Remember** Change the exported Environment Variables to your choosed Datasource! 54 | 55 | you can find many examples under the directory `examples`: 56 | 57 | $ export ICINGA_HOST=localhost ; export ICINGA_API_USER=root ; export ICINGA_API_PASSWORD=icinga 58 | $ ruby examples/informations.rb 59 | $ ruby examples/statistics.rb 60 | $ ruby examples/users.rb 61 | 62 | and so on. 63 | 64 | ### Test via CLI 65 | 66 | $ irb 67 | irb(main):001:0> require 'icinga2' 68 | => true 69 | irb(main):002:0> config = { icinga: { host: 'localhost', api: { username: 'root', password: 'icinga' } } } 70 | => {:icinga=>{:host=>"localhost", :api=>{:username=>"root", :password=>"icinga"}}} 71 | irb(main):003:0> i = Icinga2::Client.new( config ) 72 | irb(main):004:0> i.available? 73 | => true 74 | irb(main):005:0> 75 | 76 | ## Create a own gem file 77 | 78 | $ gem build icinga2.gemspec 79 | Successfully built RubyGem 80 | Name: icinga2 81 | Version: 0.9.2.7 82 | File: icinga2-0.9.2.7.gem 83 | 84 | ## Install local gem 85 | 86 | $ gem install icinga2 87 | Successfully installed icinga2-0.9.2.7 88 | 1 gem installed 89 | 90 | 91 | ## Status 92 | 93 | supports the following API Calls: 94 | 95 | - [Users](doc/users.md) 96 | * [add user](doc/users.md#add-user) 97 | * [delete user](doc/users.md#delete-dser) 98 | * [list users](doc/users.md#list-users) 99 | * [check if user exists](doc/users.md#user-exists) 100 | 101 | - [Usergroups](doc/usergroups.md) 102 | * [add usergroup](doc/usergroups.md#add-usergroup) 103 | * [delete usergroup](doc/usergroups.md#delete-usergroup) 104 | * [list usergroups](doc/usergroups.md#list-usergroups) 105 | * [check if usergroup exists](doc/usergroups.md#usergroup-exists) 106 | 107 | - [Hosts](doc/hosts.md) 108 | * [add host](doc/hosts.md#add-host) 109 | * [delete host](doc/hosts.md#delete-host) 110 | * [modify host](doc/hosts.md#modify-host) 111 | * [list hosts](doc/hosts.md#list-hosts) 112 | * [check if host exists](doc/hosts.md#host-exists) 113 | * [list host objects](doc/hosts.md#list-host-objects) 114 | * [count of hosts with problems](doc/hosts.md#count-hosts-with-problems) 115 | * [list of hosts with problems](doc/hosts.md#list-hosts-with-problems) 116 | * [count of all hosts](doc/hosts.md#count-all-hosts) 117 | * [count hosts with problems](doc/hosts.md#count-host-problems) 118 | * calculate host severity (protected) 119 | 120 | - [Hostgroups](doc/hostgroups.md) 121 | * [add hostgroup](doc/hostgroups.md#add-usergroup) 122 | * [delete hostgroup](doc/hostgroups.md#delete-usergroup) 123 | * [list hostgroups](doc/hostgroups.md#list-usergroups) 124 | * [check if hostgroup exists](doc/hostgroups.md#usergroup-exists) 125 | 126 | - [Services](doc/services.md) 127 | * [add service](doc/services.md#add-service) 128 | * [delete service](doc/services.md#delete-service) 129 | * [list unhandled services](doc/services.md#unhandled-services) 130 | * [list services](doc/services.md#list-services) 131 | * [check if service exists](doc/services.md#service-exists) 132 | * [list service objects](doc/services.md#list-service-objects) 133 | * [count services with problems](doc/services.md#count-services-with-problems) 134 | * [list of services with problems](doc/services.md#list-services-with-problems) 135 | * [count of all services](doc/services.md#count-all-services) 136 | * [count all services with handled problems](doc/services.md#count-all-services-handled) 137 | * calculate service severity (protected) 138 | 139 | - [Servicegroups](doc/servicegroups.md) 140 | * [add servicegroup](doc/servicegroups.md#add-servicegroup) 141 | * [delete servicegroup](doc/servicegroups.md#delete-servicegroup) 142 | * [list servicegroups](doc/servicegroups.md#list-servicegroup) 143 | * [check if servicegroup exists](doc/servicegroups.md#servicegroup-exists) 144 | 145 | - [Downtimes](doc/downtimes.md) 146 | * [add downtime](doc/downtimes.md#add-downtime) 147 | * [remove downtime](doc/downtimes.md#remove-downtime) 148 | * [list downtimes](doc/downtimes.md#list-downtimes) 149 | 150 | - [Notifications](doc/notifications.md) 151 | * [enable host notifications](doc/notifications.md#enable-host-notification) 152 | * [disable host notifications](doc/notifications.md#disable-host-notification) 153 | * [enable service notifications](doc/notifications.md#enable-service-notification) 154 | * [disable service notifications](doc/notifications.md#disable-service-notification) 155 | * [enable hostgroup notifications](doc/notifications.md#enable-hostgroup-notification) 156 | * [disable hostgroup notifications](doc/notifications.md#disable-hostgroup-notification) 157 | * [list all notifications](doc/notifications.md#list-notifications) 158 | * host notification (protected) 159 | * hostgroup notification (protected) 160 | * service notification (protected) 161 | 162 | - [Statistics](doc/statistics.md) 163 | * [statistic data for latence and execution time](doc/statistics.md#stats-avg) 164 | * [statistic data for interval data](doc/statistics.md#stats-interval) 165 | * [statistic data for services](doc/statistics.md#stats-services) 166 | * [statistic data for hosts](doc/statistics.md#stats-hosts) 167 | * [queue statistics from the api](doc/statistics.md#stats-work-queue) 168 | 169 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | 2 | require 'bundler/gem_tasks' 3 | require 'rspec/core/rake_task' 4 | require 'bundler/gem_tasks' 5 | require 'rubocop/rake_task' 6 | require 'rake/testtask' 7 | 8 | # Default directory to look in is `/specs` 9 | # Run with `rake spec` 10 | RSpec::Core::RakeTask.new(:spec) do |task| 11 | task.rspec_opts = ['--color'] 12 | end 13 | 14 | desc 'Run all style checks' 15 | task style: ['style:ruby'] 16 | 17 | desc 'Run all regular tasks' 18 | task default: :spec 19 | 20 | desc 'Run all tests' 21 | task test: ['test'] 22 | 23 | namespace :style do 24 | desc 'Run Ruby style checks' 25 | RuboCop::RakeTask.new(:ruby) do |task| 26 | task.patterns = ['**/*.rb'] 27 | # don't abort rake on failure 28 | task.fail_on_error = false 29 | end 30 | end 31 | 32 | 33 | Rake::TestTask.new('test:all') do |t| 34 | t.libs = %w[lib spec] 35 | t.warning = true 36 | t.test_files = FileList['spec/**/*_spec.rb'] 37 | end 38 | -------------------------------------------------------------------------------- /config.reek: -------------------------------------------------------------------------------- 1 | --- 2 | UncommunicativeModuleName: 3 | accept: 4 | - Icinga2 5 | 6 | TooManyConstants: 7 | max_constants: 7 8 | 9 | TooManyStatements: 10 | enabled: true 11 | exclude: 12 | - initialize 13 | max_statements: 30 14 | 15 | LongParameterList: 16 | enabled: true 17 | max_params: 4 18 | 19 | UncommunicativeVariableName: 20 | enabled: false 21 | -------------------------------------------------------------------------------- /doc/downtimes.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Downtimes 2 | 3 | 4 | ## add a downtime 5 | add_downtime( params ) 6 | 7 | ### Example 8 | 9 | param = { 10 | name: 'test', 11 | type: 'service', 12 | host: 'icinga2', 13 | comment: 'test downtime', 14 | author: 'icingaadmin', 15 | start_time: Time.now.to_i, 16 | end_time: Time.now.to_i + 20 17 | } 18 | @icinga.add_downtime( param ) 19 | 20 | 21 | ## remove a downtime 22 | remove_downtime( params ) 23 | 24 | ### Example 25 | 26 | remove all downtimes from the user `icingaadmin` and the comment `test downtime` 27 | 28 | ```bash 29 | param = { 30 | comment: 'test downtime', 31 | author: 'icingaadmin' 32 | } 33 | @icinga.remove_downtime(param) 34 | ``` 35 | 36 | remove a downtime from a host but not the services filtered by the author name. 37 | This example uses filter variables explained in the 38 | [advanced filters](https://github.com/Icinga/icinga2/blob/master/doc/12-icinga2-api.md#icinga2-api-advanced-filters) 39 | chapter from the official API documentation. 40 | 41 | ```bash 42 | param = { 43 | filter: '"host.name == filterHost && !service && downtime.author == filterAuthor"', 44 | filter_vars: { filterHost: 'c1-mysql-1', filterAuthor: 'icingaadmin' } 45 | ) 46 | @icinga.remove_downtime(param) 47 | ``` 48 | 49 | remove a downtime for service `ping4` and host `c1-mysql-1` 50 | 51 | ```bash 52 | param = { 53 | host_name: 'c1-mysql-1', 54 | service_name: 'ping4' 55 | } 56 | @icinga.remove_downtime(param) 57 | ``` 58 | 59 | 60 | ## list all downtimes 61 | downtimes 62 | 63 | ### Example 64 | @icinga.downtimes 65 | -------------------------------------------------------------------------------- /doc/examples: -------------------------------------------------------------------------------- 1 | 2 | To add hostgroup : 3 | 4 | curl -k -s -u icingaadmin:icinga 'https://localhost:5665/v1/objects/hostgroups/testgrp' \ 5 | -X PUT -d '{ "attrs": { "name" : "testgrp" ,"display_name" : "testgrp" , "state_loaded" :true }}' 6 | 7 | To add host : 8 | 9 | curl -k -s -u icingaadmin:icinga 'https://localhost:5665/v1/objects/hosts/8.8.8.8' \ 10 | -X PUT -d '{ "templates": [ "generic-host" ], "attrs": { "address": "8.8.8.8" , "groups" : [ "testgrp" ]} }' 11 | 12 | 13 | https://localhost:5665/v1/objects/users 14 | https://localhost:5665/v1/objects/usergroups 15 | 16 | 17 | https://localhost:5665/v1/objects/hostgroups 18 | https://localhost:5665/v1/objects/servicegroups 19 | 20 | https://localhost:5665/v1/objects/hosts 21 | https://localhost:5665/v1/objects/services 22 | 23 | # list service from host 24 | curl -k -u root:icinga -H 'Accept: application/json' -X GET 'https://localhost:5665/v1/objects/services/pandora-17-01!Runlevel-master-live-server' 25 | 26 | 27 | https://localhost:5665/v1/objects/notifications 28 | 29 | # get usergroups: 30 | curl -k -s -u root:icinga -H 'Accept: application/json' -X GET 'https://localhost:5665/v1/objects/usergroups' 31 | 32 | # add usergroup: 33 | curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/usergroups/foo' --data '{ "attrs": {"display_name": "Foo Bar" } }' 34 | 35 | # delete usergroup: 36 | curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: DELETE' -X POST 'https://localhost:5665/v1/objects/usergroups/foo' 37 | 38 | 39 | # delete user: 40 | curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: DELETE' -X POST 'https://localhost:5665/v1/objects/users/foo' 41 | 42 | # add user: 43 | curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/users/foo' --data '{ "attrs": {"display_name": "Foo Bar", "email": "foo.bar@coremedia.com","enable_notifications": false, "groups": [ "coreme 44 | dia" ] } }' 45 | 46 | 47 | 48 | # add notification 49 | curl -k -s -u root:icinga -H 'Accept: application/json' \ 50 | -X PUT 'https://localhost:5665/v1/objects/notifications/debian7.example.com!jabber' -d '{ 51 | "attrs": { 52 | "command":"mail-service-notification", 53 | "service_name":"apt", 54 | "user_groups": ["icingaadmins"] } }' 55 | 56 | 57 | # delete notification 58 | curl -k -s -u root:icinga -H 'Accept: application/json' \ 59 | -H 'X-HTTP-Method-Override: DELETE' \ 60 | -X POST 'https://localhost:5665/v1/objects/notifications/debian7.example.com!apt!jabber?cascade=1' 61 | 62 | 63 | 64 | 65 | 66 | # enable notification für host: 67 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/hosts/api_dummy_host_1' --data '{ "attrs": { "enable_notifications": true } }' 68 | 69 | # disable notification für host: 70 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/hosts/api_dummy_host_1' --data '{ "attrs": { "enable_notifications": false } }' 71 | 72 | # enable notification für service x von host: 73 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/services' --data '{ "filter": "host.name==\"api_dummy_host_1\"", "attrs": { "enable_notifications": true } }' 74 | 75 | # disable notification für service x von host: 76 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/services' --data '{ "filter": "host.name==\"api_dummy_host_1\"", "attrs": { "enable_notifications": false } }' 77 | 78 | # enable notification für hostgroup: 79 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/services' --data '{ "filter": "\"api_dummy_hostgroup\" in host.groups", "attrs": { "enable_notifications": true } }' 80 | 81 | # disable notification für hostgroup: 82 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/services' --data '{ "filter": "\"api_dummy_hostgroup\" in host.groups", "attrs": { "enable_notifications": false } }' 83 | 84 | 85 | # get downtimes 86 | curl -k -s -u root:icinga -H 'Accept: application/json' -X GET 'https://localhost:5665/v1/objects/downtimes' 87 | 88 | # delete named downtime 89 | curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: DELETE' -X POST 'https://localhost:5665/v1/objects/downtimes/icinga2-master!load!icinga2-master-1496045418-0' 90 | 91 | 92 | # schedule downtime for a host 93 | 94 | # current_time=$(date +%s) 95 | # 1449057010 96 | # current_time_add_30_second=$(date +%s --date="+30 seconds") 97 | # 1449057040 98 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/schedule-downtime' \ 99 | --data '{ "type": "Host", "filter": "host.name==\"api_dummy_host_1\"", "start_time": 1449057685, "end_time": 1449057715, "author": "api_user", "comment": "api_comment", "fixed": true, "duration": 30 }' 100 | 101 | # schedule downtime for all services of a host - change the timestamps accordingly 102 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/schedule-downtime' \ 103 | --data '{ "type": "Service", "filter": "host.name==\"api_dummy_host_1\"", "start_time": 1449064981, "end_time": 1449065129, "author": "api_user", "comment": "api_comment", "fixed": true, "duration": 30 }' 104 | 105 | 106 | # schedule downtime for all hosts and services in a hostgroup - change the timestamps accordingly 107 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/schedule-downtime' \ 108 | --data '{ "type": "Host", "filter": "\"api_dummy_hostgroup\" in host.groups", "start_time": 1449065680, "end_time": 1449065823, "author": "api_user", "comment": "api_comment", "duration": 120, "fixed": true, "duration": 30 }' 109 | 110 | curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/schedule-downtime' \ 111 | --data '{ "type": "Service", "filter": "\"api_dummy_hostgroup\" in host.groups)", "start_time": 1449065680, "end_time": 1449065823, "author": "api_user", "comment": "api_comment", "duration": 120, "fixed": true, "duration": 30 }' 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /doc/hostgroups.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Hostgroups 2 | 3 | 4 | ## add a hostgroup 5 | add_hostgroup( params ) 6 | 7 | ### Example 8 | @icinga.add_hostgroup(host_group: 'foo', display_name: 'FOO') 9 | 10 | 11 | ## delete a hostgroup 12 | delete_hostgroup( params ) 13 | 14 | ### Example 15 | @icinga.delete_hostgroup(host_group: 'foo') 16 | 17 | 18 | ## list hostgroups 19 | 20 | ### list named hostgroup 21 | hostgroups( params ) 22 | 23 | #### Example 24 | @icinga.hostgroups(host_group: 'linux-servers') 25 | 26 | ### list all hostgroups 27 | hostgroups 28 | 29 | ### Example 30 | @icinga.hostgroups 31 | 32 | 33 | ## check if the hostgroup exists 34 | exists_hostgroup?( hostgroup ) 35 | 36 | ### Example 37 | @icinga.exists_hostgroup?('linux-servers') 38 | -------------------------------------------------------------------------------- /doc/hosts.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Hosts 2 | 3 | ## add a host 4 | add_host( params ) 5 | 6 | ### Example 7 | param = { 8 | name: 'foo', 9 | address: 'foo.bar.com', 10 | display_name: 'test node', 11 | max_check_attempts: 5, 12 | notes: 'test node', 13 | vars: { 14 | description: 'host foo', 15 | os: 'Linux', 16 | partitions: { 17 | '/' => { 18 | crit: '95%', 19 | warn: '90%' 20 | } 21 | } 22 | } 23 | } 24 | @icinga.add_host(param) 25 | 26 | 27 | ## delete a host 28 | delete_host( params ) 29 | 30 | ### Example 31 | @icinga.delete_host(name: 'foo') 32 | 33 | 34 | ## modify a host 35 | modify_host( params ) 36 | 37 | ### Example 38 | 39 | 40 | param = { 41 | name: 'foo', 42 | address: 'foo.bar.com', 43 | display_name: 'Host for an example Problem', 44 | max_check_attempts: 10, 45 | } 46 | 47 | or 48 | 49 | param = { 50 | name: 'foo', 51 | address: 'foo.bar.com', 52 | notes: 'an demonstration object', 53 | vars: { 54 | description: 'schould be delete ASAP', 55 | os: 'Linux', 56 | partitions: { 57 | '/' => { 58 | crit: '98%', 59 | warn: '95%' 60 | } 61 | } 62 | }, 63 | merge_vars: true 64 | } 65 | 66 | or 67 | 68 | param = { 69 | name: 'foo', 70 | address: 'foo.bar.com', 71 | vars: { 72 | description: 'removed all other custom vars', 73 | } 74 | } 75 | 76 | @icinga.modify_host( name: 'foo') 77 | 78 | 79 | ## list hosts 80 | 81 | ### list a named host 82 | hosts( params ) 83 | 84 | #### Example 85 | @icinga.host(name: 'icinga2') 86 | 87 | ### list all hosts 88 | hosts 89 | 90 | #### Example 91 | @icinga.hosts 92 | 93 | 94 | ## check if the host exists 95 | exists_host?( host_name ) 96 | 97 | ### Example 98 | @icinga.exists_host?('icinga2') 99 | 100 | 101 | ## get host objects 102 | host_objects( params ) 103 | 104 | ### Example 105 | @icinga.host_objects(attrs: ['name', 'state']) 106 | 107 | 108 | ## count of hosts with problems 109 | count_hosts_with_problems 110 | 111 | ### Example 112 | @icinga.count_hosts_with_problems 113 | 114 | 115 | ## a hash of hosts with problems 116 | list_hosts_with_problems( max_items ) 117 | 118 | ### Example 119 | @icinga.list_hosts_with_problems 120 | @icinga.list_hosts_with_problems( 10 ) 121 | 122 | 123 | ## count of all hosts 124 | hosts_all 125 | 126 | ### Example 127 | @icinga.hosts_all 128 | 129 | 130 | ## count all hosts with problems (down, warning, unknown state) 131 | host_problems 132 | 133 | ### Example 134 | all, down, critical, unknown, handled, adjusted = @icinga.host_problems.values 135 | 136 | or 137 | 138 | p = @icinga.host_problems 139 | down = h.dig(:down) 140 | 141 | 142 | ## (protected) calculate a host severity 143 | host_severity( params ) 144 | 145 | original code are from [Icinga Web2](/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php) 146 | 147 | ### Example 148 | host_severity( {'attrs' => { 'state' => 0.0, 'acknowledgement' => 0.0, 'downtime_depth' => 0.0 } } ) 149 | -------------------------------------------------------------------------------- /doc/notifications.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Notifications 2 | 3 | 4 | ## enable host notifications 5 | enable_host_notification( host ) 6 | 7 | ### Example 8 | @icinga.enable_host_notification('icinga') 9 | 10 | 11 | ## disable host notifications 12 | disable_host_notification( host ) 13 | 14 | ### Example 15 | @icinga.disable_host_notification('icinga') 16 | 17 | 18 | ## enable service notifications 19 | enable_service_notification( host ) 20 | 21 | ### Example 22 | @icinga.enable_service_notification('icinga') 23 | 24 | 25 | ## disable service notifications 26 | disable_service_notification( host ) 27 | 28 | ### Example 29 | @icinga.disable_service_notification('icinga') 30 | 31 | 32 | ## enable hostgroup notifications 33 | enable_hostgroup_notification( params ) 34 | 35 | ### Example 36 | @icinga.enable_hostgroup_notification(host: 'icinga2', host_group: 'linux-servers') 37 | 38 | 39 | ## disable hostgroup notifications 40 | disable_hostgroup_notification( params ) 41 | 42 | ### Example 43 | @icinga.disable_hostgroup_notification(host: 'icinga2', host_group: 'linux-servers') 44 | 45 | 46 | ## list all notifications 47 | notifications 48 | 49 | ### Example 50 | @icinga.notifications 51 | 52 | 53 | ## (protected) function for host notifications 54 | host_notification( params = {} ) 55 | 56 | ## (protected) function for hostgroup notifications 57 | hostgroup_notification( params = {} ) 58 | 59 | ## (protected) function for service notifications 60 | service_notification( params = {} ) 61 | -------------------------------------------------------------------------------- /doc/servicegroups.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Servicegroups 2 | 3 | 4 | ## add a servicegroup 5 | add_servicegroup( params ) 6 | 7 | ### Example 8 | @icinga.add_servicegroup(service_group: 'foo', display_name: 'FOO') 9 | 10 | ## delete a servicegroup 11 | delete_servicegroup( params ) 12 | 13 | ### Example 14 | @icinga.delete_servicegroup(service_group: 'foo') 15 | 16 | ## list servicegroups 17 | 18 | ### list a named servicegroup 19 | servicegroups( params ) 20 | 21 | #### Example 22 | @icinga.servicegroups(service_group: 'disk') 23 | 24 | ### list all servicegroups 25 | servicegroups 26 | 27 | #### Example 28 | @icinga.servicegroups 29 | 30 | 31 | ## checks if the servicegroup exists 32 | exists_servicegroup?( service_group ) 33 | 34 | ### Example 35 | @icinga.exists_servicegroup?('disk') 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/services.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Services 2 | 3 | 4 | ## *add_services( params )* 5 | 6 | Add a Service to Icinga2 7 | 8 | `params` is an `Hash` with following Parameters: 9 | 10 | | Parameter | Type | Example | Description 11 | | :-------------------- | :-----: | :----- | :----------- 12 | | `host_name` | String | `foo` | existing Host for these Service 13 | | `name` | String | `ping4` | Service Name they will be create 14 | | `display_name` | String | `ping4 check` | displayed Name 15 | | `templates` | Array | `['own-service']` | (optional) a Array of templates (default: `['generic-service']`) 16 | | `check_command` | String | `ping4` | The Check Command to execute (**Importand** This Check-Comand must be exists! Otherwise an error will occur) 17 | | `check_interval` | Integer | `10` | The check Interval 18 | | `retry_interval` | Integer | `30` | The retry Interval 19 | | `notes` | String | `` | 20 | | `notes_url` | String | `` | 21 | | `action_url` | String | `` | 22 | | `check_period` | String | `` | 23 | | `check_timeout` | Integer | `` | 24 | | `command_endpoint` | String | `` | 25 | | `enable_active_checks` | Bool | `` | 26 | | `enable_event_handler` | Bool | `` | 27 | | `enable_flapping` | Bool | `` | 28 | | `enable_notifications` | Bool | `` | 29 | | `enable_passive_checks` | Bool | `` | 30 | | `enable_perfdata` | Bool | `` | 31 | | `event_command` | String | `` | 32 | | `flapping_threshold_high`| Integer | `` | 33 | | `flapping_threshold_low` | Integer | `` | 34 | | `flapping_threshold` | Integer | `` | 35 | | `icon_image_alt` | String | `` | 36 | | `icon_image` | String | `` | 37 | | `max_check_attempts` | Integer | `` | 38 | | `volatile` | Bool | `` | 39 | | `vars` | Hash | (see below) | optional config params for the `check_command` 40 | 41 | The result are an `Hash` 42 | 43 | ### Example 44 | 45 | @icinga.add_services( 46 | host_name: 'foo', 47 | name: 'ping4', 48 | check_command: 'ping4', 49 | check_interval: 10, 50 | retry_interval: 30 51 | ) 52 | 53 | or 54 | 55 | @icinga.add_service( 56 | host_name: 'foo', 57 | name: 'http', 58 | check_command: 'http', 59 | check_interval: 10, 60 | retry_interval: 30, 61 | vars: { 62 | http_address: '127.0.0.1', 63 | http_url: '/access/index', 64 | http_port: 80 65 | } 66 | ) 67 | 68 | 69 | 70 | ## *delete_service( params )* 71 | 72 | Delete an Service From Icinga2 73 | 74 | `params` is an `Hash` with following Parameters: 75 | 76 | | Parameter | Type | Example | Description 77 | | :-------------------- | :-----: | :----- | :----------- 78 | | `host` | String | `foo` | existing Host for these Service 79 | | `name` | String | `ping4` | Service Name they will be deleted 80 | | `cascade` | Bool | `true` | delete service also when other objects depend on it (default: `false`) 81 | 82 | 83 | The result are an `Hash` 84 | 85 | #### Example 86 | 87 | @icinga.delete_service(host_name: 'foo', name: 'ping4') 88 | 89 | or 90 | 91 | @icinga.delete_service(host_name: 'foo', name: 'new_ping4', cascade: true) 92 | 93 | 94 | ## *modify_service( params )* 95 | 96 | Modify an Service. 97 | 98 | `params` is an `Hash` with following Parameters: 99 | 100 | | Parameter | Type | Example | Description 101 | | :-------------------- | :-----: | :----- | :----------- 102 | | `name` | String | `ping4` | Service Name they will be deleted 103 | | `templates` | Array | `['own-service']` | (optional) a Array of templates (default: `['generic-service']`) 104 | | `vars` | Hash | (see below) | Hash with custom options (see `add_services()`) 105 | 106 | The result are an `Hash` 107 | 108 | #### Example 109 | 110 | @icinga.modify_service( 111 | name: 'http2', 112 | check_interval: 60, 113 | retry_interval: 10, 114 | vars: { 115 | http_url: '/access/login' , 116 | http_address: '10.41.80.63' 117 | } 118 | ) 119 | 120 | 121 | ## *unhandled_services* 122 | 123 | return all unhandled services 124 | 125 | The result are an `Hash` 126 | 127 | #### Example 128 | @icinga.unhandled_services 129 | 130 | 131 | ## *services* or *services( params )* 132 | 133 | returns all or a named service 134 | 135 | the optional `params` is an `Hash` with following Parameters: 136 | 137 | | Parameter | Type | Example | Description 138 | | :-------------------- | :-----: | :----- | :----------- 139 | | `host` | String | `foo` | Hostname 140 | | `service` | String | `ping4` | service to list 141 | 142 | The result are an `Hash` 143 | 144 | ### list all services 145 | services 146 | 147 | #### Example 148 | @icinga.services 149 | 150 | 151 | ### list named service 152 | services( params ) 153 | 154 | #### Example 155 | @icinga.services( host_name: 'icinga2', service: 'ping4' ) 156 | 157 | 158 | ## *exists_service?( params )* 159 | 160 | check if the service exists 161 | 162 | the optional `params` is an `Hash` with following Parameters: 163 | 164 | | Parameter | Type | Example | Description 165 | | :-------------------- | :-----: | :----- | :----------- 166 | | `host` | String | `foo` | Hostname 167 | | `service` | String | `ping4` | servicename 168 | 169 | The result are an `Hash` 170 | 171 | ### Example 172 | @icinga.exists_service?( host_name: 'icinga2', service: 'users' ) 173 | 174 | 175 | ## *service_objects( params )* 176 | 177 | list service objects 178 | 179 | the optional `params` is an `Hash` with following Parameters: 180 | 181 | | Parameter | Type | Example | Description 182 | | :-------------------- | :-----: | :----- | :----------- 183 | | `attrs` | Array | `[]` | Array of `attrs` 184 | | `filter` | Array | `[]` | Array of `filter` 185 | | `joins` | Array | `[]` | Array of `joins` 186 | 187 | For more Examples for Quering Objects read the [Icinga2 Documentation](https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#querying-objects) 188 | 189 | - defaults for `attrs` are `['name', 'state', 'acknowledgement', 'downtime_depth', 'last_check']` 190 | - defaults for `filter` are `[]` 191 | - defaults for `joins` are `['host.name','host.state','host.acknowledgement','host.downtime_depth','host.last_check']` 192 | 193 | The result are an `Array` 194 | 195 | ### Example 196 | @icinga.service_objects( 197 | attrs: ['name', 'state'], 198 | joins: ['host.name','host.state'] 199 | ) 200 | 201 | 202 | ## *services_adjusted* 203 | 204 | returns adjusted service state 205 | 206 | The result are an `Hash` 207 | 208 | ### Example 209 | 210 | warning, critical, unknown = @icinga.services_adjusted.values 211 | 212 | or 213 | 214 | s = @icinga.services_adjusted 215 | unknown = s.dig(:unknown) 216 | 217 | 218 | ## *count_services_with_problems* 219 | 220 | count services with problems 221 | 222 | The result are an `Integer` 223 | 224 | ### Example 225 | @icinga.count_services_with_problems 226 | 227 | 228 | ## *list_services_with_problems( max_items )* 229 | 230 | list of services with problems 231 | 232 | The result are an `Hash` 233 | 234 | ### Example 235 | 236 | problems, problems_and_severity = @icinga.list_services_with_problems(10).values 237 | 238 | or 239 | 240 | l = @icinga.list_services_with_problems(10) 241 | problems_and_severity = l.dig(:services_with_problems_and_severity) 242 | 243 | 244 | ## *services_all* 245 | 246 | count all services 247 | 248 | The result are an `Integer` 249 | 250 | ### Example 251 | 252 | @icinga.services_all 253 | 254 | 255 | ## *service_problems* 256 | 257 | returns data with service problems 258 | 259 | The result are an `Hash` 260 | 261 | ### Example 262 | 263 | all, warning, critical, unknown, pending, in_downtime, acknowledged, adjusted_warning, adjusted_critical, adjusted_unknown = @icinga.service_problems.values 264 | 265 | or 266 | 267 | p = @icinga.service_problems 268 | warning = p.dig(:warning) 269 | 270 | 271 | ## *service_severity( params )* (protected) 272 | 273 | calculate a service severity 274 | (taken from the IcingaWeb2 Code) 275 | 276 | The result are an `Integer` 277 | 278 | ### Example 279 | service_severity( {'attrs' => { 'state' => 0.0, 'acknowledgement' => 0.0, 'downtime_depth' => 0.0 } } ) 280 | 281 | 282 | -------------------------------------------------------------------------------- /doc/statistics.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Statistics 2 | 3 | 4 | ## *average_statistics* 5 | 6 | statistic data for latency and execution_time 7 | 8 | The result are an `Hash` 9 | 10 | ### Example 11 | @icinga.cib_data 12 | latency, execution_time = @icinga.average_statistics.values 13 | 14 | or 15 | 16 | h = @icinga.average_statistics 17 | latency = h.dig(:latency) 18 | 19 | ## *interval_statistics* 20 | 21 | statistic data for intervall data 22 | 23 | The result are an `Hash` 24 | 25 | ### Example 26 | @icinga.cib_data 27 | hosts_active_checks, hosts_passive_checks, services_active_checks, services_passive_checks = @icinga.interval_statistics.values 28 | 29 | or 30 | i = @icinga.interval_statistics 31 | hosts_active_checks = i.dig(:hosts_active_checks) 32 | 33 | 34 | ## *service_statistics* 35 | 36 | statistic data for services 37 | 38 | The result are an `Hash` 39 | 40 | ### Example 41 | @icinga.cib_data 42 | ok, warning, critical, unknown, pending, in_downtime, ack = @icinga.service_statistics.values 43 | 44 | or 45 | s = @icinga.service_statistics 46 | critical = s.dig(:critical) 47 | 48 | ## *host_statistics* 49 | 50 | statistic data for hosts 51 | 52 | The result are an `Hash` 53 | 54 | ### Example 55 | @icinga.cib_data 56 | up, down, pending, unreachable, in_downtime, ack = @icinga.host_statistics.values 57 | 58 | or 59 | 60 | h = @icinga.host_statistics 61 | pending = h.dig(:pending) 62 | 63 | 64 | ## work_queue_statistics 65 | 66 | queue statistics from the api 67 | 68 | The result are an `Hash` 69 | 70 | ### Example 71 | @icinga.work_queue_statistics 72 | 73 | -------------------------------------------------------------------------------- /doc/usergroups.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Usergroups 2 | 3 | 4 | ## *add_usergroup( params )* 5 | 6 | Creates an Icinga2 Usergroup. 7 | 8 | `params` are an `Hash` with following Parameters: 9 | 10 | | Parameter | Type | Example | Description 11 | | :-------------------- | :-----: | :----- | :----------- 12 | | `user_group` | String | `foo` | Usergroup they will be created 13 | | `display_name` | String | `User Foo` | the displayed Name 14 | 15 | The result are an `Hash` 16 | 17 | ### Example 18 | @icinga.add_usergroup(user_group: 'foo', display_name: 'FOO') 19 | 20 | 21 | ## *delete_usergroup( params )* 22 | 23 | Delete a Usergroup. 24 | 25 | `params` are an `Hash` with following Parameters: 26 | 27 | | Parameter | Type | Example | Description 28 | | :-------------------- | :-----: | :----- | :----------- 29 | | `user_group` | String | `foo` | Usergroup they will be deleted 30 | 31 | The result are an `Hash` 32 | 33 | ### Example 34 | @icinga.delete_usergroup(user_group: 'foo') 35 | 36 | 37 | ## *usergroups* or *usergroups( params )* 38 | 39 | returns all or a named usergroup. 40 | 41 | the optional `params` is an `Hash` with following Parameters: 42 | 43 | | Parameter | Type | Example | Description 44 | | :-------------------- | :-----: | :----- | :----------- 45 | | `user_group` | String | `foo` | Usergroup they will be listed 46 | 47 | The result are an `Hash` 48 | 49 | 50 | ### list all usergroups 51 | usergroups 52 | 53 | #### Example 54 | @icinga.usergroups 55 | 56 | 57 | ### list named usergroup 58 | usergroups( params ) 59 | 60 | #### Example 61 | @icinga.usergroups(user_group: 'icingaadmins') 62 | 63 | 64 | 65 | ## *exists_usergroup?( user_group )* 66 | 67 | check if the Usergroup exists 68 | 69 | `params` is an `String` with the Usergroupname. 70 | 71 | The result are an `Boolean` 72 | 73 | ### Example 74 | 75 | @icinga.exists_usergroup?('icingaadmins') 76 | -------------------------------------------------------------------------------- /doc/users.md: -------------------------------------------------------------------------------- 1 | # Icinga2 - Users 2 | 3 | ## *add_user( params )* 4 | 5 | creates an Icinga2 User. 6 | 7 | `params` are an `Hash` with following Parameters: 8 | 9 | | Parameter | Type | Example | Description 10 | | :-------------------- | :-----: | :----- | :----------- 11 | | `user_name` | String | `foo` | User they will be created 12 | | `display_name` | String | `User Foo` | the displayed Name 13 | | `email` | String | `foo@bar.tld` | the Email for this Users 14 | | `pager` | String | `+49 000 000000` | an optional Pager Number 15 | | `enable_notifications` | Bool | `true` | enable notifications for this user (default: **false**) 16 | | `groups` | Array | `['icingaadmins','dba']` | a hash with (existing!) groups 17 | 18 | The result are an `Hash` 19 | 20 | ### Example 21 | 22 | params = { 23 | user_name: 'foo', 24 | display_name: 'FOO', 25 | email: 'foo@bar.com', 26 | pager: '0000', 27 | groups: ['icingaadmins'] 28 | } 29 | puts @icinga.add_user( params ) 30 | {"code"=>200, "name"=>nil, "status"=>"Object was created"} 31 | 32 | 33 | ## *delete_user( params )* 34 | 35 | delete an Icinga2 User. 36 | 37 | `params` is an `Hash` with following Parameters: 38 | 39 | | Parameter | Type | Example | Description 40 | | :-------------------- | :-----: | :----- | :----------- 41 | | `user_name` | String | `foo` | User they will be deleted 42 | 43 | The result are an `Hash` 44 | 45 | ### Example 46 | 47 | puts @icinga.delete_user(user_name: 'foo') 48 | {"code"=>200, "name"=>"foo", "status"=>"Object was deleted."} 49 | 50 | 51 | ## *users* or *users( params )* 52 | 53 | returns all or a named user. 54 | 55 | the optional `params` is an `Hash` with following Parameters: 56 | 57 | | Parameter | Type | Example | Description 58 | | :-------------------- | :-----: | :----- | :----------- 59 | | `user_name` | String | `foo` | User they will be listed 60 | 61 | The result are an `Hash` 62 | 63 | ### list all users 64 | users 65 | 66 | #### Example 67 | @icinga.users 68 | {"attrs"=>{"__name"=>"icingaadmin", "active"=>true, "display_name"=>"Icinga 2 Admin", "email"=>"icinga@localhost", "enable_notifications"=>true, "groups"=>["icingaadmins"], "ha_mode"=>0.0, "last_notification"=>0.0, "name"=>"icingaadmin", "original_attributes"=>nil, "package"=>"_etc", "pager"=>"", "paused"=>false, "period"=>"", "source_location"=>{"first_column"=>1.0, "first_line"=>6.0, "last_column"=>25.0, "last_line"=>6.0, "path"=>"/etc/icinga2/conf.d/users.conf"}, "states"=>nil, "templates"=>["icingaadmin", "generic-user"], "type"=>"User", "types"=>nil, "vars"=>nil, "version"=>0.0, "zone"=>""}, "joins"=>{}, "meta"=>{}, "name"=>"icingaadmin", "type"=>"User"} 69 | 70 | ### list named user 71 | users( params ) 72 | 73 | #### Example 74 | @icinga.users(user_name: 'foo') 75 | {"attrs"=>{"__name"=>"foo", "active"=>true, "display_name"=>"FOO", "email"=>"foo@bar.com", "enable_notifications"=>false, "groups"=>["icingaadmins"], "ha_mode"=>0.0, "last_notification"=>0.0, "name"=>"foo", "original_attributes"=>nil, "package"=>"_api", "pager"=>"0000", "paused"=>false, "period"=>"", "source_location"=>{"first_column"=>0.0, "first_line"=>1.0, "last_column"=>16.0, "last_line"=>1.0, "path"=>"/var/lib/icinga2/api/packages/_api/icinga2-master.matrix.lan-1507365860-1/conf.d/users/foo.conf"}, "states"=>nil, "templates"=>["foo"], "type"=>"User", "types"=>nil, "vars"=>nil, "version"=>1507609817.587105, "zone"=>"icinga2-master.matrix.lan"}, "joins"=>{}, "meta"=>{}, "name"=>"foo", "type"=>"User"} 76 | 77 | 78 | 79 | ## *exists_user?( params )* 80 | 81 | check if an User exists. 82 | 83 | `params` is an `String` with the Username. 84 | 85 | The result are an `Boolean` 86 | 87 | ### Example 88 | 89 | puts @icinga.exists_user?('icingaadmin') 90 | true 91 | -------------------------------------------------------------------------------- /examples/_blank.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | 13 | # ----------------------------------------------------------------------------- 14 | 15 | icinga_host = ENV.fetch( 'ICINGA_HOST' , 'icinga2' ) 16 | icinga_api_port = ENV.fetch( 'ICINGA_API_PORT' , 5665 ) 17 | icinga_api_user = ENV.fetch( 'ICINGA_API_USER' , 'admin' ) 18 | icinga_api_pass = ENV.fetch( 'ICINGA_API_PASSWORD' , nil ) 19 | icinga_api_pki_path = ENV.fetch( 'ICINGA_API_PKI_PATH' , '/etc/icinga2' ) 20 | icinga_api_node_name = ENV.fetch( 'ICINGA_API_NODE_NAME' , nil ) 21 | icinga_cluster = ENV.fetch( 'ICINGA_CLUSTER' , false ) 22 | icinga_satellite = ENV.fetch( 'ICINGA_CLUSTER_SATELLITE', nil ) 23 | 24 | 25 | # convert string to bool 26 | icinga_cluster = icinga_cluster.to_s.eql?('true') ? true : false 27 | 28 | config = { 29 | icinga: { 30 | host: icinga_host, 31 | api: { 32 | port: icinga_api_port, 33 | user: icinga_api_user, 34 | password: icinga_api_pass, 35 | pki_path: icinga_api_pki_path, 36 | node_name: icinga_api_node_name 37 | }, 38 | cluster: icinga_cluster, 39 | satellite: icinga_satellite 40 | } 41 | } 42 | 43 | # --------------------------------------------------------------------------------------- 44 | 45 | i = Icinga2::Client.new( config ) 46 | 47 | unless( i.nil? ) 48 | 49 | # run tests ... 50 | # 51 | # 52 | 53 | begin 54 | 55 | puts ' ------------------------------------------------------------- ' 56 | puts '' 57 | 58 | 59 | 60 | puts ' ------------------------------------------------------------- ' 61 | puts '' 62 | 63 | rescue => e 64 | warn( e ) 65 | warn( e.backtrace.join("\n") ) 66 | end 67 | end 68 | 69 | 70 | # ----------------------------------------------------------------------------- 71 | 72 | # EOF 73 | -------------------------------------------------------------------------------- /examples/cert-manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Supported commands: 4 | # * pki new-ca (sets up a new CA) 5 | # * pki new-cert (creates a new CSR) 6 | # Command options: 7 | # --cn arg Common Name 8 | # --key arg Key file path (output 9 | # --csr arg CSR file path (optional, output) 10 | # --cert arg Certificate file path (optional, output) 11 | # * pki request (requests a certificate) 12 | # Command options: 13 | # --key arg Key file path (input) 14 | # --cert arg Certificate file path (input + output) 15 | # --ca arg CA file path (output) 16 | # --trustedcert arg Trusted certificate file path (input) 17 | # --host arg Icinga 2 host 18 | # --port arg Icinga 2 port 19 | # --ticket arg Icinga 2 PKI ticket 20 | # * pki save-cert (saves another Icinga 2 instance's certificate) 21 | # Command options: 22 | # --key arg Key file path (input), obsolete 23 | # --cert arg Certificate file path (input), obsolete 24 | # --trustedcert arg Trusted certificate file path (output) 25 | # --host arg Icinga 2 host 26 | # --port arg (=5665) Icinga 2 port 27 | # * pki sign-csr (signs a CSR) 28 | # Command options: 29 | # --csr arg CSR file path (input) 30 | # --cert arg Certificate file path (output) 31 | # * pki ticket (generates a ticket) 32 | # Command options: 33 | # --cn arg Certificate common name 34 | # --salt arg Ticket salt 35 | 36 | HOSTNAME="$(hostname -s)" 37 | 38 | PKI_KEY="/etc/icinga2/pki/${HOSTNAME}.key" 39 | PKI_CSR="/etc/icinga2/pki/${HOSTNAME}.csr" 40 | PKI_CRT="/etc/icinga2/pki/${HOSTNAME}.crt" 41 | 42 | ICINGA_MASTER="icinga2-core" 43 | 44 | PKI_CMD="icinga2 pki" 45 | 46 | # -------------------------------------------------------------------------------------------- 47 | 48 | chown -R icinga: /var/lib/icinga2 49 | 50 | icinga2 api setup 51 | ${PKI_CMD} new-cert --cn ${HOSTNAME} --key ${PKI_KEY} --csr ${PKI_CSR} 52 | ${PKI_CMD} sign-csr --csr ${PKI_CSR} --cert ${PKI_CRT} 53 | 54 | # if [ $(icinga2 feature list | grep Enabled | grep api | wc -l) -eq 0 ] 55 | # then 56 | # icinga2 feature enable api 57 | # fi 58 | 59 | supervisorctl restart icinga2 60 | 61 | echo -e "\n\n" 62 | 63 | 64 | SATELLITES="icinga2-satellite-1 icinga2-satellite-2" 65 | 66 | for s in ${SATELLITES} 67 | do 68 | dir="/tmp/${s}" 69 | 70 | chown icinga: ${dir} 71 | 72 | salt=$(echo ${s} | sha256sum | cut -f 1 -d ' ') 73 | 74 | mkdir ${dir} 75 | 76 | 77 | ${PKI_CMD} new-cert --cn ${s} --key ${dir}/${s}.key --csr ${dir}/${s}.csr 78 | ${PKI_CMD} sign-csr --csr ${dir}/${s}.csr --cert ${dir}/${s}.crt 79 | ${PKI_CMD} save-cert --key ${dir}/${s}.key --cert ${dir}/${s}.crt --trustedcert ${dir}/trusted-master.crt --host ${ICINGA_MASTER} 80 | # Receive Ticket from master... 81 | pki_ticket=$(${PKI_CMD} ticket --cn ${HOSTNAME} --salt ${salt}) 82 | ${PKI_CMD} request --host ${ICINGA_MASTER} --port 5665 --ticket ${pki_ticket} --key ${dir}/${s}.key --cert ${dir}/${s}.crt --trustedcert ${dir}/trusted-master.crt --ca /etc/icinga2/pki/ca.crt 83 | 84 | # openssl x509 -in ${dir}/${s}.crt -text -noout 85 | # openssl req -in ${dir}/${s}.csr -noout -text 86 | 87 | done 88 | 89 | exit 0 90 | 91 | 92 | #icinga2 pki new-cert --cn ${HOSTNAME} --key /etc/icinga2/pki/${HOSTNAME}.key --cert /etc/icinga2/pki/${HOSTNAME}.crt 93 | # 94 | ## Set trusted Cert 95 | #icinga2 pki save-cert --key /etc/icinga2/pki/${HOSTNAME}.key --cert /etc/icinga2/pki/${HOSTNAME}.crt --trustedcert /etc/icinga2/pki/trusted-master.crt --host ${ICINGA_MASTER} 96 | # 97 | #salt=$(echo $(hostname) | sha256sum | cut -f 1 -d ' ') 98 | ## Receive Ticket from master... 99 | #pki_ticket=$(icinga2 pki ticket --cn ${HOSTNAME} --salt ${salt}) 100 | #echo " [i] PKI Ticket for '${HOSTNAME}' : '${pki_ticket}'" # => delegate_to: "${ICINGA_MASTER}" 101 | # 102 | ## Request PKI 103 | #icinga2 pki request --host ${ICINGA_MASTER} --port 5665 --ticket ${pki_ticket} --key /etc/icinga2/pki/${HOSTNAME}.key --cert /etc/icinga2/pki/${HOSTNAME}.crt --trustedcert /etc/icinga2/pki/trusted-master.crt --ca /etc/icinga2/pki/ca.crt 104 | # 105 | ## Set Master as Endpoint 106 | #icinga2 node setup --ticket ${pki_ticket} --endpoint ${ICINGA_MASTER} --zone ${HOSTNAME} --master_host ${ICINGA_MASTER} --trustedcert /etc/icinga2/pki/trusted-master.crt 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /examples/config.rb: -------------------------------------------------------------------------------- 1 | 2 | icinga_host = ENV.fetch( 'ICINGA_HOST' , 'icinga2' ) 3 | icinga_api_port = ENV.fetch( 'ICINGA_API_PORT' , 5665 ) 4 | icinga_api_user = ENV.fetch( 'ICINGA_API_USER' , 'admin' ) 5 | icinga_api_pass = ENV.fetch( 'ICINGA_API_PASSWORD' , nil ) 6 | icinga_api_pki_path = ENV.fetch( 'ICINGA_API_PKI_PATH' , '/etc/icinga2' ) 7 | icinga_api_node_name = ENV.fetch( 'ICINGA_API_NODE_NAME' , nil ) 8 | 9 | @config = { 10 | icinga: { 11 | host: icinga_host, 12 | api: { 13 | port: icinga_api_port, 14 | user: icinga_api_user, 15 | password: icinga_api_pass, 16 | pki_path: icinga_api_pki_path, 17 | node_name: icinga_api_node_name 18 | } 19 | } 20 | } 21 | 22 | # --------------------------------------------------------------------------------------- 23 | 24 | -------------------------------------------------------------------------------- /examples/downtimes.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | # puts ' ==> DOWNTIMES' 30 | # puts '' 31 | # puts 'add Downtime \'test\'' 32 | # puts i.add_downtime( name: 'test', type: 'service', host: 'foo', comment: 'test downtime', author: 'icingaadmin', start_time: Time.now.to_i, end_time: Time.now.to_i + 20 ) 33 | # puts '' 34 | # puts 'list all Downtimes' 35 | # puts i.downtimes 36 | # puts '' 37 | 38 | puts ' ------------------------------------------------------------- ' 39 | puts '' 40 | 41 | rescue => e 42 | warn( e ) 43 | warn( e.backtrace.join("\n") ) 44 | end 45 | end 46 | 47 | 48 | # ----------------------------------------------------------------------------- 49 | 50 | # EOF 51 | -------------------------------------------------------------------------------- /examples/hostgroups.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts '= check if Hostgroup \'linux-servers\' exists' 30 | puts i.exists_hostgroup?( 'linux-servers' ) ? 'true' : 'false' 31 | puts '' 32 | puts '= check if Hostgroup \'docker\' exists' 33 | puts i.exists_hostgroup?( 'docker' ) ? 'true' : 'false' 34 | puts '' 35 | puts '= list named Hostgroup \'linux-servers\'' 36 | puts i.hostgroups( host_group: 'linux-servers' ) 37 | puts '' 38 | puts '= list named Hostgroup \'foo\'' 39 | puts i.hostgroups( host_group: 'foo' ) 40 | puts '' 41 | puts '= list all Hostgroups' 42 | puts i.hostgroups 43 | puts '' 44 | puts '= add hostgroup \'foo\'' 45 | puts i.add_hostgroup( host_group: 'foo', display_name: 'FOO' ) 46 | puts '' 47 | puts '= delete Hostgroup \'foo\'' 48 | puts i.delete_hostgroup( host_group: 'foo' ) 49 | 50 | puts ' ------------------------------------------------------------- ' 51 | puts '' 52 | 53 | rescue => e 54 | warn( e ) 55 | warn( e.backtrace.join("\n") ) 56 | end 57 | end 58 | 59 | 60 | # ----------------------------------------------------------------------------- 61 | 62 | # EOF 63 | -------------------------------------------------------------------------------- /examples/hosts.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hosts 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | puts ' ==> HOSTS' 29 | puts '' 30 | 31 | puts format( '= count of all hosts : %d', i.hosts_all ) 32 | puts format( '= count_hosts_with_problems: %d', i.count_hosts_with_problems) 33 | puts '' 34 | 35 | all, down, critical, unknown, handled, adjusted = i.host_problems.values 36 | 37 | puts '= hosts with problems' 38 | puts format( ' - all : %d', all ) 39 | puts format( ' - down : %d', down ) 40 | puts format( ' - critical: %d', critical ) 41 | puts format( ' - unknown : %d', unknown ) 42 | puts format( ' - handled : %d', handled ) 43 | puts format( ' - adjusted: %d', adjusted ) 44 | puts '' 45 | 46 | puts '' 47 | ['c1-mysql-1', 'bp-foo'].each do |h| 48 | 49 | e = i.exists_host?( h ) ? 'true' : 'false' 50 | puts format( '= check if Host \'%s\' exists : %s', h, e ) 51 | end 52 | 53 | puts '' 54 | 55 | puts '= 5 Hosts with Problem ' 56 | puts i.list_hosts_with_problems 57 | puts '' 58 | 59 | ['c1-mysql-1', 'bp-foo'].each do |h| 60 | puts format('= list named Hosts \'%s\'', h ) 61 | puts i.hosts( name: h ) 62 | puts '' 63 | end 64 | 65 | puts ' = add Host \'foo\'' 66 | 67 | options = { 68 | name: 'foo', 69 | address: 'foo.bar.com', 70 | display_name: 'test node', 71 | max_check_attempts: 5, 72 | notes: 'test node', 73 | vars: { 74 | description: 'spec test', 75 | os: 'Docker', 76 | partitions: { 77 | '/' => { 78 | crit: '95%', 79 | warn: '90%' 80 | } 81 | } 82 | } 83 | } 84 | 85 | puts i.add_host(options) 86 | puts '' 87 | 88 | puts ' = add Host \'foo\' (again)' 89 | puts i.add_host(options) 90 | puts '' 91 | 92 | puts ' = modify Host \'foo\' with merge vars' 93 | options = { 94 | name: 'foo', 95 | display_name: 'test node (changed)', 96 | max_check_attempts: 10, 97 | notes: 'spec test', 98 | vars: { 99 | description: 'changed at ...' 100 | }, 101 | merge_vars: true 102 | } 103 | puts i.modify_host(options) 104 | puts '' 105 | 106 | puts ' = modify Host \'foo\' with overwrite vars' 107 | options = { 108 | name: 'foo', 109 | display_name: 'test node (changed)', 110 | max_check_attempts: 10, 111 | notes: 'spec test', 112 | vars: { 113 | description: 'change and overwrite vars' 114 | } 115 | } 116 | puts i.modify_host(options) 117 | puts '' 118 | 119 | puts ' = delete Host \'test\'' 120 | puts i.delete_host( name: 'test' ) 121 | puts '' 122 | 123 | puts ' = delete Host \'foo\'' 124 | puts i.delete_host( name: 'foo' ) 125 | puts '' 126 | 127 | puts ' = delete Host \'foo\' (again)' 128 | puts i.delete_host( name: 'foo' ) 129 | puts '' 130 | 131 | puts '= list all Hosts' 132 | puts i.hosts 133 | puts '' 134 | 135 | puts '= list named Hosts \'c1-mysql-1\'' 136 | puts i.hosts(name: 'c1-mysql-1') 137 | puts '' 138 | 139 | puts '= list named Hosts \'c1-mysql-1\' (with attrs and filter)' 140 | puts i.hosts( 141 | name: 'c1-mysql-1', 142 | attrs: %w[display_name name address] 143 | ) 144 | puts '' 145 | 146 | puts '= host object with attrs and filter' 147 | # Get host name, address of hosts belonging to a specific hostgroup 148 | puts i.host_objects( 149 | attrs: %w[display_name name address], 150 | filter: '"linux-servers" in host.groups' 151 | ) 152 | 153 | puts ' ------------------------------------------------------------- ' 154 | puts '' 155 | 156 | rescue => e 157 | warn( e ) 158 | warn( e.backtrace.join("\n") ) 159 | end 160 | end 161 | 162 | 163 | # ----------------------------------------------------------------------------- 164 | 165 | # EOF 166 | -------------------------------------------------------------------------------- /examples/informations.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | i.cib_data 27 | 28 | puts ' ------------------------------------------------------------- ' 29 | puts '' 30 | 31 | v, r = i.version.values 32 | l, e = i.average_statistics.values 33 | puts format( '= version: %s, revision %s', v, r ) 34 | puts format( '= avg_latency: %s, avg_execution_time %s', l, e ) 35 | puts format( '= start time: %s', i.start_time ) 36 | puts format( '= uptime: %s', i.uptime ) 37 | puts format( '= node name: %s', i.node_name ) 38 | puts '' 39 | 40 | puts '= icinga2 status' 41 | puts i.status_data 42 | puts '' 43 | 44 | puts '= icinga2 application data' 45 | puts i.application_data 46 | puts '' 47 | puts '= CIB' 48 | puts i.cib_data 49 | puts '' 50 | puts '= API Listener' 51 | puts i.api_listener 52 | puts '' 53 | 54 | puts ' ------------------------------------------------------------- ' 55 | puts '' 56 | 57 | rescue => e 58 | warn( e ) 59 | warn( e.backtrace.join("\n") ) 60 | end 61 | end 62 | 63 | 64 | # ----------------------------------------------------------------------------- 65 | 66 | # EOF 67 | -------------------------------------------------------------------------------- /examples/notifications.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts ' ==> NOTIFICATIONS' 30 | puts '' 31 | puts '= list all Notifications' 32 | puts i.notifications 33 | puts '' 34 | 35 | ['c1-mysql-1', 'bp-foo'].each do |h| 36 | puts format( '= enable Notifications for \'%s\'', h ) 37 | puts i.enable_host_notification( h ) 38 | end 39 | puts '' 40 | 41 | ['c1-mysql-1', 'bp-foo'].each do |h| 42 | puts format( '= disable Notifications for \'%s\'', h ) 43 | puts i.disable_host_notification( h ) 44 | end 45 | puts '' 46 | 47 | ['c1-mysql-1', 'bp-foo'].each do |h| 48 | puts format( '= enable Notifications for \'%s\' and they services', h ) 49 | puts i.enable_service_notification( h ) 50 | end 51 | puts '' 52 | 53 | ['c1-mysql-1', 'bp-foo'].each do |h| 54 | puts format( '= disable Notifications for \'%s\' and they services', h ) 55 | puts i.disable_service_notification( h ) 56 | end 57 | puts '' 58 | 59 | puts '= enable Notifications for hostgroup' 60 | puts i.enable_hostgroup_notification( host_group: 'linux-servers') 61 | puts '' 62 | 63 | 64 | puts '= disable Notifications for hostgroup' 65 | puts i.disable_hostgroup_notification( host_group: 'linux-servers') 66 | puts '' 67 | 68 | puts ' ------------------------------------------------------------- ' 69 | puts '' 70 | 71 | rescue => e 72 | warn( e ) 73 | warn( e.backtrace.join("\n") ) 74 | end 75 | end 76 | 77 | 78 | # ----------------------------------------------------------------------------- 79 | 80 | # EOF 81 | -------------------------------------------------------------------------------- /examples/servicegroups.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Servicegroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts ' ==> SERVICEGROUPS' 30 | puts '' 31 | 32 | %w[disk foo].each do |h| 33 | 34 | e = i.exists_servicegroup?( h ) ? 'true' : 'false' 35 | puts format( '= check if Servicegroup \'%s\' exists : %s', h, e ) 36 | end 37 | puts '' 38 | 39 | %w[disk foo].each do |h| 40 | puts format( '= list named Servicegroup \'%s\':', h ) 41 | puts i.servicegroups( service_group: h ) 42 | end 43 | puts '' 44 | 45 | puts '= list all Servicegroup' 46 | puts i.servicegroups 47 | puts '' 48 | 49 | puts '= add Servicegroup \'foo\'' 50 | puts i.add_servicegroup( service_group: 'foo', display_name: 'FOO' ) 51 | puts '' 52 | 53 | puts '= add Servicegroup \'foo\' (again)' 54 | puts i.add_servicegroup( service_group: 'foo', display_name: 'FOO' ) 55 | puts '' 56 | 57 | puts '= list named Servicegroup \'foo\'' 58 | puts i.servicegroups( service_group: 'foo' ) 59 | puts '' 60 | 61 | puts '= delete Servicegroup \'foo\'' 62 | puts i.delete_servicegroup( service_group: 'foo' ) 63 | puts '' 64 | 65 | puts '= delete Servicegroup \'foo\' (again)' 66 | puts i.delete_servicegroup( service_group: 'foo' ) 67 | puts '' 68 | 69 | puts ' ------------------------------------------------------------- ' 70 | puts '' 71 | 72 | rescue => e 73 | warn( e ) 74 | warn( e.backtrace.join("\n") ) 75 | end 76 | end 77 | 78 | 79 | # ----------------------------------------------------------------------------- 80 | 81 | # EOF 82 | -------------------------------------------------------------------------------- /examples/services.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts ' ==> SERVICES' 30 | puts '' 31 | 32 | puts '= service objects' 33 | puts i.service_objects 34 | puts '' 35 | 36 | puts '= service objects with \'attrs\' and \'joins\'' 37 | puts i.service_objects( 38 | attrs: %w[name state], 39 | joins: ['host.name','host.state'] 40 | ) 41 | puts '' 42 | 43 | puts '= service objects with \'attrs\', \'filter\' and \'joins\'' 44 | puts ' match host.address = 1.2.3.4' 45 | puts i.service_objects( 46 | attrs: %w[display_name check_command], 47 | filter: 'match("1.2.3.4", host.address)', 48 | joins: ['host.name','host.address'] 49 | ) 50 | puts '' 51 | 52 | # Get all services in critical state and filter out the ones for which active checks are disabled 53 | # service.states - 0 = OK, 1 = WARNING, 2 = CRITICAL 54 | # 55 | # { "joins": ["host.name", "host.address"], "filter": "service.state==2", "attrs": ["display_name", "check_command", "enable_active_checks"] } 56 | puts '= service objects with \'attrs\', \'filter\' and \'joins\'' 57 | puts ' filter service.sate == 1' 58 | puts i.service_objects( 59 | attrs: %w[display_name check_command enable_active_checks], 60 | filter: 'service.state == 1' , 61 | joins: ['host.name', 'host.address'] 62 | ) 63 | puts '' 64 | 65 | puts '= unhandled services' 66 | puts i.unhandled_services 67 | puts '' 68 | 69 | puts format( '= count of all services: %s', i.services_all ) 70 | puts '' 71 | 72 | puts format( '= count of services with problems: %d', i.count_services_with_problems) 73 | puts '' 74 | 75 | all, warning, critical, unknown, pending, in_downtime, acknowledged, 76 | adjusted_warning, adjusted_critical, adjusted_unknown, 77 | handled_all, handled_warning, handled_critical, handled_unknown = i.service_problems.values 78 | 79 | puts '= services with problems' 80 | puts i.service_problems 81 | puts format( ' - all : %d', all ) 82 | puts format( ' - warning : %d', warning ) 83 | puts format( ' - critical : %d', critical ) 84 | puts format( ' - unknown : %d', unknown ) 85 | puts format( ' - pending : %d', pending ) 86 | puts format( ' - in_downtime : %d', in_downtime ) 87 | puts format( ' - acknowledged : %d', acknowledged ) 88 | puts format( ' - adj. warning : %d', adjusted_warning ) 89 | puts format( ' - adj. critical : %d', adjusted_critical ) 90 | puts format( ' - adj. unknown : %d', adjusted_unknown ) 91 | puts format( ' - handled all : %d', handled_all ) 92 | puts format( ' - handled warning : %d', handled_warning ) 93 | puts format( ' - handled critical: %d', handled_critical ) 94 | puts format( ' - handled unknown : %d', handled_unknown ) 95 | puts '' 96 | 97 | puts '= check if Service exists' 98 | ['c1-mysql-1', 'bp-foo'].each do |h| 99 | e = i.exists_service?( host_name: h, name: 'ssh' ) ? 'true' : 'false' 100 | puts format( ' - Service \'ssh\' for Host \'%s\' : %s', h, e ) 101 | end 102 | puts '' 103 | ['c1-mysql-1', 'bp-foo'].each do |h| 104 | e = i.exists_service?( host_name: h, name: 'hdb' ) ? 'true' : 'false' 105 | puts format( ' - Service \'hdb\' for Host \'%s\' : %s', h, e ) 106 | end 107 | puts '' 108 | 109 | puts '= 5 Services with Problems' 110 | 111 | problems, problems_and_severity = i.list_services_with_problems.values 112 | 113 | puts format( ' - problems: %s', problems ) 114 | puts format( ' - problems and severity: %s', problems_and_severity ) 115 | puts '' 116 | 117 | puts '= add service' 118 | puts i.add_service( 119 | host_name: 'c1-mysql-1', 120 | name: 'http2', 121 | check_command: 'http', 122 | check_interval: 10, 123 | retry_interval: 30, 124 | vars: { 125 | http_address: '127.0.0.1', 126 | http_url: '/access/index', 127 | http_port: 80 128 | } 129 | ) 130 | 131 | puts '= add service (again)' 132 | puts i.add_service( 133 | host_name: 'c1-mysql-1', 134 | name: 'http2', 135 | check_command: 'http', 136 | check_interval: 10, 137 | retry_interval: 30, 138 | vars: { 139 | http_address: '127.0.0.1', 140 | http_url: '/access/index', 141 | http_port: 80 142 | } 143 | ) 144 | 145 | puts '= modify service' 146 | puts i.modify_service( 147 | name: 'http2', 148 | check_interval: 60, 149 | retry_interval: 10, 150 | vars: { 151 | http_url: '/access/login' , 152 | http_address: '10.41.80.63' 153 | } 154 | ) 155 | 156 | puts '= delete service' 157 | puts i.delete_service(host_name: 'c1-mysql-1', name: 'http2' ) 158 | 159 | puts '= delete service (again)' 160 | puts i.delete_service(host_name: 'c1-mysql-1', name: 'http2' ) 161 | 162 | puts '' 163 | puts '= list named Service \'ping4\' from Host \'icinga2\'' 164 | puts i.services( host_name: 'c1-mysql-1', service: 'ping4' ) 165 | puts '' 166 | puts '= list all Services' 167 | puts i.services 168 | 169 | puts ' ------------------------------------------------------------- ' 170 | puts '' 171 | 172 | rescue => e 173 | warn( e ) 174 | warn( e.backtrace.join("\n") ) 175 | end 176 | end 177 | 178 | 179 | # ----------------------------------------------------------------------------- 180 | 181 | # EOF 182 | -------------------------------------------------------------------------------- /examples/statistics.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | i.cib_data 27 | 28 | puts ' ------------------------------------------------------------- ' 29 | puts '' 30 | 31 | latency, execution_time = i.average_statistics.values 32 | 33 | puts format( '= latency: %s', latency ) 34 | puts format( '= execution_time: %s', execution_time ) 35 | puts '' 36 | 37 | interval_stats = i.interval_statistics 38 | host_stats = i.host_statistics 39 | service_stats = i.service_statistics 40 | work_queue_stats = i.work_queue_statistics 41 | 42 | hosts_active_checks = interval_stats.dig(:hosts_active_checks) 43 | hosts_passive_checks = interval_stats.dig(:hosts_passive_checks) 44 | services_active_checks = interval_stats.dig(:services_active_checks) 45 | services_passive_checks = interval_stats.dig(:services_passive_checks) 46 | 47 | host_stats_up = host_stats.dig(:up) 48 | host_stats_down = host_stats.dig(:down) 49 | host_stats_pending = host_stats.dig(:pending) 50 | host_stats_unreachable = host_stats.dig(:unreachable) 51 | host_stats_in_downtime = host_stats.dig(:in_downtime) 52 | host_stats_acknowledged = host_stats.dig(:acknowledged) 53 | 54 | service_stats_ok = service_stats.dig(:ok) 55 | service_stats_warning = service_stats.dig(:warning) 56 | service_stats_critical = service_stats.dig(:critical) 57 | service_stats_unknown = service_stats.dig(:unknown) 58 | service_stats_pending = service_stats.dig(:pending) 59 | service_stats_in_downtime = service_stats.dig(:in_downtime) 60 | service_stats_acknowledged = service_stats.dig(:acknowledged) 61 | 62 | puts format( '= hosts') 63 | puts format( ' active checks : %s', hosts_active_checks ) 64 | puts format( ' passive checks: %s', hosts_passive_checks ) 65 | puts '' 66 | puts format( '= host statistics') 67 | puts format( ' up : %s', host_stats_up ) 68 | puts format( ' down : %s', host_stats_down ) 69 | puts format( ' pending : %s', host_stats_pending ) 70 | puts format( ' unreachable : %s', host_stats_unreachable ) 71 | puts format( ' in downtime : %s', host_stats_in_downtime ) 72 | puts format( ' acknowledged : %s', host_stats_acknowledged ) 73 | puts '' 74 | 75 | puts format( '= services') 76 | puts format( ' active checks : %s', services_active_checks ) 77 | puts format( ' passive checks: %s', services_passive_checks ) 78 | puts '' 79 | puts format( '= service statistics') 80 | puts format( ' ok : %s', service_stats_ok ) 81 | puts format( ' warning : %s', service_stats_warning ) 82 | puts format( ' critical : %s', service_stats_critical ) 83 | puts format( ' unknown : %s', service_stats_unknown ) 84 | puts format( ' pending : %s', service_stats_pending ) 85 | puts format( ' in downtime : %s', service_stats_in_downtime ) 86 | puts format( ' acknowledged : %s', service_stats_acknowledged ) 87 | puts '' 88 | puts format( '= workqueue statistics') 89 | 90 | work_queue_stats.each do |k,v| 91 | puts format(' %s : %s', k, v ) 92 | end 93 | puts '' 94 | 95 | puts ' ------------------------------------------------------------- ' 96 | puts '' 97 | 98 | rescue => e 99 | warn( e ) 100 | warn( e.backtrace.join("\n") ) 101 | end 102 | end 103 | 104 | 105 | # ----------------------------------------------------------------------------- 106 | 107 | # EOF 108 | 109 | -------------------------------------------------------------------------------- /examples/test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 23.01.2017 - Bodo Schulz 5 | # 6 | # 7 | # v0.9.2 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | begin 24 | # examples from: https://github.com/saurabh-hirani/icinga2-api-examples 25 | # 26 | # Get display_name, check_command attribute for services applied for filtered hosts matching host.address == 1.2.3.4. 27 | # Join the output with the hosts on which these checks run (services are applied to hosts) 28 | # 29 | puts i.service_objects( 30 | attrs: %w[display_name check_command], 31 | filter: 'match("1.2.3.4",host.address)' , 32 | joins: ['host.name', 'host.address'] 33 | ) 34 | puts '' 35 | # Get all services in critical state and filter out the ones for which active checks are disabled 36 | # service.states - 0 = OK, 1 = WARNING, 2 = CRITICAL 37 | # 38 | # { "joins": ['host.name', 'host.address'], "filter": "service.state==2", "attrs": ['display_name', 'check_command', 'enable_active_checks'] } 39 | puts i.service_objects( 40 | attrs: %w[display_name check_command enable_active_checks], 41 | filter: 'service.state==1', 42 | joins: ['host.name', 'host.address'] 43 | ) 44 | puts '' 45 | # Get host name, address of hosts belonging to a specific hostgroup 46 | puts i.host_objects( 47 | attrs: %w[display_name name address], 48 | filter: '"windows-servers" in host.groups' 49 | ) 50 | 51 | rescue => e 52 | warn( e ) 53 | warn( e.backtrace.join("\n") ) 54 | end 55 | end 56 | 57 | 58 | # ----------------------------------------------------------------------------- 59 | 60 | # EOF 61 | -------------------------------------------------------------------------------- /examples/usergroups.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts ' ==> USERGROUPS' 30 | puts '' 31 | 32 | ['icingaadmins', 'linux-admins'].each do |h| 33 | e = i.exists_usergroup?( h ) ? 'true' : 'false' 34 | puts format( '= check if Usergroup \'%s\' exists : %s', h, e ) 35 | end 36 | puts '' 37 | 38 | puts '= add Usergroup \'foo\'' 39 | puts i.add_usergroup( user_group: 'foo', display_name: 'FOO' ) 40 | puts '' 41 | 42 | puts 'list named Usergroup \'foo\'' 43 | puts i.usergroups( user_group: 'foo' ) 44 | puts '' 45 | 46 | puts '= delete Usergroup \'foo\'' 47 | puts i.delete_usergroup( user_group: 'foo' ) 48 | puts '' 49 | 50 | 51 | puts 'list all Usergroup' 52 | puts i.usergroups 53 | puts '' 54 | puts ' ------------------------------------------------------------- ' 55 | puts '' 56 | 57 | rescue => e 58 | warn( e ) 59 | warn( e.backtrace.join("\n") ) 60 | end 61 | end 62 | 63 | 64 | # ----------------------------------------------------------------------------- 65 | 66 | # EOF 67 | -------------------------------------------------------------------------------- /examples/users.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # 07.10.2017 - Bodo Schulz 5 | # 6 | # 7 | # Examples for Hostgroups 8 | 9 | # ----------------------------------------------------------------------------- 10 | 11 | require_relative '../lib/icinga2' 12 | require_relative 'config' 13 | 14 | # ----------------------------------------------------------------------------- 15 | 16 | i = Icinga2::Client.new( @config ) 17 | 18 | unless( i.nil? ) 19 | 20 | # run tests ... 21 | # 22 | # 23 | 24 | begin 25 | 26 | puts ' ------------------------------------------------------------- ' 27 | puts '' 28 | 29 | puts ' ==> USERS' 30 | puts '' 31 | 32 | ['icingaadmin', 'icinga-admin'].each do |h| 33 | e = i.exists_user?( h ) ? 'true' : 'false' 34 | puts format( '= check if User \'%s\' exists : %s', h, e ) 35 | end 36 | puts '' 37 | 38 | puts '= add User \'foo\'' 39 | puts i.add_user( user_name: 'foo', display_name: 'FOO', email: 'foo@bar.com', pager: '0000', groups: ['icingaadmins'] ) 40 | puts '' 41 | puts '= add User \'foo\' (again)' 42 | puts i.add_user( user_name: 'foo', display_name: 'FOO', email: 'foo@bar.com', pager: '0000', groups: ['icingaadmins'] ) 43 | puts '' 44 | 45 | puts '= list named User \'foo\'' 46 | puts i.users( user_name: 'foo' ) 47 | puts '' 48 | 49 | puts '= delete User \'foo\'' 50 | puts i.delete_user( user_name: 'foo' ) 51 | puts '' 52 | 53 | puts '= list all User' 54 | puts i.users 55 | puts '' 56 | 57 | puts ' ------------------------------------------------------------- ' 58 | puts '' 59 | 60 | rescue => e 61 | warn( e ) 62 | warn( e.backtrace.join("\n") ) 63 | end 64 | end 65 | 66 | 67 | # ----------------------------------------------------------------------------- 68 | 69 | # EOF 70 | -------------------------------------------------------------------------------- /icinga2.gemspec: -------------------------------------------------------------------------------- 1 | 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'icinga2/version' 5 | 6 | Gem::Specification.new do |s| 7 | 8 | s.name = 'icinga2' 9 | s.version = Icinga2::VERSION 10 | s.date = '2018-03-29' 11 | s.summary = 'Ruby SDK for easly access to the Icinga2 API' 12 | s.description = 'An enhanced ruby gem to communicate with Icinga2 API.' + 13 | 'It\'s allowed create small applications to connect to Icinga2 to add Hosts, Services,' + 14 | 'User and so on.' 15 | s.authors = ['Bodo Schulz'] 16 | s.email = 'bodo@boone-schulz.de' 17 | 18 | s.files = Dir[ 19 | 'README.md', 20 | 'LICENSE', 21 | 'lib/**/*', 22 | 'spec/*', 23 | 'doc/*.md', 24 | 'examples/*.rb' 25 | ] 26 | 27 | s.homepage = 'https://github.com/bodsch/ruby-icinga2' 28 | s.license = 'LGPL-2.1+' 29 | 30 | begin 31 | 32 | if( RUBY_VERSION >= '2.0' ) 33 | s.required_ruby_version = '~> 2.0' 34 | elsif( RUBY_VERSION <= '2.1' ) 35 | s.required_ruby_version = '~> 2.1' 36 | elsif( RUBY_VERSION <= '2.2' ) 37 | s.required_ruby_version = '~> 2.2' 38 | elsif( RUBY_VERSION <= '2.3' ) 39 | s.required_ruby_version = '~> 2.3' 40 | end 41 | 42 | s.add_dependency('ruby_dig', '~> 0') if RUBY_VERSION < '2.3' 43 | 44 | s.add_dependency('openssl', '~> 2.0') if RUBY_VERSION >= '2.3' 45 | rescue => e 46 | warn "#{$PROGRAM_NAME}: #{e}" 47 | exit! 48 | end 49 | 50 | s.add_dependency('json', '~> 2.1') 51 | s.add_dependency('rest-client', '~> 2.0') 52 | 53 | s.add_development_dependency('rake', '~> 0') 54 | s.add_development_dependency('rake-notes', '~> 0') 55 | s.add_development_dependency('rubocop', '~> 0.49.0') 56 | s.add_development_dependency('rubocop-checkstyle_formatter', '~> 0') 57 | s.add_development_dependency('rspec', '~> 0') 58 | s.add_development_dependency('rspec_junit_formatter', '~> 0') 59 | s.add_development_dependency('rspec-nc', '~> 0') 60 | s.add_development_dependency('guard', '~> 0') 61 | s.add_development_dependency('guard-rspec', '~> 0') 62 | s.add_development_dependency('pry', '~> 0') 63 | s.add_development_dependency('pry-remote', '~> 0') 64 | s.add_development_dependency('pry-nav', '~> 0') 65 | 66 | end 67 | -------------------------------------------------------------------------------- /lib/icinga2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'ruby_dig' if RUBY_VERSION < '2.3' 4 | 5 | require 'rest-client' 6 | require 'openssl' 7 | 8 | require 'json' 9 | require 'net/http' 10 | require 'uri' 11 | 12 | require_relative 'logging' 13 | require_relative 'monkey_patches' 14 | require_relative 'icinga2/client' 15 | 16 | module Icinga2 17 | end 18 | -------------------------------------------------------------------------------- /lib/icinga2/actions.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: false 3 | 4 | module Icinga2 5 | 6 | # namespace for action handling 7 | # 8 | # There are several actions available for Icinga 2 provided by the /v1/actions URL endpoint. 9 | # 10 | # 11 | # original API Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#actions 12 | # 13 | module Actions 14 | 15 | # Process a check result for a host or a service. 16 | # 17 | # FUNCTION IS NOT IMPLEMENTED YET 18 | # 19 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#process-check-result 20 | # 21 | # @param [Hash] params 22 | # @option params [Integer] exit_status For services: 0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN, for hosts: 0=OK, 1=CRITICAL. 23 | # @option params [String] plugin_output One or more lines of the plugin main output. Does not contain the performance data. 24 | # @option params [Array] performance_data The performance data. 25 | # @option params [Array] check_command The first entry should be the check commands path, then one entry for each command line option followed by an entry for each of its argument. 26 | # @option params [String] check_source Usually the name of the command_endpoint 27 | # @option params [Integer] execution_start The timestamp where a script/process started its execution. 28 | # @option params [Integer] execution_end The timestamp where a script/process ended its execution. This timestamp is used in features to determine e.g. the metric timestamp. 29 | # @option params [String] host_name 30 | # @option params [String] service_name 31 | # @option params [String] type 32 | # @option params [String] filter 33 | # 34 | # @example 35 | # params = { 36 | # host_name: 'example.localdomain', 37 | # service_name: 'passive-ping6', 38 | # exit_status: 2, 39 | # plugin_output: 'PING CRITICAL - Packet loss = 100%', 40 | # performance_data: [ 41 | # 'rta=5000.000000ms;3000.000000;5000.000000;0.000000', 42 | # 'pl=100%;80;100;0' 43 | # ], 44 | # check_source: 'example.localdomain' 45 | # } 46 | # process_check_result(params) 47 | # 48 | # params = { 49 | # exit_status: 1, 50 | # plugin_output: 'Host is not available.', 51 | # type: 'Host', 52 | # filter: 'host.name == "example.localdomain"' 53 | # } 54 | # process_check_result(params) 55 | # 56 | # @return [Hash] result 57 | # 58 | # def process_check_result(params) 59 | # 60 | # raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 61 | # raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 62 | # 63 | # # exit_status = validate( params, required: true, var: 'exit_status', type: Integer ) 64 | # # plugin_output = validate( params, required: true, var: 'plugin_output', type: String ) 65 | # # performance_data = validate( params, required: false, var: 'performance_data', type: Array ) 66 | # # check_command = validate( params, required: false, var: 'check_command', type: Array ) 67 | # # check_source = validate( params, required: false, var: 'check_source', type: String ) 68 | # # execution_start = validate( params, required: false, var: 'execution_start', type: Integer ) 69 | # # execution_end = validate( params, required: false, var: 'execution_end', type: String ) 70 | # 71 | # end 72 | 73 | # 74 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#reschedule-check 75 | # def reschedule_check(params) 76 | # 77 | # # $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/reschedule-check' \ 78 | # # -d '{ "type": "Service", "filter": "service.name==\"ping6\"" }' | python -m json.tool 79 | # end 80 | 81 | # 82 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#send-custom-notification 83 | # def send_custom_notification 84 | # end 85 | 86 | # 87 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#delay-notification 88 | # def delay_notification 89 | # end 90 | 91 | # 92 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#acknowledge-problem 93 | # def acknowledge_problem 94 | # end 95 | 96 | # 97 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#remove-acknowledgement 98 | # def remove_acknowledgement 99 | # end 100 | 101 | # 102 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#add-comment 103 | # def add_comment 104 | # end 105 | 106 | # 107 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#remove-comment 108 | # def remove_comment 109 | # end 110 | 111 | # 112 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#schedule-downtime 113 | # def schedule_downtime 114 | # end 115 | 116 | # Shuts down Icinga2. 117 | # 118 | # @example 119 | # shutdown_process 120 | # 121 | # @return [Hash] 122 | # 123 | def shutdown_process 124 | post( 125 | url: format('%s/actions/shutdown-process', @icinga_api_url_base), 126 | headers: @headers, 127 | options: @options 128 | ) 129 | end 130 | 131 | # Restarts Icinga2. 132 | # 133 | # @example 134 | # restart_process 135 | # 136 | # @return [Hash] 137 | # 138 | def restart_process 139 | post( 140 | url: format('%s/actions/restart-process', @icinga_api_url_base), 141 | headers: @headers, 142 | options: @options 143 | ) 144 | end 145 | 146 | # 147 | # original Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#generate-ticket 148 | # def generate_ticket 149 | # end 150 | 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /lib/icinga2/client.rb: -------------------------------------------------------------------------------- 1 | 2 | require_relative 'version' 3 | require_relative 'validator' 4 | require_relative 'network' 5 | require_relative 'statistics' 6 | require_relative 'converts' 7 | require_relative 'tools' 8 | require_relative 'downtimes' 9 | require_relative 'notifications' 10 | require_relative 'hosts' 11 | require_relative 'hostgroups' 12 | require_relative 'services' 13 | require_relative 'servicegroups' 14 | require_relative 'users' 15 | require_relative 'usergroups' 16 | require_relative 'configuration_management' 17 | require_relative 'actions' 18 | 19 | # ------------------------------------------------------------------------------------------------------------------- 20 | # 21 | # @abstract # Namespace for classes and modules that handle all Icinga2 API calls 22 | # 23 | # @author Bodo Schulz 24 | # 25 | # 26 | module Icinga2 27 | 28 | # static variable for hosts down 29 | HOSTS_DOWN = 1 30 | # static variable for hosts critical 31 | HOSTS_CRITICAL = 2 32 | # static variable for hosts unknown 33 | HOSTS_UNKNOWN = 3 34 | 35 | # static variables for handled warning 36 | SERVICE_STATE_WARNING = 1 37 | # static variables for handled critical 38 | SERVICE_STATE_CRITICAL = 2 39 | # static variables for handled unknown 40 | SERVICE_STATE_UNKNOWN = 3 41 | 42 | # Abstract base class for the API calls. 43 | # Provides some helper methods 44 | # 45 | # @author Bodo Schulz 46 | # 47 | class Client 48 | 49 | include Logging 50 | 51 | include Icinga2::Validator 52 | include Icinga2::Network 53 | include Icinga2::Statistics 54 | include Icinga2::Converts 55 | include Icinga2::Tools 56 | include Icinga2::Downtimes 57 | include Icinga2::Notifications 58 | include Icinga2::Hosts 59 | include Icinga2::Hostgroups 60 | include Icinga2::Services 61 | include Icinga2::Servicegroups 62 | include Icinga2::Users 63 | include Icinga2::Usergroups 64 | include Icinga2::ConfigurationManagement 65 | include Icinga2::Actions 66 | 67 | # Returns a new instance of Client 68 | # 69 | # @param [Hash, #read] settings the settings for Icinga2 70 | # @option settings [String] host the Icinga2 Hostname 71 | # @option settings [Integer] port (5665) the Icinga2 API Port 72 | # @option settings [String] username the Icinga2 API User 73 | # @option settings [String] password the Icinga2 API Password 74 | # @option settings [Integer] version (1) the Icinga2 API Version 75 | # @option settings [String] pki_path the location of the Certificate Files 76 | # @option settings [String] node_name overwrite the Icnag2 hostname for the PKI. if the node_name no set, we try to resolve with gethostbyname() 77 | # 78 | # @example to create an new Instance 79 | # config = { 80 | # icinga: { 81 | # host: '192.168.33.5', 82 | # api: { 83 | # username: 'root', 84 | # password: 'icinga', 85 | # version: 1 86 | # } 87 | # } 88 | # } 89 | # @icinga = Icinga2::Client.new(config) 90 | # 91 | # @return [instance, #read] 92 | # 93 | def initialize( settings ) 94 | 95 | raise ArgumentError.new(format('wrong type. \'settings\' must be an Hash, given \'%s\'', settings.class.to_s)) unless( settings.is_a?(Hash) ) 96 | raise ArgumentError.new('missing settings') if( settings.size.zero? ) 97 | 98 | icinga_host = settings.dig(:icinga, :host) 99 | icinga_api_port = settings.dig(:icinga, :api, :port) || 5665 100 | icinga_api_user = settings.dig(:icinga, :api, :username) 101 | icinga_api_pass = settings.dig(:icinga, :api, :password) 102 | icinga_api_version = settings.dig(:icinga, :api, :version) || 1 103 | icinga_api_pki_path = settings.dig(:icinga, :api, :pki_path) 104 | icinga_api_node_name = settings.dig(:icinga, :api, :node_name) 105 | 106 | @last_call_timeout = 320 107 | @last_cib_data_called = 0 108 | @last_status_data_called = 0 109 | @last_application_data_called = 0 110 | @last_service_objects_called = 0 111 | @last_host_objects_called = 0 112 | 113 | @icinga_api_url_base = format( 'https://%s:%d/v%s', icinga_host, icinga_api_port, icinga_api_version ) 114 | 115 | _has_cert, @options = cert?( 116 | pki_path: icinga_api_pki_path, 117 | node_name: icinga_api_node_name, 118 | username: icinga_api_user, 119 | password: icinga_api_pass 120 | ) 121 | 122 | @headers = { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } 123 | end 124 | 125 | # create a HTTP Header based on a Icinga2 Certificate or an User API Login 126 | # 127 | # @param [Hash, #read] params 128 | # @option params [String] pki_path the location of the Certificate Files 129 | # @option params [String] node_name the Icinga2 Hostname 130 | # @option params [String] user the Icinga2 API User 131 | # @option params [String] password the Icinga2 API Password 132 | # 133 | # @example with Certificate 134 | # cert?(pki_path: '/etc/icinga2', node_name: 'icinga2-dashing') 135 | # 136 | # @example with User 137 | # cert?(username: 'root', password: 'icinga') 138 | # 139 | # @return [Array] 140 | # 141 | def cert?( params ) 142 | 143 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 144 | raise ArgumentError.new('missing params') if( params.size.zero? ) 145 | 146 | pki_path = params.dig(:pki_path) 147 | node_name = params.dig(:node_name) 148 | username = params.dig(:username) 149 | password = params.dig(:password) 150 | 151 | if( node_name.nil? ) 152 | begin 153 | node_name = Socket.gethostbyname(Socket.gethostname).first 154 | logger.debug(format('node name: %s', node_name)) 155 | rescue SocketError => e 156 | raise format("can't resolve hostname (%s)", e) 157 | end 158 | end 159 | 160 | ssl_cert_file = format( '%s/%s.crt', pki_path, node_name ) 161 | ssl_key_file = format( '%s/%s.key', pki_path, node_name ) 162 | ssl_ca_file = format( '%s/ca.crt', pki_path ) 163 | 164 | if( File.file?( ssl_cert_file ) && File.file?( ssl_key_file ) && File.file?( ssl_ca_file ) ) 165 | 166 | logger.debug( 'PKI found, using client certificates for connection to Icinga 2 API' ) 167 | 168 | ssl_cert_file = File.read( ssl_cert_file ) 169 | ssl_key_file = File.read( ssl_key_file ) 170 | ssl_ca_file = File.read( ssl_ca_file ) 171 | 172 | cert = OpenSSL::X509::Certificate.new( ssl_cert_file ) 173 | key = OpenSSL::PKey::RSA.new( ssl_key_file ) 174 | 175 | [true, { 176 | ssl_client_cert: cert, 177 | ssl_client_key: key, 178 | ssl_ca_file: ssl_ca_file, 179 | verify_ssl: OpenSSL::SSL::VERIFY_NONE 180 | } ] 181 | 182 | else 183 | logger.debug( 'PKI not found, using basic auth for connection to Icinga 2 API' ) 184 | 185 | raise ArgumentError.new('Missing \'username\'') if( username.nil? ) 186 | raise ArgumentError.new('Missing \'password\'') if( password.nil? ) 187 | 188 | [false, { 189 | user: username, 190 | password: password, 191 | verify_ssl: OpenSSL::SSL::VERIFY_NONE 192 | } ] 193 | end 194 | end 195 | 196 | # return Icinga2 Application data 197 | # 198 | # @example 199 | # application_data 200 | # 201 | # @return [Hash] 202 | # 203 | def application_data 204 | 205 | data = icinga_application_data( 206 | url: format( '%s/status/IcingaApplication', @icinga_api_url_base ), 207 | headers: @headers, 208 | options: @options 209 | ) 210 | 211 | return nil if( data.nil? ) 212 | return nil unless(data.is_a?(Hash)) 213 | 214 | app_data = data.dig('icingaapplication','app') 215 | 216 | # version and revision 217 | @version, @revision = parse_version(app_data.dig('version')) 218 | # - node_name 219 | @node_name = app_data.dig('node_name') 220 | # - start_time 221 | @start_time = Time.at(app_data.dig('program_start').to_f) 222 | 223 | data 224 | end 225 | 226 | # return Icinga2 CIB 227 | # 228 | # @example 229 | # cib_data 230 | # 231 | # @return [Hash] 232 | # 233 | def cib_data 234 | 235 | data = icinga_application_data( 236 | url: format( '%s/status/CIB', @icinga_api_url_base ), 237 | headers: @headers, 238 | options: @options 239 | ) 240 | 241 | return nil if( data.nil? ) 242 | 243 | @last_cib_data_called = 0 #Time.now.to_i 244 | 245 | if( data.is_a?(Hash)) 246 | 247 | cib_data = data.clone 248 | 249 | # extract 250 | # - uptime 251 | uptime = cib_data.dig('uptime').round(2) 252 | @uptime = Time.at(uptime).utc.strftime('%H:%M:%S') 253 | # - avg_latency / avg_execution_time 254 | @avg_latency = cib_data.dig('avg_latency').round(2) 255 | @avg_execution_time = cib_data.dig('avg_execution_time').round(2) 256 | 257 | # - hosts 258 | @hosts_up = cib_data.dig('num_hosts_up').to_i 259 | @hosts_down = cib_data.dig('num_hosts_down').to_i 260 | @hosts_pending = cib_data.dig('num_hosts_pending').to_i 261 | @hosts_unreachable = cib_data.dig('num_hosts_unreachable').to_i 262 | @hosts_in_downtime = cib_data.dig('num_hosts_in_downtime').to_i 263 | @hosts_acknowledged = cib_data.dig('num_hosts_acknowledged').to_i 264 | 265 | # - services 266 | @services_ok = cib_data.dig('num_services_ok').to_i 267 | @services_warning = cib_data.dig('num_services_warning').to_i 268 | @services_critical = cib_data.dig('num_services_critical').to_i 269 | @services_unknown = cib_data.dig('num_services_unknown').to_i 270 | @services_pending = cib_data.dig('num_services_pending').to_i 271 | @services_in_downtime = cib_data.dig('num_services_in_downtime').to_i 272 | @services_acknowledged = cib_data.dig('num_services_acknowledged').to_i 273 | 274 | # - check stats 275 | @hosts_active_checks_1min = cib_data.dig('active_host_checks_1min') 276 | @hosts_passive_checks_1min = cib_data.dig('passive_host_checks_1min') 277 | @services_active_checks_1min = cib_data.dig('active_service_checks_1min') 278 | @services_passive_checks_1min = cib_data.dig('passive_service_checks_1min') 279 | 280 | end 281 | 282 | data 283 | end 284 | 285 | # return Icinga2 Status Data 286 | # 287 | # @example 288 | # status_data 289 | # 290 | # @return [Hash] 291 | # 292 | def status_data 293 | 294 | @last_status_data_called = Time.now.to_i 295 | 296 | icinga_application_data( 297 | url: format( '%s/status', @icinga_api_url_base ), 298 | headers: @headers, 299 | options: @options 300 | ) 301 | end 302 | 303 | # return Icinga2 API Listener 304 | # 305 | # @example 306 | # api_listener 307 | # 308 | # @return [Hash] 309 | # 310 | def api_listener 311 | 312 | @last_application_data_called = Time.now.to_i 313 | 314 | icinga_application_data( 315 | url: format( '%s/status/ApiListener', @icinga_api_url_base ), 316 | headers: @headers, 317 | options: @options 318 | ) 319 | end 320 | 321 | # check the availability of a Icinga network connect 322 | # 323 | # @example 324 | # available? 325 | # 326 | # @return [Bool] 327 | # 328 | def available? 329 | 330 | data = application_data 331 | 332 | return true unless( data.nil? ) 333 | 334 | false 335 | end 336 | 337 | # return Icinga2 version and revision 338 | # 339 | # @example 340 | # version.values 341 | # 342 | # v = version 343 | # version = v.dig(:version) 344 | # 345 | # @return [Hash] 346 | # * version 347 | # * revision 348 | # 349 | def version 350 | 351 | application_data if((Time.now.to_i - @last_application_data_called).to_i > @last_call_timeout) 352 | 353 | version = @version.nil? ? 0 : @version 354 | revision = @revision.nil? ? 0 : @revision 355 | 356 | { 357 | version: version.to_s, 358 | revision: revision.to_s 359 | } 360 | end 361 | 362 | # return Icinga2 node_name 363 | # 364 | # @example 365 | # node_name 366 | # 367 | # @return [String] 368 | # 369 | def node_name 370 | 371 | application_data if((Time.now.to_i - @last_application_data_called).to_i > @last_call_timeout) 372 | 373 | return @node_name if( @node_name ) 374 | 375 | nil 376 | end 377 | 378 | # return Icinga2 start time 379 | # 380 | # @example 381 | # start_time 382 | # 383 | # @return [String] 384 | # 385 | def start_time 386 | 387 | application_data if((Time.now.to_i - @last_application_data_called).to_i > @last_call_timeout) 388 | 389 | return @start_time if( @start_time ) 390 | 391 | nil 392 | end 393 | 394 | # return Icinga2 uptime 395 | # 396 | # @example 397 | # cib_data 398 | # uptime 399 | # 400 | # @return [String] 401 | # 402 | def uptime 403 | 404 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 405 | 406 | return @uptime if( @uptime ) 407 | 408 | nil 409 | end 410 | 411 | end 412 | end 413 | -------------------------------------------------------------------------------- /lib/icinga2/configuration_management.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for config packages 7 | # 8 | # The main idea behind configuration management is to allow external applications creating configuration packages and stages based on configuration files and directory trees. 9 | # 10 | # This replaces any additional SSH connection and whatnot to dump configuration files to Icinga 2 directly. 11 | # 12 | # In case you are pushing a new configuration stage to a package, Icinga 2 will validate the configuration asynchronously and populate a status log which can be fetched in a separated request. 13 | # 14 | # original API Documentation: https://www.icinga.com/docs/icinga2/latest/doc/12-icinga2-api/#configuration-management 15 | # 16 | module ConfigurationManagement 17 | 18 | # create a new empty configuration package. 19 | # 20 | # Package names starting with an underscore are reserved for internal packages and can not be used. 21 | # 22 | # @param [String] name the name for the new package. 23 | # 24 | # @example 25 | # create_config_package('cfg-package') 26 | # 27 | # @return [Hash] 28 | # 29 | def create_config_package(name) 30 | 31 | raise ArgumentError.new(format('wrong type. \'name\' must be an String, given \'%s\'', name.class.to_s)) unless( name.is_a?(String) ) 32 | raise ArgumentError.new('missing \'name\'') if( name.size.zero? ) 33 | 34 | return { 'code' => 404, 'name' => name, 'status' => 'Package names starting with an underscore are reserved for internal packages and can not be used.' } if( name.initial == '_' ) 35 | 36 | post( 37 | url: format( '%s/config/packages/%s', @icinga_api_url_base, name ), 38 | headers: @headers, 39 | options: @options 40 | ) 41 | end 42 | 43 | # Configuration files in packages are managed in stages. 44 | # Stages provide a way to maintain multiple configuration versions for a package. 45 | # 46 | # @param [Hash] params 47 | # @option params [String] package name of the package 48 | # @option params [String] name name for the package 49 | # @option params [Bool] cluser (false) package for an satellite 50 | # @option params [Bool] reload (true) reload icinga2 after upload 51 | # @option params [String] vars 52 | # 53 | # @example 54 | # params = { 55 | # package: 'cfg-package', 56 | # name: 'host1', 57 | # cluster: false, 58 | # vars: 'object Host "cmdb-host" { chec_command = "dummy" }', 59 | # reload: false 60 | # } 61 | # upload_config_package(params) 62 | # 63 | # @return [Hash] 64 | # 65 | def upload_config_package(params) 66 | 67 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 68 | raise ArgumentError.new('missing params') if( params.size.zero? ) 69 | 70 | package = validate( params, required: true, var: 'package', type: String ) 71 | name = validate( params, required: true, var: 'name', type: String ) 72 | cluster = validate( params, required: false, var: 'cluster', type: Boolean ) || false 73 | vars = validate( params, required: false, var: 'vars', type: String ) 74 | reload = validate( params, required: false, var: 'reload', type: Boolean ) || true 75 | name = name.gsub('.conf','') 76 | 77 | return { 'code' => 404, 'status' => format('no package \'%s\' exists', package) } unless(package_exists?(package)) 78 | 79 | path = 'conf.d' 80 | path = 'zones.d/satellite' if(cluster) 81 | file = format( '%s/%s.conf', path, name ) 82 | 83 | payload = { 84 | 'files' => { 85 | file.to_s => vars 86 | }, 87 | 'reload' => reload 88 | } 89 | 90 | post( 91 | url: format( '%s/config/stages/%s', @icinga_api_url_base, package ), 92 | headers: @headers, 93 | options: @options, 94 | payload: payload 95 | ) 96 | end 97 | 98 | # A list of packages. 99 | # 100 | # @example 101 | # list_config_packages 102 | # 103 | # @return [Hash] 104 | # 105 | def list_config_packages 106 | 107 | get( 108 | url: format( '%s/config/packages', @icinga_api_url_base ), 109 | headers: @headers, 110 | options: @options 111 | ) 112 | end 113 | 114 | # A list of packages and their stages. 115 | # 116 | # @param [Hash] params 117 | # @option params [String] package 118 | # @option params [String] stage 119 | # 120 | # @example 121 | # params = { 122 | # package: 'cfg-package', 123 | # stage: 'example.localdomain-1441625839-0' 124 | # } 125 | # list_config_stages(params) 126 | # 127 | # @return [Hash] 128 | # 129 | def list_config_stages(params) 130 | 131 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 132 | raise ArgumentError.new('missing params') if( params.size.zero? ) 133 | 134 | package = validate( params, required: true, var: 'package', type: String ) 135 | stage = validate( params, required: true, var: 'stage', type: String ) 136 | 137 | get( 138 | url: format( '%s/config/stages/%s/%s', @icinga_api_url_base, package, stage ), 139 | headers: @headers, 140 | options: @options 141 | ) 142 | end 143 | 144 | 145 | # fetched the whole config package and return them as a String. 146 | # 147 | # @param [Hash] params 148 | # @option params [String] package 149 | # @option params [String] stage 150 | # @option params [Bool] cluser (false) package for an satellite 151 | # @option params [String] name 152 | # 153 | # @example 154 | # params = { 155 | # package: 'cfg-package', 156 | # stage: 'example.localdomain-1441625839-0', 157 | # name: 'host1', 158 | # cluster: false 159 | # } 160 | # fetch_config_stages(params) 161 | # 162 | # @return [String] 163 | # 164 | def fetch_config_stages(params) 165 | 166 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 167 | raise ArgumentError.new('missing params') if( params.size.zero? ) 168 | 169 | package = validate( params, required: true, var: 'package', type: String ) 170 | stage = validate( params, required: true, var: 'stage', type: String ) 171 | name = validate( params, required: true, var: 'name', type: String ) 172 | cluster = validate( params, required: false, var: 'cluster', type: Boolean ) || false 173 | name = name.gsub('.conf','') 174 | 175 | return { 'code' => 404, 'status' => format('no package \'%s\' exists', package) } unless(package_exists?(package)) 176 | 177 | path = 'conf.d' 178 | path = 'zones.d/satellite' if(cluster) 179 | file = format( '%s/%s/%s/%s.conf', package, stage, path, name ) 180 | 181 | get( 182 | url: format( '%s/config/files/%s', @icinga_api_url_base, file ), 183 | headers: {}, 184 | options: @options 185 | ) 186 | end 187 | 188 | # fetch the startup.log from the named packe / stage combination to see possible errors. 189 | # 190 | # @param [Hash] params 191 | # @option params [String] package 192 | # @option params [String] stage 193 | # @option params [Bool] cluser (false) package for an satellite 194 | # 195 | # @example 196 | # params = { 197 | # package: 'cfg-package', 198 | # stage: 'example.localdomain-1441625839-0', 199 | # cluster: false 200 | # } 201 | # package_stage_errors(params) 202 | # 203 | # @return [String] 204 | # 205 | def package_stage_errors(params) 206 | 207 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 208 | raise ArgumentError.new('missing params') if( params.size.zero? ) 209 | 210 | package = validate( params, required: true, var: 'package', type: String ) 211 | stage = validate( params, required: true, var: 'stage', type: String ) 212 | # cluster = validate( params, required: false, var: 'cluster', type: Boolean ) || false 213 | 214 | return { 'code' => 404, 'status' => format('no package \'%s\' exists', package) } unless(package_exists?(package)) 215 | 216 | file = format( '%s/%s/startup.log', package, stage ) 217 | 218 | get( 219 | url: format( '%s/config/files/%s', @icinga_api_url_base, file ), 220 | headers: {}, 221 | options: @options 222 | ) 223 | end 224 | 225 | # Deleting Configuration Package Stage 226 | # 227 | # @param [Hash] params 228 | # @option params [String] package 229 | # @option params [String] stage 230 | # 231 | # @example 232 | # params = { 233 | # package: 'cfg-package', 234 | # stage: 'example.localdomain-1441625839-0', 235 | # cluster: false 236 | # } 237 | # remove_config_stage(params) 238 | # 239 | # @return [Hash] 240 | # 241 | def remove_config_stage(params) 242 | 243 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 244 | raise ArgumentError.new('missing params') if( params.size.zero? ) 245 | 246 | package = validate( params, required: true, var: 'package', type: String ) 247 | stage = validate( params, required: true, var: 'stage', type: String ) 248 | 249 | return { 'code' => 404, 'name' => package, 'status' => 'Package names starting with an underscore are reserved for internal packages and can not be used.' } if( package.initial == '_' ) 250 | return { 'code' => 404, 'status' => format('no package \'%s\' exists', name) } unless(package_exists?(package)) 251 | 252 | delete( 253 | url: format( '%s/config/stages/%s/%s', @icinga_api_url_base, package, stage ), 254 | headers: @headers, 255 | options: @options 256 | ) 257 | end 258 | 259 | # Deleting Configuration Package 260 | # 261 | # @param [String] name the name for the package. 262 | # 263 | # @example 264 | # remove_config_package('cfg-package') 265 | # 266 | # @return [Hash] 267 | # 268 | def remove_config_package(name) 269 | 270 | raise ArgumentError.new(format('wrong type. \'name\' must be an String, given \'%s\'', name.class.to_s)) unless( name.is_a?(String) ) 271 | raise ArgumentError.new('missing \'name\'') if( name.size.zero? ) 272 | 273 | return { 'code' => 404, 'name' => name, 'status' => 'Package names starting with an underscore are reserved for internal packages and can not be used.' } if( name.initial == '_' ) 274 | return { 'code' => 404, 'status' => format('no package \'%s\' exists', name) } unless(package_exists?(name)) 275 | 276 | delete( 277 | url: format( '%s/config/packages/%s', @icinga_api_url_base, name ), 278 | headers: @headers, 279 | options: @options 280 | ) 281 | end 282 | 283 | # check if a package exists 284 | # 285 | # @param [String] name the name for the package. 286 | # 287 | # @example 288 | # package_exists?('cfg-package') 289 | # 290 | # @return [Bool] 291 | # 292 | def package_exists?(name) 293 | 294 | raise ArgumentError.new(format('wrong type. \'name\' must be an String, given \'%s\'', name.class.to_s)) unless( name.is_a?(String) ) 295 | raise ArgumentError.new('missing \'name\'') if( name.size.zero? ) 296 | 297 | current_packages = list_config_packages 298 | 299 | return { 'code' => 404, 'status' => 'error to get packages' } if( current_packages.nil? && current_packages.dig('code') != 200 ) 300 | 301 | current_packages = current_packages.dig('results') 302 | 303 | data = current_packages.select { |k,_| k['name'] == name } 304 | data = data.first if( data ) 305 | 306 | return false unless(data) 307 | 308 | true 309 | end 310 | 311 | end 312 | end 313 | -------------------------------------------------------------------------------- /lib/icinga2/converts.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # many convert functions 7 | # 8 | # 9 | module Converts 10 | 11 | HOST_STATE_STRING = %w[Up Down].freeze 12 | SERVICE_STATE_STRING = %w[OK Warning Critical Unknown].freeze 13 | 14 | HOST_STATE_COLOR = %w[green red].freeze 15 | SERVICE_STATE_COLOR = %w[green yellow red purple].freeze 16 | 17 | # convert a Icinga2 state into a human readable state 18 | # 19 | # @param [String] state the Icinga2 State 20 | # @param [Bool] is_host (false) if this a Host or a Service Check 21 | # 22 | # @return [String] 23 | # 24 | def state_to_string( state, is_host = false ) 25 | result = SERVICE_STATE_STRING[state] unless( is_host ) 26 | result = HOST_STATE_STRING[state] if( is_host ) 27 | result = 'Undefined' if( result.nil? ) 28 | result 29 | end 30 | 31 | # convert a Icinga2 state into a named color 32 | # 33 | # @param [String] state the Icinga2 State 34 | # @param [Bool] is_host (false) if this a Host or a Service Check 35 | # 36 | # @return [String] 37 | # 38 | def state_to_color( state, is_host = false ) 39 | result = SERVICE_STATE_COLOR[state] unless( is_host ) 40 | result = HOST_STATE_COLOR[state] if( is_host ) 41 | result = 'blue' if( result.nil? ) 42 | result 43 | end 44 | 45 | # reformat a service check name 46 | # 47 | # @param [String] name 48 | # 49 | # @return [String] 50 | # 51 | def self.format_service( name ) 52 | service_map = name.split('!', 2) 53 | service_map.join( ' - ' ) 54 | end 55 | 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/icinga2/downtimes.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for downtimes handling 7 | # 8 | # Schedule a downtime for hosts and services. 9 | # 10 | module Downtimes 11 | 12 | # add downtime 13 | # 14 | # @param [Hash] params 15 | # @option params [String] host_name 16 | # @option params [String] host_group 17 | # @option params [String] type 'host' or 'service' downtime 18 | # @option params [Integer] start_time (Time.new.to_i) Timestamp marking the beginning of the downtime. (required) 19 | # @option params [Integer] end_time Timestamp marking the end of the downtime. (required) 20 | # @option params [String] author Name of the author. (required) 21 | # @option params [String] comment Comment text. (required) 22 | # @option params [String] config_owner 23 | # @option params [Integer] duration Duration of the downtime in seconds if fixed is set to false. (Required for flexible downtimes.) 24 | # @option params [Integer] entry_time 25 | # @option params [Bool] fixed (true) Defaults to true. If true, the downtime is fixed otherwise flexible. See downtimes for more information. 26 | # @option params [String] scheduled_by 27 | # @option params [String] service_name 28 | # @option params [String] triggered_by Sets the trigger for a triggered downtime. See downtimes for more information on triggered downtimes. 29 | # 30 | # @example 31 | # param = { 32 | # name: 'test', 33 | # type: 'service', 34 | # host_name: 'icinga2', 35 | # comment: 'test downtime', 36 | # author: 'icingaadmin', 37 | # start_time: Time.now.to_i, 38 | # end_time: Time.now.to_i + 20 39 | # } 40 | # add_downtime(param) 41 | # 42 | # @return [Hash] 43 | # 44 | def add_downtime( params ) 45 | 46 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 47 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 48 | 49 | host_name = validate( params, required: false, var: 'host_name', type: String ) 50 | host_group = validate( params, required: false, var: 'host_group', type: String ) 51 | start_time = validate( params, required: false, var: 'start_time', type: Integer ) || Time.now.to_i 52 | end_time = validate( params, required: false, var: 'end_time', type: Integer ) 53 | author = validate( params, required: true, var: 'author', type: String ) 54 | comment = validate( params, required: true, var: 'comment', type: String ) 55 | type = validate( params, required: false, var: 'type', type: String ) 56 | fixed = validate( params, required: false, var: 'fixed', type: Boolean ) || true 57 | duration_required = true if( fixed == false ) 58 | duration = validate( params, required: duration_required, var: 'duration', type: Integer ) 59 | entry_time = validate( params, required: false, var: 'entry_time', type: Integer ) 60 | scheduled_by = validate( params, required: false, var: 'scheduled_by', type: String ) 61 | service_name = validate( params, required: false, var: 'service_name', type: String ) 62 | triggered_by = validate( params, required: false, var: 'triggered_by', type: String ) 63 | config_owner = validate( params, required: false, var: 'config_owner', type: String ) 64 | filter = nil 65 | 66 | # sanitychecks 67 | # 68 | raise ArgumentError.new(format('wrong downtype type. only \'host\' or \'service\' allowed, given \%s\'', type)) if( %w[host service].include?(type.downcase) == false ) 69 | raise ArgumentError.new('choose \'host_name\' or \'host_group\', not both') unless( host_group.nil? || host_name.nil? ) 70 | raise ArgumentError.new(format('these \'author\' are not exists: \'%s\'', author)) unless( exists_user?( author ) ) 71 | raise ArgumentError.new('Missing downtime \'end_time\'') if( end_time.nil? ) 72 | raise ArgumentError.new('\'end_time\' are equal or smaller then \'start_time\'') if( end_time.to_i <= start_time ) 73 | 74 | # TODO 75 | # - more flexibility (e.g. support scheduled_by ...) 76 | 77 | unless( host_name.nil? ) 78 | return { 'code' => 404, 'name' => host_name, 'status' => 'Object not Found' } unless( exists_host?( host_name ) ) 79 | filter = format( 'host.name == "%s"', host_name ) 80 | end 81 | 82 | unless( host_group.nil? ) 83 | return { 'code' => 404, 'name' => host_group, 'status' => 'Object not Found' } unless( exists_hostgroup?( host_group ) ) 84 | filter = format( '"%s" in host.groups', host_group ) 85 | end 86 | 87 | payload = { 88 | type: type.capitalize, # we need the first char as Uppercase 89 | filter: filter, 90 | fixed: fixed, 91 | start_time: start_time, 92 | end_time: end_time, 93 | author: author, 94 | comment: comment, 95 | duration: duration, 96 | entry_time: entry_time, 97 | scheduled_by: scheduled_by, 98 | host_name: host_name, 99 | host_group: host_group, 100 | service_name: service_name, 101 | triggered_by: triggered_by, 102 | config_owner: config_owner 103 | } 104 | 105 | # remove all empty attrs 106 | payload.reject!{ |_k, v| v.nil? } 107 | 108 | post( 109 | url: format( '%s/actions/schedule-downtime', @icinga_api_url_base ), 110 | headers: @headers, 111 | options: @options, 112 | payload: payload 113 | ) 114 | end 115 | 116 | # remove downtime 117 | # 118 | # @param [Hash] params 119 | # @option params [String] host_name 120 | # @option params [String] host_group 121 | # @option params [String] author Name of the author. (required) 122 | # @option params [String] comment Comment text. (required) 123 | # @option params [String] service_name 124 | # @option params [String] filter 125 | # @option params [Hash] filter_vars 126 | # 127 | # 128 | # @example 129 | # param = { 130 | # comment: 'test downtime', 131 | # author: 'icingaadmin' 132 | # } 133 | # remove_downtime(param) 134 | # 135 | # param = { 136 | # filter: '"host.name == filterHost && !service && downtime.author == filterAuthor"', 137 | # filter_vars: { filterHost: 'c1-mysql-1', filterAuthor: 'icingaadmin' } 138 | # ) 139 | # remove_downtime(param) 140 | # 141 | # param = { 142 | # host_name: 'c1-mysql-1', 143 | # service_name: 'ping4' 144 | # } 145 | # remove_downtime(param) 146 | # 147 | # @return [Hash] 148 | # 149 | def remove_downtime( params ) 150 | 151 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 152 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 153 | 154 | host_name = validate( params, required: false, var: 'host_name', type: String ) 155 | host_group = validate( params, required: false, var: 'host_group', type: String ) 156 | author = validate( params, required: false, var: 'author', type: String ) 157 | comment = validate( params, required: false, var: 'comment', type: String ) 158 | service_name = validate( params, required: false, var: 'service_name', type: String ) 159 | filter = validate( params, required: false, var: 'filter', type: String ) 160 | filter_vars = validate( params, required: false, var: 'filter_vars', type: Hash ) 161 | 162 | payload = { 163 | type: 'Downtime', 164 | host_name: host_name, 165 | service_name: service_name, 166 | host_group: host_group, 167 | comment: comment, 168 | author: author, 169 | filter: filter, 170 | filter_vars: filter_vars 171 | } 172 | 173 | # remove all empty attrs 174 | payload.reject!{ |_k, v| v.nil? } 175 | 176 | post( 177 | url: format( '%s/actions/remove-downtime', @icinga_api_url_base ), 178 | headers: @headers, 179 | options: @options, 180 | payload: payload 181 | ) 182 | end 183 | 184 | # return downtimes 185 | # 186 | # @example 187 | # downtimes 188 | # 189 | # @return [Array] 190 | # 191 | def downtimes 192 | 193 | api_data( 194 | url: format( '%s/objects/downtimes' , @icinga_api_url_base ), 195 | headers: @headers, 196 | options: @options 197 | ) 198 | end 199 | 200 | end 201 | end 202 | -------------------------------------------------------------------------------- /lib/icinga2/hostgroups.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: false 3 | 4 | module Icinga2 5 | 6 | # namespace for hostgroup handling 7 | module Hostgroups 8 | 9 | # add a hostgroup 10 | # 11 | # @param [Hash] params 12 | # @option params [String] host_group hostgroup to create 13 | # @option params [String] display_name the displayed name 14 | # @option params [String] notes 15 | # @option params [String] notes_url 16 | # @option params [String] action_url 17 | # @option params [Hash] vars ({}) 18 | # 19 | # @example 20 | # add_hostgroup(host_group: 'foo', display_name: 'FOO') 21 | # 22 | # @return [Hash] result 23 | # 24 | def add_hostgroup( params ) 25 | 26 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 27 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 28 | 29 | host_group = validate( params, required: true, var: 'host_group', type: String ) 30 | display_name = validate( params, required: false, var: 'display_name', type: String ) 31 | notes = validate( params, required: false, var: 'notes', type: String ) 32 | notes_url = validate( params, required: false, var: 'notes_url', type: String ) 33 | action_url = validate( params, required: false, var: 'action_url', type: String ) 34 | vars = validate( params, required: false, var: 'vars', type: Hash ) || {} 35 | 36 | payload = { 37 | attrs: { 38 | display_name: display_name, 39 | notes: notes, 40 | notes_url: notes_url, 41 | action_url: action_url, 42 | vars: vars 43 | } 44 | } 45 | 46 | # remove all empty attrs 47 | payload.reject!{ |_k, v| v.nil? } 48 | payload[:attrs].reject!{ |_k, v| v.nil? } 49 | 50 | put( 51 | url: format('%s/objects/hostgroups/%s', @icinga_api_url_base, host_group), 52 | headers: @headers, 53 | options: @options, 54 | payload: payload 55 | ) 56 | end 57 | 58 | # delete a hostgroup 59 | # 60 | # @param [Hash] params 61 | # @option params [String] name hostgroup to delete 62 | # @option params [Bool] cascade (false) delete hostgroup also when other objects depend on it 63 | # 64 | # @example 65 | # delete_hostgroup(name: 'foo') 66 | # delete_hostgroup(name: 'foo', cascade: true) 67 | # 68 | # @return [Hash] result 69 | # 70 | def delete_hostgroup( params ) 71 | 72 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 73 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 74 | 75 | name = validate( params, required: true, var: 'name', type: String ) 76 | cascade = validate( params, required: false, var: 'cascade', type: Boolean ) || false 77 | 78 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_hostgroup?( name ) == false ) 79 | 80 | url = format( '%s/objects/hostgroups/%s%s', @icinga_api_url_base, name, cascade.is_a?(TrueClass) ? '?cascade=1' : nil ) 81 | 82 | delete( 83 | url: url, 84 | headers: @headers, 85 | options: @options 86 | ) 87 | end 88 | 89 | # returns all usersgroups 90 | # 91 | # @param [String] host_group (nil) optional for a single hostgroup 92 | # 93 | # @example to get all users 94 | # hostgroups 95 | # 96 | # @example to get one user 97 | # hostgroups(host_group: 'linux-servers') 98 | # 99 | # @return [Hash] returns a hash with all hostgroups 100 | # 101 | def hostgroups( host_group = nil ) 102 | 103 | raise ArgumentError.new(format('wrong type. \'host_group\' must be an String, given \'%s\'', host_group.class.to_s)) unless( host_group.nil? || host_group.is_a?(String) ) 104 | 105 | url = format( '%s/objects/hostgroups' , @icinga_api_url_base ) 106 | url = format( '%s/objects/hostgroups/%s', @icinga_api_url_base, host_group ) unless( host_group.nil? ) 107 | 108 | api_data( 109 | url: url, 110 | headers: @headers, 111 | options: @options 112 | ) 113 | end 114 | 115 | # returns true if the hostgroup exists 116 | # 117 | # @param [String] host_group the name of the hostgroup 118 | # 119 | # @example 120 | # exists_hostgroup?('linux-servers') 121 | # 122 | # @return [Bool] returns true if the hostgroup exists 123 | # 124 | def exists_hostgroup?( host_group ) 125 | 126 | raise ArgumentError.new(format('wrong type. \'host_group\' must be an String, given \'%s\'', host_group.class.to_s)) unless( host_group.is_a?(String) ) 127 | raise ArgumentError.new('Missing \'host_group\'') if( host_group.size.zero? ) 128 | 129 | result = hostgroups(host_group) 130 | result = JSON.parse( result ) if( result.is_a?(String) ) 131 | result = result.first if( result.is_a?(Array) ) 132 | 133 | return false if( result.is_a?(Hash) && result.dig('code') == 404 ) 134 | 135 | true 136 | end 137 | 138 | end 139 | end 140 | -------------------------------------------------------------------------------- /lib/icinga2/hosts.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | module Icinga2 4 | 5 | # namespace for host handling 6 | module Hosts 7 | 8 | # add host 9 | # 10 | # @param [Hash] params 11 | # @option params [String] name 12 | # @option params [String] address 13 | # @option params [String] address6 14 | # @option params [String] display_name 15 | # @option params [Bool] enable_notifications (false) 16 | # @option params [Integer] max_check_attempts (3) 17 | # @option params [Integer] check_interval (60) 18 | # @option params [Integer] retry_interval (45) 19 | # @option params [String] notes 20 | # @option params [String] notes_url 21 | # @option params [String] action_url 22 | # @option params [String] check_command 23 | # @option params [Integer] check_interval 24 | # @option params [String] check_period 25 | # @option params [Integer] check_timeout 26 | # @option params [String] command_endpoint 27 | # @option params [Bool] enable_active_checks 28 | # @option params [Bool] enable_event_handler 29 | # @option params [Bool] enable_flapping 30 | # @option params [Bool] enable_passive_checks 31 | # @option params [Bool] enable_perfdata 32 | # @option params [String] event_command 33 | # @option params [Integer] flapping_threshold 34 | # @option params [Integer] flapping_threshold_high 35 | # @option params [Integer] flapping_threshold_low 36 | # @option params [String] icon_image 37 | # @option params [String] icon_image_alt 38 | # @option params [Integer] retry_interval 39 | # @option params [Bool] volatile 40 | # @option params [Hash] vars ({}) 41 | # 42 | # @example 43 | # param = { 44 | # name: 'foo', 45 | # address: 'foo.bar.com', 46 | # display_name: 'test node', 47 | # max_check_attempts: 5, 48 | # notes: 'test node', 49 | # vars: { 50 | # description: 'host foo', 51 | # os: 'Linux', 52 | # partitions: { 53 | # '/' => { 54 | # crit: '95%', 55 | # warn: '90%' 56 | # } 57 | # } 58 | # } 59 | # } 60 | # add_host(param) 61 | # 62 | # @return [Hash] 63 | # 64 | def add_host( params ) 65 | 66 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 67 | raise ArgumentError.new('missing params') if( params.size.zero? ) 68 | 69 | name = validate( params, required: true, var: 'name', type: String ) 70 | action_url = validate( params, required: false, var: 'action_url', type: String ) 71 | address = validate( params, required: false, var: 'address', type: String ) 72 | address6 = validate( params, required: false, var: 'address6', type: String ) 73 | check_command = validate( params, required: false, var: 'check_command', type: String ) 74 | check_interval = validate( params, required: false, var: 'check_interval', type: Integer ) || 60 75 | check_period = validate( params, required: false, var: 'check_period', type: Integer ) 76 | check_timeout = validate( params, required: false, var: 'check_timeout', type: Integer ) 77 | command_endpoint = validate( params, required: false, var: 'command_endpoint', type: String ) 78 | display_name = validate( params, required: false, var: 'display_name', type: String ) 79 | enable_active_checks = validate( params, required: false, var: 'enable_active_checks', type: Boolean ) 80 | enable_event_handler = validate( params, required: false, var: 'enable_event_handler', type: Boolean ) 81 | enable_flapping = validate( params, required: false, var: 'enable_flapping', type: Boolean ) 82 | enable_notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) || false 83 | enable_passive_checks = validate( params, required: false, var: 'enable_passive_checks', type: Boolean ) 84 | volatile = validate( params, required: false, var: 'volatile', type: Boolean ) 85 | enable_perfdata = validate( params, required: false, var: 'enable_perfdata', type: Boolean ) 86 | event_command = validate( params, required: false, var: 'event_command', type: String ) 87 | flapping_threshold = validate( params, required: false, var: 'flapping_threshold', type: Integer ) 88 | groups = validate( params, required: false, var: 'groups', type: Array ) 89 | icon_image = validate( params, required: false, var: 'icon_image', type: String ) 90 | icon_image_alt = validate( params, required: false, var: 'icon_image_alt', type: String ) 91 | notes = validate( params, required: false, var: 'notes', type: String ) 92 | notes_url = validate( params, required: false, var: 'notes_url', type: String ) 93 | max_check_attempts = validate( params, required: false, var: 'max_check_attempts', type: Integer ) || 3 94 | retry_interval = validate( params, required: false, var: 'retry_interval', type: Integer ) || 45 95 | templates = validate( params, required: false, var: 'templates', type: Array ) || [ 'generic-host' ] 96 | vars = validate( params, required: false, var: 'vars', type: Hash ) || {} 97 | zone = validate( params, required: false, var: 'zone', type: String ) 98 | 99 | address = Socket.gethostbyname( name ).first if( address.nil? ) 100 | 101 | payload = { 102 | templates: templates, 103 | attrs: { 104 | action_url: action_url, 105 | address: address, 106 | address6: address6, 107 | check_period: check_period, 108 | check_command: check_command, 109 | check_interval: check_interval, 110 | check_timeout: check_timeout, 111 | command_endpoint: command_endpoint, 112 | display_name: display_name, 113 | enable_active_checks: enable_active_checks, 114 | enable_event_handler: enable_event_handler, 115 | enable_flapping: enable_flapping, 116 | enable_notifications: enable_notifications, 117 | enable_passive_checks: enable_passive_checks, 118 | enable_perfdata: enable_perfdata, 119 | event_command: event_command, 120 | flapping_threshold: flapping_threshold, 121 | groups: groups, 122 | icon_image: icon_image, 123 | icon_image_alt: icon_image_alt, 124 | max_check_attempts: max_check_attempts, 125 | notes: notes, 126 | notes_url: notes_url, 127 | retry_interval: retry_interval, 128 | volatile: volatile, 129 | zone: zone, 130 | vars: vars 131 | } 132 | } 133 | 134 | # remove all empty attrs 135 | payload.reject!{ |_k, v| v.nil? } 136 | payload[:attrs].reject!{ |_k, v| v.nil? } 137 | 138 | # puts JSON.pretty_generate payload 139 | 140 | put( 141 | url: format( '%s/objects/hosts/%s', @icinga_api_url_base, name ), 142 | headers: @headers, 143 | options: @options, 144 | payload: payload 145 | ) 146 | end 147 | 148 | # delete a host 149 | # 150 | # @param [Hash] params 151 | # @option params [String] name host to delete 152 | # @option params [Bool] cascade (false) delete host also when other objects depend on it 153 | # 154 | # @example 155 | # delete_host(name: 'foo') 156 | # delete_host(name: 'foo', cascade: true) 157 | # 158 | # 159 | # @return [Hash] result 160 | # 161 | def delete_host( params ) 162 | 163 | raise ArgumentError.new('only Hash are allowed') unless( params.is_a?(Hash) ) 164 | raise ArgumentError.new('missing params') if( params.size.zero? ) 165 | 166 | name = validate( params, required: true, var: 'name', type: String ) 167 | cascade = validate( params, required: false, var: 'cascade', type: Boolean ) || false 168 | 169 | url = format( '%s/objects/hosts/%s%s', @icinga_api_url_base, name, cascade.is_a?(TrueClass) ? '?cascade=1' : nil ) 170 | 171 | delete( 172 | url: url, 173 | headers: @headers, 174 | options: @options 175 | ) 176 | end 177 | 178 | # modify a host 179 | # 180 | # @param [Hash] params 181 | # @option params [String] name 182 | # @option params [String] name 183 | # @option params [String] address 184 | # @option params [String] address6 185 | # @option params [String] display_name 186 | # @option params [Bool] enable_notifications 187 | # @option params [Integer] max_check_attempts 188 | # @option params [Integer] check_interval 189 | # @option params [Integer] retry_interval 190 | # @option params [String] notes 191 | # @option params [String] notes_url 192 | # @option params [String] action_url 193 | # @option params [String] check_command 194 | # @option params [Integer] check_interval 195 | # @option params [String] check_period 196 | # @option params [Integer] check_timeout 197 | # @option params [String] command_endpoint 198 | # @option params [Bool] enable_active_checks 199 | # @option params [Bool] enable_event_handler 200 | # @option params [Bool] enable_flapping 201 | # @option params [Bool] enable_passive_checks 202 | # @option params [Bool] enable_perfdata 203 | # @option params [String] event_command 204 | # @option params [Integer] flapping_threshold 205 | # @option params [Integer] flapping_threshold_high 206 | # @option params [Integer] flapping_threshold_low 207 | # @option params [String] icon_image 208 | # @option params [String] icon_image_alt 209 | # @option params [Integer] retry_interval 210 | # @option params [Bool] volatile 211 | # @option params [Hash] vars ({}) 212 | # @option params [Bool] merge_vars (false) 213 | # 214 | # @example 215 | # param = { 216 | # name: 'foo', 217 | # address: 'foo.bar.com', 218 | # display_name: 'Host for an example Problem', 219 | # max_check_attempts: 10, 220 | # } 221 | # 222 | # param = { 223 | # name: 'foo', 224 | # address: 'foo.bar.com', 225 | # notes: 'an demonstration object', 226 | # vars: { 227 | # description: 'schould be delete ASAP', 228 | # os: 'Linux', 229 | # partitions: { 230 | # '/' => { 231 | # crit: '98%', 232 | # warn: '95%' 233 | # } 234 | # } 235 | # }, 236 | # merge_vars: true 237 | # } 238 | # 239 | # param = { 240 | # name: 'foo', 241 | # address: 'foo.bar.com', 242 | # vars: { 243 | # description: 'removed all other custom vars', 244 | # } 245 | # } 246 | # 247 | # add_host(param) 248 | # 249 | # @return [Hash] 250 | # 251 | def modify_host( params ) 252 | 253 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 254 | raise ArgumentError.new('missing params') if( params.size.zero? ) 255 | 256 | name = validate( params, required: true, var: 'name', type: String ) 257 | action_url = validate( params, required: false, var: 'action_url', type: String ) 258 | address = validate( params, required: false, var: 'address', type: String ) 259 | address6 = validate( params, required: false, var: 'address6', type: String ) 260 | check_command = validate( params, required: false, var: 'check_command', type: String ) 261 | check_interval = validate( params, required: false, var: 'check_interval', type: Integer ) 262 | check_period = validate( params, required: false, var: 'check_period', type: Integer ) 263 | check_timeout = validate( params, required: false, var: 'check_timeout', type: Integer ) 264 | command_endpoint = validate( params, required: false, var: 'command_endpoint', type: String ) 265 | display_name = validate( params, required: false, var: 'display_name', type: String ) 266 | enable_active_checks = validate( params, required: false, var: 'enable_active_checks', type: Boolean ) 267 | enable_event_handler = validate( params, required: false, var: 'enable_event_handler', type: Boolean ) 268 | enable_flapping = validate( params, required: false, var: 'enable_flapping', type: Boolean ) 269 | enable_notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) 270 | enable_passive_checks = validate( params, required: false, var: 'enable_passive_checks', type: Boolean ) 271 | volatile = validate( params, required: false, var: 'volatile', type: Boolean ) 272 | enable_perfdata = validate( params, required: false, var: 'enable_perfdata', type: Boolean ) 273 | event_command = validate( params, required: false, var: 'event_command', type: String ) 274 | flapping_threshold = validate( params, required: false, var: 'flapping_threshold', type: Integer ) 275 | groups = validate( params, required: false, var: 'groups', type: Array ) 276 | icon_image = validate( params, required: false, var: 'icon_image', type: String ) 277 | icon_image_alt = validate( params, required: false, var: 'icon_image_alt', type: String ) 278 | notes = validate( params, required: false, var: 'notes', type: String ) 279 | notes_url = validate( params, required: false, var: 'notes_url', type: String ) 280 | max_check_attempts = validate( params, required: false, var: 'max_check_attempts', type: Integer ) 281 | retry_interval = validate( params, required: false, var: 'retry_interval', type: Integer ) 282 | templates = validate( params, required: false, var: 'templates', type: Array ) || [ 'generic-host' ] 283 | vars = validate( params, required: false, var: 'vars', type: Hash ) || {} 284 | zone = validate( params, required: false, var: 'zone', type: String ) 285 | merge_vars = validate( params, required: false, var: 'merge_vars', type: Boolean ) || false 286 | 287 | # check if host exists 288 | return { 'code' => 404, 'name' => name, 'status' => 'Object not Found' } unless( exists_host?( name ) ) 289 | 290 | # merge the new with the old vars 291 | if( merge_vars == true ) 292 | current_host = hosts( name: name ) 293 | current_host_vars = current_host.first 294 | current_host_vars = current_host_vars.dig('attrs','vars') 295 | current_host_vars = current_host_vars.deep_string_keys 296 | vars = vars.deep_string_keys unless( vars.empty? ) 297 | vars = current_host_vars.merge( vars ) 298 | end 299 | 300 | payload = { 301 | templates: templates, 302 | attrs: { 303 | action_url: action_url, 304 | address: address, 305 | address6: address6, 306 | check_period: check_period, 307 | check_command: check_command, 308 | check_interval: check_interval, 309 | check_timeout: check_timeout, 310 | command_endpoint: command_endpoint, 311 | display_name: display_name, 312 | enable_active_checks: enable_active_checks, 313 | enable_event_handler: enable_event_handler, 314 | enable_flapping: enable_flapping, 315 | enable_notifications: enable_notifications, 316 | enable_passive_checks: enable_passive_checks, 317 | enable_perfdata: enable_perfdata, 318 | event_command: event_command, 319 | flapping_threshold: flapping_threshold, 320 | groups: groups, 321 | icon_image: icon_image, 322 | icon_image_alt: icon_image_alt, 323 | max_check_attempts: max_check_attempts, 324 | notes: notes, 325 | notes_url: notes_url, 326 | retry_interval: retry_interval, 327 | volatile: volatile, 328 | zone: zone, 329 | vars: vars 330 | } 331 | } 332 | 333 | # remove all empty attrs 334 | payload.reject!{ |_k, v| v.nil? } 335 | payload[:attrs].reject!{ |_k, v| v.nil? } 336 | 337 | post( 338 | url: format( '%s/objects/hosts/%s', @icinga_api_url_base, name ), 339 | headers: @headers, 340 | options: @options, 341 | payload: payload 342 | ) 343 | end 344 | 345 | 346 | # return hosts 347 | # 348 | # @param [Hash] params 349 | # @option params [String] name 350 | # @option params [Array] attrs 351 | # @option params [String] filter 352 | # @option params [Array] joins 353 | # 354 | # @example to get all hosts 355 | # hosts 356 | # 357 | # @example to get one host 358 | # hosts( name: 'icinga2') 359 | # 360 | # @return [Array] 361 | # 362 | def hosts( params = {} ) 363 | 364 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 365 | 366 | name = validate( params, required: false, var: 'name', type: String ) 367 | attrs = validate( params, required: false, var: 'attrs', type: Array ) 368 | filter = validate( params, required: false, var: 'filter', type: String ) 369 | joins = validate( params, required: false, var: 'joins', type: Array ) 370 | 371 | payload = { 372 | attrs: attrs, 373 | filter: filter, 374 | joins: joins 375 | } 376 | payload.reject!{ |_k, v| v.nil? } 377 | 378 | api_data( 379 | url: format( '%s/objects/hosts/%s', @icinga_api_url_base, name ), 380 | headers: @headers, 381 | options: @options, 382 | payload: payload 383 | ) 384 | end 385 | 386 | # returns true if the host exists 387 | # 388 | # @param [String] host_name 389 | # 390 | # @example 391 | # exists_host?('icinga2') 392 | # 393 | # @return [Bool] 394 | # 395 | def exists_host?( host_name ) 396 | 397 | raise ArgumentError.new(format('wrong type. \'host_name\' must be an String, given \'%s\'',host_name.class.to_s)) unless( host_name.is_a?(String) ) 398 | raise ArgumentError.new('Missing host_name') if( host_name.size.zero? ) 399 | 400 | result = hosts( name: host_name ) 401 | result = JSON.parse( result ) if( result.is_a?(String) ) 402 | result = result.first if( result.is_a?(Array) ) 403 | 404 | return false if( result.is_a?(Hash) && result.dig('code') == 404 ) 405 | 406 | true 407 | end 408 | 409 | # returns host objects 410 | # 411 | # @param [Hash] params 412 | # @option params [Array] attrs (['name', 'state', 'acknowledgement', 'downtime_depth', 'last_check']) 413 | # @option params [String] filter ([]) 414 | # @option params [Array] joins ([]) 415 | # 416 | # @example with default attrs and joins 417 | # host_objects 418 | # 419 | # @example 420 | # host_objects(attrs: ['name', 'state']) 421 | # 422 | # @return [Hash] 423 | # 424 | def host_objects( params = {} ) 425 | 426 | attrs = validate( params, required: false, var: 'attrs', type: Array ) || %w[name state acknowledgement downtime_depth last_check] 427 | filter = validate( params, required: false, var: 'filter', type: String ) 428 | joins = validate( params, required: false, var: 'joins', type: Array ) 429 | 430 | payload = { 431 | attrs: attrs, 432 | filter: filter, 433 | joins: joins 434 | } 435 | payload.reject!{ |_k, v| v.nil? } 436 | 437 | data = api_data( 438 | url: format( '%s/objects/hosts', @icinga_api_url_base ), 439 | headers: @headers, 440 | options: @options, 441 | payload: payload 442 | ) 443 | 444 | @last_host_objects_called = Time.now.to_i 445 | 446 | if( !data.nil? && data.is_a?(Array) ) 447 | all_hosts = data.clone 448 | unless( all_hosts.nil? ) 449 | # global var for count of all hosts 450 | @hosts_all = all_hosts.size 451 | # global var for count of all host with a problem 452 | @hosts_problems = count_problems(all_hosts) 453 | # global var for count of all gost with state HOSTS_DOWN 454 | @hosts_problems_down = count_problems(all_hosts, Icinga2::HOSTS_DOWN) 455 | @hosts_problems_critical = count_problems(all_hosts, Icinga2::HOSTS_CRITICAL) 456 | @hosts_problems_unknown = count_problems(all_hosts, Icinga2::HOSTS_UNKNOWN) 457 | end 458 | end 459 | 460 | data 461 | end 462 | 463 | # returns adjusted hosts state 464 | # OBSOLETE 465 | # 466 | # @example 467 | # handled, down = hosts_adjusted.values 468 | # 469 | # h = hosts_adjusted 470 | # down = h.dig(:down_adjusted) 471 | # 472 | # @return [Hash] 473 | # * handled_problems 474 | # * down_adjusted 475 | # 476 | def hosts_adjusted 477 | 478 | puts 'function hosts_adjusted() is obsolete' 479 | puts 'Please use host_problems()' 480 | 481 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 482 | host_objects if((Time.now.to_i - @last_host_objects_called).to_i > @last_call_timeout) 483 | 484 | raise ArgumentError.new('Integer for @hosts_problems_down needed') unless( @hosts_problems_down.is_a?(Integer) ) 485 | raise ArgumentError.new('Integer for @hosts_problems_critical needed') unless( @hosts_problems_critical.is_a?(Integer) ) 486 | raise ArgumentError.new('Integer for @hosts_problems_unknown needed') unless( @hosts_problems_unknown.is_a?(Integer) ) 487 | raise ArgumentError.new('Integer for @hosts_down needed') unless( @hosts_down.is_a?(Integer) ) 488 | 489 | # calculate host problems adjusted by handled problems 490 | # count togther handled host problems 491 | handled_problems = @hosts_problems_down + @hosts_problems_critical + @hosts_problems_unknown 492 | down_adjusted = @hosts_down - handled_problems 493 | 494 | { 495 | handled_problems: handled_problems.to_i, 496 | down_adjusted: down_adjusted.to_i 497 | } 498 | end 499 | 500 | # return count of hosts with problems 501 | # 502 | # @example 503 | # count_hosts_with_problems 504 | # 505 | # @return [Integer] 506 | # 507 | def count_hosts_with_problems 508 | 509 | host_data = host_objects 510 | host_data = JSON.parse(host_data) if host_data.is_a?(String) 511 | 512 | f = host_data.select { |t| t.dig('attrs','state') != 0 && t.dig('attrs','downtime_depth').zero? && t.dig('attrs','acknowledgement').zero? } 513 | 514 | f.size 515 | end 516 | 517 | # return a list of hosts with problems 518 | # 519 | # @param [Integer] max_items numbers of list entries 520 | # 521 | # @example 522 | # list_hosts_with_problems 523 | # 524 | # @return [Hash] 525 | # 526 | def list_hosts_with_problems( max_items = 5 ) 527 | 528 | raise ArgumentError.new(format('wrong type. \'max_items\' must be an Integer, given \'%s\'', max_items.class.to_s)) unless( max_items.is_a?(Integer) ) 529 | 530 | host_problems = {} 531 | host_problems_severity = {} 532 | 533 | host_data = host_objects 534 | host_data = JSON.parse( host_data ) if host_data.is_a?(String) 535 | 536 | unless( host_data.nil? ) 537 | host_data.each do |h,_v| 538 | name = h.dig('name') 539 | state = h.dig('attrs','state') 540 | 541 | next if state.to_i.zero? 542 | 543 | host_problems[name] = host_severity(h) 544 | end 545 | end 546 | 547 | # get the count of problems 548 | # 549 | host_problems.keys[1..max_items].each { |k| host_problems_severity[k] = host_problems[k] } if( host_problems.count != 0 ) 550 | 551 | host_problems_severity 552 | end 553 | 554 | # returns a counter of all hosts 555 | # 556 | # @example 557 | # hosts_all 558 | # 559 | # @return [Integer] 560 | # 561 | def hosts_all 562 | host_objects if( @hosts_all.nil? || @hosts_all.zero? ) 563 | @hosts_all 564 | end 565 | 566 | # returns data with host problems 567 | # 568 | # @example 569 | # host_objects 570 | # all, down, critical, unknown, handled, adjusted = host_problems.values 571 | # 572 | # p = host_problems 573 | # down = h.dig(:down) 574 | # 575 | # @return [Hash] 576 | # * all 577 | # * down 578 | # * critical 579 | # * unknown 580 | # 581 | def host_problems 582 | 583 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 584 | host_objects if((Time.now.to_i - @last_host_objects_called).to_i > @last_call_timeout) 585 | 586 | raise ArgumentError.new(format('wrong type. \'@hosts_problems_down\' must be an Integer, given \'%s\'', @hosts_problems_down.class.to_s)) unless( @hosts_problems_down.is_a?(Integer)) 587 | raise ArgumentError.new(format('wrong type. \'@hosts_problems_critical\' must be an Integer, given \'%s\'', @hosts_problems_critical.class.to_s)) unless( @hosts_problems_critical.is_a?(Integer)) 588 | raise ArgumentError.new(format('wrong type. \'@hosts_problems_critical\' must be an Integer, given \'%s\'', @hosts_problems_critical.class.to_s)) unless( @hosts_problems_critical.is_a?(Integer)) 589 | raise ArgumentError.new(format('wrong type. \'@hosts_down\' must be an Integer, given \'%s\'', @hosts_down.class.to_s)) unless( @hosts_down.is_a?(Integer)) 590 | 591 | problems_all = @hosts_problems.nil? ? 0 : @hosts_problems 592 | problems_down = @hosts_problems_down.nil? ? 0 : @hosts_problems_down 593 | problems_critical = @hosts_problems_critical.nil? ? 0 : @hosts_problems_critical 594 | problems_unknown = @hosts_problems_unknown.nil? ? 0 : @hosts_problems_unknown 595 | 596 | # calculate host problems adjusted by handled problems 597 | # count togther handled host problems 598 | problems_handled = @hosts_problems_down + @hosts_problems_critical + @hosts_problems_unknown 599 | problems_adjusted = @hosts_down - problems_handled 600 | 601 | { 602 | all: problems_all.to_i, 603 | down: problems_down.to_i, 604 | critical: problems_critical.to_i, 605 | unknown: problems_unknown.to_i, 606 | handled: problems_handled.to_i, 607 | adjusted: problems_adjusted.to_i 608 | } 609 | end 610 | 611 | protected 612 | # calculate a host severity 613 | # 614 | # stolen from Icinga Web 2 615 | # ./modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php 616 | # 617 | # @param [Hash] params 618 | # @option params [hash] attrs () 619 | # * state [Float] 620 | # * acknowledgement [Float] (default: 0) 621 | # * downtime_depth [Float] (default: 0) 622 | # 623 | # @api protected 624 | # 625 | # @example 626 | # host_severity( {'attrs' => { 'state' => 0.0, 'acknowledgement' => 0.0, 'downtime_depth' => 0.0 } } ) 627 | # 628 | # @return [Integer] 629 | # 630 | def host_severity( params ) 631 | 632 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 633 | raise ArgumentError.new('missing params') if( params.size.zero? ) 634 | 635 | attrs = params.dig('attrs') 636 | 637 | state = validate( attrs, required: true, var: 'state', type: Float ) 638 | acknowledgement = validate( attrs, required: false, var: 'acknowledgement', type: Float ) || 0 639 | downtime_depth = validate( attrs, required: false, var: 'downtime_depth', type: Float ) || 0 640 | 641 | severity = 0 642 | 643 | severity += 644 | if acknowledgement != 0 645 | 2 646 | elsif downtime_depth > 0 647 | 1 648 | else 649 | 4 650 | end 651 | 652 | severity += 16 if object_has_been_checked?(params) 653 | 654 | unless state.zero? 655 | severity += 656 | if state == 1 657 | 32 658 | elsif state == 2 659 | 64 660 | else 661 | 256 662 | end 663 | end 664 | 665 | severity 666 | end 667 | 668 | end 669 | end 670 | -------------------------------------------------------------------------------- /lib/icinga2/network.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | module Icinga2 4 | 5 | # namespace for network handling 6 | module Network 7 | 8 | # static function for GET Requests 9 | # 10 | # @param [Hash] params 11 | # @option params [String] host 12 | # @option params [String] url 13 | # @option params [String] headers 14 | # @option params [String] options 15 | # @option params [Hash] payload 16 | # 17 | # 18 | # @return [Hash] 19 | # 20 | def api_data( params ) 21 | 22 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 23 | raise ArgumentError.new('missing params') if( params.size.zero? ) 24 | 25 | url = validate( params, required: true, var: 'url', type: String ) 26 | headers = validate( params, required: true, var: 'headers', type: Hash ) 27 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 28 | payload = validate( params, required: false, var: 'payload', type: Hash ) 29 | 30 | rest_client = RestClient::Resource.new( URI.encode( url ), options ) 31 | 32 | headers['X-HTTP-Method-Override'] = 'GET' 33 | method = 'GET' 34 | method = 'POST' if( payload ) 35 | 36 | begin 37 | data = request( rest_client, method, headers, payload ) 38 | 39 | data = JSON.parse( data ) if( data.is_a?(String) ) 40 | data = data.deep_string_keys 41 | data = data.dig('results') if( data.is_a?(Hash) ) 42 | 43 | return data 44 | rescue => e 45 | logger.error(e) 46 | logger.error(e.backtrace.join("\n")) 47 | 48 | return nil 49 | end 50 | end 51 | 52 | # static function for GET Requests without filters 53 | # 54 | # @param [Hash] params 55 | # @option params [String] host 56 | # @option params [String] url 57 | # @option params [String] headers 58 | # @option params [String] options 59 | # @option params [Hash] payload 60 | # 61 | # 62 | # @return [Hash] 63 | # 64 | def icinga_application_data( params ) 65 | 66 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 67 | raise ArgumentError.new('missing params') if( params.size.zero? ) 68 | 69 | url = validate( params, required: true, var: 'url', type: String ) 70 | headers = validate( params, required: true, var: 'headers', type: Hash ) 71 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 72 | 73 | begin 74 | data = api_data( url: url, headers: headers, options: options ) 75 | data = data.first if( data.is_a?(Array) ) 76 | 77 | return data.dig('status') unless( data.nil? ) 78 | rescue => e 79 | logger.error(e) 80 | logger.error(e.backtrace.join("\n")) 81 | 82 | return nil 83 | end 84 | 85 | end 86 | 87 | # static function for POST Requests 88 | # 89 | # @param [Hash] params 90 | # @option params [String] url 91 | # @option params [String] headers 92 | # @option params [String] options 93 | # @option params [Hash] payload 94 | # 95 | # 96 | # @return [Hash] 97 | # 98 | def post( params ) 99 | 100 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 101 | raise ArgumentError.new('missing params') if( params.size.zero? ) 102 | 103 | url = validate( params, required: true, var: 'url', type: String ) 104 | headers = validate( params, required: true, var: 'headers', type: Hash ) 105 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 106 | payload = validate( params, required: false, var: 'payload', type: Hash ) 107 | 108 | rest_client = RestClient::Resource.new( URI.encode( url ), options ) 109 | 110 | headers['X-HTTP-Method-Override'] = 'POST' 111 | 112 | begin 113 | data = request( rest_client, 'POST', headers, payload ) 114 | data = JSON.parse( data ) if( data.is_a?(String) ) 115 | data = data.deep_string_keys 116 | data = data.dig('results') if( data.is_a?(Hash) ) 117 | 118 | if( data.count.zero? ) 119 | code = 404 120 | name = nil 121 | status = 'Object not found.' 122 | elsif( data.count == 1 ) 123 | data = data.first 124 | code = data.dig('code').to_i 125 | name = data.dig('name') 126 | status = data.dig('status') 127 | else 128 | code = data.max_by{|k| k['code'] }.dig('code') 129 | status = data.map do |hash| 130 | hash['status'] 131 | end 132 | end 133 | 134 | return { 'code' => code, 'name' => name, 'status' => status } 135 | rescue => e 136 | logger.error(e) 137 | logger.error(e.backtrace.join("\n")) 138 | 139 | puts e 140 | puts e.backtrace.join("\n") 141 | 142 | return nil 143 | end 144 | end 145 | 146 | # static function for PUT Requests 147 | # 148 | # @param [Hash] params 149 | # @option params [String] host 150 | # @option params [String] url 151 | # @option params [String] headers 152 | # @option params [String] options 153 | # @option params [Hash] payload 154 | # 155 | # 156 | # @return [Hash] 157 | # 158 | def put( params ) 159 | 160 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 161 | raise ArgumentError.new('missing params') if( params.size.zero? ) 162 | 163 | url = validate( params, required: true, var: 'url', type: String ) 164 | headers = validate( params, required: true, var: 'headers', type: Hash ) 165 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 166 | payload = validate( params, required: false, var: 'payload', type: Hash ) 167 | 168 | rest_client = RestClient::Resource.new( URI.encode( url ), options ) 169 | 170 | headers['X-HTTP-Method-Override'] = 'PUT' 171 | 172 | begin 173 | data = request( rest_client, 'PUT', headers, payload ) 174 | data = JSON.parse( data ) if( data.is_a?(String) ) 175 | data = data.deep_string_keys 176 | 177 | if( data.is_a?(Hash) ) 178 | results = data.dig('results') 179 | results = results.first if( results.is_a?(Array) ) 180 | else 181 | results = data 182 | end 183 | 184 | return { 'code' => results.dig('code').to_i, 'name' => results.dig('name'), 'status' => results.dig('status') } unless( results.nil? ) 185 | rescue => e 186 | logger.error(e) 187 | logger.error(e.backtrace.join("\n")) 188 | 189 | return nil 190 | end 191 | end 192 | 193 | # static function for DELETE Requests 194 | # 195 | # @param [Hash] params 196 | # @option params [String] url 197 | # @option params [String] headers 198 | # @option params [String] options 199 | # 200 | # 201 | # @return [Hash] 202 | # 203 | def delete( params ) 204 | 205 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 206 | raise ArgumentError.new('missing params') if( params.size.zero? ) 207 | 208 | url = validate( params, required: true, var: 'url', type: String ) 209 | headers = validate( params, required: true, var: 'headers', type: Hash ) 210 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 211 | 212 | rest_client = RestClient::Resource.new( URI.encode( url ), options ) 213 | 214 | headers['X-HTTP-Method-Override'] = 'DELETE' 215 | 216 | begin 217 | data = request( rest_client, 'DELETE', headers ) 218 | 219 | data = JSON.parse( data ) if( data.is_a?(String) ) 220 | data = data.deep_string_keys 221 | 222 | if( data.is_a?(Hash) ) 223 | results = data.dig('results') 224 | results = results.first if( results.is_a?(Array) ) 225 | else 226 | results = data 227 | end 228 | 229 | return { 'code' => results.dig('code').to_i, 'name' => results.dig('name'), 'status' => results.dig('status') } unless( results.nil? ) 230 | rescue => e 231 | logger.error(e) 232 | logger.error(e.backtrace.join("\n")) 233 | 234 | return nil 235 | end 236 | end 237 | 238 | # static function for GET Requests 239 | # 240 | # @param [Hash] params 241 | # @option params [String] url 242 | # @option params [String] headers 243 | # @option params [String] options 244 | # 245 | # 246 | # @return [Hash] 247 | # 248 | def get(params) 249 | 250 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 251 | raise ArgumentError.new('missing params') if( params.size.zero? ) 252 | 253 | url = validate( params, required: true, var: 'url', type: String ) 254 | headers = validate( params, required: true, var: 'headers', type: Hash ) 255 | options = validate( params, required: true, var: 'options', type: Hash ).deep_symbolize_keys 256 | 257 | rest_client = RestClient::Resource.new( URI.encode( url ), options ) 258 | 259 | begin 260 | data = request( rest_client, 'GET', headers ) 261 | 262 | # puts "data: #{data}" 263 | 264 | begin 265 | data = JSON.parse( data ) if( data.is_a?(String) ) 266 | data = data.deep_string_keys 267 | data['code'] = 200 268 | rescue 269 | data 270 | end 271 | 272 | return data 273 | rescue => e 274 | logger.error(e) 275 | logger.error(e.backtrace.join("\n")) 276 | 277 | return nil 278 | end 279 | end 280 | 281 | private 282 | # 283 | # internal functionfor the Rest-Client Request 284 | # 285 | def request( client, method, headers, data = {} ) 286 | 287 | # logger.debug( "request( #{client.to_s}, #{method}, #{headers}, #{data} )" ) 288 | 289 | raise ArgumentError.new('client must be an RestClient::Resource') unless( client.is_a?(RestClient::Resource) ) 290 | raise ArgumentError.new('method must be an \'GET\', \'POST\', \'PUT\' or \'DELETE\'') unless( %w[GET POST PUT DELETE].include?(method) ) 291 | raise ArgumentError.new(format('data must be an Hash (%s)', data.class.to_s)) unless( data.nil? || data.is_a?(Hash) ) 292 | 293 | max_retries = 3 294 | retried = 0 295 | 296 | begin 297 | 298 | case method.upcase 299 | when 'GET' 300 | response = client.get( headers ) 301 | when 'POST' 302 | response = client.post( data.to_json, headers ) 303 | when 'PATCH' 304 | response = client.patch( data, headers ) 305 | when 'PUT' 306 | # response = @api_instance[endpoint].put( data, @headers ) 307 | client.put( data.to_json, headers ) do |response, req, _result| 308 | 309 | @req = req 310 | @response_body = response.body 311 | @response_code = response.code.to_i 312 | 313 | case response.code 314 | when 200 315 | return @response_body 316 | when 400 317 | raise RestClient::BadRequest 318 | when 404 319 | raise RestClient::NotFound 320 | when 500 321 | raise RestClient::InternalServerError 322 | else 323 | response.return 324 | end 325 | end 326 | 327 | when 'DELETE' 328 | response = client.delete( @headers ) 329 | else 330 | return false 331 | end 332 | 333 | response_body = response.body 334 | # response_headers = response.headers 335 | 336 | begin 337 | return JSON.parse( response_body ) if( response_body.is_a?(String) ) 338 | rescue 339 | return response_body 340 | end 341 | 342 | rescue RestClient::BadRequest 343 | 344 | response_body = JSON.parse(response_body) if response_body.is_a?(String) 345 | 346 | return { 'results' => [{ 'code' => 400, 'status' => response_body.nil? ? 'Bad Request' : response_body }] } 347 | 348 | rescue RestClient::Unauthorized 349 | 350 | return { 'results' => [{ 'code' => 401, 'status' => format('Not authorized to connect \'%s\' - wrong username or password?', @icinga_api_url_base) }] } 351 | 352 | rescue RestClient::NotFound 353 | 354 | return { 'results' => [{ 'code' => 404, 'status' => 'Object not Found' }] } 355 | 356 | rescue RestClient::InternalServerError => error 357 | 358 | response_body = JSON.parse(@response_body) if @response_body.is_a?(String) 359 | 360 | # begin 361 | # puts '-------------------------------------' 362 | # puts response 363 | # puts response.class.to_s 364 | # 365 | # puts response.code.to_i 366 | # puts response_body 367 | # puts response_body.class.to_s 368 | # puts '-------------------------------------' 369 | # rescue 370 | # 371 | # end 372 | 373 | return { 'results' => [{ 'code' => 500, 'status' => error }] } if( response_body.nil? ) 374 | 375 | results = response_body.dig('results') 376 | results = results.first if( results.is_a?(Array) ) 377 | status = results.dig('status') 378 | errors = results.dig('errors') 379 | errors = errors.first if( errors.is_a?(Array) ) 380 | errors = errors.sub(/ \'.*\'/,'') 381 | 382 | return { 'results' => [{ 'code' => 500, 'status' => format('%s (%s)', status, errors).delete('.') }] } 383 | 384 | rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e 385 | 386 | # TODO 387 | # ist hier ein raise sinnvoll? 388 | raise format( "Maximum retries (%d) against '%s' reached. Giving up ...", max_retries, @icinga_api_url_base ) if( retried >= max_retries ) 389 | 390 | retried += 1 391 | warn(format("Cannot execute request against '%s': '%s' (retry %d / %d)", @icinga_api_url_base, e, retried, max_retries)) 392 | sleep(3) 393 | retry 394 | 395 | rescue RestClient::ExceptionWithResponse => e 396 | 397 | response = e.response 398 | response_body = response.body 399 | # response_code = response.code 400 | 401 | if( response_body =~ /{(.*)}{(.*)}/ ) 402 | parts = response_body.match( /^{(?(.+))}{(.*)}/ ) 403 | response_body = parts['regular'].to_s.strip 404 | response_body = format('{%s}', response_body ) 405 | end 406 | 407 | begin 408 | response_body = JSON.parse(response_body) if response_body.is_a?(String) 409 | code = response.code.to_i 410 | status = response_body.dig('status') 411 | 412 | return { 'results' => [{ 'code' => code, 'status' => status }] } 413 | 414 | rescue => error 415 | puts(error) 416 | puts(error.backtrace.join("\n")) 417 | 418 | return { 'results' => [{ 'code' => 500, 'status' => error }] } 419 | end 420 | 421 | rescue RestClient::ExceptionWithResponse => e 422 | 423 | @logger.error( "Error: #{__method__} #{method_type.upcase} on #{endpoint} error: '#{e}'" ) 424 | @logger.error( data ) 425 | # @logger.error( @headers ) 426 | # @logger.error( JSON.pretty_generate( response_headers ) ) 427 | 428 | return { 'results' => [{ 'code' => 500, 'status' => e }] } 429 | end 430 | 431 | end 432 | 433 | 434 | end 435 | end 436 | -------------------------------------------------------------------------------- /lib/icinga2/notifications.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for servicegroup handling 7 | module Notifications 8 | 9 | # enable host notifications 10 | # 11 | # @param [String] host 12 | # 13 | # @example 14 | # enable_host_notification('icinga') 15 | # 16 | # @return [Hash] 17 | # 18 | def enable_host_notification( host ) 19 | 20 | raise ArgumentError.new(format('wrong type. \'host\' must be an String, given \'%s\'', host.class.to_s)) unless( host.is_a?(String) ) 21 | raise ArgumentError.new('missing \'host\'') if( host.size.zero? ) 22 | 23 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_host?( host ) == false ) 24 | 25 | host_notification( name: host, enable_notifications: true ) 26 | end 27 | 28 | # disable host notifications 29 | # 30 | # @param [String] host 31 | # 32 | # @example 33 | # disable_host_notification('icinga') 34 | # 35 | # @return [Hash] 36 | # 37 | def disable_host_notification( host ) 38 | 39 | raise ArgumentError.new(format('wrong type. \'host\' must be an String, given \'%s\'', host.class.to_s)) unless( host.is_a?(String) ) 40 | raise ArgumentError.new('missing \'host\'') if( host.size.zero? ) 41 | 42 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_host?( host ) == false ) 43 | 44 | host_notification( name: host, enable_notifications: false ) 45 | end 46 | 47 | # enable service notifications 48 | # 49 | # @param [String] host 50 | # 51 | # @example 52 | # enable_service_notification('icinga') 53 | # 54 | # @return [Hash] 55 | # 56 | def enable_service_notification( host ) 57 | 58 | raise ArgumentError.new(format('wrong type. \'host\' must be an String, given \'%s\'', host.class.to_s)) unless( host.is_a?(String) ) 59 | raise ArgumentError.new('missing \'host\'') if( host.size.zero? ) 60 | 61 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_host?( host ) == false ) 62 | 63 | service_notification( name: host, enable_notifications: true ) 64 | end 65 | 66 | # disable service notifications 67 | # 68 | # @param [String] host 69 | # 70 | # @example 71 | # disable_service_notification('icinga') 72 | # 73 | # @return [Hash] 74 | # 75 | def disable_service_notification( host ) 76 | 77 | raise ArgumentError.new(format('wrong type. \'host\' must be an String, given \'%s\'', host.class.to_s)) unless( host.is_a?(String) ) 78 | raise ArgumentError.new('missing \'host\'') if( host.size.zero? ) 79 | 80 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_host?( host ) == false ) 81 | 82 | service_notification( name: host, enable_notifications: false ) 83 | end 84 | 85 | # enable hostgroup notifications 86 | # 87 | # @param [String] host_group 88 | # 89 | # @example 90 | # enable_hostgroup_notification('linux-servers') 91 | # 92 | # @return [Hash] 93 | # 94 | def enable_hostgroup_notification( host_group ) 95 | 96 | raise ArgumentError.new(format('wrong type. \'host_group\' must be an String, given \'%s\'', host_group.class.to_s)) unless( host_group.is_a?(String) ) 97 | raise ArgumentError.new('missing \'host_group\'') if( host_group.size.zero? ) 98 | 99 | return { 'code' => 404, 'status' => 'Object not Found' } unless( exists_hostgroup?( host_group ) ) 100 | 101 | hostgroup_notification( host_group: host_group, enable_notifications: true ) 102 | end 103 | 104 | # disable hostgroup notifications 105 | # 106 | # @param [String] host_group 107 | # 108 | # @example 109 | # disable_hostgroup_notification('linux-servers') 110 | # 111 | # @return [Hash] 112 | # 113 | def disable_hostgroup_notification( host_group ) 114 | 115 | raise ArgumentError.new(format('wrong type. \'host_group\' must be an String, given \'%s\'', host_group.class.to_s)) unless( host_group.is_a?(String) ) 116 | raise ArgumentError.new('missing \'host_group\'') if( host_group.size.zero? ) 117 | 118 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_hostgroup?( host_group ) == false ) 119 | 120 | hostgroup_notification( host_group: host_group, enable_notifications: false ) 121 | end 122 | 123 | # return all notifications 124 | # 125 | # 126 | # @return [Array] 127 | # 128 | def notifications 129 | 130 | api_data( 131 | url: format( '%s/objects/notifications', @icinga_api_url_base ), 132 | headers: @headers, 133 | options: @options 134 | ) 135 | end 136 | 137 | protected 138 | # function for host notifications 139 | # @api protected 140 | # 141 | # @param [Hash] params 142 | # @option params [String] name 143 | # @option params [Bool] enable_notifications (false) 144 | # 145 | # @return [Hash] 146 | # 147 | def host_notification( params ) 148 | 149 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 150 | raise ArgumentError.new('missing params') if( params.size.zero? ) 151 | 152 | name = validate( params, required: true, var: 'name', type: String ) 153 | notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) || false 154 | 155 | payload = { 156 | attrs: { 157 | enable_notifications: notifications 158 | } 159 | } 160 | 161 | post( 162 | url: format( '%s/objects/hosts/%s', @icinga_api_url_base, name ), 163 | headers: @headers, 164 | options: @options, 165 | payload: payload 166 | ) 167 | end 168 | 169 | # function for hostgroup notifications 170 | # @api protected 171 | # 172 | # @param [Hash] params 173 | # @option params [String] :host_group 174 | # @option params [Bool] :enable_notifications (false) 175 | # 176 | # @return [Hash] 177 | # 178 | def hostgroup_notification( params ) 179 | 180 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 181 | raise ArgumentError.new('missing params') if( params.size.zero? ) 182 | 183 | group = validate( params, required: true, var: 'host_group', type: String ) 184 | notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) || false 185 | 186 | payload = { 187 | filter: format( '"%s" in host.groups', group ), 188 | attrs: { 189 | enable_notifications: notifications 190 | } 191 | } 192 | 193 | post( 194 | url: format( '%s/objects/services', @icinga_api_url_base ), 195 | headers: @headers, 196 | options: @options, 197 | payload: payload 198 | ) 199 | end 200 | 201 | # function for service notifications 202 | # @api protected 203 | # 204 | # @param [Hash] params 205 | # @option params [String] name 206 | # @option params [Bool] enable_notifications (false) 207 | # 208 | # @return [Hash] 209 | # 210 | def service_notification( params ) 211 | 212 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 213 | raise ArgumentError.new('missing params') if( params.size.zero? ) 214 | 215 | name = validate( params, required: true, var: 'name', type: String ) 216 | notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) || false 217 | 218 | payload = { 219 | filter: format( 'host.name=="%s"', name ), 220 | attrs: { 221 | enable_notifications: notifications 222 | } 223 | } 224 | 225 | post( 226 | url: format( '%s/objects/services', @icinga_api_url_base ), 227 | headers: @headers, 228 | options: @options, 229 | payload: payload 230 | ) 231 | end 232 | 233 | end 234 | end 235 | -------------------------------------------------------------------------------- /lib/icinga2/servicegroups.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for servicegroup handling 7 | module Servicegroups 8 | 9 | # add a servicegroup 10 | # 11 | # @param [Hash] params 12 | # @option params [String] service_group servicegroup to create 13 | # @option params [String] display_name the displayed name 14 | # @option params [String] notes 15 | # @option params [String] notes_url 16 | # @option params [String] action_url 17 | # 18 | # @example 19 | # add_servicegroup(service_group: 'foo', display_name: 'FOO') 20 | # 21 | # @return [Hash] result 22 | # 23 | def add_servicegroup( params ) 24 | 25 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 26 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 27 | 28 | service_group = validate( params, required: true, var: 'service_group', type: String ) 29 | display_name = validate( params, required: true, var: 'display_name', type: String ) 30 | notes = validate( params, required: false, var: 'notes', type: String ) 31 | notes_url = validate( params, required: false, var: 'notes_url', type: String ) 32 | action_url = validate( params, required: false, var: 'action_url', type: String ) 33 | 34 | payload = { 35 | attrs: { 36 | display_name: display_name, 37 | notes: notes, 38 | notes_url: notes_url, 39 | action_url: action_url 40 | } 41 | } 42 | 43 | # remove all empty attrs 44 | payload.reject!{ |_k, v| v.nil? } 45 | payload[:attrs].reject!{ |_k, v| v.nil? } 46 | 47 | put( 48 | url: format( '%s/objects/servicegroups/%s', @icinga_api_url_base, service_group ), 49 | headers: @headers, 50 | options: @options, 51 | payload: payload 52 | ) 53 | end 54 | 55 | # delete a servicegroup 56 | # 57 | # @param [Hash] params 58 | # @option params [String] name servicegroup to delete 59 | # @option params [Bool] cascade (false) delete servicegroup also when other objects depend on it 60 | # 61 | # @example 62 | # delete_servicegroup('foo') 63 | # 64 | # @return [Array] result 65 | # 66 | def delete_servicegroup( params ) 67 | 68 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 69 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 70 | 71 | name = validate( params, required: true, var: 'name', type: String ) 72 | cascade = validate( params, required: false, var: 'cascade', type: Boolean ) || false 73 | 74 | return { 'code' => 404, 'status' => 'Object not Found' } if( exists_servicegroup?( name ) == false ) 75 | 76 | url = format( '%s/objects/servicegroups/%s%s', @icinga_api_url_base, name, cascade.is_a?(TrueClass) ? '?cascade=1' : nil ) 77 | 78 | delete( 79 | url: url, 80 | headers: @headers, 81 | options: @options 82 | ) 83 | end 84 | 85 | # returns all servicegroups 86 | # 87 | # @param [String] service_group (nil) optional for a single servicegroup 88 | # 89 | # @example to get all users 90 | # servicegroups 91 | # 92 | # @example to get one user 93 | # servicegroups(service_group: 'disk') 94 | # 95 | # @return [Array] returns a hash with all servicegroups 96 | # 97 | def servicegroups( service_group = nil ) 98 | 99 | raise ArgumentError.new(format('wrong type. \'service_group\' must be an String, given \'%s\'', service_group.class.to_s)) unless( service_group.nil? || service_group.is_a?(String) ) 100 | 101 | url = format( '%s/objects/servicegroups' , @icinga_api_url_base ) 102 | url = format( '%s/objects/servicegroups/%s', @icinga_api_url_base, service_group ) unless( service_group.nil? ) 103 | 104 | api_data( 105 | url: url, 106 | headers: @headers, 107 | options: @options 108 | ) 109 | end 110 | 111 | # checks if the servicegroup exists 112 | # 113 | # @param [String] service_group the name of the servicegroup 114 | # 115 | # @example 116 | # exists_servicegroup?('disk') 117 | # 118 | # @return [Bool] returns true if the servicegroup exists 119 | # 120 | def exists_servicegroup?( service_group ) 121 | 122 | raise ArgumentError.new(format('wrong type. \'service_group\' must be an String, given \'%s\'', service_group.class.to_s)) unless( service_group.is_a?(String) ) 123 | raise ArgumentError.new('Missing \'service_group\'') if( service_group.size.zero? ) 124 | 125 | result = servicegroups(service_group) 126 | result = JSON.parse( result ) if result.is_a?( String ) 127 | result = result.first if( result.is_a?(Array) ) 128 | 129 | return false if( result.is_a?(Hash) && result.dig('code') == 404 ) 130 | 131 | true 132 | end 133 | 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /lib/icinga2/statistics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # 3 | 4 | module Icinga2 5 | 6 | # namespace for icinga2 statistics 7 | module Statistics 8 | 9 | 10 | # return statistic data for latency and execution_time 11 | # 12 | # @example 13 | # latency, execution_time = average_statistics.values 14 | # 15 | # h = average_statistics 16 | # latency = h.dig(:latency) 17 | # 18 | # @return [Hash] 19 | # * latency (Float) 20 | # * execution_time (Float) 21 | # 22 | def average_statistics 23 | 24 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 25 | 26 | avg_latency = @avg_latency.nil? ? 0 : @avg_latency 27 | avg_execution_time = @avg_execution_time.nil? ? 0 : @avg_execution_time 28 | 29 | { 30 | latency: avg_latency.to_f, 31 | execution_time: avg_execution_time.to_f 32 | } 33 | end 34 | 35 | # return statistic data for intervall data 36 | # 37 | # @example 38 | # hosts_active_checks, hosts_passive_checks, services_active_checks, services_passive_checks = interval_statistics.values 39 | # 40 | # i = interval_statistics 41 | # hosts_active_checks = i.dig(:hosts_active_checks) 42 | # 43 | # @return [Hash] 44 | # * hosts_active_checks (Float) 45 | # * hosts_passive_checks (Float) 46 | # * services_active_checks (Float) 47 | # * services_passive_checks (Float) 48 | # 49 | def interval_statistics 50 | 51 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 52 | 53 | # take a look into https://github.com/Icinga/pkg-icinga2-debian/blob/master/lib/icinga/cib.cpp 54 | 55 | hosts_active_checks = @hosts_active_checks_1min.nil? ? 0 : @hosts_active_checks_1min 56 | hosts_passive_checks = @hosts_passive_checks_1min.nil? ? 0 : @hosts_passive_checks_1min 57 | services_active_checks = @services_active_checks_1min.nil? ? 0 : @services_active_checks_1min 58 | services_passive_checks = @services_passive_checks_1min.nil? ? 0 : @services_passive_checks_1min 59 | 60 | { 61 | hosts_active_checks: hosts_active_checks.to_f, 62 | hosts_passive_checks: hosts_passive_checks.to_f, 63 | services_active_checks: services_active_checks.to_f, 64 | services_passive_checks: services_passive_checks.to_f 65 | } 66 | end 67 | 68 | # return statistic data for services 69 | # 70 | # @example 71 | # ok, warning, critical, unknown, pending, in_downtime, ack = service_statistics.values 72 | # 73 | # s = service_statistics 74 | # critical = s.dig(:critical) 75 | # 76 | # @return [Hash] 77 | # * ok (Integer) 78 | # * warning (Integer) 79 | # * critical (Integer) 80 | # * unknown (Integer) 81 | # * pending (Integer) 82 | # * in_downtime (Integer) 83 | # * acknowledged (Integer) 84 | # 85 | def service_statistics 86 | 87 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 88 | 89 | services_ok = @services_ok.nil? ? 0 : @services_ok 90 | services_warning = @services_warning.nil? ? 0 : @services_warning 91 | services_critical = @services_critical.nil? ? 0 : @services_critical 92 | services_unknown = @services_unknown.nil? ? 0 : @services_unknown 93 | services_pending = @services_pending.nil? ? 0 : @services_pending 94 | services_in_downtime = @services_in_downtime.nil? ? 0 : @services_in_downtime 95 | services_acknowledged = @services_acknowledged.nil? ? 0 : @services_acknowledged 96 | 97 | { 98 | ok: services_ok.to_i, 99 | warning: services_warning.to_i, 100 | critical: services_critical.to_i, 101 | unknown: services_unknown.to_i, 102 | pending: services_pending.to_i, 103 | in_downtime: services_in_downtime.to_i, 104 | acknowledged: services_acknowledged.to_i 105 | } 106 | end 107 | 108 | # return statistic data for hosts 109 | # 110 | # @example 111 | # up, down, pending, unreachable, in_downtime, ack = host_statistics.values 112 | # 113 | # h = host_statistics 114 | # pending = h.dig(:pending) 115 | # 116 | # @return [Hash] 117 | # * up (Integer) 118 | # * down (Integer) 119 | # * pending (Integer) 120 | # * unreachable (Integer) 121 | # * in_downtime (Integer) 122 | # * acknowledged (Integer) 123 | # 124 | def host_statistics 125 | 126 | cib_data if((Time.now.to_i - @last_cib_data_called).to_i > @last_call_timeout) 127 | 128 | hosts_up = @hosts_up.nil? ? 0 : @hosts_up 129 | hosts_down = @hosts_down.nil? ? 0 : @hosts_down 130 | hosts_pending = @hosts_pending.nil? ? 0 : @hosts_pending 131 | hosts_unreachable = @hosts_unreachable.nil? ? 0 : @hosts_unreachable 132 | hosts_in_downtime = @hosts_in_downtime.nil? ? 0 : @hosts_in_downtime 133 | hosts_acknowledged = @hosts_acknowledged.nil? ? 0 : @hosts_acknowledged 134 | 135 | { 136 | up: hosts_up.to_i, 137 | down: hosts_down.to_i, 138 | pending: hosts_pending.to_i, 139 | unreachable: hosts_unreachable.to_i, 140 | in_downtime: hosts_in_downtime.to_i, 141 | acknowledged: hosts_acknowledged.to_i 142 | } 143 | end 144 | 145 | 146 | # return queue statistics from the api 147 | # 148 | # @example 149 | # work_queue_statistics 150 | # 151 | # @return [Hash] 152 | # 153 | def work_queue_statistics 154 | 155 | stats = {} 156 | data = api_data( 157 | url: format( '%s/status', @icinga_api_url_base ), 158 | headers: @headers, 159 | options: @options 160 | ) 161 | 162 | return stats if data.nil? 163 | 164 | if( data.is_a?(Array) ) 165 | 166 | json_rpc_data = data.find { |k| k['name'] == 'ApiListener' } 167 | graphite_data = data.find { |k| k['name'] == 'GraphiteWriter' } 168 | ido_mysql_data = data.find { |k| k['name'] == 'IdoMysqlConnection' } 169 | 170 | json_rpc_data = json_rpc_data.dig('status', 'api', 'json_rpc') unless( json_rpc_data.nil? ) 171 | graphite_data = graphite_data.dig('status', 'graphitewriter', 'graphite') unless( graphite_data.nil? ) 172 | ido_mysql_data = ido_mysql_data.dig('status', 'idomysqlconnection', 'ido-mysql') unless( ido_mysql_data.nil? ) 173 | 174 | payload = { 175 | json_rpc: json_rpc_data, 176 | graphite: graphite_data, 177 | ido_mysql: ido_mysql_data 178 | } 179 | 180 | payload.reject!{ |_k, v| v.nil? } 181 | 182 | key_list = %w[work_queue_item_rate query_queue_item_rate] 183 | 184 | payload.each do |k,v| 185 | key_list.each do |key| 186 | if( v.include?( key )) 187 | attr_name = format('%s queue rate', k) 188 | stats[attr_name] = v[key].to_f.round(3) 189 | end 190 | end 191 | end 192 | end 193 | 194 | stats 195 | end 196 | 197 | end 198 | end 199 | -------------------------------------------------------------------------------- /lib/icinga2/tools.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: false 3 | 4 | module Icinga2 5 | 6 | # namespache for tools 7 | module Tools 8 | 9 | # returns true for the last check 10 | # @private 11 | # 12 | # @param [Hash] object 13 | # 14 | # @return [Bool] 15 | # 16 | def object_has_been_checked?( object ) 17 | object.dig('attrs', 'last_check') > 0 18 | end 19 | 20 | # parse version string and extract version and revision 21 | # 22 | # @param [String] version 23 | # 24 | # @return [String, String] 25 | # 26 | def parse_version( version ) 27 | 28 | # version = "v2.4.10-504-gab4ba18" 29 | # version = "v2.4.10" 30 | version_map = version.split('-', 2) 31 | version_str = version_map.first 32 | # strip v2.4.10 (default) and r2.4.10 (Debian) 33 | version_str = version_str.scan(/^[vr]+(.*)/).last.first 34 | 35 | revision = 36 | if version_map.size > 1 37 | version_map.last 38 | else 39 | 'release' 40 | end 41 | 42 | [version_str, revision] 43 | end 44 | 45 | 46 | # return count of handled problems 47 | # 48 | # @param [Array] objects 49 | # @param [Integer] state (nil) 50 | # 51 | # @example for host objects 52 | # h_objects = host_objects 53 | # all = count_problems(h_objects) 54 | # down = count_problems(h_objects, Icinga2::HOSTS_DOWN) 55 | # critical = count_problems(h_objects, Icinga2::HOSTS_CRITICAL) 56 | # unknown = count_problems(h_objects, Icinga2::HOSTS_UNKNOWN) 57 | # 58 | # @example for service objects 59 | # s_objects = service_objects 60 | # all = count_problems(s_objects) 61 | # warning = count_problems(s_objects, Icinga2::SERVICE_STATE_WARNING) 62 | # critical = count_problems(s_objects, Icinga2::SERVICE_STATE_CRITICAL) 63 | # unknown = count_problems(s_objects, Icinga2::SERVICE_STATE_UNKNOWN) 64 | # 65 | # @return [Integer] 66 | # 67 | def count_problems( objects, state = nil ) 68 | 69 | raise ArgumentError.new(format('wrong type. \'objects\' must be an Array, given \'%s\'', objects.class.to_s)) unless( objects.is_a?(Array) ) 70 | #raise ArgumentError.new('missing objects') if( objects.size.zero? ) 71 | 72 | raise ArgumentError.new(format('wrong type. \'state\' must be an Integer, given \'%s\'', state.class.to_s)) unless( state.nil? || state.is_a?(Integer) ) 73 | 74 | # 0 = "Up" or "OK" 75 | # 1 = "Down" or "Warning" 76 | # 2 = "Critical" 77 | # 3 = "Unknown" 78 | compare_states = [] 79 | compare_states = [1, 2, 3] unless( state.nil? ) 80 | 81 | compare_states.push(state) if( state.is_a?(Integer) ) 82 | 83 | objects = JSON.parse(objects) if objects.is_a?(String) 84 | 85 | f = objects.select do |t| 86 | t.dig('attrs','state') == state && \ 87 | ( !t.dig('attrs','downtime_depth').nil? && t.dig('attrs','downtime_depth').zero?) && \ 88 | ( !t.dig('attrs','acknowledgement').nil? && t.dig('attrs','acknowledgement').zero? ) 89 | end 90 | 91 | f.size 92 | end 93 | 94 | 95 | # check, it an String a valid Json 96 | # 97 | # @param json [String] json 98 | # 99 | # @example 100 | # valid_json?( json ) 101 | # 102 | # @return [Bool] 103 | # 104 | def valid_json?( json ) 105 | 106 | begin 107 | JSON.parse( json ) 108 | return true 109 | rescue JSON::ParserError => e 110 | @logger.error("json parse error: #{e}") if @debug 111 | return false 112 | end 113 | 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /lib/icinga2/usergroups.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for usergroup handling 7 | module Usergroups 8 | 9 | # add a usergroup 10 | # 11 | # @param [Hash] params 12 | # @option params [String] user_group usergroup to create 13 | # @option params [String] display_name the displayed name 14 | # 15 | # @example 16 | # add_usergroup(user_group: 'foo', display_name: 'FOO') 17 | # 18 | # @return [Hash] result 19 | # 20 | def add_usergroup( params ) 21 | 22 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 23 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 24 | 25 | user_group = validate( params, required: true, var: 'user_group', type: String ) 26 | display_name = validate( params, required: false, var: 'display_name', type: String ) 27 | 28 | payload = { 29 | attrs: { 30 | display_name: display_name 31 | } 32 | } 33 | 34 | # remove all empty attrs 35 | payload.reject!{ |_k, v| v.nil? } 36 | payload[:attrs].reject!{ |_k, v| v.nil? } 37 | 38 | put( 39 | url: format( '%s/objects/usergroups/%s', @icinga_api_url_base, user_group ), 40 | headers: @headers, 41 | options: @options, 42 | payload: payload 43 | ) 44 | end 45 | 46 | # delete a usergroup 47 | # 48 | # @param [String] user_group usergroup to delete 49 | # 50 | # @example 51 | # delete_usergroup('foo') 52 | # 53 | # @return [Hash] result 54 | # 55 | def delete_usergroup( user_group ) 56 | 57 | raise ArgumentError.new(format('wrong type. \'user_group\' must be an String, given \'%s\'', user_group.class.to_s)) unless( user_group.is_a?(String) ) 58 | raise ArgumentError.new('missing \'user_group\'') if( user_group.size.zero? ) 59 | 60 | delete( 61 | url: format( '%s/objects/usergroups/%s?cascade=1', @icinga_api_url_base, user_group ), 62 | headers: @headers, 63 | options: @options 64 | ) 65 | end 66 | 67 | # returns all usersgroups 68 | # 69 | # @param [String] user_group (nil) optional for a single usergroup 70 | # 71 | # @example to get all users 72 | # usergroups 73 | # 74 | # @example to get one user 75 | # usergroups('icingaadmins') 76 | # 77 | # @return [Hash] returns a hash with all usergroups 78 | # 79 | def usergroups( user_group = nil ) 80 | 81 | url = format( '%s/objects/usergroups' , @icinga_api_url_base ) 82 | url = format( '%s/objects/usergroups/%s', @icinga_api_url_base, user_group ) unless( user_group.nil? ) 83 | 84 | api_data( 85 | url: url, 86 | headers: @headers, 87 | options: @options 88 | ) 89 | end 90 | 91 | # returns true if the usergroup exists 92 | # 93 | # @param [String] user_group the name of the usergroups 94 | # 95 | # @example 96 | # exists_usergroup?('icingaadmins') 97 | # 98 | # @return [Bool] returns true if the usergroup exists 99 | # 100 | def exists_usergroup?( user_group ) 101 | 102 | raise ArgumentError.new(format('wrong type. \'user_group\' must be an String, given \'%s\'', user_group.class.to_s)) unless( user_group.is_a?(String) ) 103 | raise ArgumentError.new('Missing \'user_group\'') if( user_group.size.zero? ) 104 | 105 | result = usergroups( user_group ) 106 | result = JSON.parse( result ) if result.is_a?( String ) 107 | result = result.first if( result.is_a?(Array) ) 108 | 109 | return false if( result.is_a?(Hash) && result.dig('code') == 404 ) 110 | 111 | true 112 | end 113 | 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /lib/icinga2/users.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | 6 | # namespace for User handling 7 | module Users 8 | 9 | # add a user 10 | # 11 | # @param [Hash] params 12 | # @option params [String] user_name user to create 13 | # @option params [String] display_name ('') the displayed name 14 | # @option params [String] email ('') the user email 15 | # @option params [String] pager ('') optional a pager 16 | # @option params [Bool] enable_notifications (false) enable notifications for this user 17 | # @option params [Array] groups ([]) a hash with groups 18 | # @option params [String] period 19 | # @option params [Array] states 20 | # @option params [Array] types 21 | # @option params [Hash] vars 22 | # 23 | # @example 24 | # param = { 25 | # user_name: 'foo', 26 | # display_name: 'FOO', 27 | # email: 'foo@bar.com', 28 | # pager: '0000', 29 | # groups: ['icingaadmins'] 30 | # } 31 | # add_user(param) 32 | # 33 | # @return [Hash] result 34 | # * code [Integer] 35 | # * message [String] 36 | # * data (optional) 37 | # 38 | def add_user( params ) 39 | 40 | raise ArgumentError.new(format('wrong type. \'params\' must be an Hash, given \'%s\'', params.class.to_s)) unless( params.is_a?(Hash) ) 41 | raise ArgumentError.new('missing \'params\'') if( params.size.zero? ) 42 | 43 | user_name = validate( params, required: true, var: 'user_name', type: String ) 44 | display_name = validate( params, required: false, var: 'display_name', type: String ) 45 | email = validate( params, required: false, var: 'email', type: String ) 46 | pager = validate( params, required: false, var: 'pager', type: String ) 47 | notifications = validate( params, required: false, var: 'enable_notifications', type: Boolean ) || false 48 | groups = validate( params, required: false, var: 'groups', type: Array ) || [] 49 | period = validate( params, required: false, var: 'period', type: String ) 50 | states = validate( params, required: false, var: 'states', type: Array ) 51 | types = validate( params, required: false, var: 'types', type: Array ) 52 | vars = validate( params, required: false, var: 'vars', type: Hash ) || {} 53 | 54 | group_validate = [] 55 | 56 | groups.each do |g| 57 | group_validate << g if exists_usergroup?( g ) == false 58 | end 59 | 60 | if( group_validate.count != 0 ) 61 | return { 62 | 'code' => 404, 63 | 'message' => format('these groups are not exists: \'%s\'', group_validate.join(', ')), 64 | 'data' => params 65 | } 66 | end 67 | 68 | payload = { 69 | attrs: { 70 | display_name: display_name, 71 | email: email, 72 | pager: pager, 73 | enable_notifications: notifications, 74 | groups: groups, 75 | period: period, 76 | states: states, 77 | types: types, 78 | vars: vars 79 | } 80 | } 81 | 82 | # remove all empty attrs 83 | payload.reject!{ |_k, v| v.nil? } 84 | payload[:attrs].reject!{ |_k, v| v.nil? } 85 | 86 | put( 87 | url: format( '%s/objects/users/%s', @icinga_api_url_base, user_name ), 88 | headers: @headers, 89 | options: @options, 90 | payload: payload 91 | ) 92 | end 93 | 94 | # delete a user 95 | # 96 | # @param [String] user_name user to delete 97 | # 98 | # @example 99 | # delete_user('foo') 100 | # 101 | # @return [Hash] result 102 | # 103 | def delete_user( user_name ) 104 | 105 | raise ArgumentError.new(format('wrong type. \'user_name\' must be an String, given \'%s\'',user_name.class.to_s)) unless( user_name.is_a?(String) ) 106 | raise ArgumentError.new('Missing user_name') if( user_name.size.zero? ) 107 | 108 | delete( 109 | url: format( '%s/objects/users/%s?cascade=1', @icinga_api_url_base, user_name ), 110 | headers: @headers, 111 | options: @options 112 | ) 113 | end 114 | 115 | # returns a named or all users 116 | # 117 | # @param [String] user_name ('') optional for a single user 118 | # 119 | # @example to get all users 120 | # users 121 | # 122 | # @example to get one user 123 | # users('icingaadmin') 124 | # 125 | # @return [Array] 126 | # 127 | def users( user_name = nil ) 128 | 129 | url = format( '%s/objects/users' , @icinga_api_url_base ) 130 | url = format( '%s/objects/users/%s', @icinga_api_url_base, user_name ) unless( user_name.nil? ) 131 | 132 | api_data( 133 | url: url, 134 | headers: @headers, 135 | options: @options 136 | ) 137 | end 138 | 139 | # checks if the user exists 140 | # 141 | # @param [String] user_name the name of the user 142 | # 143 | # @example 144 | # exists_user?('icingaadmin') 145 | # 146 | # @return [Bool] returns true if the user exists 147 | # 148 | def exists_user?( user_name ) 149 | 150 | raise ArgumentError.new(format('wrong type. \'user_name\' must be an String, given \'%s\'', user_name.class.to_s)) unless( user_name.is_a?(String) ) 151 | raise ArgumentError.new('Missing \'user_name\'') if( user_name.size.zero? ) 152 | 153 | result = users( user_name ) 154 | result = JSON.parse( result ) if result.is_a?( String ) 155 | result = result.first if( result.is_a?(Array) ) 156 | 157 | return false if( result.is_a?(Hash) && result.dig('code') == 404 ) 158 | 159 | true 160 | end 161 | 162 | end 163 | end 164 | -------------------------------------------------------------------------------- /lib/icinga2/validator.rb: -------------------------------------------------------------------------------- 1 | 2 | # class Hash 3 | # def assert_required_keys(*keys) 4 | # keys.flatten.each do |key| 5 | # raise ArgumentError.new("Required key: #{key.inspect}") unless key?(key) 6 | # end 7 | # end 8 | # 9 | # def assert_valid_keys(params, *valid_keys) 10 | # valid_keys.flatten! 11 | # params.each_key do |k| 12 | # unless valid_keys.include?(k) 13 | # raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}") 14 | # end 15 | # end 16 | # end 17 | # end 18 | 19 | 20 | module Icinga2 21 | 22 | # namespace for validate options 23 | module Validator 24 | 25 | # def validate_options!(params, options) 26 | # options[:optional] ||= [] 27 | # options[:required] ||= [] 28 | # 29 | # params = params.deep_symbolize_keys 30 | # params.assert_required_keys(options[:required]) 31 | # params.assert_valid_keys(params, options[:required] + options[:optional]) 32 | # end 33 | 34 | # function to validate function parameters 35 | # 36 | # @param [Hash] params 37 | # @param [Hash] options 38 | # @option options [Bool] requiered 39 | # @option options [String] vat 40 | # @option options [Object] type Ruby Object to check the valid type. e.g String, Ineger Hash, ... 41 | # 42 | # @example 43 | # name = validate( params, required: true, var: 'name', type: String ) 44 | # vars = validate( params, required: false, var: 'vars', type: Hash ) 45 | # 46 | # @return [Mixed] the variable from the parmas Hash or nil 47 | # 48 | def validate( params, options ) 49 | required = options.dig(:required) || false 50 | var = options.dig(:var) 51 | type = options.dig(:type) 52 | 53 | params = params.deep_symbolize_keys 54 | variable = params.dig(var.to_sym) 55 | 56 | clazz = Object.const_get(type.to_s) 57 | 58 | raise ArgumentError.new(format('\'%s\' is requiered and missing!', var)) if(variable.nil? && required == true ) 59 | raise ArgumentError.new(format('wrong type. \'%s\' must be an %s, given \'%s\'', var, type, variable.class.to_s)) unless( variable.nil? || variable.is_a?(clazz) ) 60 | 61 | variable 62 | end 63 | 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/icinga2/version.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | module Icinga2 5 | # Current version of gem. 6 | VERSION = '1.0.0'.freeze 7 | end 8 | -------------------------------------------------------------------------------- /lib/logging.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | 4 | require 'logger' 5 | 6 | # taken from https://stackoverflow.com/questions/917566/ruby-share-logger-instance-among-module-classes 7 | # 8 | module Logging 9 | 10 | # 11 | # 12 | # 13 | def logger 14 | @logger ||= Logging.logger_for( self.class.name ) 15 | end 16 | 17 | # Use a hash class-ivar to cache a unique Logger per class: 18 | @loggers = {} 19 | 20 | # 21 | # 22 | # 23 | class << self 24 | def logger_for( classname ) 25 | @loggers[classname] ||= configure_logger_for( classname ) 26 | end 27 | 28 | def configure_logger_for( classname ) 29 | 30 | logger = Logger.new(STDOUT) 31 | logger.progname = classname 32 | logger.level = Logger::UNKNOWN 33 | logger.datetime_format = '%Y-%m-%d %H:%M:%S::%3N' 34 | logger.formatter = proc do |severity, datetime, progname, msg| 35 | "[#{datetime.strftime( logger.datetime_format )}] #{severity.ljust(5)} : #{progname} - #{msg}\n" 36 | end 37 | 38 | logger 39 | end 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /lib/monkey_patches.rb: -------------------------------------------------------------------------------- 1 | 2 | # ----------------------------------------------------------------------------- 3 | # Monkey patches 4 | 5 | # Modify `Object` 6 | # 7 | # original from (https://gist.github.com/Integralist/9503099) 8 | # 9 | # None of the above solutions work with a multi-level hash 10 | # They only work on the first level: {:foo=>"bar", :level1=>{"level2"=>"baz"}} 11 | # The following two variations solve the problem in the same way 12 | # transform hash keys to symbols 13 | # 14 | # @example 15 | # multi_hash = { 'foo' => 'bar', 'level1' => { 'level2' => 'baz' } } 16 | # multi_hash = multi_hash.deep_string_keys 17 | # 18 | class Object 19 | 20 | def deep_symbolize_keys 21 | if( is_a?( Hash ) ) 22 | return inject({}) do |memo, (k, v)| 23 | memo.tap { |m| m[k.to_sym] = v.deep_string_keys } 24 | end 25 | elsif( is_a?( Array ) ) 26 | return map(&:deep_string_keys) 27 | end 28 | 29 | self 30 | end 31 | 32 | def deep_string_keys 33 | if( is_a?( Hash ) ) 34 | return inject({}) do |memo, (k, v)| 35 | memo.tap { |m| m[k.to_s] = v.deep_string_keys } 36 | end 37 | elsif( is_a?( Array ) ) 38 | return map(&:deep_string_keys) 39 | end 40 | 41 | self 42 | end 43 | 44 | end 45 | 46 | # ----------------------------------------------------------------------------- 47 | 48 | # Monkey Patch for Array 49 | # 50 | class Array 51 | 52 | # add a compare function to Array class 53 | # 54 | # @example 55 | # a = ['aaa','bbb'] 56 | # b = ['ccc','xxx'] 57 | # a.compare(b) 58 | # 59 | # @return [Bool] 60 | # 61 | def compare( comparate ) 62 | to_set == comparate.to_set 63 | end 64 | end 65 | 66 | # ----------------------------------------------------------------------------- 67 | 68 | # Monkey Patch for Hash 69 | # 70 | class Hash 71 | 72 | # add a filter function to Hash Class 73 | # 74 | # @example 75 | # tags = [ 'foo', 'bar', 'fii' ] 76 | # useableTags = tags.filter( 'fii' ) 77 | # 78 | # @return [Hash] 79 | # 80 | def filter( *args ) 81 | if( args.size == 1 ) 82 | args[0] = args[0].to_s if args[0].is_a?( Symbol ) 83 | select { |key| key.to_s.match( args.first ) } 84 | else 85 | select { |key| args.include?( key ) } 86 | end 87 | end 88 | end 89 | 90 | # ----------------------------------------------------------------------------- 91 | 92 | # Monkey Patch for Time 93 | # 94 | class Time 95 | 96 | # add function add_minutes to Time Class 97 | # 98 | # @example 99 | # time = Time.now 100 | # time = time.add_minutes(10) 101 | # 102 | # @return [Time] 103 | # 104 | def add_minutes(m) 105 | self + (60 * m) 106 | end 107 | end 108 | 109 | # ----------------------------------------------------------------------------- 110 | 111 | # Monkey Patch to implement an Boolean Check 112 | # original from: https://stackoverflow.com/questions/3028243/check-if-ruby-object-is-a-boolean/3028378#3028378 113 | # 114 | # 115 | module Boolean; end 116 | class TrueClass; include Boolean; end 117 | class FalseClass; include Boolean; end 118 | 119 | true.is_a?(Boolean) #=> true 120 | false.is_a?(Boolean) #=> true 121 | 122 | # ----------------------------------------------------------------------------- 123 | 124 | # Monkey Patch for String Class 125 | # 126 | class String 127 | 128 | # get the first character in a string 129 | # 130 | # original from https://stackoverflow.com/a/2730984 131 | # 132 | # @example 133 | # 'foo'.initial 134 | # 135 | # @return [String] 136 | # 137 | def initial 138 | self[0,1] 139 | end 140 | end 141 | 142 | # ----------------------------------------------------------------------------- 143 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | 2 | # frozen_string_literal: true 3 | # require 'pry' 4 | require 'rspec' 5 | require 'icinga2' 6 | 7 | # RSpec.configure do |config| 8 | # config.color_enabled = true 9 | # config.formatter = 'documentation' 10 | # 11 | # # Configure Timezone for proper tests 12 | # ENV['TZ'] = 'UTC' 13 | # end 14 | --------------------------------------------------------------------------------