pax_global_header00006660000000000000000000000064132276215660014524gustar00rootroot0000000000000052 comment=be102d9d4e4de7ed657f7272f635e9aadf3e162e icinga2-2.8.1/000077500000000000000000000000001322762156600130505ustar00rootroot00000000000000icinga2-2.8.1/.github/000077500000000000000000000000001322762156600144105ustar00rootroot00000000000000icinga2-2.8.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000035011322762156600171140ustar00rootroot00000000000000 ## Expected Behavior ## Current Behavior ## Possible Solution ## Steps to Reproduce (for bugs) 1. 2. 3. 4. ## Context ## Your Environment * Version used (`icinga2 --version`): * Operating System and version: * Enabled features (`icinga2 feature list`): * Icinga Web 2 version and modules (System - About): * Config validation (`icinga2 daemon -C`): * If you run multiple Icinga 2 instances, the `zones.conf` file (or `icinga2 object list --type Endpoint` and `icinga2 object list --type Zone`) from all affected nodes. icinga2-2.8.1/.gitignore000066400000000000000000000002071322762156600150370ustar00rootroot00000000000000.vagrant .idea *.patch *.komodoproject *.playground .*.swp .*.swo build/ build-debug/ build-release/ build32/ build64/ debug/ release/ icinga2-2.8.1/.mailmap000066400000000000000000000035331322762156600144750ustar00rootroot00000000000000 Gunnar Beutner Michael Insel Jean Flach Jean Flach Jean Flach Jean Flach Dolf Schimmel Markus Waldmüller Claudio Kuenzler Marianne Spiller Robin O'Brien icinga2-2.8.1/.travis.yml000066400000000000000000000011301322762156600151540ustar00rootroot00000000000000dist: trusty sudo: false language: cpp cache: ccache addons: apt_packages: - libboost-all-dev - flex - bison - libssl-dev - libpq-dev - libmysqlclient-dev - libedit-dev - libyajl-dev - libwxbase3.0-dev - libwxgtk3.0-dev before_script: - mkdir build - cd build - cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/tmp/icinga2 -DICINGA2_PLUGINDIR=/tmp/icinga2/sbin script: - make - make test - make install - /tmp/icinga2/sbin/icinga2 --version - /tmp/icinga2/sbin/icinga2 daemon -C -DRunAsUser=$(id -u -n) -DRunAsGroup=$(id -g -n) icinga2-2.8.1/AUTHORS000066400000000000000000000155561322762156600141340ustar00rootroot00000000000000Adam Bolte Adam James Alexander A. Klimov Alexander Fuhr Alexander Schomburg Alexander Wirt Andreas Scherbaum Andres Ivanov Andrew Meyer Andy Grunwald Arnd Hannemann Assaf Flatto Bastian Guse Benedikt Heine Bernd Erk Berthold Cogel Blerim Sheqa Brendan Jurd Brian De Wolf Brian Dockter Bruno Lingner Bård Dahlmo-Lerbæk Carlos Cesario Carsten Köbke Christian Birk Christian Gut Christian Harke Christian Jonak Christian Lehmann Christian Loos Christian Schmidt Claudio Bilotta Claudio Kuenzler Conrad Clement Daniel Helgenberger Daniel Kesselberg Daniil Yaroslavtsev David Beck Denis Dinesh Majrekar Dirk Goetz Dirk Melchers Dolf Schimmel Edgar Fuß Eduard Güldner Edvin Seferovic Eric Lippmann Evgeni Golov Ewoud Kohl van Wijngaarden Federico Cuello Ferdi Gueran Francesco Colista Gaël Beaudoin Georg Faerber Georg Haas Gerd von Egidy Gerhardt Roman Glauco Vinicius Gunnar Beutner Hannes Happle Hannes Van de Vel Heike Jurzik Hendrik Röder Ian Kelling Ildar Hizbulin Irina Kaprizkina James Pharaoh Jan Andres Jan Wagner Jason Young Jean Flach Jean-Louis Dupond Jens Schanz Jeremy Armstrong Jesse Morgan Jo Goossens Johannes Meyer Jonas Meurer Joseph L. Casale Julian Brost Jérôme Drouet Kai Goller Konstantin Kelemen Kálmán Szalai - KAMI Lars Engels Lars Krüger Lee Clemens Lennart Betz Louis Sautier Luca Lesinigo Lucas Fairchild-Madar Malte Rabenseifner Manuel Reiter Marcus van Dam MarcusCaepio Marianne Spiller Marius Bergmann Marius Sturm Markus Frosch Markus Waldmüller Martin Stiborsky Mathieu Arnold Mathieu Lutfy Matthaus Owens Matthias Schales Max Rosin Max Zhang Mhd Sulhan Micha Ahrweiler Michael Friedrich Michael Insel Michael Insel Michael Kraus Michael Newton Mikesch-mp Mirco Bauer Mirko Nardin Nicolai Nicolas Limage Nicole Lang Niflou Noah Hilverling Pall Sigurdsson Paolo Schiro Patrick Huy Paul Richards Pawel Szafer Per von Zweigbergk Peter Eckel Petr Ruzicka Phil Hutchinson Philipp Dallig Ralph Breier Reto Zeder Ricardo Bartels Robin O'Brien Roland Hopferwieser Roman Gerhardt Rudy Gevaert Rune Darrud Sam Kottler Sebastian Brückner Sebastian Chrostek Sebastian Marsching Simon Murray Simon Ruderich Siyalrach Anton Thomas Stefan Triep Stefar77 Stephan Platz Stephan Tesch Steve McMaster Strajan Sebastian Ioan Strix <660956+MrStrix@users.noreply.github.com> Sven Nierlein Thomas Gelf Thomas Niedermeier Thomas Widhalm Tim Hardeck Tim Weippert Timo Buhrmester Tobias Birnbaum Tobias von der Krone Tom Geissler Uwe Ebel Valentin Hoebel Vytenis Darulis Wenger Florian Winfried Angele Wolfgang Nieder Yannick Charton Yohan Jarosz Zachary McGibbon Zoltan Nagy bascarsija cstegm ctrlaltca gitmopp krishna mocruz noobahoi <20069422+noobahoi@users.noreply.github.com> pv2b ryanohnemus Élie Bouttier icinga2-2.8.1/CHANGELOG.md000066400000000000000000010646341322762156600146770ustar00rootroot00000000000000# Icinga 2.x CHANGELOG ## 2.8.1 (2018-01-17) ### Enhancement * [#5856](https://github.com/Icinga/icinga2/issues/5856) (PR): Implement AppLocal deployment support for UCRT ### Bug * [#5986](https://github.com/Icinga/icinga2/issues/5986) (DB IDO, PR): Fix wrong schema constraint for fresh 2.8.0 installations * [#5947](https://github.com/Icinga/icinga2/issues/5947) (DB IDO): Duplicate entry constraint violations in 2.8 * [#5907](https://github.com/Icinga/icinga2/issues/5907) (PR): Windows plugin check\_swap build fix * [#5808](https://github.com/Icinga/icinga2/issues/5808) (Crash, PR): Fix missing variable name which can lead to segfaults * [#5807](https://github.com/Icinga/icinga2/issues/5807) (Crash): icinga v2.8.0 crashes frequently with "segmentation fault" on Debian 8.9 * [#5804](https://github.com/Icinga/icinga2/issues/5804) (Log, PR): Silence UpdateRepository message errors * [#5776](https://github.com/Icinga/icinga2/issues/5776) (Cluster, Log): 2.8.0: warning/JsonRpcConnection: Call to non-existent function 'event::UpdateRepository' * [#5746](https://github.com/Icinga/icinga2/issues/5746) (Livestatus, PR): livestatus: custom variables return empty arrays instead of strings * [#5716](https://github.com/Icinga/icinga2/issues/5716) (Livestatus, PR): add bogus zero reply in livestatus when aggregate and non matching filter * [#5626](https://github.com/Icinga/icinga2/issues/5626) (Livestatus, help wanted): Empty result set with non-matching filters in Livestatus stats query ### ITL * [#5785](https://github.com/Icinga/icinga2/issues/5785) (ITL, PR): ITL: Drop ssl\_sni default setting * [#5775](https://github.com/Icinga/icinga2/issues/5775) (ITL): Default usage of ssl\_sni in check\_tcp ### Documentation * [#5972](https://github.com/Icinga/icinga2/issues/5972) (Documentation, PR): Update 08-advanced-topics.md * [#5942](https://github.com/Icinga/icinga2/issues/5942) (Documentation, PR): Add some technical insights into the cluster-zone health check and log lag * [#5922](https://github.com/Icinga/icinga2/issues/5922) (Documentation, PR): Fix link format in documentation * [#5918](https://github.com/Icinga/icinga2/issues/5918) (Documentation, PR): Fix typo in SELinux documentation * [#5911](https://github.com/Icinga/icinga2/issues/5911) (Documentation, PR): Update ElasticsearchWriter docs for 5.x support only * [#5866](https://github.com/Icinga/icinga2/issues/5866) (Documentation, PR): Remove redundant FreeBSD from restart instructions and add openSUSE * [#5864](https://github.com/Icinga/icinga2/issues/5864) (Documentation, PR): Add missing initdb to PostgreSQL documentation * [#5835](https://github.com/Icinga/icinga2/issues/5835) (Documentation, PR): Fixes postgres schema upgrade path * [#5833](https://github.com/Icinga/icinga2/issues/5833) (Documentation, PR): fix formatting error * [#5790](https://github.com/Icinga/icinga2/issues/5790) (Documentation, PR): Documentation fixes * [#5783](https://github.com/Icinga/icinga2/issues/5783) (Documentation, PR): Fix formatting in value types docs * [#5773](https://github.com/Icinga/icinga2/issues/5773) (Documentation, Windows, PR): Update Windows Client requirements for 2.8 * [#5757](https://github.com/Icinga/icinga2/issues/5757) (Documentation, PR): Add documentation about automatic service restarts with systemd ### Support * [#5989](https://github.com/Icinga/icinga2/issues/5989) (PR): changelog.py: Adjust categories and labels: Enhancement, Bug, ITL, Documentation, Support * [#5938](https://github.com/Icinga/icinga2/issues/5938) (Packages, Windows): chocolatey outdated version * [#5893](https://github.com/Icinga/icinga2/issues/5893) (code-quality, PR): Whitespace fix * [#5892](https://github.com/Icinga/icinga2/issues/5892) (Installation, PR): Enable installing the init scripts on Solaris * [#5851](https://github.com/Icinga/icinga2/issues/5851) (Plugins, Windows, PR): Fix check\_service returning Warning instead of Critical * [#5780](https://github.com/Icinga/icinga2/issues/5780) (Packages, Windows): Icinga Agent Windows 2.8.0 msvcr120.dll is missing ## 2.8.0 (2017-11-16) ### Notes * Certificate path changed to /var/lib/icinga2/certs - check the upgrading docs! * DB IDO 2.8.0 schema upgrade * Cluster/Clients: Forward certificate signing requests over multiple levels * Cluster/Clients: Support on-demand signing next to ticket based certificate request signing * New flapping detection algorithm * Add ElasticsearchWriter feature with HTTP proxy support * Add CORS support for the REST API * Deprecate `flapping_threshold` config option * Remove client configuration mode "bottom up" * Remove classicui meta configuration package * Remove deprecated `enable_legacy_mode` in Graphite feature * Spec file was moved to https://github.com/icinga/icinga-packaging * ITL CheckCommand definition updates * Documentation updates ### Enhancement * [#5682](https://github.com/Icinga/icinga2/issues/5682) (Cluster, Configuration, PR): Implement support for migrating certificates to /var/lib/icinga2/certs * [#5681](https://github.com/Icinga/icinga2/issues/5681) (CLI, Cluster, Windows): Update Windows wizard from enhanced CSR signing \(optional ticket\) * [#5679](https://github.com/Icinga/icinga2/issues/5679) (CLI, Cluster): Migration path for improved certificate signing in the cluster * [#5606](https://github.com/Icinga/icinga2/issues/5606) (Cluster, PR): Remove bottom-up client mode * [#5602](https://github.com/Icinga/icinga2/issues/5602) (Windows, PR): Add windows process elevation and log message if user does not have privileges to read/write files * [#5587](https://github.com/Icinga/icinga2/issues/5587) (Log, PR): SyslogLogger: Implement option to set syslog facility * [#5580](https://github.com/Icinga/icinga2/issues/5580) (Configuration, PR): Implement new script functions: path\_exists, glob and glob\_recursive * [#5571](https://github.com/Icinga/icinga2/issues/5571) (CLI, Cluster, PR): Implement support for forwarding certificate signing requests in the cluster * [#5569](https://github.com/Icinga/icinga2/issues/5569) (Performance Data, PR): ElasticWriter: Add basic auth and TLS support for Elasticsearch behind an HTTP proxy * [#5554](https://github.com/Icinga/icinga2/issues/5554) (API, Cluster, PR): Add subjectAltName extension for all non-CA certificates * [#5547](https://github.com/Icinga/icinga2/issues/5547) (API, PR): Add optional reload parameter to config stage upload * [#5538](https://github.com/Icinga/icinga2/issues/5538) (Performance Data): Add ElasticsearchWriter feature * [#5534](https://github.com/Icinga/icinga2/issues/5534) (Configuration, PR): Implement get\_services\(host {name,object}\) and add host object support for get\_service\(\) * [#5527](https://github.com/Icinga/icinga2/issues/5527) (API, PR): API: Add execution\_{start,end} attribute to 'process-check-result' action * [#5450](https://github.com/Icinga/icinga2/issues/5450) (CLI, Cluster): Enhance CSR Autosigning \(CA proxy, etc.\) * [#5443](https://github.com/Icinga/icinga2/issues/5443) (API, PR): Add CORS support and set response header 'Access-Control-Allow-Origin' * [#5435](https://github.com/Icinga/icinga2/issues/5435) (Plugins, Windows, PR): Add -d option to check\_service * [#5002](https://github.com/Icinga/icinga2/issues/5002) (API, wishlist): API process-check-result allow setting timestamp * [#4912](https://github.com/Icinga/icinga2/issues/4912) (Configuration): new function get\_services\(host\_name\) * [#4799](https://github.com/Icinga/icinga2/issues/4799) (Cluster): Remove cluster/client mode "bottom up" w/ repository.d and node update-config * [#4769](https://github.com/Icinga/icinga2/issues/4769) (API): Validate and activate config package stages without triggering a reload * [#4326](https://github.com/Icinga/icinga2/issues/4326) (API): API should provide CORS Header * [#3891](https://github.com/Icinga/icinga2/issues/3891) (Plugins): Add option to specify ServiceDescription instead of ServiceName with check\_service.exe ### Bug * [#5728](https://github.com/Icinga/icinga2/issues/5728) (Plugins, Windows, PR): Fix check\_service not working with names * [#5720](https://github.com/Icinga/icinga2/issues/5720) (Check Execution): Flapping tests and bugs * [#5710](https://github.com/Icinga/icinga2/issues/5710) (CLI, Configuration, PR): Include default global zones during node wizard/setup * [#5707](https://github.com/Icinga/icinga2/issues/5707) (CLI): node wizard/setup override zones.conf but do not include default global zones \(director-global, global-templates\) * [#5696](https://github.com/Icinga/icinga2/issues/5696) (PR): Fix fork error handling * [#5641](https://github.com/Icinga/icinga2/issues/5641) (PR): Fix compiler warnings on macOS 10.13 * [#5635](https://github.com/Icinga/icinga2/issues/5635) (Configuration, PR): Fix match\(\), regex\(\), cidr\_match\(\) behaviour with MatchAll and empty arrays * [#5634](https://github.com/Icinga/icinga2/issues/5634) (Configuration): match\(\) for arrays returns boolean true if array is empty * [#5620](https://github.com/Icinga/icinga2/issues/5620) (API, PR): Ensure that the REST API config package/stage creation is atomic * [#5617](https://github.com/Icinga/icinga2/issues/5617): Crash with premature EOF on resource limited OS * [#5614](https://github.com/Icinga/icinga2/issues/5614) (PR): Fixed missing include statement in unit tests * [#5584](https://github.com/Icinga/icinga2/issues/5584) (Windows): Build error on Windows * [#5581](https://github.com/Icinga/icinga2/issues/5581) (API, Cluster, Crash, PR): Fix possible race condition in ApiListener locking * [#5558](https://github.com/Icinga/icinga2/issues/5558) (API, PR): Don't sent scheme and hostname in request * [#5515](https://github.com/Icinga/icinga2/issues/5515) (Windows): Config validation fails on Windows with unprivileged account * [#5500](https://github.com/Icinga/icinga2/issues/5500) (Crash, PR): Process: Fix JSON parsing error on process helper crash * [#5497](https://github.com/Icinga/icinga2/issues/5497) (API, PR): API: Fix requested attrs/joins/meta type errors in object query response * [#5485](https://github.com/Icinga/icinga2/issues/5485) (DB IDO, PR): Ensure that expired/removed downtimes/comments are correctly updated in DB IDO * [#5377](https://github.com/Icinga/icinga2/issues/5377) (API, Log): Sending wrong value for key causes ugly stacktrace * [#5231](https://github.com/Icinga/icinga2/issues/5231) (Check Execution, PR): Report failure to kill check command after exceeding timeout * [#4981](https://github.com/Icinga/icinga2/issues/4981) (Check Execution): Failure to kill check command after exceeding timeout is not reported ### ITL * [#5678](https://github.com/Icinga/icinga2/issues/5678) (ITL, PR): Added missing "-q" parameter to check\_ntp\_peer * [#5672](https://github.com/Icinga/icinga2/issues/5672) (ITL, PR): add itl snmp-service for manubulon plugin check\_snmp\_win.pl * [#5647](https://github.com/Icinga/icinga2/issues/5647) (ITL, PR): Allow to disable thresholds for ipmi CheckCommand * [#5640](https://github.com/Icinga/icinga2/issues/5640) (ITL, PR): ITL: Support weathermap data in snmp\_interface CheckCommand * [#5638](https://github.com/Icinga/icinga2/issues/5638) (ITL, PR): Add support for check\_address as default in database CheckCommand objects * [#5578](https://github.com/Icinga/icinga2/issues/5578) (ITL, PR): ITL: Re-Add ssl\_sni attribute for check\_tcp * [#5577](https://github.com/Icinga/icinga2/issues/5577) (ITL): ssl CheckCommand does not support SNI * [#5570](https://github.com/Icinga/icinga2/issues/5570) (ITL, PR): check\_esxi\_hardware.py with new --no-lcd parameter * [#5559](https://github.com/Icinga/icinga2/issues/5559) (ITL, PR): Exclude configfs from disk checks * [#5427](https://github.com/Icinga/icinga2/issues/5427) (ITL): Update negate CheckCommand definition * [#5401](https://github.com/Icinga/icinga2/issues/5401) (ITL, PR): itl: Add manubulon/check\_snmp\_env.pl as CheckCommand snmp-env * [#5394](https://github.com/Icinga/icinga2/issues/5394) (ITL, PR): itl: add additional mssql\_health arguments * [#5387](https://github.com/Icinga/icinga2/issues/5387) (ITL, PR): Add missing options to snmp CheckCommand definition ### Documentation * [#5768](https://github.com/Icinga/icinga2/issues/5768) (Documentation, PR): Update .mailmap and AUTHORS * [#5761](https://github.com/Icinga/icinga2/issues/5761) (Documentation, PR): Fix wrong anchors in the documentation * [#5755](https://github.com/Icinga/icinga2/issues/5755) (Documentation, PR): Fix missing Accept header in troubleshooting docs * [#5754](https://github.com/Icinga/icinga2/issues/5754) (Documentation, PR): Improve documentation of cipher\_list * [#5752](https://github.com/Icinga/icinga2/issues/5752) (Documentation, PR): Add Noah Hilverling to .mailmap * [#5748](https://github.com/Icinga/icinga2/issues/5748) (Documentation, PR): Fix missing word in pin checks in a zone doc chapter * [#5741](https://github.com/Icinga/icinga2/issues/5741) (Documentation, PR): Fix manual certificate creation chapter in the docs * [#5738](https://github.com/Icinga/icinga2/issues/5738) (Documentation, PR): Update release docs * [#5734](https://github.com/Icinga/icinga2/issues/5734) (Documentation, PR): Fix broken links inside the documentation * [#5727](https://github.com/Icinga/icinga2/issues/5727) (Documentation, PR): Update upgrading documentation for 2.8 * [#5708](https://github.com/Icinga/icinga2/issues/5708) (Documentation, PR): Fixed grammar and spelling mistakes * [#5703](https://github.com/Icinga/icinga2/issues/5703) (Documentation): Minor documentation typos in flapping detection description * [#5695](https://github.com/Icinga/icinga2/issues/5695) (Documentation, PR): Enhance Security chapter for Distributed Monitoring documentation * [#5691](https://github.com/Icinga/icinga2/issues/5691) (Documentation, PR): Fixed doc formatting * [#5690](https://github.com/Icinga/icinga2/issues/5690) (Documentation): Improve documentation of cipher\_list * [#5688](https://github.com/Icinga/icinga2/issues/5688) (Documentation, PR): Fixed typos and punctuation * [#5680](https://github.com/Icinga/icinga2/issues/5680) (Documentation): Review documentation for enhanced CSR signing and update migration chapter for 2.8 * [#5677](https://github.com/Icinga/icinga2/issues/5677) (Documentation, PR): Fix typo in threshold syntax documentation * [#5668](https://github.com/Icinga/icinga2/issues/5668) (Documentation, PR): Enhance Monitoring Basics in the documentation * [#5667](https://github.com/Icinga/icinga2/issues/5667) (Documentation): Explain which values can be used for set\_if in command arguments * [#5666](https://github.com/Icinga/icinga2/issues/5666) (Documentation): Explain the notification with users defined on host/service in a dedicated docs chapter * [#5665](https://github.com/Icinga/icinga2/issues/5665) (Documentation): Better explanations and iteration details for "apply for" documentation * [#5664](https://github.com/Icinga/icinga2/issues/5664) (Documentation): Add usage examples to the "apply" chapter based on custom attribute values * [#5663](https://github.com/Icinga/icinga2/issues/5663) (Documentation): Explain custom attribute value types and nested dictionaries * [#5662](https://github.com/Icinga/icinga2/issues/5662) (Documentation): Explain how to use a different host check command * [#5655](https://github.com/Icinga/icinga2/issues/5655) (Documentation, PR): Enhance documentation with more details on value types for object attributes * [#5576](https://github.com/Icinga/icinga2/issues/5576) (Documentation, PR): Fixed downtime example in documentation * [#5568](https://github.com/Icinga/icinga2/issues/5568) (Documentation, PR): Add documentation for multi-line plugin output for API actions * [#5511](https://github.com/Icinga/icinga2/issues/5511) (Cluster, Documentation, Windows): SSL errors with leading zeros in certificate serials \(created \< v2.4\) with OpenSSL 1.1.0 * [#5379](https://github.com/Icinga/icinga2/issues/5379) (Documentation, PR): Set shell prompt for commands to be \# * [#5186](https://github.com/Icinga/icinga2/issues/5186) (Documentation): Document boolean values understood by set\_if * [#5060](https://github.com/Icinga/icinga2/issues/5060) (Documentation): Missing documentation for macro\(\) * [#4015](https://github.com/Icinga/icinga2/issues/4015) (Documentation): Add documentation for host state calculation from plugin exit codes ### Support * [#5765](https://github.com/Icinga/icinga2/issues/5765) (Configuration, PR): Fix default configuration example for ElasticsearchWriter * [#5739](https://github.com/Icinga/icinga2/issues/5739) (Performance Data, PR): Rename ElasticWriter to ElasticsearchWriter * [#5732](https://github.com/Icinga/icinga2/issues/5732) (Check Execution, DB IDO, PR): Fix flapping calculation and events * [#5730](https://github.com/Icinga/icinga2/issues/5730) (PR): Add missing trims to GetMasterHostPort and remove Convert.ToString from variables that are strings already * [#5719](https://github.com/Icinga/icinga2/issues/5719) (Cluster, Installation, Windows, PR): Update Windows Wizard for 2.8 and new signing methods * [#5687](https://github.com/Icinga/icinga2/issues/5687) (Cluster, Log, PR): Improve error message for unknown cluster message functions * [#5686](https://github.com/Icinga/icinga2/issues/5686) (Log): Ugly stacktrace with mismatching versions in cluster * [#5643](https://github.com/Icinga/icinga2/issues/5643) (PR): Fix debug builds on Apple Clang 9.0.0 \(macOS High Sierra\) * [#5637](https://github.com/Icinga/icinga2/issues/5637) (InfluxDB, PR): Fix unnecessary String\(\) casts in InfluxdbWriter * [#5629](https://github.com/Icinga/icinga2/issues/5629) (InfluxDB, Performance Data, code-quality): Remove the unnecessary String\(\) casts in influxdbwriter.cpp * [#5624](https://github.com/Icinga/icinga2/issues/5624) (PR): Fixed missing include statement in unit test * [#5619](https://github.com/Icinga/icinga2/issues/5619) (Packages, PR): Exit early in changelog.py if GitHub API fetch fails * [#5616](https://github.com/Icinga/icinga2/issues/5616) (PR): Fix a build warning * [#5608](https://github.com/Icinga/icinga2/issues/5608) (CLI, Cluster, PR): Fix certificate paths for installers * [#5604](https://github.com/Icinga/icinga2/issues/5604) (Packages, PR): Remove the icinga2-classicui-package and update documentation * [#5601](https://github.com/Icinga/icinga2/issues/5601) (Installation, Packages, PR): Ensure that the cache directory always is set and add a note to upgrading docs * [#5563](https://github.com/Icinga/icinga2/issues/5563) (Cluster, PR): Implement additional logging for the JsonRpc class * [#5545](https://github.com/Icinga/icinga2/issues/5545) (Installation, Windows, PR): Add Edit button to Windows Setup Wizard * [#5488](https://github.com/Icinga/icinga2/issues/5488) (code-quality, PR): Implement additional functions for printing values with LLDB/GDB * [#5486](https://github.com/Icinga/icinga2/issues/5486) (Graphite, PR): Graphite: Remove deprecated legacy schema mode * [#5301](https://github.com/Icinga/icinga2/issues/5301) (Installation, Packages): Remove the icinga2-classicui-config package * [#5258](https://github.com/Icinga/icinga2/issues/5258) (Installation, PR): Fix clang compiler detection on Fedora and macOS * [#4992](https://github.com/Icinga/icinga2/issues/4992) (Graphite): Remove deprecated GraphiteWriter feature enable\_legacy\_mode * [#4982](https://github.com/Icinga/icinga2/issues/4982) (Notifications, Tests): Verify and fix flapping detection ## 2.7.2 (2017-11-09) ### Notes * Fixed invalid attribute names in the systemd unit file * Fixed incorrect unique constraint for IDO DB * Moved spec file to the icinga-packaging Git repository * Documentation updates ### Bug * [#5636](https://github.com/Icinga/icinga2/issues/5636) (DB IDO, PR): Fix unique constraint matching for UPDATE downtime/comment runtime tables in DB IDO * [#5623](https://github.com/Icinga/icinga2/issues/5623) (DB IDO): Duplicate Key on MySQL after upgrading to v2.7.1 * [#5603](https://github.com/Icinga/icinga2/issues/5603) (DB IDO): Icinga 2.7.1 IDO Unique Key Constraint Violation with PostgreSQL ### Documentation * [#5653](https://github.com/Icinga/icinga2/issues/5653) (Documentation, PR): Docs: Fix default value for `snmp\_nocrypt` for Manubulon CheckCommand definitions * [#5652](https://github.com/Icinga/icinga2/issues/5652) (Documentation, PR): Docs: Fix missing default value for cluster-zone checks * [#5632](https://github.com/Icinga/icinga2/issues/5632) (Documentation, PR): Docs: Mention SELinux in Getting Started chapter ### Support * [#5736](https://github.com/Icinga/icinga2/issues/5736) (Packages, PR): Remove spec file * [#5612](https://github.com/Icinga/icinga2/issues/5612) (Documentation, Packages, PR): Improve documentation and systemd config on TaskMax ## 2.7.1 (2017-09-21) ### Notes * Fixes and upgrade documentation for notificatication scripts introduced in 2.7.0 * InfluxdbWriter attribute `socket_timeout` introduced in 2.7.0 was deprecated (will be removed in 2.8.0). Details in #5469 and #5460 * Livestatus bygroup table stats fixes for NagVis * DB IDO: Fixes for downtime/comment history queries not correctly updating the end time * check_nscp_api allows white spaces in arguments * Bugfixes * Documentation updates ### Enhancement * [#5523](https://github.com/Icinga/icinga2/issues/5523) (Cluster, Log, PR): Enhance client connect/sync logging and include bytes/zone in logs * [#5474](https://github.com/Icinga/icinga2/issues/5474) (Notifications, PR): Notification scripts - make HOSTADDRESS optional * [#5468](https://github.com/Icinga/icinga2/issues/5468) (Notifications, PR): Make notification mails more readable. Remove redundancy and cruft. ### Bug * [#5585](https://github.com/Icinga/icinga2/issues/5585) (DB IDO, PR): Fix where clause for non-matching {downtime,comment}history IDO database updates * [#5566](https://github.com/Icinga/icinga2/issues/5566) (Cluster, Log, PR): Logs: Change config sync update to highlight an information, not an error * [#5539](https://github.com/Icinga/icinga2/issues/5539) (Plugins, Windows, PR): check\_nscp\_api: Allow arguments containing spaces * [#5537](https://github.com/Icinga/icinga2/issues/5537) (Plugins): check\_nscp\_api: support spaces in query arguments * [#5524](https://github.com/Icinga/icinga2/issues/5524) (Cluster, PR): Change FIFO::Optimize\(\) frequency for large messages * [#5513](https://github.com/Icinga/icinga2/issues/5513) (Cluster): Node in Cluster loses connection * [#5504](https://github.com/Icinga/icinga2/issues/5504) (InfluxDB, PR): Fix TLS Race Connecting to InfluxDB * [#5503](https://github.com/Icinga/icinga2/issues/5503) (Livestatus, PR): Fix grouping for Livestatus queries with 'Stats' * [#5502](https://github.com/Icinga/icinga2/issues/5502) (Notifications, PR): Fix duplicate variable in notification scripts * [#5495](https://github.com/Icinga/icinga2/issues/5495) (Notifications, PR): Fix parameter order for AcknowledgeSvcProblem / AcknowledgeHostProblem / apiactions:AcknowledgeProblem * [#5492](https://github.com/Icinga/icinga2/issues/5492) (DB IDO): Comments may not be removed correctly * [#5484](https://github.com/Icinga/icinga2/issues/5484) (Log): Timestamp comparison of config files logs a wrong message * [#5483](https://github.com/Icinga/icinga2/issues/5483) (DB IDO, PR): Fix config validation for DB IDO categories 'DbCatEverything' * [#5469](https://github.com/Icinga/icinga2/issues/5469) (InfluxDB): Failure to connect to InfluxDB increases CPU utilisation by 100% for every failure * [#5466](https://github.com/Icinga/icinga2/issues/5466) (DB IDO, PR): DB IDO: Fix host's unreachable state in history tables * [#5460](https://github.com/Icinga/icinga2/issues/5460) (InfluxDB): Icinga 2.7 InfluxdbWriter fails to write metrics to InfluxDB over HTTPS * [#5458](https://github.com/Icinga/icinga2/issues/5458) (DB IDO): IDO donwtimehistory records orphaned from scheduleddowntime records following restart * [#5405](https://github.com/Icinga/icinga2/issues/5405) (DB IDO): IDO statehistory table does not show hosts going to "UNREACHABLE" state. * [#5078](https://github.com/Icinga/icinga2/issues/5078) (Compat, Livestatus): Livestatus hostsbygroup and servicesbyhostgroup do not work ### ITL * [#5543](https://github.com/Icinga/icinga2/issues/5543) (ITL, PR): ITL: Correct arguments for ipmi-sensor CheckCommand ### Documentation * [#5594](https://github.com/Icinga/icinga2/issues/5594) (Documentation, PR): Docs: Enhance certificate and configuration troubleshooting chapter * [#5593](https://github.com/Icinga/icinga2/issues/5593) (Documentation, PR): Docs: Add a note for upgrading to 2.7 * [#5583](https://github.com/Icinga/icinga2/issues/5583) (Documentation, PR): Docs: Add example for Windows service monitoring with check\_nscp\_api * [#5582](https://github.com/Icinga/icinga2/issues/5582) (Documentation, PR): Docs: Add firewall details for check\_nscp\_api * [#5549](https://github.com/Icinga/icinga2/issues/5549) (Documentation, PR): Fix cli command used to enable debuglog feature on windows * [#5536](https://github.com/Icinga/icinga2/issues/5536) (Documentation, PR): Fixed nscp-disk service example * [#5522](https://github.com/Icinga/icinga2/issues/5522) (Documentation, PR): Docs: Update freshness checks; add chapter for external check results * [#5516](https://github.com/Icinga/icinga2/issues/5516) (Documentation, PR): Updates the install dependencies for Debian 9 'stretch' * [#5506](https://github.com/Icinga/icinga2/issues/5506) (Documentation, PR): Docs: Fix wrong parameter for ITL CheckCommand nscp\_api * [#5496](https://github.com/Icinga/icinga2/issues/5496) (Documentation, PR): Docs: Update examples for match/regex/cidr\_match and mode for arrays \(Match{All,Any}\) * [#5494](https://github.com/Icinga/icinga2/issues/5494) (Documentation, PR): Docs: Add section for multiple template imports * [#5491](https://github.com/Icinga/icinga2/issues/5491) (Documentation, PR): Update "Getting Started" documentation with Alpine Linux * [#5487](https://github.com/Icinga/icinga2/issues/5487) (Documentation, PR): Docs: Enhance Troubleshooting with nscp-local, check\_source, wrong thresholds * [#5476](https://github.com/Icinga/icinga2/issues/5476) (Documentation, PR): Docs: Fix ITL chapter TOC; add introduction with mini TOC * [#5475](https://github.com/Icinga/icinga2/issues/5475) (Documentation, PR): Docs: Add a note on required configuration updates for new notification scripts in v2.7.0 * [#5461](https://github.com/Icinga/icinga2/issues/5461) (Documentation, PR): Update Icinga repository release rpm location * [#5457](https://github.com/Icinga/icinga2/issues/5457) (Documentation, PR): Add Changelog generation script for GitHub API * [#5428](https://github.com/Icinga/icinga2/issues/5428) (Documentation): "Plugin Check Commands" section inside ITL docs needs adjustments ### Support * [#5599](https://github.com/Icinga/icinga2/issues/5599) (PR): changelog.py: Add "backported" to the list of ignored labels * [#5590](https://github.com/Icinga/icinga2/issues/5590) (Cluster, Log, PR): Silence log level for configuration file updates * [#5529](https://github.com/Icinga/icinga2/issues/5529) (Log, PR): Change two more loglines for checkables so checkable is quoted * [#5528](https://github.com/Icinga/icinga2/issues/5528) (Log, PR): Change loglines for checkables so checkable is quoted * [#5501](https://github.com/Icinga/icinga2/issues/5501) (Installation, Packages, PR): SELinux: fixes for 2.7.0 * [#5479](https://github.com/Icinga/icinga2/issues/5479) (Packages): Icinga2 2.7.0 requires SELinux boolean icinga2\_can\_connect\_all on CentOS 7 even for default port * [#5477](https://github.com/Icinga/icinga2/issues/5477) (Installation, Packages, PR): Systemd: Add DefaultTasksMax=infinity to service file * [#5392](https://github.com/Icinga/icinga2/issues/5392) (Packages, PR): Ensure the cache directory exists * [#4918](https://github.com/Icinga/icinga2/issues/4918) (Packages): cgroup: fork rejected by pids controller in /system.slice/icinga2.service * [#4414](https://github.com/Icinga/icinga2/issues/4414) (Packages): /usr/lib/icinga2/prepare-dirs does not create /var/cache/icinga2 ## 2.7.0 (2017-08-02) ### Notes * New mail notification scripts. Please note that this requires a configuration update to NotificationCommand objects, Notification apply rules for specific settings and of course the notification scripts. More can be found [here](https://github.com/Icinga/icinga2/pull/5475). * check_nscp_api plugin for NSClient++ REST API checks * Work queues for features including logs & metrics * More metrics for the "icinga" check * Many bugfixes ### Enhancement * [#5421](https://github.com/Icinga/icinga2/issues/5421) (Plugins, Windows, PR): Windows Plugins: Add new parameter to check\_disk to show used space * [#5348](https://github.com/Icinga/icinga2/issues/5348) (Configuration, PR): Implement support for handling exceptions in user scripts * [#5331](https://github.com/Icinga/icinga2/issues/5331) (Graylog, PR): GelfWriter: Add 'check\_command' to CHECK RESULT/\* NOTIFICATION/STATE CHANGE messages * [#5330](https://github.com/Icinga/icinga2/issues/5330) (Graphite, PR): GraphiteWriter: Add 'connected' to stats; fix reconnect exceptions * [#5329](https://github.com/Icinga/icinga2/issues/5329) (Graylog, PR): GelfWriter: Use async work queue and add feature metric stats * [#5320](https://github.com/Icinga/icinga2/issues/5320) (Configuration, PR): zones.conf: Add global-templates & director-global by default * [#5287](https://github.com/Icinga/icinga2/issues/5287) (Graphite, InfluxDB, Performance Data, PR): Use workqueues in Graphite and InfluxDB features * [#5284](https://github.com/Icinga/icinga2/issues/5284) (Check Execution, PR): Add feature stats to 'icinga' check as performance data metrics * [#5280](https://github.com/Icinga/icinga2/issues/5280) (API, Cluster, Log, PR): Implement WorkQueue metric stats and periodic logging * [#5266](https://github.com/Icinga/icinga2/issues/5266) (API, Cluster, PR): Add API & Cluster metric stats to /v1/status & icinga check incl. performance data * [#5264](https://github.com/Icinga/icinga2/issues/5264) (Configuration, PR): Implement new array match functionality * [#5247](https://github.com/Icinga/icinga2/issues/5247) (Log, PR): Add target object in cluster error messages to debug log * [#5246](https://github.com/Icinga/icinga2/issues/5246) (API, Cluster, PR): Add subjectAltName X509 ext for certificate requests * [#5242](https://github.com/Icinga/icinga2/issues/5242) (Configuration, PR): Allow expressions for the type in object/template declarations * [#5241](https://github.com/Icinga/icinga2/issues/5241) (InfluxDB, PR): Verbose InfluxDB Error Logging * [#5239](https://github.com/Icinga/icinga2/issues/5239) (Plugins, Windows, PR): Add NSCP API check plugin for NSClient++ HTTP API * [#5212](https://github.com/Icinga/icinga2/issues/5212) (Cluster, Log): Add additional logging for config sync * [#5145](https://github.com/Icinga/icinga2/issues/5145): Add a GitHub issue template * [#5133](https://github.com/Icinga/icinga2/issues/5133) (API, wishlist): ApiListener: Metrics for cluster data * [#5106](https://github.com/Icinga/icinga2/issues/5106) (Configuration): Add director-global as global zone to the default zones.conf configuration * [#4945](https://github.com/Icinga/icinga2/issues/4945) (API, Log): No hint for missing permissions in Icinga2 log for API user * [#4925](https://github.com/Icinga/icinga2/issues/4925): Update changelog generation scripts for GitHub * [#4411](https://github.com/Icinga/icinga2/issues/4411) (InfluxDB, Log, Performance Data): Better Debugging for InfluxdbWriter * [#4288](https://github.com/Icinga/icinga2/issues/4288) (Cluster, Log): Add check information to the debuglog when check result is discarded * [#4242](https://github.com/Icinga/icinga2/issues/4242) (Configuration): Default mail notification from header * [#3557](https://github.com/Icinga/icinga2/issues/3557) (Log): Log started and stopped features ### Bug * [#5433](https://github.com/Icinga/icinga2/issues/5433) (CLI, PR): Fix: update feature list help text * [#5367](https://github.com/Icinga/icinga2/issues/5367) (CLI, Crash): Unable to start icinga2 with kernel-3.10.0-514.21.2 RHEL7 * [#5350](https://github.com/Icinga/icinga2/issues/5350) (Plugins): check\_nscp\_api not building on Debian wheezy * [#5316](https://github.com/Icinga/icinga2/issues/5316) (Livestatus, PR): Fix for stats min operator * [#5308](https://github.com/Icinga/icinga2/issues/5308) (Configuration, PR): Improve validation for attributes which must not be 'null' * [#5297](https://github.com/Icinga/icinga2/issues/5297) (PR): Fix compiler warnings * [#5295](https://github.com/Icinga/icinga2/issues/5295) (Notifications, PR): Fix missing apostrophe in notification log * [#5292](https://github.com/Icinga/icinga2/issues/5292) (PR): Build fix for OpenSSL 0.9.8 and stack\_st\_X509\_EXTENSION * [#5288](https://github.com/Icinga/icinga2/issues/5288) (Configuration): Hostgroup using assign for Host with groups = null segfault * [#5278](https://github.com/Icinga/icinga2/issues/5278) (PR): Build fix for I2\_LEAK\_DEBUG * [#5262](https://github.com/Icinga/icinga2/issues/5262) (Graylog, PR): Fix performance data processing in GelfWriter feature * [#5259](https://github.com/Icinga/icinga2/issues/5259) (API, PR): Don't allow acknowledgement expire timestamps in the past * [#5256](https://github.com/Icinga/icinga2/issues/5256) (Configuration): Config type changes break object serialization \(JsonEncode\) * [#5250](https://github.com/Icinga/icinga2/issues/5250) (API, Compat): Acknowledgement expire time in the past * [#5245](https://github.com/Icinga/icinga2/issues/5245) (Notifications, PR): Fix that host downtimes might be triggered even if their state is Up * [#5224](https://github.com/Icinga/icinga2/issues/5224) (Configuration, Notifications): Icinga sends notifications even though a Downtime object exists * [#5223](https://github.com/Icinga/icinga2/issues/5223) (Plugins, Windows): Wrong return Code for Windows ICMP * [#5219](https://github.com/Icinga/icinga2/issues/5219) (InfluxDB): InfluxDBWriter feature might block and leak memory * [#5211](https://github.com/Icinga/icinga2/issues/5211) (API, Cluster): Config received is always accepted by client even if own config is newer * [#5194](https://github.com/Icinga/icinga2/issues/5194) (API, CLI): No subjectAltName in Icinga CA created CSRs * [#5168](https://github.com/Icinga/icinga2/issues/5168) (Windows): include files from other volume/partition * [#5146](https://github.com/Icinga/icinga2/issues/5146) (Configuration): parsing of scheduled downtime object allow typing range instead of ranges * [#5132](https://github.com/Icinga/icinga2/issues/5132) (Graphite): GraphiteWriter can slow down Icinga's check result processing * [#5062](https://github.com/Icinga/icinga2/issues/5062) (Compat): icinga2 checkresults error * [#5043](https://github.com/Icinga/icinga2/issues/5043) (API): API POST request with 'attrs' as array returns bad\_cast error * [#5040](https://github.com/Icinga/icinga2/issues/5040) (Cluster): CRL loading fails due to incorrect return code check * [#5033](https://github.com/Icinga/icinga2/issues/5033) (DB IDO): Flexible downtimes which are not triggered must not update DB IDO's actual\_end\_time in downtimehistory table * [#4984](https://github.com/Icinga/icinga2/issues/4984) (API): Wrong response type when unauthorized * [#4983](https://github.com/Icinga/icinga2/issues/4983) (Livestatus): Typo in livestatus key worst\_services\_state for hostgroups table * [#4956](https://github.com/Icinga/icinga2/issues/4956) (DB IDO, PR): Fix persistent comments for Acknowledgements * [#4941](https://github.com/Icinga/icinga2/issues/4941) (Performance Data, PR): PerfData: Server Timeouts for InfluxDB Writer * [#4927](https://github.com/Icinga/icinga2/issues/4927) (InfluxDB, Performance Data): InfluxDbWriter error 500 hanging Icinga daemon * [#4913](https://github.com/Icinga/icinga2/issues/4913) (API): acknowledge-problem api sending notifications when notify is false * [#4909](https://github.com/Icinga/icinga2/issues/4909) (CLI): icinga2 feature disable fails on already disabled feature * [#4896](https://github.com/Icinga/icinga2/issues/4896) (Plugins): Windows Agent: performance data of check\_perfmon * [#4832](https://github.com/Icinga/icinga2/issues/4832) (API, Configuration): API max\_check\_attempts validation * [#4818](https://github.com/Icinga/icinga2/issues/4818): Acknowledgements marked with Persistent Comment are not honored * [#4779](https://github.com/Icinga/icinga2/issues/4779): Superflous error messages for non-exisiting lsb\_release/sw\_vers commands \(on NetBSD\) * [#4778](https://github.com/Icinga/icinga2/issues/4778): Fix for traditional glob\(3\) behaviour * [#4777](https://github.com/Icinga/icinga2/issues/4777): NetBSD execvpe.c fix * [#4709](https://github.com/Icinga/icinga2/issues/4709) (API): Posting config stage fails on FreeBSD * [#4696](https://github.com/Icinga/icinga2/issues/4696) (Notifications): Notifications are sent when reloading Icinga 2 even though they're deactivated via modified attributes * [#4666](https://github.com/Icinga/icinga2/issues/4666) (Graylog, Performance Data): GelfWriter with enable\_send\_perfdata breaks checks * [#4532](https://github.com/Icinga/icinga2/issues/4532) (Graylog, Performance Data): Icinga 2 "hangs" if the GelfWriter cannot send messages * [#4440](https://github.com/Icinga/icinga2/issues/4440) (DB IDO, Log): Exceptions might be better than exit in IDO * [#3664](https://github.com/Icinga/icinga2/issues/3664) (DB IDO): mysql\_error cannot be used for mysql\_init * [#3483](https://github.com/Icinga/icinga2/issues/3483) (Compat): Stacktrace on Command Pipe Error * [#3410](https://github.com/Icinga/icinga2/issues/3410) (Livestatus): Livestatus: Problem with stats min operator * [#121](https://github.com/Icinga/icinga2/issues/121) (CLI, PR): give only warnings if feature is already disabled ### ITL * [#5384](https://github.com/Icinga/icinga2/issues/5384) (ITL, PR): Remove default value for 'dns\_query\_type' * [#5383](https://github.com/Icinga/icinga2/issues/5383) (ITL): Monitoring-Plugins check\_dns command does not support the `-q` flag * [#5372](https://github.com/Icinga/icinga2/issues/5372) (ITL, PR): Update ITL CheckCommand description attribute, part 2 * [#5363](https://github.com/Icinga/icinga2/issues/5363) (ITL, PR): Update missing description attributes for ITL CheckCommand definitions * [#5347](https://github.com/Icinga/icinga2/issues/5347) (ITL, PR): Improve ITL CheckCommand description attribute * [#5344](https://github.com/Icinga/icinga2/issues/5344) (ITL, PR): Add ip4-or-ipv6 import to logstash ITL command * [#5343](https://github.com/Icinga/icinga2/issues/5343) (ITL): logstash ITL command misses import * [#5236](https://github.com/Icinga/icinga2/issues/5236) (ITL, PR): ITL: Add some missing arguments to ssl\_cert * [#5210](https://github.com/Icinga/icinga2/issues/5210) (ITL, PR): Add report mode to db2\_health * [#5170](https://github.com/Icinga/icinga2/issues/5170) (ITL, PR): Enhance mail notifications scripts and add support for command line parameters * [#5139](https://github.com/Icinga/icinga2/issues/5139) (ITL, PR): Add more options to ldap CheckCommand * [#5129](https://github.com/Icinga/icinga2/issues/5129) (ITL): Additional parameters for perfout manubulon scripts * [#5126](https://github.com/Icinga/icinga2/issues/5126) (ITL, PR): Added support to NRPE v2 in NRPE CheckCommand * [#5075](https://github.com/Icinga/icinga2/issues/5075) (ITL, PR): fix mitigation for nwc\_health * [#5063](https://github.com/Icinga/icinga2/issues/5063) (ITL, PR): Add additional arguments to mssql\_health * [#5046](https://github.com/Icinga/icinga2/issues/5046) (ITL): Add querytype to dns check * [#5019](https://github.com/Icinga/icinga2/issues/5019) (ITL, PR): Added CheckCommand definitions for SMART, RAID controller and IPMI ping check * [#5015](https://github.com/Icinga/icinga2/issues/5015) (ITL, PR): nwc\_health\_report attribute requires a value * [#4987](https://github.com/Icinga/icinga2/issues/4987) (ITL): Review `dummy` entry in ITL * [#4985](https://github.com/Icinga/icinga2/issues/4985) (ITL): Allow hpasm command from ITL to run in local mode * [#4964](https://github.com/Icinga/icinga2/issues/4964) (ITL, PR): ITL: check\_icmp: add missing TTL attribute * [#4839](https://github.com/Icinga/icinga2/issues/4839) (ITL): Remove deprecated dns\_expected\_answer attribute * [#4826](https://github.com/Icinga/icinga2/issues/4826) (ITL): Prepare icingacli-businessprocess for next release * [#4661](https://github.com/Icinga/icinga2/issues/4661) (ITL): ITL - check\_oracle\_health - report option to shorten output * [#124](https://github.com/Icinga/icinga2/issues/124) (ITL, PR): FreeBSD's /dev/fd can either be inside devfs, or be of type fdescfs. * [#123](https://github.com/Icinga/icinga2/issues/123) (ITL, PR): ITL: Update ipmi CheckCommand attributes * [#120](https://github.com/Icinga/icinga2/issues/120) (ITL, PR): Add new parameter for check\_http: -L: Wrap output in HTML link * [#117](https://github.com/Icinga/icinga2/issues/117) (ITL, PR): Support --only-critical for check\_apt * [#115](https://github.com/Icinga/icinga2/issues/115) (ITL, PR): Inverse Interface Switch for snmp-interface * [#114](https://github.com/Icinga/icinga2/issues/114) (ITL, PR): Adding -A to snmp interfaces check ### Documentation * [#5448](https://github.com/Icinga/icinga2/issues/5448) (Documentation, PR): Update documentation for 2.7.0 * [#5440](https://github.com/Icinga/icinga2/issues/5440) (Documentation, PR): Add missing notification state filter to documentation * [#5425](https://github.com/Icinga/icinga2/issues/5425) (Documentation, PR): Fix formatting in API docs * [#5410](https://github.com/Icinga/icinga2/issues/5410) (Documentation): Update docs for better compatibility with mkdocs * [#5393](https://github.com/Icinga/icinga2/issues/5393) (Documentation, PR): Fix typo in the documentation * [#5378](https://github.com/Icinga/icinga2/issues/5378) (Documentation, PR): Fixed warnings when using mkdocs * [#5370](https://github.com/Icinga/icinga2/issues/5370) (Documentation, PR): Rename ChangeLog to CHANGELOG.md * [#5366](https://github.com/Icinga/icinga2/issues/5366) (Documentation, PR): Fixed wrong node in documentation chapter Client/Satellite Linux Setup * [#5365](https://github.com/Icinga/icinga2/issues/5365) (Documentation, PR): Update package documentation for Debian Stretch * [#5358](https://github.com/Icinga/icinga2/issues/5358) (Documentation, PR): Add documentation for securing mysql on Debian/Ubuntu. * [#5357](https://github.com/Icinga/icinga2/issues/5357) (Documentation, Notifications, PR): Notification Scripts: Ensure that mail from address works on Debian/RHEL/SUSE \(mailutils vs mailx\) * [#5354](https://github.com/Icinga/icinga2/issues/5354) (Documentation, PR): Docs: Fix built-in template description and URLs * [#5349](https://github.com/Icinga/icinga2/issues/5349) (Documentation, PR): Docs: Fix broken format for notes/tips in CLI command chapter * [#5339](https://github.com/Icinga/icinga2/issues/5339) (Documentation, ITL, PR): Add accept\_cname to dns CheckCommand * [#5336](https://github.com/Icinga/icinga2/issues/5336) (Documentation, PR): Docs: Fix formatting issues and broken URLs * [#5333](https://github.com/Icinga/icinga2/issues/5333) (Documentation, PR): Update documentation for enhanced notification scripts * [#5324](https://github.com/Icinga/icinga2/issues/5324) (Documentation, PR): Fix phrasing in Getting Started chapter * [#5317](https://github.com/Icinga/icinga2/issues/5317) (Documentation, PR): Fix typo in INSTALL.md * [#5315](https://github.com/Icinga/icinga2/issues/5315) (Documentation, PR): Docs: Replace nagios-plugins by monitoring-plugins for Debian/Ubuntu * [#5314](https://github.com/Icinga/icinga2/issues/5314) (Documentation, PR): Document Common name \(CN\) in client setup * [#5309](https://github.com/Icinga/icinga2/issues/5309) (Documentation, PR): Docs: Replace the command pipe w/ the REST API as Icinga Web 2 requirement in 'Getting Started' chapter * [#5291](https://github.com/Icinga/icinga2/issues/5291) (Documentation): Update docs for RHEL/CentOS 5 EOL * [#5285](https://github.com/Icinga/icinga2/issues/5285) (Documentation, PR): Fix sysstat installation in troubleshooting docs * [#5279](https://github.com/Icinga/icinga2/issues/5279) (Documentation, PR): Docs: Add API query example for acknowledgements w/o expire time * [#5275](https://github.com/Icinga/icinga2/issues/5275) (Documentation, PR): Add troubleshooting hints for cgroup fork errors * [#5244](https://github.com/Icinga/icinga2/issues/5244) (Documentation, PR): Add a PR review section to CONTRIBUTING.md * [#5237](https://github.com/Icinga/icinga2/issues/5237) (Documentation, PR): Docs: Add a note for Windows debuglog to the troubleshooting chapter * [#5227](https://github.com/Icinga/icinga2/issues/5227) (Documentation, ITL, PR): feature/itl-vmware-esx-storage-path-standbyok * [#5216](https://github.com/Icinga/icinga2/issues/5216) (Documentation, PR): Remove "... is is ..." in CONTRIBUTING.md * [#5206](https://github.com/Icinga/icinga2/issues/5206) (Documentation): Typo in Getting Started Guide * [#5203](https://github.com/Icinga/icinga2/issues/5203) (Documentation, PR): Fix typo in Getting Started chapter * [#5184](https://github.com/Icinga/icinga2/issues/5184) (Documentation, PR): Doc/appendix: fix malformed markdown links * [#5181](https://github.com/Icinga/icinga2/issues/5181) (Documentation, PR): List SELinux packages required for building RPMs * [#5178](https://github.com/Icinga/icinga2/issues/5178) (Documentation, Windows): Documentation vague on "update-windows" check plugin * [#5175](https://github.com/Icinga/icinga2/issues/5175) (Documentation): Add a note about flapping problems to the docs * [#5174](https://github.com/Icinga/icinga2/issues/5174) (Documentation, PR): Add missing object type to Apply Rules doc example * [#5173](https://github.com/Icinga/icinga2/issues/5173) (Documentation): Object type missing from ping Service example in docs * [#5167](https://github.com/Icinga/icinga2/issues/5167) (Documentation): Add more assign where expression examples * [#5166](https://github.com/Icinga/icinga2/issues/5166) (API, Documentation): Set zone attribute to no\_user\_modify for API POST requests * [#5165](https://github.com/Icinga/icinga2/issues/5165) (Documentation, PR): Syntax error In Dependencies chapter * [#5164](https://github.com/Icinga/icinga2/issues/5164) (Documentation, ITL, PR): ITL: Add CheckCommand ssl\_cert, fix ssl attributes * [#5161](https://github.com/Icinga/icinga2/issues/5161) (Documentation, PR): ITL documentation - disk-windows usage note with % thresholds * [#5157](https://github.com/Icinga/icinga2/issues/5157) (Documentation): "Three Levels with master, Satellites, and Clients" chapter is not clear about client config * [#5156](https://github.com/Icinga/icinga2/issues/5156) (Documentation): Add CONTRIBUTING.md * [#5155](https://github.com/Icinga/icinga2/issues/5155) (Documentation): 3.5. Apply Rules topic in the docs needs work. * [#5151](https://github.com/Icinga/icinga2/issues/5151) (Documentation, PR): Replace http:// links with https:// links where a secure website exists * [#5150](https://github.com/Icinga/icinga2/issues/5150) (Documentation): Invalid links in documentation * [#5149](https://github.com/Icinga/icinga2/issues/5149) (Documentation, PR): Update documentation, change http:// links to https:// links where a website exists * [#5144](https://github.com/Icinga/icinga2/issues/5144) (Documentation): Extend troubleshooting docs w/ environment analysis and common tools * [#5143](https://github.com/Icinga/icinga2/issues/5143) (Documentation): Docs: Explain how to include your own config tree instead of conf.d * [#5142](https://github.com/Icinga/icinga2/issues/5142) (Documentation): Add an Elastic Stack Integrations chapter to feature documentation * [#5140](https://github.com/Icinga/icinga2/issues/5140) (Documentation): Documentation should explain that runtime modifications are not immediately updated for "object list" * [#5137](https://github.com/Icinga/icinga2/issues/5137) (Documentation): Doc updates: Getting Started w/ own config, Troubleshooting w/ debug console * [#5111](https://github.com/Icinga/icinga2/issues/5111) (Documentation): Fix duration attribute requirement for schedule-downtime API action * [#5104](https://github.com/Icinga/icinga2/issues/5104) (Documentation, PR): Correct link to nscp documentation * [#5097](https://github.com/Icinga/icinga2/issues/5097) (Documentation): The last example for typeof\(\) is missing the result * [#5090](https://github.com/Icinga/icinga2/issues/5090) (Cluster, Documentation): EventHandler to be executed at the endpoint * [#5077](https://github.com/Icinga/icinga2/issues/5077) (Documentation): Replace the 'command' feature w/ the REST API for Icinga Web 2 * [#5016](https://github.com/Icinga/icinga2/issues/5016) (Documentation, ITL, PR): Add fuse.gvfs-fuse-daemon to disk\_exclude\_type * [#5010](https://github.com/Icinga/icinga2/issues/5010) (Documentation): \[Documentation\] Missing parameter for SNMPv3 auth * [#3560](https://github.com/Icinga/icinga2/issues/3560) (Documentation): Explain check\_memorys and check\_disks thresholds * [#1880](https://github.com/Icinga/icinga2/issues/1880) (Documentation): add a section for 'monitoring the icinga2 node' ### Support * [#5359](https://github.com/Icinga/icinga2/issues/5359) (CLI, PR): Fixed missing closing bracket in CLI command pki new-cert. * [#5332](https://github.com/Icinga/icinga2/issues/5332) (Configuration, Notifications, PR): Notification Scripts: notification\_type is always required * [#5326](https://github.com/Icinga/icinga2/issues/5326) (Documentation, Installation, PR): Install the images directory containing the needed PNGs for the markd * [#5310](https://github.com/Icinga/icinga2/issues/5310) (Packages, PR): RPM: Disable SELinux policy hardlink * [#5306](https://github.com/Icinga/icinga2/issues/5306) (Documentation, Packages, PR): Remove CentOS 5 from 'Getting started' docs * [#5304](https://github.com/Icinga/icinga2/issues/5304) (Documentation, Packages, PR): Update INSTALL.md for RPM builds * [#5303](https://github.com/Icinga/icinga2/issues/5303) (Packages, PR): RPM: Fix builds on Amazon Linux * [#5299](https://github.com/Icinga/icinga2/issues/5299) (Notifications): Ensure that "mail from" works on RHEL/CentOS * [#5286](https://github.com/Icinga/icinga2/issues/5286) (Configuration, PR): Fix verbose mode in notifications scripts * [#5265](https://github.com/Icinga/icinga2/issues/5265) (PR): Move PerfdataValue\(\) class into base library * [#5252](https://github.com/Icinga/icinga2/issues/5252) (Tests, PR): travis: Update to trusty as CI environment * [#5251](https://github.com/Icinga/icinga2/issues/5251) (Tests): Update Travis CI environment to trusty * [#5248](https://github.com/Icinga/icinga2/issues/5248) (Tests, PR): Travis: Run config validation at the end * [#5238](https://github.com/Icinga/icinga2/issues/5238) (DB IDO, PR): Remove deprecated "DbCat1 | DbCat2" notation for DB IDO categories * [#5229](https://github.com/Icinga/icinga2/issues/5229) (Installation, PR): CMake: require a GCC version according to INSTALL.md * [#5226](https://github.com/Icinga/icinga2/issues/5226) (Packages, PR): RPM spec: don't enable features after an upgrade * [#5225](https://github.com/Icinga/icinga2/issues/5225) (DB IDO, PR): Don't call mysql\_error\(\) after a failure of mysql\_init\(\) * [#5218](https://github.com/Icinga/icinga2/issues/5218) (Packages): icinga2.spec: Allow selecting g++ compiler on older SUSE release builds * [#5189](https://github.com/Icinga/icinga2/issues/5189) (Documentation, Packages, PR): RPM packaging updates * [#5188](https://github.com/Icinga/icinga2/issues/5188) (Documentation, Packages): Boost \>= 1.48 required * [#5177](https://github.com/Icinga/icinga2/issues/5177) (Packages): Issues Packing icinga 2.6.3 tar.gz to RPM * [#5153](https://github.com/Icinga/icinga2/issues/5153) (Packages, PR): Changed dependency of selinux subpackage * [#5127](https://github.com/Icinga/icinga2/issues/5127) (Installation, PR): Improve systemd service file * [#5102](https://github.com/Icinga/icinga2/issues/5102) (Compat, Configuration, Packages): Deprecate the icinga2-classicui-config package * [#5101](https://github.com/Icinga/icinga2/issues/5101) (Packages, Windows): Fix incorrect metadata for the Chocolatey package * [#5100](https://github.com/Icinga/icinga2/issues/5100) (Packages, Windows): Update Chocolatey package to match current guidelines * [#5094](https://github.com/Icinga/icinga2/issues/5094) (Cluster, Configuration): Log message "Object cannot be deleted because it was not created using the API" * [#5087](https://github.com/Icinga/icinga2/issues/5087) (Configuration): Function metadata should show available arguments * [#5042](https://github.com/Icinga/icinga2/issues/5042) (DB IDO, PR): Add link to upgrade documentation to log message * [#4977](https://github.com/Icinga/icinga2/issues/4977) (Cluster, Installation): icinga2/api/log directory is not created * [#4921](https://github.com/Icinga/icinga2/issues/4921) (Installation, Packages): No network dependency for /etc/init.d/icinga2 * [#4781](https://github.com/Icinga/icinga2/issues/4781) (Packages): Improve SELinux Policy * [#4776](https://github.com/Icinga/icinga2/issues/4776) (Installation): NetBSD install path fixes * [#4621](https://github.com/Icinga/icinga2/issues/4621) (Configuration, Notifications, Packages): notifications always enabled after update ## 2.6.3 (2017-03-29) ### Bug * [#5080](https://github.com/Icinga/icinga2/issues/5080) (DB IDO): Missing index use can cause icinga\_downtimehistory queries to hang indefinitely * [#4989](https://github.com/Icinga/icinga2/issues/4989) (Check Execution): Icinga daemon runs with nice 5 after reload * [#4930](https://github.com/Icinga/icinga2/issues/4930) (Cluster): Change "Discarding 'config update object'" log messages to notice log level * [#4603](https://github.com/Icinga/icinga2/issues/4603) (DB IDO): With too many comments, Icinga reload process won't finish reconnecting to Database ### Documentation * [#5057](https://github.com/Icinga/icinga2/issues/5057) (Documentation): Update Security section in the Distributed Monitoring chapter * [#5055](https://github.com/Icinga/icinga2/issues/5055) (Documentation, ITL): mysql\_socket attribute missing in the documentation for the mysql CheckCommand * [#5035](https://github.com/Icinga/icinga2/issues/5035) (Documentation): Docs: Typo in Distributed Monitoring chapter * [#5030](https://github.com/Icinga/icinga2/issues/5030) (Documentation): Advanced topics: Mention the API and explain stick acks, fixed/flexible downtimes * [#5029](https://github.com/Icinga/icinga2/issues/5029) (Documentation): Advanced topics: Wrong acknowledgement notification filter * [#4996](https://github.com/Icinga/icinga2/issues/4996) (Documentation): documentation: mixed up host names in 6-distributed-monitoring.md * [#4980](https://github.com/Icinga/icinga2/issues/4980) (Documentation): Add OpenBSD and AlpineLinux package repositories to the documentation * [#4955](https://github.com/Icinga/icinga2/issues/4955) (Documentation, ITL): Review CheckCommand documentation including external URLs * [#4954](https://github.com/Icinga/icinga2/issues/4954) (Documentation): Add an example for /v1/actions/process-check-result which uses filter/type * [#3133](https://github.com/Icinga/icinga2/issues/3133) (Documentation): Add practical examples for apply expressions ## 2.6.2 (2017-02-13) ### Bug * [#4952](https://github.com/Icinga/icinga2/issues/4952) (API, CLI): Icinga crashes while trying to remove configuration files for objects which no longer exist ## 2.6.1 (2017-01-31) ### Notes This release addresses a number of bugs we have identified in version 2.6.0. The documentation changes reflect our recent move to GitHub. ### Enhancement * [#4923](https://github.com/Icinga/icinga2/issues/4923): Migration to Github * [#4813](https://github.com/Icinga/icinga2/issues/4813): Include argument name for log message about incorrect set\_if values ### Bug * [#4950](https://github.com/Icinga/icinga2/issues/4950): IDO schema update is not compatible to MySQL 5.7 * [#4882](https://github.com/Icinga/icinga2/issues/4882): Crash - Error: parse error: premature EOF * [#4877](https://github.com/Icinga/icinga2/issues/4877) (DB IDO): IDO MySQL schema not working on MySQL 5.7 * [#4874](https://github.com/Icinga/icinga2/issues/4874) (DB IDO): IDO: Timestamps in PostgreSQL may still have a time zone offset * [#4867](https://github.com/Icinga/icinga2/issues/4867): SIGPIPE shutdown on config reload ### Documentation * [#4944](https://github.com/Icinga/icinga2/issues/4944) (Documentation, PR): doc/6-distributed-monitoring.md: Fix typo * [#4934](https://github.com/Icinga/icinga2/issues/4934) (Documentation): Update contribution section for GitHub * [#4917](https://github.com/Icinga/icinga2/issues/4917) (Documentation): Incorrect license file mentioned in README.md * [#4916](https://github.com/Icinga/icinga2/issues/4916) (Documentation): Add travis-ci build status logo to README.md * [#4908](https://github.com/Icinga/icinga2/issues/4908) (Documentation): Move domain to icinga.com * [#4885](https://github.com/Icinga/icinga2/issues/4885) (Documentation): SLES 12 SP2 libboost\_thread package requires libboost\_chrono * [#4869](https://github.com/Icinga/icinga2/issues/4869) (Documentation): Update RELEASE.md * [#4868](https://github.com/Icinga/icinga2/issues/4868) (Documentation): Add more build details to INSTALL.md * [#4803](https://github.com/Icinga/icinga2/issues/4803) (Documentation): Update Repositories in Docs ### Support * [#4870](https://github.com/Icinga/icinga2/issues/4870) (Packages): SLES11 SP4 dependency on Postgresql \>= 8.4 ## 2.6.0 (2016-12-13) ### Notes * Client/Satellite setup * The "bottom up" client configuration mode has been deprecated. Check [#13255](https://dev.icinga.com/issues/13255) for additional details and migration. * Linux/Unix daemon * Ensure that Icinga 2 does not leak file descriptors to executed commands. * There are 2 processes started instead of previously just one process. * Windows client * Package bundles NSClient++ 0.5.0. ITL CheckCommands have been updated too. * Allow to configure the user account for the Icinga 2 service. This is useful if several checks require administrator permissions (e.g. check_update.exe) * Bugfixes for check plugins * Cluster and API * Provide location information for objects and templates in the API * Improve log message for ignored config updates * Fix cluster resync problem with API created objects (hosts, downtimes, etc.) * Fix that API-created objects in a global zone are not synced to child endpoints * Notifications * Several bugfixes for downtime, custom and flapping notifications * New ITL CheckCommands: logstash, glusterfs, iostats * Package builds require a compiler which supports C++11 features (gcc-c++ >= 4.7, clang++) * DB IDO * Schema upgrade required (2.6.0.sql) * This update fixes timestamp columns required by Icinga Web 2 and might take a while. Please ensure to schedule a maintenance task for your database upgrade. ### Enhancement * [#4798](https://github.com/Icinga/icinga2/issues/4798) (Cluster): Deprecate cluster/client mode "bottom up" w/ repository.d and node update-config * [#4770](https://github.com/Icinga/icinga2/issues/4770) (API): Allow to evaluate macros through the API * [#4713](https://github.com/Icinga/icinga2/issues/4713) (Cluster): Check whether nodes are synchronizing the API log before putting them into UNKNOWN * [#4651](https://github.com/Icinga/icinga2/issues/4651) (Plugins): Review windows plugins performance output * [#4631](https://github.com/Icinga/icinga2/issues/4631) (Configuration): Suppress compiler warnings for auto-generated code * [#4622](https://github.com/Icinga/icinga2/issues/4622) (Cluster): Improve log message for ignored config updates * [#4590](https://github.com/Icinga/icinga2/issues/4590): Make sure that libmethods is automatically loaded even when not using the ITL * [#4587](https://github.com/Icinga/icinga2/issues/4587) (Configuration): Implement support for default templates * [#4580](https://github.com/Icinga/icinga2/issues/4580) (API): Provide location information for objects and templates in the API * [#4576](https://github.com/Icinga/icinga2/issues/4576): Use lambda functions for INITIALIZE\_ONCE * [#4575](https://github.com/Icinga/icinga2/issues/4575): Use 'auto' for iterator declarations * [#4571](https://github.com/Icinga/icinga2/issues/4571): Implement an rvalue constructor for the String and Value classes * [#4570](https://github.com/Icinga/icinga2/issues/4570) (Configuration): Implement a command-line argument for "icinga2 console" to allow specifying a script file * [#4563](https://github.com/Icinga/icinga2/issues/4563) (Configuration): Remove unused method: ApplyRule::DiscardRules * [#4559](https://github.com/Icinga/icinga2/issues/4559): Replace BOOST\_FOREACH with range-based for loops * [#4557](https://github.com/Icinga/icinga2/issues/4557): Add -fvisibility=hidden to the default compiler flags * [#4537](https://github.com/Icinga/icinga2/issues/4537): Implement an environment variable to keep Icinga from closing FDs on startup * [#4536](https://github.com/Icinga/icinga2/issues/4536): Avoid unnecessary string copies * [#4535](https://github.com/Icinga/icinga2/issues/4535): Remove deprecated functions * [#3684](https://github.com/Icinga/icinga2/issues/3684) (Configuration): Command line option for config syntax validation * [#2968](https://github.com/Icinga/icinga2/issues/2968): Better message for apply errors ### Bug * [#4831](https://github.com/Icinga/icinga2/issues/4831) (CLI): Wrong help string for node setup cli command argument --master\_host * [#4828](https://github.com/Icinga/icinga2/issues/4828) (API): Crash in CreateObjectHandler \(regression from \#11684 * [#4802](https://github.com/Icinga/icinga2/issues/4802): Icinga tries to delete Downtime objects that were statically configured * [#4801](https://github.com/Icinga/icinga2/issues/4801): Sending a HUP signal to the child process for execution actually kills it * [#4791](https://github.com/Icinga/icinga2/issues/4791) (DB IDO): PostgreSQL: Don't use timestamp with timezone for UNIX timestamp columns * [#4789](https://github.com/Icinga/icinga2/issues/4789) (Notifications): Recovery notifications sent for Not-Problem notification type if notified before * [#4775](https://github.com/Icinga/icinga2/issues/4775) (Cluster): Crash w/ SendNotifications cluster handler and check result with empty perfdata * [#4771](https://github.com/Icinga/icinga2/issues/4771): Config validation crashes when using command\_endpoint without also having an ApiListener object * [#4752](https://github.com/Icinga/icinga2/issues/4752) (Graphite): Performance data writer for Graphite : Values without fraction limited to 2147483647 \(7FFFFFFF\) * [#4740](https://github.com/Icinga/icinga2/issues/4740): SIGALRM handling may be affected by recent commit * [#4726](https://github.com/Icinga/icinga2/issues/4726) (Notifications): Flapping notifications sent for soft state changes * [#4717](https://github.com/Icinga/icinga2/issues/4717) (API): Icinga crashes while deleting a config file which doesn't exist anymore * [#4678](https://github.com/Icinga/icinga2/issues/4678) (Configuration): Configuration validation fails when setting tls\_protocolmin to TLSv1.2 * [#4674](https://github.com/Icinga/icinga2/issues/4674) (CLI): Parse error: "premature EOF" when running "icinga2 node update-config" * [#4665](https://github.com/Icinga/icinga2/issues/4665): Crash in ClusterEvents::SendNotificationsAPIHandler * [#4646](https://github.com/Icinga/icinga2/issues/4646) (Notifications): Forced custom notification is setting "force\_next\_notification": true permanently * [#4644](https://github.com/Icinga/icinga2/issues/4644) (API): Crash in HttpRequest::Parse while processing HTTP request * [#4630](https://github.com/Icinga/icinga2/issues/4630) (Configuration): Validation does not highlight the correct attribute * [#4629](https://github.com/Icinga/icinga2/issues/4629) (CLI): broken: icinga2 --version * [#4620](https://github.com/Icinga/icinga2/issues/4620) (API): Invalid API filter error messages * [#4619](https://github.com/Icinga/icinga2/issues/4619) (CLI): Cli: boost::bad\_get on icinga::String::String\(icinga::Value&&\) * [#4616](https://github.com/Icinga/icinga2/issues/4616): Build fails with Visual Studio 2015 * [#4606](https://github.com/Icinga/icinga2/issues/4606): Remove unused last\_in\_downtime field * [#4602](https://github.com/Icinga/icinga2/issues/4602) (CLI): Last option highlighted as the wrong one, even when it is not the culprit * [#4599](https://github.com/Icinga/icinga2/issues/4599): Unexpected state changes with max\_check\_attempts = 2 * [#4583](https://github.com/Icinga/icinga2/issues/4583) (Configuration): Debug hints for dictionary expressions are nested incorrectly * [#4574](https://github.com/Icinga/icinga2/issues/4574) (Notifications): Don't send Flapping\* notifications when downtime is active * [#4573](https://github.com/Icinga/icinga2/issues/4573) (DB IDO): Getting error during schema update * [#4572](https://github.com/Icinga/icinga2/issues/4572) (Configuration): Config validation shouldnt allow 'endpoints = \[ "" \]' * [#4566](https://github.com/Icinga/icinga2/issues/4566) (Notifications): Fixed downtimes scheduled for a future date trigger DOWNTIMESTART notifications * [#4564](https://github.com/Icinga/icinga2/issues/4564): Add missing initializer for WorkQueue::m\_NextTaskID * [#4555](https://github.com/Icinga/icinga2/issues/4555): Fix compiler warnings * [#4541](https://github.com/Icinga/icinga2/issues/4541) (DB IDO): Don't link against libmysqlclient\_r * [#4538](https://github.com/Icinga/icinga2/issues/4538): Don't update TimePeriod ranges for inactive objects * [#4423](https://github.com/Icinga/icinga2/issues/4423) (Performance Data): InfluxdbWriter does not write state other than 0 * [#4369](https://github.com/Icinga/icinga2/issues/4369) (Plugins): check\_network performance data in invalid format - ingraph * [#4169](https://github.com/Icinga/icinga2/issues/4169) (Cluster): Cluster resync problem with API created objects * [#4098](https://github.com/Icinga/icinga2/issues/4098) (API): Objects created in a global zone are not synced to child endpoints * [#4010](https://github.com/Icinga/icinga2/issues/4010) (API): API requests from execute-script action are too verbose * [#3802](https://github.com/Icinga/icinga2/issues/3802) (Compat): SCHEDULE\_AND\_PROPAGATE\_HOST\_DOWNTIME command missing * [#3801](https://github.com/Icinga/icinga2/issues/3801) (Compat): SCHEDULE\_AND\_PROPAGATE\_TRIGGERED\_HOST\_DOWNTIME command missing * [#3575](https://github.com/Icinga/icinga2/issues/3575) (DB IDO): MySQL 5.7.9, Incorrect datetime value Error * [#3565](https://github.com/Icinga/icinga2/issues/3565) (Plugins): Windows Agent: performance data of check\_perfmon * [#3564](https://github.com/Icinga/icinga2/issues/3564) (Plugins): Windows Agent: Performance data values for check\_perfmon.exe are invalid sometimes * [#3220](https://github.com/Icinga/icinga2/issues/3220) (Plugins): Implement support for resolving DNS hostnames in check\_ping.exe * [#2847](https://github.com/Icinga/icinga2/issues/2847): File descriptors are leaked to child processes which makes SELinux unhappy ### ITL * [#4842](https://github.com/Icinga/icinga2/issues/4842) (ITL): Add tempdir attribute to postgres CheckCommand * [#4837](https://github.com/Icinga/icinga2/issues/4837) (ITL): Add sudo option to mailq CheckCommand * [#4836](https://github.com/Icinga/icinga2/issues/4836) (ITL): Add verbose parameter to http CheckCommand * [#4835](https://github.com/Icinga/icinga2/issues/4835) (ITL): Add timeout option to mysql\_health CheckCommand * [#4714](https://github.com/Icinga/icinga2/issues/4714) (ITL): Default values for check\_swap are incorrect * [#4710](https://github.com/Icinga/icinga2/issues/4710) (ITL): snmp\_miblist variable to feed the -m option of check\_snmp is missing in the snmpv3 CheckCommand object * [#4684](https://github.com/Icinga/icinga2/issues/4684) (ITL): Add a radius CheckCommand for the radius check provide by nagios-plugins * [#4681](https://github.com/Icinga/icinga2/issues/4681) (ITL): Add CheckCommand definition for check\_logstash * [#4677](https://github.com/Icinga/icinga2/issues/4677) (ITL): Problem passing arguments to nscp-local CheckCommand objects * [#4672](https://github.com/Icinga/icinga2/issues/4672) (ITL): Add timeout option to oracle\_health CheckCommand * [#4618](https://github.com/Icinga/icinga2/issues/4618) (ITL): Hangman easter egg is broken * [#4608](https://github.com/Icinga/icinga2/issues/4608) (ITL): Add CheckCommand definition for check\_iostats * [#4597](https://github.com/Icinga/icinga2/issues/4597) (ITL): Default disk plugin check should not check inodes * [#4595](https://github.com/Icinga/icinga2/issues/4595) (ITL): Manubulon: Add missing procurve memory flag * [#4585](https://github.com/Icinga/icinga2/issues/4585) (ITL): Fix code style violations in the ITL * [#4582](https://github.com/Icinga/icinga2/issues/4582) (ITL): Incorrect help text for check\_swap * [#4543](https://github.com/Icinga/icinga2/issues/4543) (ITL): ITL - check\_vmware\_esx - specify a datacenter/vsphere server for esx/host checks * [#4324](https://github.com/Icinga/icinga2/issues/4324) (ITL): Add CheckCommand definition for check\_glusterfs ### Documentation * [#4862](https://github.com/Icinga/icinga2/issues/4862) (Documentation): "2.1.4. Installation Paths" should contain systemd paths * [#4861](https://github.com/Icinga/icinga2/issues/4861) (Documentation): Update "2.1.3. Enabled Features during Installation" - outdated "feature list" * [#4859](https://github.com/Icinga/icinga2/issues/4859) (Documentation): Update package instructions for Fedora * [#4851](https://github.com/Icinga/icinga2/issues/4851) (Documentation): Update README.md and correct project URLs * [#4846](https://github.com/Icinga/icinga2/issues/4846) (Documentation): Add a note for boolean values in the disk CheckCommand section * [#4845](https://github.com/Icinga/icinga2/issues/4845) (Documentation): Troubleshooting: Add examples for fetching the executed command line * [#4840](https://github.com/Icinga/icinga2/issues/4840) (Documentation): Update Windows screenshots in the client documentation * [#4838](https://github.com/Icinga/icinga2/issues/4838) (Documentation): Add example for concurrent\_checks in CheckerComponent object type * [#4829](https://github.com/Icinga/icinga2/issues/4829) (Documentation): Missing API headers for X-HTTP-Method-Override * [#4827](https://github.com/Icinga/icinga2/issues/4827) (Documentation): Fix example in PNP template docs * [#4821](https://github.com/Icinga/icinga2/issues/4821) (Documentation): Add a note about removing "conf.d" on the client for "top down command endpoint" setups * [#4809](https://github.com/Icinga/icinga2/issues/4809) (Documentation): Update API and Library Reference chapters * [#4804](https://github.com/Icinga/icinga2/issues/4804) (Documentation): Add a note about default template import to the CheckCommand object * [#4800](https://github.com/Icinga/icinga2/issues/4800) (Documentation): Docs: Typo in "CLI commands" chapter * [#4793](https://github.com/Icinga/icinga2/issues/4793) (Documentation): Docs: ITL plugins contrib order * [#4787](https://github.com/Icinga/icinga2/issues/4787) (Documentation): Doc: Swap packages.icinga.org w/ DebMon * [#4780](https://github.com/Icinga/icinga2/issues/4780) (Documentation): Add a note about pinning checks w/ command\_endpoint * [#4736](https://github.com/Icinga/icinga2/issues/4736) (Documentation): Docs: wrong heading level for commands.conf and groups.conf * [#4708](https://github.com/Icinga/icinga2/issues/4708) (Documentation): Add more Timeperiod examples in the documentation * [#4706](https://github.com/Icinga/icinga2/issues/4706) (Documentation): Add an example of multi-parents configuration for the Migration chapter * [#4705](https://github.com/Icinga/icinga2/issues/4705) (Documentation): Typo in the documentation * [#4699](https://github.com/Icinga/icinga2/issues/4699) (Documentation): Fix some spelling mistakes * [#4667](https://github.com/Icinga/icinga2/issues/4667) (Documentation): Add documentation for logrotation for the mainlog feature * [#4653](https://github.com/Icinga/icinga2/issues/4653) (Documentation): Corrections for distributed monitoring chapter * [#4641](https://github.com/Icinga/icinga2/issues/4641) (Documentation): Docs: Migrating Notification example tells about filters instead of types * [#4639](https://github.com/Icinga/icinga2/issues/4639) (Documentation): GDB example in the documentation isn't working * [#4636](https://github.com/Icinga/icinga2/issues/4636) (Documentation): Add development docs for writing a core dump file * [#4601](https://github.com/Icinga/icinga2/issues/4601) (Documentation): Typo in distributed monitoring docs * [#4596](https://github.com/Icinga/icinga2/issues/4596) (Documentation): Update service monitoring and distributed docs * [#4589](https://github.com/Icinga/icinga2/issues/4589) (Documentation): Fix help output for update-links.py * [#4584](https://github.com/Icinga/icinga2/issues/4584) (Documentation): Add missing reference to libmethods for the default ITL command templates * [#4492](https://github.com/Icinga/icinga2/issues/4492) (Documentation): Add information about function 'range' ### Support * [#4796](https://github.com/Icinga/icinga2/issues/4796) (Installation): Sort Changelog by category * [#4792](https://github.com/Icinga/icinga2/issues/4792) (Tests): Add unit test for notification state/type filter checks * [#4724](https://github.com/Icinga/icinga2/issues/4724) (Packages): Update .mailmap for icinga.com * [#4671](https://github.com/Icinga/icinga2/issues/4671) (Packages): Windows Installer should include NSClient++ 0.5.0 * [#4612](https://github.com/Icinga/icinga2/issues/4612) (Tests): Unit tests randomly crash after the tests have completed * [#4607](https://github.com/Icinga/icinga2/issues/4607) (Packages): Improve support for building the chocolatey package * [#4588](https://github.com/Icinga/icinga2/issues/4588) (Installation): Use raw string literals in mkembedconfig * [#4578](https://github.com/Icinga/icinga2/issues/4578) (Installation): Improve detection for the -flto compiler flag * [#4569](https://github.com/Icinga/icinga2/issues/4569) (Installation): Set versions for all internal libraries * [#4558](https://github.com/Icinga/icinga2/issues/4558) (Installation): Update cmake config to require a compiler that supports C++11 * [#4556](https://github.com/Icinga/icinga2/issues/4556) (Installation): logrotate file is not properly generated when the logrotate binary resides in /usr/bin * [#4551](https://github.com/Icinga/icinga2/issues/4551) (Tests): Implement unit tests for state changes * [#2943](https://github.com/Icinga/icinga2/issues/2943) (Installation): Make the user account configurable for the Windows service * [#2792](https://github.com/Icinga/icinga2/issues/2792) (Tests): Livestatus tests don't work on OS X ## 2.5.4 (2016-08-30) ### Notes * Bugfixes ### Bug * [#4277](https://github.com/Icinga/icinga2/issues/4277): many check commands executed at same time when master reload ## 2.5.3 (2016-08-25) ### Notes This release addresses an issue with PostgreSQL support for the IDO database module. ### Bug * [#4554](https://github.com/Icinga/icinga2/issues/4554) (DB IDO): ido pgsql migration from 2.4.0 to 2.5.0 : wrong size for config\_hash ## 2.5.2 (2016-08-24) ### Notes * Bugfixes ### Bug * [#4550](https://github.com/Icinga/icinga2/issues/4550): Icinga 2 sends SOFT recovery notifications * [#4549](https://github.com/Icinga/icinga2/issues/4549) (DB IDO): Newly added group member tables in the IDO database are not updated ### Documentation * [#4548](https://github.com/Icinga/icinga2/issues/4548) (Documentation): Wrong formatting in client docs ## 2.5.1 (2016-08-23) ### Notes * Bugfixes ### Bug * [#4544](https://github.com/Icinga/icinga2/issues/4544) (Notifications): Icinga 2 sends recovery notifications for SOFT NOT-OK states ## 2.5.0 (2016-08-23) ### Notes * InfluxdbWriter feature * API * New endpoints: /v1/variables and /v1/templates (GET requests), /v1/action/generate-ticket (POST request) * State/type filters for notifications/users are now string values (PUT, POST, GET requests) * Configuration * TimePeriod excludes/includes attributes * DateTime object for formatting time strings * New prototype methods: Array#filter, Array#unique, Array#map, Array#reduce * icinga2.conf now includes plugins-contrib, manubulon, windows-plugins, nscp by default (ITL CheckCommand definitions) * Performance improvements (config compiler and validation) * CLI * 'icinga2 object list' formats state/type filters as string values * Compiled config files are now visible with "notice" debug level (hidden by default) * CA serial file now uses a hash value (HA cluster w/ 2 CA directories) * Cluster * There is a known issue with >2 endpoints inside a zone. Icinga 2 will now log a warning. * Support for accepted ciphers and minimum TLS version * Connection and error logging has been improved. * DB IDO * Schema upgrade required (2.5.0.sql) * Incremental config dump (performance boost) * `categories` attribute is now an array. Previous method is deprecated and to be removed. * DbCatLog is not enabled by default anymore. * SSL support for MySQL * New packages * vim-icinga2 for syntax highlighting * libicinga2 (Debian), icinga2-libs (RPM) for Icinga Studio packages ### Enhancement * [#4516](https://github.com/Icinga/icinga2/issues/4516): Remove some unused \#includes * [#4498](https://github.com/Icinga/icinga2/issues/4498): Remove unnecessary Dictionary::Contains calls * [#4493](https://github.com/Icinga/icinga2/issues/4493) (Cluster): Improve performance for Endpoint config validation * [#4491](https://github.com/Icinga/icinga2/issues/4491): Improve performance for type lookups * [#4487](https://github.com/Icinga/icinga2/issues/4487) (DB IDO): Incremental updates for the IDO database * [#4486](https://github.com/Icinga/icinga2/issues/4486) (DB IDO): Remove unused code from the IDO classes * [#4485](https://github.com/Icinga/icinga2/issues/4485) (API): Add API action for generating a PKI ticket * [#4479](https://github.com/Icinga/icinga2/issues/4479) (Configuration): Implement comparison operators for the Array class * [#4467](https://github.com/Icinga/icinga2/issues/4467): Implement the System\#sleep function * [#4465](https://github.com/Icinga/icinga2/issues/4465) (Configuration): Implement support for namespaces * [#4464](https://github.com/Icinga/icinga2/issues/4464) (CLI): Implement support for inspecting variables with LLDB/GDB * [#4457](https://github.com/Icinga/icinga2/issues/4457): Implement support for marking functions as deprecated * [#4454](https://github.com/Icinga/icinga2/issues/4454): Include compiler name/version and build host name in --version * [#4451](https://github.com/Icinga/icinga2/issues/4451) (Configuration): Move internal script functions into the 'Internal' namespace * [#4449](https://github.com/Icinga/icinga2/issues/4449): Improve logging for the WorkQueue class * [#4445](https://github.com/Icinga/icinga2/issues/4445): Rename/Remove experimental script functions * [#4443](https://github.com/Icinga/icinga2/issues/4443): Implement process\_check\_result script method for the Checkable class * [#4442](https://github.com/Icinga/icinga2/issues/4442) (API): Support for determining the Icinga 2 version via the API * [#4431](https://github.com/Icinga/icinga2/issues/4431) (Notifications): Add the notification type into the log message * [#4424](https://github.com/Icinga/icinga2/issues/4424) (Cluster): Enhance TLS handshake error messages with connection information * [#4415](https://github.com/Icinga/icinga2/issues/4415) (API): Remove obsolete debug log message * [#4410](https://github.com/Icinga/icinga2/issues/4410) (Configuration): Add map/reduce and filter functionality for the Array class * [#4403](https://github.com/Icinga/icinga2/issues/4403) (CLI): Add history for icinga2 console * [#4398](https://github.com/Icinga/icinga2/issues/4398) (Cluster): Log a warning if there are more than 2 zone endpoint members * [#4393](https://github.com/Icinga/icinga2/issues/4393) (Cluster): Include IP address and port in the "New connection" log message * [#4388](https://github.com/Icinga/icinga2/issues/4388) (Configuration): Implement the \_\_ptr script function * [#4386](https://github.com/Icinga/icinga2/issues/4386) (Cluster): Improve error messages for failed certificate validation * [#4381](https://github.com/Icinga/icinga2/issues/4381) (Cluster): Improve log message for connecting nodes without configured Endpoint object * [#4352](https://github.com/Icinga/icinga2/issues/4352) (Cluster): Enhance client disconnect message for "No data received on new API connection." * [#4348](https://github.com/Icinga/icinga2/issues/4348) (DB IDO): Do not populate logentries table by default * [#4325](https://github.com/Icinga/icinga2/issues/4325) (API): API: Add missing downtime\_depth attribute * [#4314](https://github.com/Icinga/icinga2/issues/4314) (DB IDO): Change Ido\*Connection 'categories' attribute to an array * [#4295](https://github.com/Icinga/icinga2/issues/4295) (DB IDO): Enhance IDO check with schema version info * [#4294](https://github.com/Icinga/icinga2/issues/4294) (DB IDO): Update DB IDO schema version to 1.14.1 * [#4290](https://github.com/Icinga/icinga2/issues/4290) (API): Implement support for getting a list of global variables from the API * [#4281](https://github.com/Icinga/icinga2/issues/4281) (API): Support for enumerating available templates via the API * [#4268](https://github.com/Icinga/icinga2/issues/4268) (Performance Data): InfluxDB Metadata * [#4206](https://github.com/Icinga/icinga2/issues/4206) (Cluster): Add lag threshold for cluster-zone check * [#4178](https://github.com/Icinga/icinga2/issues/4178) (API): Improve logging for HTTP API requests * [#4154](https://github.com/Icinga/icinga2/issues/4154) (Configuration): Remove the \(unused\) 'inherits' keyword * [#4129](https://github.com/Icinga/icinga2/issues/4129) (Configuration): Improve performance for field accesses * [#4061](https://github.com/Icinga/icinga2/issues/4061) (Configuration): Allow strings in state/type filters * [#4048](https://github.com/Icinga/icinga2/issues/4048): Cleanup downtimes created by ScheduleDowntime * [#4046](https://github.com/Icinga/icinga2/issues/4046) (Configuration): Config parser should not log names of included files by default * [#3999](https://github.com/Icinga/icinga2/issues/3999) (API): ApiListener: Make minimum TLS version configurable * [#3997](https://github.com/Icinga/icinga2/issues/3997) (API): ApiListener: Force server's preferred cipher * [#3911](https://github.com/Icinga/icinga2/issues/3911) (Graphite): Add acknowledgement type to Graphite, InfluxDB, OpenTSDB metadata * [#3888](https://github.com/Icinga/icinga2/issues/3888) (API): Implement SSL cipher configuration support for the API feature * [#3763](https://github.com/Icinga/icinga2/issues/3763): Add name attribute for WorkQueue class * [#3562](https://github.com/Icinga/icinga2/issues/3562) (Performance Data): Add InfluxDbWriter feature * [#3400](https://github.com/Icinga/icinga2/issues/3400): Remove the deprecated IcingaStatusWriter feature * [#3237](https://github.com/Icinga/icinga2/issues/3237) (Performance Data): Gelf module: expose 'perfdata' fields for 'CHECK\_RESULT' events * [#3224](https://github.com/Icinga/icinga2/issues/3224) (Configuration): Implement support for formatting date/time * [#3178](https://github.com/Icinga/icinga2/issues/3178) (DB IDO): Add SSL support for the IdoMysqlConnection feature * [#2970](https://github.com/Icinga/icinga2/issues/2970) (Performance Data): Add timestamp support for GelfWriter * [#2040](https://github.com/Icinga/icinga2/issues/2040): Exclude option for TimePeriod definitions ### Bug * [#4534](https://github.com/Icinga/icinga2/issues/4534) (CLI): Icinga2 segault on startup * [#4524](https://github.com/Icinga/icinga2/issues/4524) (API): API Remote crash via Google Chrome * [#4520](https://github.com/Icinga/icinga2/issues/4520) (Configuration): Memory leak when using closures * [#4512](https://github.com/Icinga/icinga2/issues/4512) (Cluster): Incorrect certificate validation error message * [#4511](https://github.com/Icinga/icinga2/issues/4511): ClrCheck is null on \*nix * [#4505](https://github.com/Icinga/icinga2/issues/4505) (CLI): Cannot set ownership for user 'icinga' group 'icinga' on file '/var/lib/icinga2/ca/serial.txt'. * [#4504](https://github.com/Icinga/icinga2/issues/4504) (API): API: events for DowntimeTriggered does not provide needed information * [#4502](https://github.com/Icinga/icinga2/issues/4502) (DB IDO): IDO query fails due to key contraint violation for the icinga\_customvariablestatus table * [#4501](https://github.com/Icinga/icinga2/issues/4501) (Cluster): DB IDO started before daemonizing \(no systemd\) * [#4500](https://github.com/Icinga/icinga2/issues/4500) (DB IDO): Query for customvariablestatus incorrectly updates the host's/service's insert ID * [#4499](https://github.com/Icinga/icinga2/issues/4499) (DB IDO): Insert fails for the icinga\_scheduleddowntime table due to duplicate key * [#4497](https://github.com/Icinga/icinga2/issues/4497): Fix incorrect detection of the 'Concurrency' variable * [#4496](https://github.com/Icinga/icinga2/issues/4496) (API): API: action schedule-downtime requires a duration also when fixed is true * [#4495](https://github.com/Icinga/icinga2/issues/4495): Use hash-based serial numbers for new certificates * [#4490](https://github.com/Icinga/icinga2/issues/4490) (Cluster): ClusterEvents::NotificationSentAllUsersAPIHandler\(\) does not set notified\_users * [#4488](https://github.com/Icinga/icinga2/issues/4488): Replace GetType\(\)-\>GetName\(\) calls with GetReflectionType\(\)-\>GetName\(\) * [#4484](https://github.com/Icinga/icinga2/issues/4484) (Cluster): Only allow sending command\_endpoint checks to directly connected child zones * [#4483](https://github.com/Icinga/icinga2/issues/4483) (DB IDO): ido CheckCommand returns returns "Could not connect to database server" when HA enabled * [#4481](https://github.com/Icinga/icinga2/issues/4481) (DB IDO): Fix the "ido" check command for use with command\_endpoint * [#4478](https://github.com/Icinga/icinga2/issues/4478): CompatUtility::GetCheckableNotificationStateFilter is returning an incorrect value * [#4476](https://github.com/Icinga/icinga2/issues/4476) (DB IDO): Importing mysql schema fails * [#4475](https://github.com/Icinga/icinga2/issues/4475) (CLI): pki sign-csr does not log where it is writing the certificate file * [#4472](https://github.com/Icinga/icinga2/issues/4472) (DB IDO): IDO marks objects as inactive on shutdown * [#4471](https://github.com/Icinga/icinga2/issues/4471) (DB IDO): IDO does duplicate config updates * [#4466](https://github.com/Icinga/icinga2/issues/4466) (Configuration): 'use' keyword cannot be used with templates * [#4462](https://github.com/Icinga/icinga2/issues/4462) (Notifications): Add log message if notifications are forced \(i.e. filters are not checked\) * [#4461](https://github.com/Icinga/icinga2/issues/4461) (Notifications): Notification resent, even if interval = 0 * [#4460](https://github.com/Icinga/icinga2/issues/4460) (DB IDO): Fixed downtime start does not update actual\_start\_time * [#4458](https://github.com/Icinga/icinga2/issues/4458): Flexible downtimes should be removed after trigger\_time+duration * [#4455](https://github.com/Icinga/icinga2/issues/4455): Disallow casting "" to an Object * [#4447](https://github.com/Icinga/icinga2/issues/4447): Handle I/O errors while writing the Icinga state file more gracefully * [#4446](https://github.com/Icinga/icinga2/issues/4446) (Notifications): Incorrect downtime notification events * [#4444](https://github.com/Icinga/icinga2/issues/4444): Fix building Icinga with -fvisibility=hidden * [#4439](https://github.com/Icinga/icinga2/issues/4439) (Configuration): Icinga doesn't delete temporary icinga2.debug file when config validation fails * [#4434](https://github.com/Icinga/icinga2/issues/4434) (Notifications): Notification sent too fast when one master fails * [#4430](https://github.com/Icinga/icinga2/issues/4430) (Cluster): Remove obsolete README files in tools/syntax * [#4427](https://github.com/Icinga/icinga2/issues/4427) (Notifications): Missing notification for recovery during downtime * [#4425](https://github.com/Icinga/icinga2/issues/4425) (DB IDO): Change the way outdated comments/downtimes are deleted on restart * [#4420](https://github.com/Icinga/icinga2/issues/4420) (Notifications): Multiple notifications when master fails * [#4418](https://github.com/Icinga/icinga2/issues/4418) (DB IDO): icinga2 IDO reload performance significant slower with latest snapshot release * [#4417](https://github.com/Icinga/icinga2/issues/4417) (Notifications): Notification interval mistimed * [#4413](https://github.com/Icinga/icinga2/issues/4413) (DB IDO): icinga2 empties custom variables, host-, servcie- and contactgroup members at the end of IDO database reconnection * [#4412](https://github.com/Icinga/icinga2/issues/4412) (Notifications): Reminder notifications ignore HA mode * [#4405](https://github.com/Icinga/icinga2/issues/4405) (DB IDO): Deprecation warning should include object type and name * [#4401](https://github.com/Icinga/icinga2/issues/4401) (Performance Data): Incorrect escaping / formatting of perfdata to InfluxDB * [#4399](https://github.com/Icinga/icinga2/issues/4399): Icinga stats min\_execution\_time and max\_execution\_time are invalid * [#4394](https://github.com/Icinga/icinga2/issues/4394): icinga check reports "-1" for minimum latency and execution time and only uptime has a number but 0 * [#4391](https://github.com/Icinga/icinga2/issues/4391) (DB IDO): Do not clear {host,service,contact}group\_members tables on restart * [#4384](https://github.com/Icinga/icinga2/issues/4384) (API): Fix URL encoding for '&' * [#4380](https://github.com/Icinga/icinga2/issues/4380) (Cluster): Increase cluster reconnect interval * [#4378](https://github.com/Icinga/icinga2/issues/4378) (Notifications): Optimize two ObjectLocks into one in Notification::BeginExecuteNotification method * [#4376](https://github.com/Icinga/icinga2/issues/4376) (Cluster): CheckerComponent sometimes fails to schedule checks in time * [#4375](https://github.com/Icinga/icinga2/issues/4375) (Cluster): Duplicate messages for command\_endpoint w/ master and satellite * [#4372](https://github.com/Icinga/icinga2/issues/4372) (API): state\_filters\_real shouldn't be visible in the API * [#4371](https://github.com/Icinga/icinga2/issues/4371) (Notifications): notification.notification\_number runtime attribute returning 0 \(instead of 1\) in first notification e-mail * [#4370](https://github.com/Icinga/icinga2/issues/4370): Test the change with HARD OK transitions * [#4363](https://github.com/Icinga/icinga2/issues/4363) (DB IDO): IDO module starts threads before daemonize * [#4356](https://github.com/Icinga/icinga2/issues/4356) (DB IDO): DB IDO query queue does not clean up with v2.4.10-520-g124c80b * [#4349](https://github.com/Icinga/icinga2/issues/4349) (DB IDO): Add missing index on state history for DB IDO cleanup * [#4345](https://github.com/Icinga/icinga2/issues/4345): Ensure to clear the SSL error queue before calling SSL\_{read,write,do\_handshake} * [#4343](https://github.com/Icinga/icinga2/issues/4343) (Configuration): include\_recursive should gracefully handle inaccessible files * [#4341](https://github.com/Icinga/icinga2/issues/4341) (API): Icinga incorrectly disconnects all endpoints if one has a wrong certificate * [#4340](https://github.com/Icinga/icinga2/issues/4340) (DB IDO): deadlock in ido reconnect * [#4329](https://github.com/Icinga/icinga2/issues/4329) (Performance Data): Key Escapes in InfluxDB Writer Don't Work * [#4313](https://github.com/Icinga/icinga2/issues/4313) (Configuration): Icinga crashes when using include\_recursive in an object definition * [#4309](https://github.com/Icinga/icinga2/issues/4309) (Configuration): ConfigWriter::EmitScope incorrectly quotes dictionary keys * [#4300](https://github.com/Icinga/icinga2/issues/4300) (DB IDO): Comment/Downtime delete queries are slow * [#4293](https://github.com/Icinga/icinga2/issues/4293) (DB IDO): Overflow in current\_notification\_number column in DB IDO MySQL * [#4287](https://github.com/Icinga/icinga2/issues/4287) (DB IDO): Program status table is not updated in IDO after starting icinga * [#4283](https://github.com/Icinga/icinga2/issues/4283) (Cluster): Icinga 2 satellite crashes * [#4278](https://github.com/Icinga/icinga2/issues/4278) (DB IDO): SOFT state changes with the same state are not logged * [#4275](https://github.com/Icinga/icinga2/issues/4275) (API): Trying to delete an object protected by a permissions filter, ends up deleting all objects that match the filter instead * [#4274](https://github.com/Icinga/icinga2/issues/4274) (Notifications): Duplicate notifications * [#4264](https://github.com/Icinga/icinga2/issues/4264) (Performance Data): InfluxWriter doesnt sanitize the data before sending * [#4259](https://github.com/Icinga/icinga2/issues/4259): Flapping Notifications dependent on state change * [#4258](https://github.com/Icinga/icinga2/issues/4258): last SOFT state should be hard \(max\_check\_attempts\) * [#4257](https://github.com/Icinga/icinga2/issues/4257) (Configuration): Incorrect custom variable name in the hosts.conf example config * [#4255](https://github.com/Icinga/icinga2/issues/4255) (Configuration): Config validation should not delete comments/downtimes w/o reference * [#4244](https://github.com/Icinga/icinga2/issues/4244): SOFT OK-state after returning from a soft state * [#4239](https://github.com/Icinga/icinga2/issues/4239) (Notifications): Downtime notifications do not pass author and comment * [#4232](https://github.com/Icinga/icinga2/issues/4232): Problems with check scheduling for HARD state changes \(standalone/command\_endpoint\) * [#4231](https://github.com/Icinga/icinga2/issues/4231) (DB IDO): Volatile check results for OK-\>OK transitions are logged into DB IDO statehistory * [#4187](https://github.com/Icinga/icinga2/issues/4187): Icinga 2 client gets killed during network scans * [#4171](https://github.com/Icinga/icinga2/issues/4171) (DB IDO): Outdated downtime/comments not removed from IDO database \(restart\) * [#4134](https://github.com/Icinga/icinga2/issues/4134) (Configuration): Don't allow flow control keywords outside of other flow control constructs * [#4121](https://github.com/Icinga/icinga2/issues/4121) (Notifications): notification interval = 0 not honoured in HA clusters * [#4106](https://github.com/Icinga/icinga2/issues/4106) (Notifications): last\_problem\_notification should be synced in HA cluster * [#4077](https://github.com/Icinga/icinga2/issues/4077): Numbers are not properly formatted in runtime macro strings * [#4002](https://github.com/Icinga/icinga2/issues/4002): Don't violate POSIX by ensuring that the argument to usleep\(3\) is less than 1000000 * [#3954](https://github.com/Icinga/icinga2/issues/3954) (Cluster): High load when pinning command endpoint on HA cluster * [#3949](https://github.com/Icinga/icinga2/issues/3949) (DB IDO): IDO: entry\_time of all comments is set to the date and time when Icinga 2 was restarted * [#3902](https://github.com/Icinga/icinga2/issues/3902): Hang in TlsStream::Handshake * [#3820](https://github.com/Icinga/icinga2/issues/3820) (Configuration): High CPU usage with self-referenced parent zone config * [#3805](https://github.com/Icinga/icinga2/issues/3805) (Performance Data): GELF multi-line output * [#3627](https://github.com/Icinga/icinga2/issues/3627) (API): /v1 returns HTML even if JSON is requested * [#3486](https://github.com/Icinga/icinga2/issues/3486) (Notifications): Notification times w/ empty begin/end specifications prevent sending notifications * [#3370](https://github.com/Icinga/icinga2/issues/3370): Race condition in CreatePipeOverlapped * [#3365](https://github.com/Icinga/icinga2/issues/3365) (DB IDO): IDO: there is no usable object index on icinga\_{scheduleddowntime,comments} * [#3364](https://github.com/Icinga/icinga2/issues/3364) (DB IDO): IDO: check\_source should not be a TEXT field * [#3361](https://github.com/Icinga/icinga2/issues/3361) (DB IDO): Missing indexes for icinga\_endpoints\* and icinga\_zones\* tables in DB IDO schema * [#3355](https://github.com/Icinga/icinga2/issues/3355) (DB IDO): IDO: icinga\_host/service\_groups alias columns are TEXT columns * [#3229](https://github.com/Icinga/icinga2/issues/3229): Function::Invoke should optionally register ScriptFrame * [#2996](https://github.com/Icinga/icinga2/issues/2996) (Cluster): Custom notification external commands do not work in a master-master setup * [#2039](https://github.com/Icinga/icinga2/issues/2039): Disable immediate hard state after first checkresult ### ITL * [#4518](https://github.com/Icinga/icinga2/issues/4518) (ITL): ITL uses unsupported arguments for check\_swap on Debian wheezy/Ubuntu trusty * [#4506](https://github.com/Icinga/icinga2/issues/4506) (ITL): Add interfacetable CheckCommand options --trafficwithpkt and --snmp-maxmsgsize * [#4477](https://github.com/Icinga/icinga2/issues/4477) (ITL): Add perfsyntax parameter to nscp-local-counter CheckCommand * [#4456](https://github.com/Icinga/icinga2/issues/4456) (ITL): Add custom variables for all check\_swap arguments * [#4437](https://github.com/Icinga/icinga2/issues/4437) (ITL): Add command definition for check\_mysql\_query * [#4421](https://github.com/Icinga/icinga2/issues/4421) (ITL): -q option for check\_ntp\_time is wrong * [#4416](https://github.com/Icinga/icinga2/issues/4416) (ITL): Add check command definition for check\_graphite * [#4397](https://github.com/Icinga/icinga2/issues/4397) (ITL): A lot of missing parameters for \(latest\) mysql\_health * [#4379](https://github.com/Icinga/icinga2/issues/4379) (ITL): Add support for "-A" command line switch to CheckCommand "snmp-process" * [#4359](https://github.com/Icinga/icinga2/issues/4359) (ITL): ITL: check\_iftraffic64.pl default values, wrong postfix value in CheckCommand * [#4332](https://github.com/Icinga/icinga2/issues/4332) (ITL): Add check command definition for db2\_health * [#4305](https://github.com/Icinga/icinga2/issues/4305) (ITL): Add check command definitions for kdc and rbl * [#4297](https://github.com/Icinga/icinga2/issues/4297) (ITL): add check command for plugin check\_apache\_status * [#4276](https://github.com/Icinga/icinga2/issues/4276) (ITL): Adding option to access ifName for manubulon snmp-interface check command * [#4254](https://github.com/Icinga/icinga2/issues/4254) (ITL): Add "fuse.gvfsd-fuse" to the list of excluded file systems for check\_disk * [#4250](https://github.com/Icinga/icinga2/issues/4250) (ITL): Add CIM port parameter for esxi\_hardware CheckCommand * [#4023](https://github.com/Icinga/icinga2/issues/4023) (ITL): Add "retries" option to check\_snmp command * [#3711](https://github.com/Icinga/icinga2/issues/3711) (ITL): icinga2.conf: Include plugins-contrib, manubulon, windows-plugins, nscp by default * [#3683](https://github.com/Icinga/icinga2/issues/3683) (ITL): Add IPv4/IPv6 support to the rest of the monitoring-plugins * [#3012](https://github.com/Icinga/icinga2/issues/3012) (ITL): Extend CheckCommand definitions for nscp-local ### Documentation * [#4521](https://github.com/Icinga/icinga2/issues/4521) (Documentation): Typo in Notification object documentation * [#4517](https://github.com/Icinga/icinga2/issues/4517) (Documentation): Documentation is missing for the API permissions that are new in 2.5.0 * [#4513](https://github.com/Icinga/icinga2/issues/4513) (Documentation): Development docs: Add own section for gdb backtrace from a running process * [#4510](https://github.com/Icinga/icinga2/issues/4510) (Documentation): Docs: API example uses wrong attribute name * [#4489](https://github.com/Icinga/icinga2/issues/4489) (Documentation): Missing documentation for "legacy-timeperiod" template * [#4470](https://github.com/Icinga/icinga2/issues/4470) (Documentation): The description for the http\_certificate attribute doesn't have the right default value * [#4468](https://github.com/Icinga/icinga2/issues/4468) (Documentation): Add URL and short description for Monitoring Plugins inside the ITL documentation * [#4453](https://github.com/Icinga/icinga2/issues/4453) (Documentation): Rewrite Client and Cluster chapter and; add service monitoring chapter * [#4419](https://github.com/Icinga/icinga2/issues/4419) (Documentation): Incorrect API permission name for /v1/status in the documentation * [#4396](https://github.com/Icinga/icinga2/issues/4396) (Documentation): Missing explanation for three level clusters with CSR auto-signing * [#4395](https://github.com/Icinga/icinga2/issues/4395) (Documentation): Incorrect documentation about apply rules in zones.d directories * [#4387](https://github.com/Icinga/icinga2/issues/4387) (Documentation): Improve author information about check\_yum * [#4361](https://github.com/Icinga/icinga2/issues/4361) (Documentation): pkg-config is not listed as a build requirement in INSTALL.md * [#4337](https://github.com/Icinga/icinga2/issues/4337) (Documentation): Add a note to the docs that API POST updates to custom attributes/groups won't trigger re-evaluation * [#4333](https://github.com/Icinga/icinga2/issues/4333) (Documentation): Documentation: Setting up Plugins section is broken * [#4328](https://github.com/Icinga/icinga2/issues/4328) (Documentation): Typo in Manubulon CheckCommand documentation * [#4318](https://github.com/Icinga/icinga2/issues/4318) (Documentation): Migration docs still show unsupported CHANGE\_\*MODATTR external commands * [#4306](https://github.com/Icinga/icinga2/issues/4306) (Documentation): Add a note about creating Zone/Endpoint objects with the API * [#4299](https://github.com/Icinga/icinga2/issues/4299) (Documentation): Incorrect URL for API examples in the documentation * [#4265](https://github.com/Icinga/icinga2/issues/4265) (Documentation): Improve "Endpoint" documentation * [#4263](https://github.com/Icinga/icinga2/issues/4263) (Documentation): Fix systemd client command formatting * [#4238](https://github.com/Icinga/icinga2/issues/4238) (Documentation): Missing quotes for API action URL * [#4236](https://github.com/Icinga/icinga2/issues/4236) (Documentation): Use HTTPS for debmon.org links in the documentation * [#4217](https://github.com/Icinga/icinga2/issues/4217) (Documentation): node setup: Add a note for --endpoint syntax for client-master connection * [#4124](https://github.com/Icinga/icinga2/issues/4124) (Documentation): Documentation review * [#3612](https://github.com/Icinga/icinga2/issues/3612) (Documentation): Update SELinux documentation ### Support * [#4526](https://github.com/Icinga/icinga2/issues/4526) (Packages): Revert dependency on firewalld on RHEL * [#4494](https://github.com/Icinga/icinga2/issues/4494) (Installation): Remove unused functions from icinga-installer * [#4452](https://github.com/Icinga/icinga2/issues/4452) (Packages): Error compiling on windows due to changes in apilistener around minimum tls version * [#4432](https://github.com/Icinga/icinga2/issues/4432) (Packages): Windows build broken since ref 11292 * [#4404](https://github.com/Icinga/icinga2/issues/4404) (Installation): Increase default systemd timeout * [#4344](https://github.com/Icinga/icinga2/issues/4344) (Packages): Build fails with Visual Studio 2013 * [#4327](https://github.com/Icinga/icinga2/issues/4327) (Packages): Icinga fails to build with OpenSSL 1.1.0 * [#4251](https://github.com/Icinga/icinga2/issues/4251) (Tests): Add debugging mode for Utility::GetTime * [#4234](https://github.com/Icinga/icinga2/issues/4234) (Tests): Boost tests are missing a dependency on libmethods * [#4230](https://github.com/Icinga/icinga2/issues/4230) (Installation): Windows: Error with repository handler \(missing /var/lib/icinga2/api/repository path\) * [#4211](https://github.com/Icinga/icinga2/issues/4211) (Packages): Incorrect filter in pick.py * [#4190](https://github.com/Icinga/icinga2/issues/4190) (Packages): Windows Installer: Remove dependency on KB2999226 package * [#4148](https://github.com/Icinga/icinga2/issues/4148) (Packages): RPM update starts disabled icinga2 service * [#4147](https://github.com/Icinga/icinga2/issues/4147) (Packages): Reload permission error with SELinux * [#4135](https://github.com/Icinga/icinga2/issues/4135) (Installation): Add script for automatically cherry-picking commits for minor versions * [#3829](https://github.com/Icinga/icinga2/issues/3829) (Packages): Provide packages for icinga-studio on Fedora * [#3708](https://github.com/Icinga/icinga2/issues/3708) (Packages): Firewalld Service definition for Icinga * [#2606](https://github.com/Icinga/icinga2/issues/2606) (Packages): Package for syntax highlighting ## 2.4.9 (2016-05-19) ### Notes This release fixes a number of issues introduced in 2.4.8. ### Bug * [#4225](https://github.com/Icinga/icinga2/issues/4225) (Compat): Command Pipe thread 100% CPU Usage * [#4224](https://github.com/Icinga/icinga2/issues/4224): Checks are not executed anymore on command * [#4222](https://github.com/Icinga/icinga2/issues/4222) (Configuration): Segfault when trying to start 2.4.8 * [#4221](https://github.com/Icinga/icinga2/issues/4221) (Performance Data): Error: Function call 'rename' for file '/var/spool/icinga2/tmp/service-perfdata' failed with error code 2, 'No such file or directory' ## 2.4.10 (2016-05-19) ### Notes * Bugfixes ### Bug * [#4227](https://github.com/Icinga/icinga2/issues/4227): Checker component doesn't execute any checks for command\_endpoint ## 2.4.8 (2016-05-17) ### Notes * Bugfixes * Support for limiting the maximum number of concurrent checks (new configuration option) * HA-aware features now wait for connected cluster nodes in the same zone (e.g. DB IDO) * The 'icinga' check now alerts on failed reloads ### Enhancement * [#4203](https://github.com/Icinga/icinga2/issues/4203) (Cluster): Only activate HARunOnce objects once there's a cluster connection * [#4198](https://github.com/Icinga/icinga2/issues/4198): Move CalculateExecutionTime and CalculateLatency into the CheckResult class * [#4196](https://github.com/Icinga/icinga2/issues/4196) (Cluster): Remove unused cluster commands * [#4149](https://github.com/Icinga/icinga2/issues/4149) (CLI): Implement SNI support for the CLI commands * [#4103](https://github.com/Icinga/icinga2/issues/4103): Add support for subjectAltName in SSL certificates * [#3919](https://github.com/Icinga/icinga2/issues/3919) (Configuration): Internal check for config problems * [#3321](https://github.com/Icinga/icinga2/issues/3321): "icinga" check should have state WARNING when the last reload failed * [#2993](https://github.com/Icinga/icinga2/issues/2993) (Performance Data): PerfdataWriter: Better failure handling for file renames across file systems * [#2896](https://github.com/Icinga/icinga2/issues/2896) (Cluster): Alert config reload failures with the icinga check * [#2468](https://github.com/Icinga/icinga2/issues/2468): Maximum concurrent service checks ### Bug * [#4219](https://github.com/Icinga/icinga2/issues/4219) (DB IDO): Postgresql warnings on startup * [#4212](https://github.com/Icinga/icinga2/issues/4212): assertion failed: GetResumeCalled\(\) * [#4210](https://github.com/Icinga/icinga2/issues/4210) (API): Incorrect variable names for joined fields in filters * [#4204](https://github.com/Icinga/icinga2/issues/4204) (DB IDO): Ensure that program status updates are immediately updated in DB IDO * [#4202](https://github.com/Icinga/icinga2/issues/4202) (API): API: Missing error handling for invalid JSON request body * [#4182](https://github.com/Icinga/icinga2/issues/4182): Crash in UnameHelper * [#4180](https://github.com/Icinga/icinga2/issues/4180): Expired downtimes are not removed * [#4170](https://github.com/Icinga/icinga2/issues/4170) (API): Icinga Crash with the workflow Create\_Host-\> Downtime for the Host -\> Delete Downtime -\> Remove Host * [#4145](https://github.com/Icinga/icinga2/issues/4145) (Configuration): Wrong log severity causes segfault * [#4120](https://github.com/Icinga/icinga2/issues/4120): notification sent out during flexible downtime * [#4038](https://github.com/Icinga/icinga2/issues/4038) (API): inconsistent API /v1/objects/\* response for PUT requests * [#4037](https://github.com/Icinga/icinga2/issues/4037) (Compat): Command pipe overloaded: Can't send external Icinga command to the local command file * [#4029](https://github.com/Icinga/icinga2/issues/4029) (API): Icinga2 API: deleting service with cascade=1 does not delete dependant notification * [#3938](https://github.com/Icinga/icinga2/issues/3938): Crash with empty ScheduledDowntime 'ranges' attribute * [#3932](https://github.com/Icinga/icinga2/issues/3932): "day -X" time specifications are parsed incorrectly * [#3912](https://github.com/Icinga/icinga2/issues/3912) (Compat): Empty author/text attribute for comment/downtimes external commands causing crash * [#3881](https://github.com/Icinga/icinga2/issues/3881) (Cluster): Icinga2 agent gets stuck after disconnect and won't relay messages * [#3707](https://github.com/Icinga/icinga2/issues/3707) (Configuration): Comments and downtimes of deleted checkable objects are not deleted * [#3526](https://github.com/Icinga/icinga2/issues/3526): Icinga crashes with a segfault on receiving a lot of check results for nonexisting hosts/services * [#3316](https://github.com/Icinga/icinga2/issues/3316) (Configuration): Service apply without name possible ### ITL * [#4184](https://github.com/Icinga/icinga2/issues/4184) (ITL): 'disk' CheckCommand: Exclude 'cgroup' and 'tracefs' by default * [#3634](https://github.com/Icinga/icinga2/issues/3634) (ITL): Provide icingacli in the ITL ### Documentation * [#4205](https://github.com/Icinga/icinga2/issues/4205) (Documentation): Add the category to the generated changelog * [#4193](https://github.com/Icinga/icinga2/issues/4193) (Documentation): Missing documentation for event commands w/ execution bridge * [#4144](https://github.com/Icinga/icinga2/issues/4144) (Documentation): Incorrect chapter headings for Object\#to\_string and Object\#type ### Support * [#4146](https://github.com/Icinga/icinga2/issues/4146) (Packages): Update chocolatey packages and RELEASE.md ## 2.4.7 (2016-04-21) ### Notes * Bugfixes ### Bug * [#4142](https://github.com/Icinga/icinga2/issues/4142) (DB IDO): Crash in IdoMysqlConnection::ExecuteMultipleQueries ## 2.4.6 (2016-04-20) ### Notes * Bugfixes ### Bug * [#4140](https://github.com/Icinga/icinga2/issues/4140) (DB IDO): Failed assertion in IdoPgsqlConnection::FieldToEscapedString ### Documentation * [#4141](https://github.com/Icinga/icinga2/issues/4141) (Documentation): Update RELEASE.md * [#4136](https://github.com/Icinga/icinga2/issues/4136) (Documentation): Docs: Zone attribute 'endpoints' is an array ### Support * [#4139](https://github.com/Icinga/icinga2/issues/4139) (Packages): Icinga 2 fails to build on Ubuntu Xenial ## 2.4.5 (2016-04-20) ### Notes * Windows Installer changed from NSIS to MSI * New configuration attribute for hosts and services: check_timeout (overrides the CheckCommand's timeout when set) * ITL updates * Lots of bugfixes ### Enhancement * [#3023](https://github.com/Icinga/icinga2/issues/3023) (Configuration): Implement support for overriding check command timeout ### Bug * [#4131](https://github.com/Icinga/icinga2/issues/4131) (Configuration): Vim Syntax Highlighting does not work with assign where * [#4116](https://github.com/Icinga/icinga2/issues/4116) (API): icinga2 crashes when a command\_endpoint is set, but the api feature is not active * [#4114](https://github.com/Icinga/icinga2/issues/4114): Compiler warning in NotifyActive * [#4109](https://github.com/Icinga/icinga2/issues/4109) (API): Navigation attributes are missing in /v1/objects/\ * [#4104](https://github.com/Icinga/icinga2/issues/4104) (Configuration): Segfault during config validation if host exists, service does not exist any longer and downtime expires * [#4095](https://github.com/Icinga/icinga2/issues/4095): DowntimesExpireTimerHandler crashes Icinga2 with \ * [#4089](https://github.com/Icinga/icinga2/issues/4089): Make the socket event engine configurable * [#4078](https://github.com/Icinga/icinga2/issues/4078) (Configuration): Overwriting global type variables causes crash in ConfigItem::Commit\(\) * [#4076](https://github.com/Icinga/icinga2/issues/4076) (API): API User gets wrongly authenticated \(client\_cn and no password\) * [#4066](https://github.com/Icinga/icinga2/issues/4066): ConfigSync broken from 2.4.3. to 2.4.4 under Windows * [#4056](https://github.com/Icinga/icinga2/issues/4056) (CLI): Remove semi-colons in the auto-generated configs * [#4052](https://github.com/Icinga/icinga2/issues/4052) (API): Config validation for Notification objects should check whether the state filters are valid * [#4035](https://github.com/Icinga/icinga2/issues/4035) (DB IDO): IDO: historical contact notifications table column notification\_id is off-by-one * [#4031](https://github.com/Icinga/icinga2/issues/4031): Downtimes are not always activated/expired on restart * [#4016](https://github.com/Icinga/icinga2/issues/4016): Symlink subfolders not followed/considered for config files * [#4014](https://github.com/Icinga/icinga2/issues/4014): Use retry\_interval instead of check\_interval for first OK -\> NOT-OK state change * [#3973](https://github.com/Icinga/icinga2/issues/3973) (Cluster): Downtimes and Comments are not synced to child zones * [#3970](https://github.com/Icinga/icinga2/issues/3970) (API): Socket Exceptions \(Operation not permitted\) while reading from API * [#3907](https://github.com/Icinga/icinga2/issues/3907) (Configuration): Too many assign where filters cause stack overflow * [#3780](https://github.com/Icinga/icinga2/issues/3780) (DB IDO): DB IDO: downtime is not in effect after restart ### ITL * [#3953](https://github.com/Icinga/icinga2/issues/3953) (ITL): Add --units, --rate and --rate-multiplier support for the snmpv3 check command * [#3903](https://github.com/Icinga/icinga2/issues/3903) (ITL): Add --method parameter for check\_{oracle,mysql,mssql}\_health CheckCommands ### Documentation * [#4122](https://github.com/Icinga/icinga2/issues/4122) (Documentation): Remove instance\_name from Ido\*Connection example * [#4108](https://github.com/Icinga/icinga2/issues/4108) (Documentation): Incorrect link in the documentation * [#4080](https://github.com/Icinga/icinga2/issues/4080) (Documentation): Update documentation URL for Icinga Web 2 * [#4058](https://github.com/Icinga/icinga2/issues/4058) (Documentation): Docs: Cluster manual SSL generation formatting is broken * [#4057](https://github.com/Icinga/icinga2/issues/4057) (Documentation): Update the CentOS installation documentation * [#4055](https://github.com/Icinga/icinga2/issues/4055) (Documentation): Add silent install / reference to NSClient++ to documentation * [#4043](https://github.com/Icinga/icinga2/issues/4043) (Documentation): Docs: Remove the migration script chapter * [#4041](https://github.com/Icinga/icinga2/issues/4041) (Documentation): Explain how to use functions for wildcard matches for arrays and/or dictionaries in assign where expressions * [#4039](https://github.com/Icinga/icinga2/issues/4039) (Documentation): Update .mailmap for Markus Frosch * [#3145](https://github.com/Icinga/icinga2/issues/3145) (Documentation): Add Windows setup wizard screenshots ### Support * [#4127](https://github.com/Icinga/icinga2/issues/4127) (Installation): Windows installer does not copy "features-enabled" on upgrade * [#4119](https://github.com/Icinga/icinga2/issues/4119) (Installation): Update chocolatey uninstall script for the MSI package * [#4118](https://github.com/Icinga/icinga2/issues/4118) (Installation): icinga2-installer.exe doesn't wait until NSIS uninstall.exe exits * [#4117](https://github.com/Icinga/icinga2/issues/4117) (Installation): Make sure to update the agent wizard banner * [#4113](https://github.com/Icinga/icinga2/issues/4113) (Installation): Package fails to build on \*NIX * [#4099](https://github.com/Icinga/icinga2/issues/4099) (Installation): make install overwrites configuration files * [#4074](https://github.com/Icinga/icinga2/issues/4074) (Installation): FatalError\(\) returns when called before Application.Run * [#4073](https://github.com/Icinga/icinga2/issues/4073) (Installation): Install 64-bit version of NSClient++ on 64-bit versions of Windows * [#4072](https://github.com/Icinga/icinga2/issues/4072) (Installation): Update NSClient++ to version 0.4.4.19 * [#4069](https://github.com/Icinga/icinga2/issues/4069) (Installation): Error compiling icinga2 targeted for x64 on Windows * [#4064](https://github.com/Icinga/icinga2/issues/4064) (Packages): Build 64-bit packages for Windows * [#4053](https://github.com/Icinga/icinga2/issues/4053) (Installation): Icinga 2 Windows Agent does not honor install path during upgrade * [#4032](https://github.com/Icinga/icinga2/issues/4032) (Packages): Remove dependency for .NET 3.5 from the chocolatey package * [#3988](https://github.com/Icinga/icinga2/issues/3988) (Packages): Incorrect base URL in the icinga-rpm-release packages for Fedora * [#3658](https://github.com/Icinga/icinga2/issues/3658) (Packages): Add application manifest for the Windows agent wizard * [#2998](https://github.com/Icinga/icinga2/issues/2998) (Installation): logrotate fails since the "su" directive was removed ## 2.4.4 (2016-03-16) ### Notes * Bugfixes ### Bug * [#4036](https://github.com/Icinga/icinga2/issues/4036) (CLI): Add the executed cli command to the Windows wizard error messages * [#4019](https://github.com/Icinga/icinga2/issues/4019) (Configuration): Segmentation fault during 'icinga2 daemon -C' * [#4017](https://github.com/Icinga/icinga2/issues/4017) (CLI): 'icinga2 feature list' fails when all features are disabled * [#4008](https://github.com/Icinga/icinga2/issues/4008) (Configuration): Windows wizard error "too many arguments" * [#4006](https://github.com/Icinga/icinga2/issues/4006): Volatile transitions from HARD NOT-OK-\>NOT-OK do not trigger notifications * [#3996](https://github.com/Icinga/icinga2/issues/3996): epoll\_ctl might cause oops on Ubuntu trusty * [#3990](https://github.com/Icinga/icinga2/issues/3990): Services status updated multiple times within check\_interval even though no retry was triggered * [#3987](https://github.com/Icinga/icinga2/issues/3987): Incorrect check interval when passive check results are used * [#3985](https://github.com/Icinga/icinga2/issues/3985): Active checks are executed even though passive results are submitted * [#3981](https://github.com/Icinga/icinga2/issues/3981): DEL\_DOWNTIME\_BY\_HOST\_NAME does not accept optional arguments * [#3961](https://github.com/Icinga/icinga2/issues/3961) (CLI): Wrong log message for trusted cert in node setup command * [#3939](https://github.com/Icinga/icinga2/issues/3939) (CLI): Common name in node wizard isn't case sensitive * [#3745](https://github.com/Icinga/icinga2/issues/3745) (API): Status code 200 even if an object could not be deleted. * [#3742](https://github.com/Icinga/icinga2/issues/3742) (DB IDO): DB IDO: User notification type filters are incorrect * [#3442](https://github.com/Icinga/icinga2/issues/3442) (API): MkDirP not working on Windows * [#3439](https://github.com/Icinga/icinga2/issues/3439) (Notifications): Host notification type is PROBLEM but should be RECOVERY * [#3303](https://github.com/Icinga/icinga2/issues/3303) (Notifications): Problem notifications while Flapping is active * [#3153](https://github.com/Icinga/icinga2/issues/3153) (Notifications): Flapping notifications are sent for hosts/services which are in a downtime ### ITL * [#3958](https://github.com/Icinga/icinga2/issues/3958) (ITL): Add "query" option to check\_postgres command. * [#3908](https://github.com/Icinga/icinga2/issues/3908) (ITL): ITL: Missing documentation for nwc\_health "mode" parameter * [#3484](https://github.com/Icinga/icinga2/issues/3484) (ITL): ITL: Allow to enforce specific SSL versions using the http check command ### Documentation * [#4033](https://github.com/Icinga/icinga2/issues/4033) (Documentation): Update development docs to use 'thread apply all bt full' * [#4018](https://github.com/Icinga/icinga2/issues/4018) (Documentation): Docs: Add API examples for creating services and check commands * [#4009](https://github.com/Icinga/icinga2/issues/4009) (Documentation): Typo in API docs * [#3845](https://github.com/Icinga/icinga2/issues/3845) (Documentation): Explain how to join hosts/services for /v1/objects/comments * [#3755](https://github.com/Icinga/icinga2/issues/3755) (Documentation): http check's URI is really just Path ### Support * [#4027](https://github.com/Icinga/icinga2/issues/4027) (Packages): Chocolatey package is missing uninstall function * [#4011](https://github.com/Icinga/icinga2/issues/4011) (Packages): Update build requirements for SLES 11 SP4 * [#3960](https://github.com/Icinga/icinga2/issues/3960) (Installation): CMake does not find MySQL libraries on Windows ## 2.4.3 (2016-02-24) ### Notes * Bugfixes ### Bug * [#3963](https://github.com/Icinga/icinga2/issues/3963): Wrong permissions for files in /var/cache/icinga2/\* * [#3962](https://github.com/Icinga/icinga2/issues/3962) (Configuration): Permission problem after running icinga2 node wizard ## 2.4.2 (2016-02-23) ### Notes * ITL Additional arguments for check_disk Fix incorrect path for the check_hpasm plugin New command: check_iostat Fix incorrect variable names for the check_impi plugin * Cluster Improve cluster performance Fix connection handling problems (multiple connections for the same endpoint) * Performance improvements for the DB IDO modules * Lots and lots of various other bugfixes * Documentation updates ### Enhancement * [#3878](https://github.com/Icinga/icinga2/issues/3878) (Configuration): Add String\#trim * [#3857](https://github.com/Icinga/icinga2/issues/3857) (Cluster): Support TLSv1.1 and TLSv1.2 for the cluster transport encryption * [#3810](https://github.com/Icinga/icinga2/issues/3810) (Plugins): Add Timeout parameter to snmpv3 check * [#3785](https://github.com/Icinga/icinga2/issues/3785) (DB IDO): Log DB IDO query queue stats * [#3784](https://github.com/Icinga/icinga2/issues/3784) (DB IDO): DB IDO: Add a log message when the connection handling is completed * [#3760](https://github.com/Icinga/icinga2/issues/3760) (Configuration): Raise a config error for "Checkable" objects in global zones * [#3754](https://github.com/Icinga/icinga2/issues/3754) (Plugins): Add "-x" parameter in command definition for disk-windows CheckCommand ### Bug * [#3957](https://github.com/Icinga/icinga2/issues/3957) (CLI): "node setup" tries to chown\(\) files before they're created * [#3947](https://github.com/Icinga/icinga2/issues/3947): CentOS 5 doesn't support epoll\_create1 * [#3922](https://github.com/Icinga/icinga2/issues/3922) (Configuration): YYYY-MM-DD time specs are parsed incorrectly * [#3915](https://github.com/Icinga/icinga2/issues/3915) (API): Connections are not cleaned up properly * [#3913](https://github.com/Icinga/icinga2/issues/3913) (Cluster): Cluster WQ thread dies after fork\(\) * [#3910](https://github.com/Icinga/icinga2/issues/3910): Clean up unused variables a bit * [#3905](https://github.com/Icinga/icinga2/issues/3905) (DB IDO): Problem with hostgroup\_members table cleanup * [#3898](https://github.com/Icinga/icinga2/issues/3898) (API): API queries on non-existant objects cause exception * [#3897](https://github.com/Icinga/icinga2/issues/3897) (Configuration): Crash in ConfigItem::RunWithActivationContext * [#3896](https://github.com/Icinga/icinga2/issues/3896) (Cluster): Ensure that config sync updates are always sent on reconnect * [#3889](https://github.com/Icinga/icinga2/issues/3889) (DB IDO): Deleting an object via API does not disable it in DB IDO * [#3871](https://github.com/Icinga/icinga2/issues/3871) (Cluster): Master reloads with agents generate false alarms * [#3870](https://github.com/Icinga/icinga2/issues/3870) (DB IDO): next\_check noise in the IDO * [#3866](https://github.com/Icinga/icinga2/issues/3866) (Cluster): Check event duplication with parallel connections involved * [#3863](https://github.com/Icinga/icinga2/issues/3863) (Cluster): Segfault in ApiListener::ConfigUpdateObjectAPIHandler * [#3859](https://github.com/Icinga/icinga2/issues/3859): Stream buffer size is 512 bytes, could be raised * [#3858](https://github.com/Icinga/icinga2/issues/3858) (CLI): Escaped sequences not properly generated with 'node update-config' * [#3848](https://github.com/Icinga/icinga2/issues/3848) (Configuration): Mistake in mongodb command definition \(mongodb\_replicaset\) * [#3843](https://github.com/Icinga/icinga2/issues/3843): Modified attributes do not work for the IcingaApplication object w/ external commands * [#3835](https://github.com/Icinga/icinga2/issues/3835) (Cluster): high load and memory consumption on icinga2 agent v2.4.1 * [#3827](https://github.com/Icinga/icinga2/issues/3827) (Configuration): Icinga state file corruption with temporary file creation * [#3817](https://github.com/Icinga/icinga2/issues/3817) (Cluster): Cluster config sync: Ensure that /var/lib/icinga2/api/zones/\* exists * [#3816](https://github.com/Icinga/icinga2/issues/3816) (Cluster): Exception stack trace on icinga2 client when the master reloads the configuration * [#3812](https://github.com/Icinga/icinga2/issues/3812) (API): API actions: Decide whether fixed: false is the right default * [#3798](https://github.com/Icinga/icinga2/issues/3798) (DB IDO): is\_active in IDO is only re-enabled on "every second" restart * [#3797](https://github.com/Icinga/icinga2/issues/3797): Remove superfluous \#ifdef * [#3794](https://github.com/Icinga/icinga2/issues/3794) (DB IDO): Icinga2 crashes in IDO when removing a comment * [#3787](https://github.com/Icinga/icinga2/issues/3787) (CLI): "repository add" cli command writes invalid "type" attribute * [#3786](https://github.com/Icinga/icinga2/issues/3786) (DB IDO): Evaluate if CanExecuteQuery/FieldToEscapedString lead to exceptions on !m\_Connected * [#3783](https://github.com/Icinga/icinga2/issues/3783) (DB IDO): Implement support for re-ordering groups of IDO queries * [#3775](https://github.com/Icinga/icinga2/issues/3775) (Configuration): Config validation doesn't fail when templates are used as object names * [#3774](https://github.com/Icinga/icinga2/issues/3774) (DB IDO): IDO breaks when writing to icinga\_programstatus with latest snapshots * [#3773](https://github.com/Icinga/icinga2/issues/3773) (Configuration): Relative path in include\_zones does not work * [#3766](https://github.com/Icinga/icinga2/issues/3766) (API): Cluster config sync ignores zones.d from API packages * [#3765](https://github.com/Icinga/icinga2/issues/3765): Use NodeName in null and random checks * [#3764](https://github.com/Icinga/icinga2/issues/3764) (DB IDO): Failed IDO query for icinga\_downtimehistory * [#3752](https://github.com/Icinga/icinga2/issues/3752): Incorrect information in --version on Linux * [#3741](https://github.com/Icinga/icinga2/issues/3741) (DB IDO): Avoid duplicate config and status updates on startup * [#3735](https://github.com/Icinga/icinga2/issues/3735) (Configuration): Disallow lambda expressions where side-effect-free expressions are not allowed * [#3730](https://github.com/Icinga/icinga2/issues/3730): Missing path in mkdir\(\) exceptions * [#3728](https://github.com/Icinga/icinga2/issues/3728) (DB IDO): build of icinga2 with gcc 4.4.7 segfaulting with ido * [#3722](https://github.com/Icinga/icinga2/issues/3722) (API): Missing num\_hosts\_pending in /v1/status/CIB * [#3715](https://github.com/Icinga/icinga2/issues/3715) (CLI): node wizard does not remember user defined port * [#3712](https://github.com/Icinga/icinga2/issues/3712) (CLI): Remove the local zone name question in node wizard * [#3705](https://github.com/Icinga/icinga2/issues/3705) (API): API is not working on wheezy * [#3704](https://github.com/Icinga/icinga2/issues/3704) (Cluster): ApiListener::ReplayLog can block with a lot of clients * [#3702](https://github.com/Icinga/icinga2/issues/3702) (Cluster): Zone::CanAccessObject is very expensive * [#3697](https://github.com/Icinga/icinga2/issues/3697) (Compat): Crash in ExternalCommandListener * [#3677](https://github.com/Icinga/icinga2/issues/3677) (API): API queries cause memory leaks * [#3613](https://github.com/Icinga/icinga2/issues/3613) (DB IDO): Non-UTF8 characters from plugins causes IDO to fail * [#3606](https://github.com/Icinga/icinga2/issues/3606) (Plugins): check\_network performance data in invalid format * [#3571](https://github.com/Icinga/icinga2/issues/3571) (Plugins): check\_memory and check\_swap plugins do unit conversion and rounding before percentage calculations resulting in imprecise percentages * [#3540](https://github.com/Icinga/icinga2/issues/3540) (Livestatus): Livestatus log query - filter "class" yields empty results * [#3440](https://github.com/Icinga/icinga2/issues/3440): Icinga2 reload timeout results in killing old and new process because of systemd * [#2866](https://github.com/Icinga/icinga2/issues/2866) (DB IDO): DB IDO: notification\_id for contact notifications is out of range * [#2746](https://github.com/Icinga/icinga2/issues/2746) (DB IDO): Add priority queue for disconnect/programstatus update events * [#2009](https://github.com/Icinga/icinga2/issues/2009): Re-checks scheduling w/ retry\_interval ### ITL * [#3927](https://github.com/Icinga/icinga2/issues/3927) (ITL): Checkcommand Disk : Option Freespace-ignore-reserved * [#3749](https://github.com/Icinga/icinga2/issues/3749) (ITL): The hpasm check command is using the PluginDir constant * [#3747](https://github.com/Icinga/icinga2/issues/3747) (ITL): Add check\_iostat to ITL * [#3729](https://github.com/Icinga/icinga2/issues/3729) (ITL): ITL check command possibly mistyped variable names ### Documentation * [#3946](https://github.com/Icinga/icinga2/issues/3946) (Documentation): Documentation: Unescaped pipe character in tables * [#3893](https://github.com/Icinga/icinga2/issues/3893) (Documentation): Outdated link to icingaweb2-module-nagvis * [#3892](https://github.com/Icinga/icinga2/issues/3892) (Documentation): Partially missing escaping in doc/7-icinga-template-library.md * [#3861](https://github.com/Icinga/icinga2/issues/3861) (Documentation): Incorrect IdoPgSqlConnection Example in Documentation * [#3850](https://github.com/Icinga/icinga2/issues/3850) (Documentation): Incorrect name in AUTHORS * [#3836](https://github.com/Icinga/icinga2/issues/3836) (Documentation): Troubleshooting: Explain how to fetch the executed command * [#3833](https://github.com/Icinga/icinga2/issues/3833) (Documentation): Better explaination for array values in "disk" CheckCommand docs * [#3826](https://github.com/Icinga/icinga2/issues/3826) (Documentation): Add example how to use custom functions in attributes * [#3808](https://github.com/Icinga/icinga2/issues/3808) (Documentation): Typos in the "troubleshooting" section of the documentation * [#3793](https://github.com/Icinga/icinga2/issues/3793) (Documentation): "setting up check plugins" section should be enhanced with package manager examples * [#3781](https://github.com/Icinga/icinga2/issues/3781) (Documentation): Formatting problem in "Advanced Filter" chapter * [#3770](https://github.com/Icinga/icinga2/issues/3770) (Documentation): Missing documentation for API packages zones.d config sync * [#3759](https://github.com/Icinga/icinga2/issues/3759) (Documentation): Missing SUSE repository for monitoring plugins documentation * [#3748](https://github.com/Icinga/icinga2/issues/3748) (Documentation): Wrong postgresql-setup initdb command for RHEL7 * [#3550](https://github.com/Icinga/icinga2/issues/3550) (Documentation): A PgSQL DB for the IDO can't be created w/ UTF8 * [#3549](https://github.com/Icinga/icinga2/issues/3549) (Documentation): Incorrect SQL command for creating the user of the PostgreSQL DB for the IDO ### Support * [#3900](https://github.com/Icinga/icinga2/issues/3900) (Packages): Windows build fails on InterlockedIncrement type * [#3838](https://github.com/Icinga/icinga2/issues/3838) (Installation): Race condition when using systemd unit file * [#3832](https://github.com/Icinga/icinga2/issues/3832) (Installation): Compiler warnings in lib/remote/base64.cpp * [#3818](https://github.com/Icinga/icinga2/issues/3818) (Installation): Logrotate on systemd distros should use systemctl not service * [#3771](https://github.com/Icinga/icinga2/issues/3771) (Installation): Build error with older CMake versions on VERSION\_LESS compare * [#3769](https://github.com/Icinga/icinga2/issues/3769) (Packages): Windows build fails with latest git master * [#3746](https://github.com/Icinga/icinga2/issues/3746) (Packages): chcon partial context error in safe-reload prevents reload * [#3723](https://github.com/Icinga/icinga2/issues/3723) (Installation): Crash on startup with incorrect directory permissions * [#3679](https://github.com/Icinga/icinga2/issues/3679) (Installation): Add CMake flag for disabling the unit tests ## 2.4.1 (2015-11-26) ### Notes * ITL * Add running_kernel_use_sudo option for the running_kernel check * Configuration * Add global constants: `PlatformName`. `PlatformVersion`, `PlatformKernel` and `PlatformKernelVersion` * CLI * Use NodeName and ZoneName constants for 'node setup' and 'node wizard' ### Enhancement * [#3706](https://github.com/Icinga/icinga2/issues/3706) (CLI): Use NodeName and ZoneName constants for 'node setup' and 'node wizard' ### Bug * [#3710](https://github.com/Icinga/icinga2/issues/3710) (CLI): Remove --master\_zone from --help because it is currently not implemented * [#3689](https://github.com/Icinga/icinga2/issues/3689) (CLI): CLI command 'repository add' doesn't work * [#3685](https://github.com/Icinga/icinga2/issues/3685) (CLI): node wizard checks for /var/lib/icinga2/ca directory but not the files * [#3674](https://github.com/Icinga/icinga2/issues/3674): lib/base/process.cpp SIGSEGV on Debian squeeze / RHEL 6 * [#3671](https://github.com/Icinga/icinga2/issues/3671) (API): Icinga 2 crashes when ScheduledDowntime objects are used * [#3670](https://github.com/Icinga/icinga2/issues/3670) (CLI): API setup command incorrectly overwrites existing certificates * [#3665](https://github.com/Icinga/icinga2/issues/3665) (CLI): "node wizard" does not ask user to verify SSL certificate ### ITL * [#3691](https://github.com/Icinga/icinga2/issues/3691) (ITL): Add running\_kernel\_use\_sudo option for the running\_kernel check * [#3682](https://github.com/Icinga/icinga2/issues/3682) (ITL): Indentation in command-plugins.conf * [#3657](https://github.com/Icinga/icinga2/issues/3657) (ITL): Add by\_ssh\_options argument for the check\_by\_ssh plugin ### Documentation * [#3701](https://github.com/Icinga/icinga2/issues/3701) (Documentation): Incorrect path for icinga2 binary in development documentation * [#3690](https://github.com/Icinga/icinga2/issues/3690) (Documentation): Fix typos in the documentation * [#3673](https://github.com/Icinga/icinga2/issues/3673) (Documentation): Documentation for schedule-downtime is missing required paremeters * [#3594](https://github.com/Icinga/icinga2/issues/3594) (Documentation): Documentation example in "Access Object Attributes at Runtime" doesn't work correctly * [#3391](https://github.com/Icinga/icinga2/issues/3391) (Documentation): Incorrect web inject URL in documentation ### Support * [#3699](https://github.com/Icinga/icinga2/issues/3699) (Installation): Windows setup wizard crashes when InstallDir registry key is not set * [#3680](https://github.com/Icinga/icinga2/issues/3680) (Installation): Incorrect redirect for stderr in /usr/lib/icinga2/prepare-dirs * [#3656](https://github.com/Icinga/icinga2/issues/3656) (Packages): Build fails on SLES 11 SP3 with GCC 4.8 ## 2.4.0 (2015-11-16) ### Notes * API * RESTful API with basic auth or client certificates * Filters, types, permissions * configuration package management * query/create/modify/delete config objects at runtime * status queries for global stats * actions (e.g. acknowledge all service problems) * event streams * ITL and Plugin Check Command definitions * The 'running_kernel' check command was moved to the plugins-contrib section. You have to update your config to include 'plugins-contrib' * Configuration * The global constants Enable* and Vars have been removed. Use the IcingaApplication object attributes instead. * Features * New Graphite tree. Please check the documentation how enable the legacy schema. * IcingaStatusWriter feature has been deprecated and will be removed in future versions. * Modified attributes are not exposed as bit mask to external interfaces anymore (api related changes). External commands like CHANGE_*_MODATTR have been removed. ### Enhancement * [#3642](https://github.com/Icinga/icinga2/issues/3642): Release 2.4.0 * [#3624](https://github.com/Icinga/icinga2/issues/3624) (API): Enhance programmatic examples for the API docs * [#3611](https://github.com/Icinga/icinga2/issues/3611) (API): Change object query result set * [#3609](https://github.com/Icinga/icinga2/issues/3609) (API): Change 'api setup' into a manual step while configuring the API * [#3608](https://github.com/Icinga/icinga2/issues/3608) (CLI): Icinga 2 script debugger * [#3591](https://github.com/Icinga/icinga2/issues/3591) (CLI): Change output format for 'icinga2 console' * [#3580](https://github.com/Icinga/icinga2/issues/3580): Change GetLastStateUp/Down to host attributes * [#3576](https://github.com/Icinga/icinga2/issues/3576) (Plugins): Missing parameters for check jmx4perl * [#3561](https://github.com/Icinga/icinga2/issues/3561) (CLI): Use ZoneName variable for parent\_zone in node update-config * [#3537](https://github.com/Icinga/icinga2/issues/3537) (CLI): Rewrite man page * [#3531](https://github.com/Icinga/icinga2/issues/3531) (DB IDO): Add the name for comments/downtimes next to legacy\_id to DB IDO * [#3515](https://github.com/Icinga/icinga2/issues/3515): Remove api.cpp, api.hpp * [#3508](https://github.com/Icinga/icinga2/issues/3508) (Cluster): Add getter for endpoint 'connected' attribute * [#3507](https://github.com/Icinga/icinga2/issues/3507) (API): Hide internal attributes * [#3506](https://github.com/Icinga/icinga2/issues/3506) (API): Original attributes list in IDO * [#3503](https://github.com/Icinga/icinga2/issues/3503) (API): Log a warning message on unauthorized http request * [#3502](https://github.com/Icinga/icinga2/issues/3502) (API): Use the API for "icinga2 console" * [#3498](https://github.com/Icinga/icinga2/issues/3498) (DB IDO): DB IDO should provide its connected state via /v1/status * [#3488](https://github.com/Icinga/icinga2/issues/3488) (API): Document that modified attributes require accept\_config for cluster/clients * [#3469](https://github.com/Icinga/icinga2/issues/3469) (Configuration): Pretty-print arrays and dictionaries when converting them to strings * [#3463](https://github.com/Icinga/icinga2/issues/3463) (API): Change object version to timestamps for diff updates on config sync * [#3452](https://github.com/Icinga/icinga2/issues/3452) (Configuration): Provide keywords to retrieve the current file name at parse time * [#3435](https://github.com/Icinga/icinga2/issues/3435) (API): Move /v1/\ to /v1/objects/\ * [#3432](https://github.com/Icinga/icinga2/issues/3432) (API): Rename statusqueryhandler to objectqueryhandler * [#3419](https://github.com/Icinga/icinga2/issues/3419) (API): Sanitize error status codes and messages * [#3414](https://github.com/Icinga/icinga2/issues/3414): Make ConfigObject::{G,S}etField\(\) method public * [#3386](https://github.com/Icinga/icinga2/issues/3386) (API): Add global status handler for the API * [#3357](https://github.com/Icinga/icinga2/issues/3357) (API): Implement CSRF protection for the API * [#3354](https://github.com/Icinga/icinga2/issues/3354) (API): Implement joins for status queries * [#3343](https://github.com/Icinga/icinga2/issues/3343) (API): Implement a demo API client: Icinga Studio * [#3341](https://github.com/Icinga/icinga2/issues/3341) (API): URL class improvements * [#3340](https://github.com/Icinga/icinga2/issues/3340) (API): Add plural\_name field to /v1/types * [#3332](https://github.com/Icinga/icinga2/issues/3332) (Configuration): Use an AST node for the 'library' keyword * [#3297](https://github.com/Icinga/icinga2/issues/3297) (Configuration): Implement ignore\_on\_error keyword * [#3296](https://github.com/Icinga/icinga2/issues/3296) (API): Rename config/modules to config/packages * [#3291](https://github.com/Icinga/icinga2/issues/3291) (API): Remove debug messages in HttpRequest class * [#3290](https://github.com/Icinga/icinga2/issues/3290): Add String::ToLower/ToUpper * [#3287](https://github.com/Icinga/icinga2/issues/3287) (API): Add package attribute for ConfigObject and set its origin * [#3285](https://github.com/Icinga/icinga2/issues/3285) (API): Implement support for restoring modified attributes * [#3283](https://github.com/Icinga/icinga2/issues/3283) (API): Implement support for indexers in ConfigObject::RestoreAttribute * [#3282](https://github.com/Icinga/icinga2/issues/3282): Implement Object\#clone and rename Array/Dictionary\#clone to shallow\_clone * [#3280](https://github.com/Icinga/icinga2/issues/3280): Add override keyword for all relevant methods * [#3278](https://github.com/Icinga/icinga2/issues/3278) (API): Figure out how to sync dynamically created objects inside the cluster * [#3277](https://github.com/Icinga/icinga2/issues/3277) (API): Ensure that runtime config objects are persisted on disk * [#3272](https://github.com/Icinga/icinga2/issues/3272): Implement the 'base' field for the Type class * [#3267](https://github.com/Icinga/icinga2/issues/3267): Rename DynamicObject/DynamicType to ConfigObject/ConfigType * [#3240](https://github.com/Icinga/icinga2/issues/3240): Implement support for attaching GDB to the Icinga process on crash * [#3238](https://github.com/Icinga/icinga2/issues/3238) (API): Implement global modified attributes * [#3233](https://github.com/Icinga/icinga2/issues/3233) (API): Implement support for . in modify\_attribute * [#3232](https://github.com/Icinga/icinga2/issues/3232) (API): Remove GetModifiedAttributes/SetModifiedAttributes * [#3231](https://github.com/Icinga/icinga2/issues/3231) (API): Re-implement events for attribute changes * [#3230](https://github.com/Icinga/icinga2/issues/3230) (API): Validation for modified attributes * [#3203](https://github.com/Icinga/icinga2/issues/3203) (Configuration): Setting global variables with i2tcl doesn't work * [#3197](https://github.com/Icinga/icinga2/issues/3197) (API): Make Comments and Downtime types available as ConfigObject type in the API * [#3193](https://github.com/Icinga/icinga2/issues/3193) (API): Update the url parsers behaviour * [#3177](https://github.com/Icinga/icinga2/issues/3177) (API): Documentation for config management API * [#3173](https://github.com/Icinga/icinga2/issues/3173) (API): Add real path sanity checks to provided file paths * [#3172](https://github.com/Icinga/icinga2/issues/3172): String::Trim\(\) should return a new string rather than modifying the current string * [#3169](https://github.com/Icinga/icinga2/issues/3169) (API): Implement support for X-HTTP-Method-Override * [#3168](https://github.com/Icinga/icinga2/issues/3168): Add Array::FromVector\(\) method * [#3167](https://github.com/Icinga/icinga2/issues/3167): Add exceptions for Utility::MkDir{,P} * [#3154](https://github.com/Icinga/icinga2/issues/3154): Move url to /lib/remote from /lib/base * [#3144](https://github.com/Icinga/icinga2/issues/3144): Register ServiceOK, ServiceWarning, HostUp, etc. as constants * [#3140](https://github.com/Icinga/icinga2/issues/3140) (API): Implement base64 de- and encoder * [#3094](https://github.com/Icinga/icinga2/issues/3094) (API): Implement ApiUser type * [#3093](https://github.com/Icinga/icinga2/issues/3093) (API): Implement URL parser * [#3090](https://github.com/Icinga/icinga2/issues/3090) (Graphite): New Graphite schema * [#3089](https://github.com/Icinga/icinga2/issues/3089) (API): Implement support for filter\_vars * [#3083](https://github.com/Icinga/icinga2/issues/3083) (API): Define RESTful url schema * [#3082](https://github.com/Icinga/icinga2/issues/3082) (API): Implement support for HTTP * [#3065](https://github.com/Icinga/icinga2/issues/3065): Allow comments when parsing JSON * [#3025](https://github.com/Icinga/icinga2/issues/3025) (DB IDO): DB IDO/Livestatus: Add zone object table w/ endpoint members * [#2934](https://github.com/Icinga/icinga2/issues/2934) (API): API Documentation * [#2933](https://github.com/Icinga/icinga2/issues/2933) (API): Implement config file management commands * [#2932](https://github.com/Icinga/icinga2/issues/2932) (API): Staging for configuration validation * [#2931](https://github.com/Icinga/icinga2/issues/2931) (API): Support validating configuration changes * [#2930](https://github.com/Icinga/icinga2/issues/2930) (API): Commands for adding and removing objects * [#2929](https://github.com/Icinga/icinga2/issues/2929) (API): Multiple sources for zone configuration tree * [#2928](https://github.com/Icinga/icinga2/issues/2928) (API): Implement support for writing configuration files * [#2927](https://github.com/Icinga/icinga2/issues/2927) (API): Update modules to support adding and removing objects at runtime * [#2926](https://github.com/Icinga/icinga2/issues/2926) (API): Dependency tracking for objects * [#2925](https://github.com/Icinga/icinga2/issues/2925) (API): Disallow changes for certain config attributes at runtime * [#2923](https://github.com/Icinga/icinga2/issues/2923) (API): Changelog for modified attributes * [#2921](https://github.com/Icinga/icinga2/issues/2921) (API): API status queries * [#2918](https://github.com/Icinga/icinga2/issues/2918) (API): API permissions * [#2917](https://github.com/Icinga/icinga2/issues/2917) (API): Create default administrative user * [#2916](https://github.com/Icinga/icinga2/issues/2916) (API): Password-based authentication for the API * [#2915](https://github.com/Icinga/icinga2/issues/2915) (API): Certificate-based authentication for the API * [#2914](https://github.com/Icinga/icinga2/issues/2914) (API): Enable the ApiListener by default * [#2913](https://github.com/Icinga/icinga2/issues/2913) (API): Configuration file management for the API * [#2912](https://github.com/Icinga/icinga2/issues/2912) (API): Runtime configuration for the API * [#2911](https://github.com/Icinga/icinga2/issues/2911) (API): Add modified attribute support for the API * [#2910](https://github.com/Icinga/icinga2/issues/2910) (API): Add commands \(actions\) for the API * [#2909](https://github.com/Icinga/icinga2/issues/2909) (API): Implement status queries for the API * [#2908](https://github.com/Icinga/icinga2/issues/2908) (API): Event stream support for the API * [#2907](https://github.com/Icinga/icinga2/issues/2907) (API): Implement filters for the API * [#2906](https://github.com/Icinga/icinga2/issues/2906) (API): Reflection support for the API * [#2904](https://github.com/Icinga/icinga2/issues/2904) (API): Basic API framework * [#2901](https://github.com/Icinga/icinga2/issues/2901) (Configuration): Implement sandbox mode for the config parser * [#2887](https://github.com/Icinga/icinga2/issues/2887) (Configuration): Remove the ScopeCurrent constant * [#2857](https://github.com/Icinga/icinga2/issues/2857): Avoid unnecessary dictionary lookups * [#2838](https://github.com/Icinga/icinga2/issues/2838): Move implementation code from thpp files into separate files * [#2826](https://github.com/Icinga/icinga2/issues/2826) (Configuration): Use DebugHint information when reporting validation errors * [#2814](https://github.com/Icinga/icinga2/issues/2814): Add support for the C++11 keyword 'override' * [#2809](https://github.com/Icinga/icinga2/issues/2809) (Configuration): Implement constructor-style casts * [#2788](https://github.com/Icinga/icinga2/issues/2788) (Configuration): Refactor the startup process * [#2785](https://github.com/Icinga/icinga2/issues/2785) (CLI): Implement support for libedit * [#2757](https://github.com/Icinga/icinga2/issues/2757): Deprecate IcingaStatusWriter feature * [#2755](https://github.com/Icinga/icinga2/issues/2755) (DB IDO): Implement support for CLIENT\_MULTI\_STATEMENTS * [#2741](https://github.com/Icinga/icinga2/issues/2741) (DB IDO): Add support for current and current-1 db ido schema version * [#2740](https://github.com/Icinga/icinga2/issues/2740) (DB IDO): Add embedded DB IDO version health check * [#2722](https://github.com/Icinga/icinga2/issues/2722): Allow some of the Array and Dictionary methods to be inlined by the compiler * [#2514](https://github.com/Icinga/icinga2/issues/2514): 'icinga2 console' should serialize temporary attributes \(rather than just config + state\) * [#2474](https://github.com/Icinga/icinga2/issues/2474) (Graphite): graphite writer should pass "-" in host names and "." in perf data * [#2438](https://github.com/Icinga/icinga2/issues/2438) (API): Add icinga, cluster, cluster-zone check information to the ApiListener status handler * [#2268](https://github.com/Icinga/icinga2/issues/2268) (Configuration): Validators should be implemented in \(auto-generated\) native code ### Bug * [#3669](https://github.com/Icinga/icinga2/issues/3669): Use notify\_one in WorkQueue::Enqueue * [#3667](https://github.com/Icinga/icinga2/issues/3667): Utility::FormatErrorNumber fails when error message uses arguments * [#3649](https://github.com/Icinga/icinga2/issues/3649) (DB IDO): Group memberships are not updated for runtime created objects * [#3648](https://github.com/Icinga/icinga2/issues/3648) (API): API overwrites \(and then deletes\) config file when trying to create an object that already exists * [#3647](https://github.com/Icinga/icinga2/issues/3647) (API): Don't allow users to set state attributes via PUT * [#3645](https://github.com/Icinga/icinga2/issues/3645): Deadlock in MacroProcessor::EvaluateFunction * [#3635](https://github.com/Icinga/icinga2/issues/3635): modify\_attribute: object cannot be cloned * [#3633](https://github.com/Icinga/icinga2/issues/3633) (API): Detailed error message is missing when object creation via API fails * [#3632](https://github.com/Icinga/icinga2/issues/3632) (API): API call doesn't fail when trying to use a template that doesn't exist * [#3625](https://github.com/Icinga/icinga2/issues/3625): Improve location information for errors in API filters * [#3622](https://github.com/Icinga/icinga2/issues/3622) (API): /v1/console should only use a single permission * [#3620](https://github.com/Icinga/icinga2/issues/3620) (API): 'remove-comment' action does not support filters * [#3619](https://github.com/Icinga/icinga2/issues/3619) (CLI): 'api setup' should create a user even when api feature is already enabled * [#3618](https://github.com/Icinga/icinga2/issues/3618) (CLI): Autocompletion doesn't work in the debugger * [#3617](https://github.com/Icinga/icinga2/issues/3617) (API): There's a variable called 'string' in filter expressions * [#3607](https://github.com/Icinga/icinga2/issues/3607) (CLI): Broken build - unresolved external symbol "public: void \_\_thiscall icinga::ApiClient::ExecuteScript... * [#3602](https://github.com/Icinga/icinga2/issues/3602) (DB IDO): Async mysql queries aren't logged in the debug log * [#3601](https://github.com/Icinga/icinga2/issues/3601): Don't validate custom attributes that aren't strings * [#3600](https://github.com/Icinga/icinga2/issues/3600): Crash in ConfigWriter::EmitIdentifier * [#3598](https://github.com/Icinga/icinga2/issues/3598) (CLI): Spaces do not work in command arguments * [#3595](https://github.com/Icinga/icinga2/issues/3595) (DB IDO): Change session\_token to integer timestamp * [#3593](https://github.com/Icinga/icinga2/issues/3593): Fix indentation for Dictionary::ToString * [#3587](https://github.com/Icinga/icinga2/issues/3587): Crash in ConfigWriter::GetKeywords * [#3586](https://github.com/Icinga/icinga2/issues/3586) (Cluster): Circular reference between \*Connection and TlsStream objects * [#3583](https://github.com/Icinga/icinga2/issues/3583) (API): Mismatch on {comment,downtime}\_id vs internal name in the API * [#3581](https://github.com/Icinga/icinga2/issues/3581): CreatePipeOverlapped is not thread-safe * [#3579](https://github.com/Icinga/icinga2/issues/3579): Figure out whether we need the Checkable attributes state\_raw, last\_state\_raw, hard\_state\_raw * [#3577](https://github.com/Icinga/icinga2/issues/3577) (Plugins): Increase the default timeout for OS checks * [#3574](https://github.com/Icinga/icinga2/issues/3574) (API): Plural name rule not treating edge case correcly * [#3572](https://github.com/Icinga/icinga2/issues/3572) (API): IcingaStudio: Accessing non-ConfigObjects causes ugly exception * [#3569](https://github.com/Icinga/icinga2/issues/3569) (API): Incorrect JSON-RPC message causes Icinga 2 to crash * [#3566](https://github.com/Icinga/icinga2/issues/3566) (DB IDO): Unique constraint violation with multiple comment inserts in DB IDO * [#3558](https://github.com/Icinga/icinga2/issues/3558) (DB IDO): IDO tries to execute empty UPDATE queries * [#3554](https://github.com/Icinga/icinga2/issues/3554) (Configuration): Crash in IndexerExpression::GetReference when attempting to set an attribute on an object other than the current one * [#3551](https://github.com/Icinga/icinga2/issues/3551) (Configuration): Line continuation is broken in 'icinga2 console' * [#3548](https://github.com/Icinga/icinga2/issues/3548) (Configuration): Don't allow scripts to access FANoUserView attributes in sandbox mode * [#3546](https://github.com/Icinga/icinga2/issues/3546) (Cluster): Improve error handling during log replay * [#3536](https://github.com/Icinga/icinga2/issues/3536) (CLI): Improve --help output for the --log-level option * [#3535](https://github.com/Icinga/icinga2/issues/3535) (CLI): "Command options" is empty when executing icinga2 without any argument. * [#3534](https://github.com/Icinga/icinga2/issues/3534) (DB IDO): Custom variables aren't removed from the IDO database * [#3524](https://github.com/Icinga/icinga2/issues/3524) (DB IDO): Changing a group's attributes causes duplicate rows in the icinga\_\*group\_members table * [#3517](https://github.com/Icinga/icinga2/issues/3517): OpenBSD: hang during ConfigItem::ActivateItems\(\) in daemon startup * [#3514](https://github.com/Icinga/icinga2/issues/3514) (CLI): Misleading wording in generated zones.conf * [#3501](https://github.com/Icinga/icinga2/issues/3501) (API): restore\_attribute does not work in clusters * [#3489](https://github.com/Icinga/icinga2/issues/3489) (API): Ensure that modified attributes work with clients with local config and no zone attribute * [#3485](https://github.com/Icinga/icinga2/issues/3485) (API): Icinga2 API performance regression * [#3482](https://github.com/Icinga/icinga2/issues/3482) (API): Version updates are not working properly * [#3468](https://github.com/Icinga/icinga2/issues/3468) (CLI): icinga2 repository host add does not work * [#3462](https://github.com/Icinga/icinga2/issues/3462): ConfigWriter::EmitValue should format floating point values properly * [#3461](https://github.com/Icinga/icinga2/issues/3461) (API): Config sync does not set endpoint syncing and plays disconnect-sync ping-pong * [#3459](https://github.com/Icinga/icinga2/issues/3459) (API): /v1/objects/\ returns an HTTP error when there are no objects of that type * [#3457](https://github.com/Icinga/icinga2/issues/3457) (API): Config Sync shouldn't send updates for objects the client doesn't have access to * [#3451](https://github.com/Icinga/icinga2/issues/3451) (API): Properly encode URLs in Icinga Studio * [#3448](https://github.com/Icinga/icinga2/issues/3448) (API): Use a temporary file for modified-attributes.conf updates * [#3445](https://github.com/Icinga/icinga2/issues/3445) (Configuration): ASCII NULs don't work in string values * [#3438](https://github.com/Icinga/icinga2/issues/3438) (API): URL parser is cutting off last character * [#3434](https://github.com/Icinga/icinga2/issues/3434) (API): PerfdataValue is not properly serialised in status queries * [#3433](https://github.com/Icinga/icinga2/issues/3433) (API): Move the Collection status handler to /v1/status * [#3422](https://github.com/Icinga/icinga2/issues/3422) (Configuration): Detect infinite recursion in user scripts * [#3411](https://github.com/Icinga/icinga2/issues/3411) (API): API actions do not follow REST guidelines * [#3383](https://github.com/Icinga/icinga2/issues/3383) (DB IDO): Add object\_id where clause for icinga\_downtimehistory * [#3345](https://github.com/Icinga/icinga2/issues/3345) (API): Error handling in HttpClient/icinga-studio * [#3338](https://github.com/Icinga/icinga2/issues/3338) (CLI): Unused variable console\_type in consolecommand.cpp * [#3336](https://github.com/Icinga/icinga2/issues/3336) (API): Filtering by name doesn't work * [#3335](https://github.com/Icinga/icinga2/issues/3335) (API): HTTP keep-alive does not work with .NET WebClient * [#3330](https://github.com/Icinga/icinga2/issues/3330): Unused variable 'dobj' in configobject.tcpp * [#3328](https://github.com/Icinga/icinga2/issues/3328) (Configuration): Don't parse config files for branches not taken * [#3315](https://github.com/Icinga/icinga2/issues/3315) (Configuration): Crash in ConfigCompiler::RegisterZoneDir * [#3302](https://github.com/Icinga/icinga2/issues/3302) (API): Implement support for '.' when persisting modified attributes * [#3301](https://github.com/Icinga/icinga2/issues/3301): Fix formatting in mkclass * [#3264](https://github.com/Icinga/icinga2/issues/3264) (API): Do not let API users create objects with invalid names * [#3250](https://github.com/Icinga/icinga2/issues/3250) (API): Missing conf.d or zones.d cause parse failure * [#3248](https://github.com/Icinga/icinga2/issues/3248): Crash during cluster log replay * [#3244](https://github.com/Icinga/icinga2/issues/3244) (CLI): Color codes in console prompt break line editing * [#3242](https://github.com/Icinga/icinga2/issues/3242) (CLI): Crash in ScriptFrame::~ScriptFrame * [#3227](https://github.com/Icinga/icinga2/issues/3227) (CLI): console autocompletion should take into account parent classes' prototypes * [#3215](https://github.com/Icinga/icinga2/issues/3215) (API): win32 build: S\_ISDIR is undefined * [#3205](https://github.com/Icinga/icinga2/issues/3205) (Configuration): ScriptFrame's 'Self' attribute gets corrupted when an expression throws an exception * [#3202](https://github.com/Icinga/icinga2/issues/3202) (Configuration): Operator - should not work with "" and numbers * [#3198](https://github.com/Icinga/icinga2/issues/3198): Accessing field ID 0 \("prototype"\) fails * [#3182](https://github.com/Icinga/icinga2/issues/3182) (API): Broken cluster config sync w/o include\_zones * [#3171](https://github.com/Icinga/icinga2/issues/3171) (API): Problem with child nodes in http url registry * [#3138](https://github.com/Icinga/icinga2/issues/3138) (CLI): 'node wizard/setup' should always generate new CN certificates * [#3131](https://github.com/Icinga/icinga2/issues/3131) (DB IDO): Overflow in freshness\_threshold column \(smallint\) w/ DB IDO MySQL * [#3109](https://github.com/Icinga/icinga2/issues/3109) (API): build failure: demo module * [#3087](https://github.com/Icinga/icinga2/issues/3087) (DB IDO): Fix incorrect datatype for the check\_source column in icinga\_statehistory table * [#2974](https://github.com/Icinga/icinga2/issues/2974) (Configuration): Remove incorrect 'ignore where' expression from 'ssh' apply example * [#2939](https://github.com/Icinga/icinga2/issues/2939) (Cluster): Wrong vars changed handler in api events * [#2884](https://github.com/Icinga/icinga2/issues/2884) (DB IDO): PostgreSQL schema sets default timestamps w/o time zone * [#2879](https://github.com/Icinga/icinga2/issues/2879): Compiler warnings with latest HEAD 5ac5f98 * [#2870](https://github.com/Icinga/icinga2/issues/2870) (DB IDO): pgsql driver does not have latest mysql changes synced * [#2863](https://github.com/Icinga/icinga2/issues/2863) (Configuration): Crash in VMOps::FunctionCall * [#2850](https://github.com/Icinga/icinga2/issues/2850) (Configuration): Validation fails even though field is not required * [#2824](https://github.com/Icinga/icinga2/issues/2824) (DB IDO): Failed assertion in IdoMysqlConnection::FieldToEscapedString * [#2808](https://github.com/Icinga/icinga2/issues/2808) (Configuration): Make default notifications include users from host.vars.notification.mail.users * [#2803](https://github.com/Icinga/icinga2/issues/2803): Don't allow users to instantiate the StreamLogger class ### ITL * [#3584](https://github.com/Icinga/icinga2/issues/3584) (ITL): Add ipv4/ipv6 only to tcp and http CheckCommand * [#3582](https://github.com/Icinga/icinga2/issues/3582) (ITL): Add check command mysql * [#3578](https://github.com/Icinga/icinga2/issues/3578) (ITL): Add check command negate * [#3532](https://github.com/Icinga/icinga2/issues/3532) (ITL): 'dig\_lookup' custom attribute for the 'dig' check command isn't optional * [#3525](https://github.com/Icinga/icinga2/issues/3525) (ITL): Ability to set port on SNMP Checks * [#3490](https://github.com/Icinga/icinga2/issues/3490) (ITL): Add check command nginx\_status * [#2964](https://github.com/Icinga/icinga2/issues/2964) (ITL): Move 'running\_kernel' check command to plugins-contrib 'operating system' section * [#2784](https://github.com/Icinga/icinga2/issues/2784) (ITL): Move the base command templates into libmethods ### Documentation * [#3663](https://github.com/Icinga/icinga2/issues/3663) (Documentation): Update wxWidgets documentation for Icinga Studio * [#3640](https://github.com/Icinga/icinga2/issues/3640) (Documentation): Explain DELETE for config stages/packages * [#3638](https://github.com/Icinga/icinga2/issues/3638) (Documentation): Documentation for /v1/types * [#3631](https://github.com/Icinga/icinga2/issues/3631) (Documentation): Documentation for the script debugger * [#3630](https://github.com/Icinga/icinga2/issues/3630) (Documentation): Explain variable names for joined objects in filter expressions * [#3629](https://github.com/Icinga/icinga2/issues/3629) (Documentation): Documentation for /v1/console * [#3628](https://github.com/Icinga/icinga2/issues/3628) (Documentation): Mention wxWidget \(optional\) requirement in INSTALL.md * [#3626](https://github.com/Icinga/icinga2/issues/3626) (Documentation): Icinga 2 API Docs * [#3621](https://github.com/Icinga/icinga2/issues/3621) (Documentation): Documentation should not reference real host names * [#3563](https://github.com/Icinga/icinga2/issues/3563) (Documentation): Documentation: Reorganize Livestatus and alternative frontends * [#3547](https://github.com/Icinga/icinga2/issues/3547) (Documentation): Incorrect attribute name in the documentation * [#3516](https://github.com/Icinga/icinga2/issues/3516) (Documentation): Add documentation for apply+for in the language reference chapter * [#3511](https://github.com/Icinga/icinga2/issues/3511) (Documentation): Escaping $ not documented * [#3500](https://github.com/Icinga/icinga2/issues/3500) (Documentation): Add 'support' tracker to changelog.py * [#3477](https://github.com/Icinga/icinga2/issues/3477) (Documentation): Remove duplicated text in section "Apply Notifications to Hosts and Services" * [#3426](https://github.com/Icinga/icinga2/issues/3426) (Documentation): Add documentation for api-users.conf and app.conf * [#3281](https://github.com/Icinga/icinga2/issues/3281) (Documentation): Document Object\#clone ### Support * [#3662](https://github.com/Icinga/icinga2/issues/3662) (Packages): Download URL for NSClient++ is incorrect * [#3615](https://github.com/Icinga/icinga2/issues/3615) (Packages): Update OpenSSL for the Windows builds * [#3614](https://github.com/Icinga/icinga2/issues/3614) (Installation): Don't try to use --gc-sections on Solaris * [#3522](https://github.com/Icinga/icinga2/issues/3522) (Packages): 'which' isn't available in a minimal CentOS container * [#3063](https://github.com/Icinga/icinga2/issues/3063) (Installation): "-Wno-deprecated-register" compiler option breaks builds on SLES 11 * [#2893](https://github.com/Icinga/icinga2/issues/2893) (Installation): icinga demo module can not be built * [#2858](https://github.com/Icinga/icinga2/issues/2858) (Packages): Specify pidfile for status\_of\_proc in the init script * [#2802](https://github.com/Icinga/icinga2/issues/2802) (Packages): Update OpenSSL for the Windows builds ## 2.3.11 (2015-10-20) ### Notes * Function for performing CIDR matches: cidr_match() * New methods: String#reverse and Array#reverse * New ITL command definitions: nwc_health, hpasm, squid, pgsql * Additional arguments for ITL command definitions: by_ssh, dig, pop, spop, imap, simap * Documentation updates * Various bugfixes ### Enhancement * [#3494](https://github.com/Icinga/icinga2/issues/3494) (DB IDO): Add a debug log message for updating the program status table in DB IDO * [#3481](https://github.com/Icinga/icinga2/issues/3481): New method: cidr\_match\(\) * [#3421](https://github.com/Icinga/icinga2/issues/3421): Implement the Array\#reverse and String\#reverse methods * [#3327](https://github.com/Icinga/icinga2/issues/3327): Implement a way for users to resolve commands+arguments in the same way Icinga does * [#3326](https://github.com/Icinga/icinga2/issues/3326): escape\_shell\_arg\(\) method * [#2969](https://github.com/Icinga/icinga2/issues/2969) (Performance Data): Add timestamp support for OpenTsdbWriter ### Bug * [#3492](https://github.com/Icinga/icinga2/issues/3492) (Cluster): Wrong connection log message for global zones * [#3491](https://github.com/Icinga/icinga2/issues/3491): cidr\_match\(\) doesn't properly validate IP addresses * [#3487](https://github.com/Icinga/icinga2/issues/3487) (Cluster): ApiListener::SyncRelayMessage doesn't send message to all zone members * [#3476](https://github.com/Icinga/icinga2/issues/3476) (Compat): Missing Start call for base class in CheckResultReader * [#3475](https://github.com/Icinga/icinga2/issues/3475) (Compat): Checkresultreader is unable to process host checks * [#3466](https://github.com/Icinga/icinga2/issues/3466): "Not after" value overflows in X509 certificates on RHEL5 * [#3464](https://github.com/Icinga/icinga2/issues/3464) (Cluster): Don't log messages we've already relayed to all relevant zones * [#3460](https://github.com/Icinga/icinga2/issues/3460) (Performance Data): Performance Data Labels including '=' will not be displayed correct * [#3454](https://github.com/Icinga/icinga2/issues/3454): Percent character whitespace on Windows * [#3449](https://github.com/Icinga/icinga2/issues/3449) (Cluster): Don't throw an exception when replaying the current replay log file * [#3446](https://github.com/Icinga/icinga2/issues/3446): Deadlock in TlsStream::Close * [#3428](https://github.com/Icinga/icinga2/issues/3428) (Configuration): config checker reports wrong error on apply for rules * [#3427](https://github.com/Icinga/icinga2/issues/3427) (Configuration): Config parser problem with parenthesis and newlines * [#3423](https://github.com/Icinga/icinga2/issues/3423) (Configuration): Remove unnecessary MakeLiteral calls in SetExpression::DoEvaluate * [#3417](https://github.com/Icinga/icinga2/issues/3417) (Configuration): null + null should not be "" * [#3416](https://github.com/Icinga/icinga2/issues/3416) (API): Problem with customvariable table update/insert queries * [#3373](https://github.com/Icinga/icinga2/issues/3373) (Livestatus): Improve error message for socket errors in Livestatus * [#3324](https://github.com/Icinga/icinga2/issues/3324) (Cluster): Deadlock in WorkQueue::Enqueue * [#3204](https://github.com/Icinga/icinga2/issues/3204) (Configuration): String methods cannot be invoked on an empty string * [#3038](https://github.com/Icinga/icinga2/issues/3038) (Livestatus): sending multiple Livestatus commands rejects all except the first * [#2568](https://github.com/Icinga/icinga2/issues/2568) (Cluster): check cluster-zone returns wrong log lag ### ITL * [#3437](https://github.com/Icinga/icinga2/issues/3437) (ITL): Add timeout argument for pop, spop, imap, simap commands * [#3407](https://github.com/Icinga/icinga2/issues/3407) (ITL): Make check\_disk.exe CheckCommand Config more verbose * [#3399](https://github.com/Icinga/icinga2/issues/3399) (ITL): expand check command dig * [#3394](https://github.com/Icinga/icinga2/issues/3394) (ITL): Add ipv4/ipv6 only to nrpe CheckCommand * [#3385](https://github.com/Icinga/icinga2/issues/3385) (ITL): Add check command pgsql * [#3382](https://github.com/Icinga/icinga2/issues/3382) (ITL): Add check command squid * [#3235](https://github.com/Icinga/icinga2/issues/3235) (ITL): check\_command for plugin check\_hpasm * [#3214](https://github.com/Icinga/icinga2/issues/3214) (ITL): add check command for check\_nwc\_health ### Documentation * [#3479](https://github.com/Icinga/icinga2/issues/3479) (Documentation): Improve timeperiod documentation * [#3478](https://github.com/Icinga/icinga2/issues/3478) (Documentation): Broken table layout in chapter 20 * [#3436](https://github.com/Icinga/icinga2/issues/3436) (Documentation): Clarify on cluster/client naming convention and add troubleshooting section * [#3430](https://github.com/Icinga/icinga2/issues/3430) (Documentation): Find a better description for cluster communication requirements * [#3409](https://github.com/Icinga/icinga2/issues/3409) (Documentation): Windows Check Update -\> Access denied * [#3408](https://github.com/Icinga/icinga2/issues/3408) (Documentation): Improve documentation for check\_memory * [#3406](https://github.com/Icinga/icinga2/issues/3406) (Documentation): Update graphing section in the docs * [#3402](https://github.com/Icinga/icinga2/issues/3402) (Documentation): Update debug docs for core dumps and full backtraces * [#3351](https://github.com/Icinga/icinga2/issues/3351) (Documentation): Command Execution Bridge: Use of same endpoint names in examples for a better understanding * [#3092](https://github.com/Icinga/icinga2/issues/3092) (Documentation): Add FreeBSD setup to getting started ### Support * [#3379](https://github.com/Icinga/icinga2/issues/3379) (Installation): Rather use unique SID when granting rights for folders in NSIS on Windows Client * [#3045](https://github.com/Icinga/icinga2/issues/3045) (Packages): icinga2 ido mysql misspelled database username ## 2.3.10 (2015-09-05) ### Notes * Feature 9218: Use the command_endpoint name as check_source value if defined ### Enhancement * [#2985](https://github.com/Icinga/icinga2/issues/2985): Use the command\_endpoint name as check\_source value if defined ### Bug * [#3369](https://github.com/Icinga/icinga2/issues/3369): Missing zero padding for generated CA serial.txt * [#3352](https://github.com/Icinga/icinga2/issues/3352): Wrong calculation for host compat state "UNREACHABLE" in DB IDO * [#3348](https://github.com/Icinga/icinga2/issues/3348) (Cluster): Missing fix for reload on Windows in 2.3.9 * [#3325](https://github.com/Icinga/icinga2/issues/3325): Nested "outer" macro calls fails on \(handled\) missing "inner" values * [#2811](https://github.com/Icinga/icinga2/issues/2811) (DB IDO): String escape problem with PostgreSQL \>= 9.1 and standard\_conforming\_strings=on ## 2.3.9 (2015-08-26) ### Notes * Fix that the first SOFT state is recognized as second SOFT state * Implemented reload functionality for Windows * New ITL check commands * Documentation updates * Various other bugfixes ### Enhancement * [#3254](https://github.com/Icinga/icinga2/issues/3254) (Livestatus): Use an empty dictionary for the 'this' scope when executing commands with Livestatus * [#3253](https://github.com/Icinga/icinga2/issues/3253): Implement the Dictionary\#keys method * [#3206](https://github.com/Icinga/icinga2/issues/3206): Implement Dictionary\#get and Array\#get * [#3170](https://github.com/Icinga/icinga2/issues/3170) (Configuration): Adding "-r" parameter to the check\_load command for dividing the load averages by the number of CPUs. ### Bug * [#3305](https://github.com/Icinga/icinga2/issues/3305) (Configuration): Icinga2 - too many open files - Exception * [#3299](https://github.com/Icinga/icinga2/issues/3299): Utility::Glob on Windows doesn't support wildcards in all but the last path component * [#3292](https://github.com/Icinga/icinga2/issues/3292): Serial number field is not properly initialized for CA certificates * [#3279](https://github.com/Icinga/icinga2/issues/3279) (DB IDO): Add missing category for IDO query * [#3266](https://github.com/Icinga/icinga2/issues/3266) (Plugins): Default disk checks on Windows fail because check\_disk doesn't support -K * [#3260](https://github.com/Icinga/icinga2/issues/3260): First SOFT state is recognized as second SOFT state * [#3255](https://github.com/Icinga/icinga2/issues/3255) (Cluster): Warning about invalid API function icinga::Hello * [#3241](https://github.com/Icinga/icinga2/issues/3241): Agent freezes when the check returns massive output * [#3222](https://github.com/Icinga/icinga2/issues/3222) (Configuration): Dict initializer incorrectly re-initializes field that is set to an empty string * [#3211](https://github.com/Icinga/icinga2/issues/3211) (Configuration): Operator + is inconsistent when used with empty and non-empty strings * [#3200](https://github.com/Icinga/icinga2/issues/3200) (CLI): icinga2 node wizard don't take zone\_name input * [#3199](https://github.com/Icinga/icinga2/issues/3199): Trying to set a field for a non-object instance fails * [#3196](https://github.com/Icinga/icinga2/issues/3196) (Cluster): Add log for missing EventCommand for command\_endpoints * [#3194](https://github.com/Icinga/icinga2/issues/3194): Set correct X509 version for certificates * [#3149](https://github.com/Icinga/icinga2/issues/3149) (CLI): missing config warning on empty port in endpoints * [#3010](https://github.com/Icinga/icinga2/issues/3010) (Cluster): cluster check w/ immediate parent and child zone endpoints * [#2867](https://github.com/Icinga/icinga2/issues/2867): Missing DEL\_DOWNTIME\_BY\_HOST\_NAME command required by Classic UI 1.x * [#2352](https://github.com/Icinga/icinga2/issues/2352) (Cluster): Reload does not work on Windows ### ITL * [#3320](https://github.com/Icinga/icinga2/issues/3320) (ITL): Add new arguments openvmtools for Open VM Tools * [#3313](https://github.com/Icinga/icinga2/issues/3313) (ITL): add check command nscp-local-counter * [#3312](https://github.com/Icinga/icinga2/issues/3312) (ITL): fix check command nscp-local * [#3265](https://github.com/Icinga/icinga2/issues/3265) (ITL): check\_command interfaces option match\_aliases has to be boolean * [#3219](https://github.com/Icinga/icinga2/issues/3219) (ITL): snmpv3 CheckCommand section improved * [#3213](https://github.com/Icinga/icinga2/issues/3213) (ITL): add check command for check\_mailq * [#3208](https://github.com/Icinga/icinga2/issues/3208) (ITL): Add check\_jmx4perl to ITL * [#3186](https://github.com/Icinga/icinga2/issues/3186) (ITL): check\_command for plugin check\_clamd * [#3164](https://github.com/Icinga/icinga2/issues/3164) (ITL): Add check\_redis to ITL * [#3162](https://github.com/Icinga/icinga2/issues/3162) (ITL): Add check\_yum to ITL * [#3111](https://github.com/Icinga/icinga2/issues/3111) (ITL): CheckCommand for check\_interfaces ### Documentation * [#3319](https://github.com/Icinga/icinga2/issues/3319) (Documentation): Duplicate severity type in the documentation for SyslogLogger * [#3308](https://github.com/Icinga/icinga2/issues/3308) (Documentation): Fix global Zone example to "Global Configuration Zone for Templates" * [#3262](https://github.com/Icinga/icinga2/issues/3262) (Documentation): typo in docs * [#3166](https://github.com/Icinga/icinga2/issues/3166) (Documentation): Update gdb pretty printer docs w/ Python 3 ### Support * [#3298](https://github.com/Icinga/icinga2/issues/3298) (Packages): Don't re-download NSCP for every build * [#3239](https://github.com/Icinga/icinga2/issues/3239) (Packages): missing check\_perfmon.exe * [#3216](https://github.com/Icinga/icinga2/issues/3216) (Tests): Build fix for Boost 1.59 ## 2.3.8 (2015-07-21) ### Notes * Bugfixes ### Bug * [#3160](https://github.com/Icinga/icinga2/issues/3160) (Performance Data): Escaping does not work for OpenTSDB perfdata plugin * [#3151](https://github.com/Icinga/icinga2/issues/3151) (DB IDO): DB IDO: Do not update endpointstatus table on config updates * [#3120](https://github.com/Icinga/icinga2/issues/3120) (Configuration): Don't allow "ignore where" for groups when there's no "assign where" ### ITL * [#3161](https://github.com/Icinga/icinga2/issues/3161) (ITL): checkcommand disk does not check free inode - check\_disk * [#3152](https://github.com/Icinga/icinga2/issues/3152) (ITL): Wrong parameter for CheckCommand "ping-common-windows" ## 2.3.7 (2015-07-15) ### Notes * Bugfixes ### Bug * [#3148](https://github.com/Icinga/icinga2/issues/3148): Missing lock in ScriptUtils::Union * [#3147](https://github.com/Icinga/icinga2/issues/3147): Assertion failed in icinga::ScriptUtils::Intersection * [#3136](https://github.com/Icinga/icinga2/issues/3136) (DB IDO): DB IDO: endpoint\* tables are cleared on reload causing constraint violations * [#3134](https://github.com/Icinga/icinga2/issues/3134): Incorrect return value for the macro\(\) function * [#3114](https://github.com/Icinga/icinga2/issues/3114) (Configuration): Config parser ignores "ignore" in template definition * [#3061](https://github.com/Icinga/icinga2/issues/3061) (Cluster): Selective cluster reconnecting breaks client communication ### Documentation * [#3142](https://github.com/Icinga/icinga2/issues/3142) (Documentation): Enhance troubleshooting ssl errors & cluster replay log * [#3135](https://github.com/Icinga/icinga2/issues/3135) (Documentation): Wrong formatting in DB IDO extensions docs ## 2.3.6 (2015-07-08) ### Notes * Require openssl1 on sles11sp3 from Security Module repository * Bug in SLES 11's OpenSSL version 0.9.8j preventing verification of generated certificates. * Re-create these certificates with 2.3.6 linking against openssl1 (cli command or CSR auto-signing). * ITL: Add ldap, ntp_peer, mongodb and elasticsearch CheckCommand definitions * Bugfixes ### Bug * [#3118](https://github.com/Icinga/icinga2/issues/3118) (Cluster): Generated certificates cannot be verified w/ openssl 0.9.8j on SLES 11 * [#3098](https://github.com/Icinga/icinga2/issues/3098) (Cluster): Add log message for discarded cluster events \(e.g. from unauthenticated clients\) * [#3097](https://github.com/Icinga/icinga2/issues/3097): Fix stability issues in the TlsStream/Stream classes * [#3088](https://github.com/Icinga/icinga2/issues/3088) (Cluster): Windows client w/ command\_endpoint broken with $nscp\_path$ and NscpPath detection * [#3084](https://github.com/Icinga/icinga2/issues/3084) (CLI): node setup: indent accept\_config and accept\_commands * [#3074](https://github.com/Icinga/icinga2/issues/3074) (Notifications): Functions can't be specified as command arguments * [#2979](https://github.com/Icinga/icinga2/issues/2979) (CLI): port empty when using icinga2 node wizard ### ITL * [#3132](https://github.com/Icinga/icinga2/issues/3132) (ITL): new options for smtp CheckCommand * [#3125](https://github.com/Icinga/icinga2/issues/3125) (ITL): Add new options for ntp\_time CheckCommand * [#3110](https://github.com/Icinga/icinga2/issues/3110) (ITL): Add ntp\_peer CheckCommand * [#3103](https://github.com/Icinga/icinga2/issues/3103) (ITL): itl/plugins-contrib.d/\*.conf should point to PluginContribDir * [#3091](https://github.com/Icinga/icinga2/issues/3091) (ITL): Incorrect check\_ping.exe parameter in the ITL * [#3066](https://github.com/Icinga/icinga2/issues/3066) (ITL): snmpv3 CheckCommand: Add possibility to set securityLevel * [#3064](https://github.com/Icinga/icinga2/issues/3064) (ITL): Add elasticsearch checkcommand to itl * [#3031](https://github.com/Icinga/icinga2/issues/3031) (ITL): Missing 'snmp\_is\_cisco' in Manubulon snmp-memory command definition * [#3002](https://github.com/Icinga/icinga2/issues/3002) (ITL): Incorrect variable name in the ITL * [#2975](https://github.com/Icinga/icinga2/issues/2975) (ITL): Add "mongodb" CheckCommand definition * [#2963](https://github.com/Icinga/icinga2/issues/2963) (ITL): Add "ldap" CheckCommand for "check\_ldap" plugin ### Documentation * [#3126](https://github.com/Icinga/icinga2/issues/3126) (Documentation): Update getting started for Debian Jessie * [#3108](https://github.com/Icinga/icinga2/issues/3108) (Documentation): wrong default port documentated for nrpe * [#3099](https://github.com/Icinga/icinga2/issues/3099) (Documentation): Missing openssl verify in cluster troubleshooting docs * [#3096](https://github.com/Icinga/icinga2/issues/3096) (Documentation): Documentation for checks in an HA zone is wrong * [#3086](https://github.com/Icinga/icinga2/issues/3086) (Documentation): Wrong file reference in README.md * [#3085](https://github.com/Icinga/icinga2/issues/3085) (Documentation): Merge documentation fixes from GitHub * [#1793](https://github.com/Icinga/icinga2/issues/1793) (Documentation): add pagerduty notification documentation ### Support * [#3123](https://github.com/Icinga/icinga2/issues/3123) (Packages): Require gcc47-c++ on sles11 from SLES software development kit repository * [#3122](https://github.com/Icinga/icinga2/issues/3122) (Packages): mysql-devel is not available in sles11sp3 * [#3081](https://github.com/Icinga/icinga2/issues/3081) (Installation): changelog.py: Allow to define project, make custom\_fields and changes optional * [#3073](https://github.com/Icinga/icinga2/issues/3073) (Installation): Enhance changelog.py with wordpress blogpost output * [#2651](https://github.com/Icinga/icinga2/issues/2651) (Packages): Add Icinga 2 to Chocolatey Windows Repository ## 2.3.5 (2015-06-17) ### Notes * NSClient++ is now bundled with the Windows setup wizard and can optionally be installed * Windows Wizard: "include " is set by default * Windows Wizard: Add update mode * Plugins: Add check_perfmon plugin for Windows * ITL: Add CheckCommand objects for Windows plugins ("include ") * ITL: Add CheckCommand definitions for "mongodb", "iftraffic", "disk_smb" * ITL: Add arguments to CheckCommands "dns", "ftp", "tcp", "nscp" ### Enhancement * [#3009](https://github.com/Icinga/icinga2/issues/3009) (Configuration): Add the --load-all and --log options for nscp-local * [#3008](https://github.com/Icinga/icinga2/issues/3008) (Configuration): Include \ by default on Windows * [#2971](https://github.com/Icinga/icinga2/issues/2971) (Performance Data): Add timestamp support for PerfdataWriter * [#2817](https://github.com/Icinga/icinga2/issues/2817) (Configuration): Add CheckCommand objects for Windows plugins * [#2794](https://github.com/Icinga/icinga2/issues/2794) (Plugins): Add check\_perfmon plugin for Windows ### Bug * [#3051](https://github.com/Icinga/icinga2/issues/3051) (Plugins): plugins-contrib.d/databases.conf: wrong argument for mssql\_health * [#3043](https://github.com/Icinga/icinga2/issues/3043) (Compat): Multiline vars are broken in objects.cache output * [#3039](https://github.com/Icinga/icinga2/issues/3039) (Compat): Multi line output not correctly handled from compat channels * [#3007](https://github.com/Icinga/icinga2/issues/3007) (Configuration): Disk and 'icinga' services are missing in the default Windows config * [#3006](https://github.com/Icinga/icinga2/issues/3006) (Configuration): Some checks in the default Windows configuration fail * [#2986](https://github.com/Icinga/icinga2/issues/2986) (DB IDO): Missing custom attributes in backends if name is equal to object attribute * [#2952](https://github.com/Icinga/icinga2/issues/2952) (DB IDO): Incorrect type and state filter mapping for User objects in DB IDO * [#2951](https://github.com/Icinga/icinga2/issues/2951) (DB IDO): Downtimes are always "fixed" * [#2945](https://github.com/Icinga/icinga2/issues/2945) (DB IDO): Possible DB deadlock * [#2940](https://github.com/Icinga/icinga2/issues/2940) (Configuration): node update-config reports critical and warning * [#2935](https://github.com/Icinga/icinga2/issues/2935) (Configuration): WIN: syslog is not an enable-able feature in windows * [#2894](https://github.com/Icinga/icinga2/issues/2894) (DB IDO): Wrong timestamps w/ historical data replay in DB IDO * [#2839](https://github.com/Icinga/icinga2/issues/2839) (CLI): Node wont connect properly to master if host is is not set for Endpoint on new installs * [#2836](https://github.com/Icinga/icinga2/issues/2836): Icinga2 --version: Error showing Distribution * [#2819](https://github.com/Icinga/icinga2/issues/2819) (Configuration): Syntax Highlighting: host.address vs host.add ### ITL * [#3019](https://github.com/Icinga/icinga2/issues/3019) (ITL): Add 'iftraffic' to plugins-contrib check command definitions * [#3003](https://github.com/Icinga/icinga2/issues/3003) (ITL): Add 'disk\_smb' Plugin CheckCommand definition * [#2959](https://github.com/Icinga/icinga2/issues/2959) (ITL): 'disk': wrong order of threshold command arguments * [#2956](https://github.com/Icinga/icinga2/issues/2956) (ITL): Add arguments to "tcp" CheckCommand * [#2955](https://github.com/Icinga/icinga2/issues/2955) (ITL): Add arguments to "ftp" CheckCommand * [#2954](https://github.com/Icinga/icinga2/issues/2954) (ITL): Add arguments to "dns" CheckCommand * [#2949](https://github.com/Icinga/icinga2/issues/2949) (ITL): Add 'check\_drivesize' as nscp-local check command * [#2938](https://github.com/Icinga/icinga2/issues/2938) (ITL): Add SHOWALL to NSCP Checkcommand * [#2880](https://github.com/Icinga/icinga2/issues/2880) (ITL): Including \ on Linux fails with unregistered function ### Documentation * [#3072](https://github.com/Icinga/icinga2/issues/3072) (Documentation): Documentation: Move configuration before advanced topics * [#3069](https://github.com/Icinga/icinga2/issues/3069) (Documentation): Enhance cluster docs with HA command\_endpoints * [#3068](https://github.com/Icinga/icinga2/issues/3068) (Documentation): Enhance cluster/client troubleshooting * [#3062](https://github.com/Icinga/icinga2/issues/3062) (Documentation): Documentation: Update the link to register a new Icinga account * [#3059](https://github.com/Icinga/icinga2/issues/3059) (Documentation): Documentation: Typo * [#3057](https://github.com/Icinga/icinga2/issues/3057) (Documentation): Documentation: Extend Custom Attributes with the boolean type * [#3056](https://github.com/Icinga/icinga2/issues/3056) (Documentation): Wrong service table attributes in Livestatus documentation * [#3055](https://github.com/Icinga/icinga2/issues/3055) (Documentation): Documentation: Typo * [#3049](https://github.com/Icinga/icinga2/issues/3049) (Documentation): Update documentation for escape sequences * [#3036](https://github.com/Icinga/icinga2/issues/3036) (Documentation): Explain string concatenation in objects by real-world example * [#3035](https://github.com/Icinga/icinga2/issues/3035) (Documentation): Use a more simple example for passing command parameters * [#3033](https://github.com/Icinga/icinga2/issues/3033) (Documentation): Add local variable scope for \*Command to documentation \(host, service, etc\) * [#3032](https://github.com/Icinga/icinga2/issues/3032) (Documentation): Add typeof in 'assign/ignore where' expression as example * [#3030](https://github.com/Icinga/icinga2/issues/3030) (Documentation): Add examples for function usage in "set\_if" and "command" attributes * [#3024](https://github.com/Icinga/icinga2/issues/3024) (Documentation): Best practices: cluster config sync * [#3017](https://github.com/Icinga/icinga2/issues/3017) (Documentation): Update service apply for documentation * [#3015](https://github.com/Icinga/icinga2/issues/3015) (Documentation): Typo in Configuration Best Practice * [#2966](https://github.com/Icinga/icinga2/issues/2966) (Documentation): Include Windows support details in the documentation * [#2965](https://github.com/Icinga/icinga2/issues/2965) (Documentation): ITL Documentation: Add a link for passing custom attributes as command parameters * [#2950](https://github.com/Icinga/icinga2/issues/2950) (Documentation): Missing "\)" in last Apply Rules example * [#2279](https://github.com/Icinga/icinga2/issues/2279) (Documentation): Add documentation and CheckCommands for the windows plugins ### Support * [#3016](https://github.com/Icinga/icinga2/issues/3016) (Installation): Wrong permission etc on windows * [#3011](https://github.com/Icinga/icinga2/issues/3011) (Installation): Add support for installing NSClient++ in the Icinga 2 Windows wizard * [#3005](https://github.com/Icinga/icinga2/issues/3005) (Installation): Determine NSClient++ installation path using MsiGetComponentPath * [#3004](https://github.com/Icinga/icinga2/issues/3004) (Installation): --scm-installs fails when the service is already installed * [#2994](https://github.com/Icinga/icinga2/issues/2994) (Installation): Bundle NSClient++ in Windows Installer * [#2973](https://github.com/Icinga/icinga2/issues/2973) (Packages): SPEC: Give group write permissions for perfdata dir * [#2451](https://github.com/Icinga/icinga2/issues/2451) (Installation): Extend Windows installer with an update mode ## 2.3.4 (2015-04-20) ### Notes * ITL: Check commands for various databases * Improve validation messages for time periods * Update max_check_attempts in generic-{host,service} templates * Update logrotate configuration * Bugfixes ### Enhancement * [#2841](https://github.com/Icinga/icinga2/issues/2841): Improve timeperiod validation error messages * [#2791](https://github.com/Icinga/icinga2/issues/2791) (Cluster): Agent Wizard: add options for API defaults ### Bug * [#2903](https://github.com/Icinga/icinga2/issues/2903) (Configuration): custom attributes with recursive macro function calls causing sigabrt * [#2898](https://github.com/Icinga/icinga2/issues/2898) (CLI): troubleshoot truncates crash reports * [#2886](https://github.com/Icinga/icinga2/issues/2886): Acknowledging problems w/ expire time does not add the expiry information to the related comment for IDO and compat * [#2883](https://github.com/Icinga/icinga2/issues/2883) (Notifications): Multiple log messages w/ "Attempting to send notifications for notification object" * [#2882](https://github.com/Icinga/icinga2/issues/2882) (DB IDO): scheduled\_downtime\_depth column is not reset when a downtime ends or when a downtime is being removed * [#2881](https://github.com/Icinga/icinga2/issues/2881) (DB IDO): Downtimes which have been triggered are not properly recorded in the database * [#2878](https://github.com/Icinga/icinga2/issues/2878) (DB IDO): Don't update scheduleddowntime table w/ trigger\_time column when only adding a downtime * [#2855](https://github.com/Icinga/icinga2/issues/2855): Fix complexity class for Dictionary::Get * [#2853](https://github.com/Icinga/icinga2/issues/2853) (CLI): Node wizard should only accept 'y', 'n', 'Y' and 'N' as answers for boolean questions * [#2842](https://github.com/Icinga/icinga2/issues/2842) (Configuration): Default max\_check\_attempts should be lower for hosts than for services * [#2840](https://github.com/Icinga/icinga2/issues/2840) (Configuration): Validation errors for time ranges which span the DST transition * [#2827](https://github.com/Icinga/icinga2/issues/2827) (Configuration): logrotate does not work * [#2801](https://github.com/Icinga/icinga2/issues/2801) (Cluster): command\_endpoint check\_results are not replicated to other endpoints in the same zone ### ITL * [#2891](https://github.com/Icinga/icinga2/issues/2891) (ITL): web.conf is not in the RPM package * [#2890](https://github.com/Icinga/icinga2/issues/2890) (ITL): check\_disk order of command arguments * [#2834](https://github.com/Icinga/icinga2/issues/2834) (ITL): Add arguments to the UPS check * [#2770](https://github.com/Icinga/icinga2/issues/2770) (ITL): Add database plugins to ITL ### Documentation * [#2902](https://github.com/Icinga/icinga2/issues/2902) (Documentation): Documentation: set\_if usage with boolean values and functions * [#2876](https://github.com/Icinga/icinga2/issues/2876) (Documentation): Typo in graphite feature enable documentation * [#2868](https://github.com/Icinga/icinga2/issues/2868) (Documentation): Fix a typo * [#2843](https://github.com/Icinga/icinga2/issues/2843) (Documentation): Add explanatory note for Icinga2 client documentation * [#2837](https://github.com/Icinga/icinga2/issues/2837) (Documentation): Fix a minor markdown error * [#2832](https://github.com/Icinga/icinga2/issues/2832) (Documentation): Reword documentation of check\_address ### Support * [#2888](https://github.com/Icinga/icinga2/issues/2888) (Installation): Vim syntax: Match groups before host/service/user objects * [#2852](https://github.com/Icinga/icinga2/issues/2852) (Installation): Windows Build: Flex detection * [#2793](https://github.com/Icinga/icinga2/issues/2793) (Packages): logrotate doesn't work on Ubuntu ## 2.3.3 (2015-03-26) ### Notes * New function: parse_performance_data * Include more details in --version * Improve documentation * Bugfixes ### Enhancement * [#2771](https://github.com/Icinga/icinga2/issues/2771): Include more details in --version * [#2743](https://github.com/Icinga/icinga2/issues/2743): New function: parse\_performance\_data * [#2737](https://github.com/Icinga/icinga2/issues/2737) (Notifications): Show state/type filter names in notice/debug log ### Bug * [#2828](https://github.com/Icinga/icinga2/issues/2828): Array in command arguments doesn't work * [#2818](https://github.com/Icinga/icinga2/issues/2818) (Configuration): Local variables in "apply for" are overridden * [#2816](https://github.com/Icinga/icinga2/issues/2816) (CLI): Segmentation fault when executing "icinga2 pki new-cert" * [#2812](https://github.com/Icinga/icinga2/issues/2812) (Configuration): Return doesn't work inside loops * [#2807](https://github.com/Icinga/icinga2/issues/2807) (Configuration): Figure out why command validators are not triggered * [#2778](https://github.com/Icinga/icinga2/issues/2778) (Configuration): object Notification + apply Service fails with error "...refers to service which doesn't exist" * [#2772](https://github.com/Icinga/icinga2/issues/2772) (Plugins): Plugin "check\_http" is missing in Windows environments * [#2768](https://github.com/Icinga/icinga2/issues/2768) (Configuration): Add missing keywords in the syntax highlighting files * [#2760](https://github.com/Icinga/icinga2/issues/2760): Don't ignore extraneous arguments for functions * [#2753](https://github.com/Icinga/icinga2/issues/2753) (DB IDO): Don't update custom vars for each status update * [#2752](https://github.com/Icinga/icinga2/issues/2752): startup.log broken when the DB schema needs an update * [#2749](https://github.com/Icinga/icinga2/issues/2749) (Configuration): Missing config validator for command arguments 'set\_if' * [#2718](https://github.com/Icinga/icinga2/issues/2718) (Configuration): Update syntax highlighting for 2.3 features * [#2557](https://github.com/Icinga/icinga2/issues/2557) (Configuration): Improve error message for invalid field access * [#2548](https://github.com/Icinga/icinga2/issues/2548) (Configuration): Fix VIM syntax highlighting for comments ### ITL * [#2823](https://github.com/Icinga/icinga2/issues/2823) (ITL): wrong 'dns\_lookup' custom attribute default in command-plugins.conf * [#2799](https://github.com/Icinga/icinga2/issues/2799) (ITL): Add "random" CheckCommand for test and demo purposes ### Documentation * [#2825](https://github.com/Icinga/icinga2/issues/2825) (Documentation): Fix incorrect perfdata templates in the documentation * [#2806](https://github.com/Icinga/icinga2/issues/2806) (Documentation): Move release info in INSTALL.md into a separate file * [#2779](https://github.com/Icinga/icinga2/issues/2779) (Documentation): Correct HA documentation * [#2777](https://github.com/Icinga/icinga2/issues/2777) (Documentation): Typo and invalid example in the runtime macro documentation * [#2776](https://github.com/Icinga/icinga2/issues/2776) (Documentation): Remove prompt to create a TicketSalt from the wizard * [#2775](https://github.com/Icinga/icinga2/issues/2775) (Documentation): Explain processing logic/order of apply rules with for loops * [#2774](https://github.com/Icinga/icinga2/issues/2774) (Documentation): Revamp migration documentation * [#2773](https://github.com/Icinga/icinga2/issues/2773) (Documentation): Typo in doc library-reference * [#2765](https://github.com/Icinga/icinga2/issues/2765) (Documentation): Fix a typo in the documentation of ICINGA2\_WITH\_MYSQL and ICINGA2\_WITH\_PGSQL * [#2756](https://github.com/Icinga/icinga2/issues/2756) (Documentation): Add "access objects at runtime" examples to advanced section * [#2738](https://github.com/Icinga/icinga2/issues/2738) (Documentation): Update documentation for "apply for" rules * [#2501](https://github.com/Icinga/icinga2/issues/2501) (Documentation): Re-order the object types in alphabetical order ### Support * [#2762](https://github.com/Icinga/icinga2/issues/2762) (Installation): Flex version check does not reject unsupported versions * [#2761](https://github.com/Icinga/icinga2/issues/2761) (Installation): Build warnings with CMake 3.1.3 ## 2.3.2 (2015-03-12) ### Notes * Bugfixes ### Bug * [#2747](https://github.com/Icinga/icinga2/issues/2747): Log message for cli commands breaks the init script ## 2.3.1 (2015-03-12) ### Notes * Bugfixes Please note that this version fixes the default thresholds for the disk check which were inadvertently broken in 2.3.0; if you're using percent-based custom thresholds you will need to add the '%' sign to your custom attributes ### Enhancement * [#2717](https://github.com/Icinga/icinga2/issues/2717) (Configuration): Implement String\#contains ### Bug * [#2739](https://github.com/Icinga/icinga2/issues/2739): Crash in Dependency::Stop * [#2736](https://github.com/Icinga/icinga2/issues/2736): Fix formatting for the GDB stacktrace * [#2735](https://github.com/Icinga/icinga2/issues/2735): Make sure that the /var/log/icinga2/crash directory exists * [#2731](https://github.com/Icinga/icinga2/issues/2731) (Configuration): Config validation fail because of unexpected new-line * [#2727](https://github.com/Icinga/icinga2/issues/2727) (Cluster): Api heartbeat message response time problem * [#2716](https://github.com/Icinga/icinga2/issues/2716) (CLI): Missing program name in 'icinga2 --version' * [#2672](https://github.com/Icinga/icinga2/issues/2672): Kill signal sent only to check process, not whole process group ### ITL * [#2483](https://github.com/Icinga/icinga2/issues/2483) (ITL): Fix check\_disk thresholds: make sure partitions are the last arguments ### Documentation * [#2732](https://github.com/Icinga/icinga2/issues/2732) (Documentation): Update documentation for DB IDO HA Run-Once * [#2728](https://github.com/Icinga/icinga2/issues/2728) (Documentation): Fix check\_disk default thresholds and document the change of unit ### Support * [#2742](https://github.com/Icinga/icinga2/issues/2742) (Packages): Debian packages do not create /var/log/icinga2/crash ## 2.3.0 (2015-03-10) ### Notes * Improved configuration validation * Unnecessary escapes are no longer permitted (e.g. \') * Dashes are no longer permitted in identifier names (as their semantics are ambiguous) * Unused values are detected (e.g. { "-M" }) * Validation for time ranges has been improved * Additional validation rules for some object types (Notification and User) * New language features * Implement a separate type for boolean values * Support for user-defined functions * Support for conditional statements (if/else) * Support for 'for' and 'while' loops * Support for local variables using the 'var' keyword * New operators: % (modulo), ^ (xor), - (unary minus) and + (unary plus) * Implemented prototype-based methods for most built-in types (e.g. [ 3, 2 ].sort()) * Explicit access to local and global variables using the 'locals' and 'globals' keywords * Changed the order in which filters are evaluated for apply rules with 'for' * Make type objects accessible as global variables * Support for using functions in custom attributes * Access objects and their runtime attributes in functions (e.g. get_host(NodeName).state) * ITL improvements * Additional check commands were added to the ITL * Additional arguments for existing check commands * CLI improvements * Add the 'icinga2 console' CLI command which can be used to test expressions * Add the 'icinga2 troubleshoot' CLI command for collecting troubleshooting information * Performance improvements for the 'icinga2 node update-config' CLI command * Implement argument auto-completion for short options (e.g. daemon -c) * 'node setup' and 'node wizard' create backups for existing certificate files * Add ignore_soft_states option for Dependency object configuration * Fewer threads are used for socket I/O * Flapping detection for hosts and services is disabled by default * Added support for OpenTSDB * New Livestatus tables: hostsbygroup, servicesbygroup, servicesbyhostgroup * Include GDB backtrace in crash reports * Various documentation improvements * Solved a number of issues where cluster instances would not reconnect after intermittent connection problems * A lot of other, minor changes * [DB IDO schema upgrade](17-upgrading-icinga-2.md#upgrading-icinga-2) to `1.13.0` required! ### Enhancement * [#2704](https://github.com/Icinga/icinga2/issues/2704): Support the SNI TLS extension * [#2702](https://github.com/Icinga/icinga2/issues/2702): Add validator for time ranges in ScheduledDowntime objects * [#2701](https://github.com/Icinga/icinga2/issues/2701): Remove macro argument for IMPL\_TYPE\_LOOKUP * [#2696](https://github.com/Icinga/icinga2/issues/2696): Include GDB backtrace in crash reports * [#2678](https://github.com/Icinga/icinga2/issues/2678) (Configuration): Add support for else-if * [#2663](https://github.com/Icinga/icinga2/issues/2663) (Livestatus): Change Livestatus query log level to 'notice' * [#2657](https://github.com/Icinga/icinga2/issues/2657) (Cluster): Show slave lag for the cluster-zone check * [#2635](https://github.com/Icinga/icinga2/issues/2635) (Configuration): introduce time dependent variable values * [#2634](https://github.com/Icinga/icinga2/issues/2634) (Cluster): Add the ability to use a CA certificate as a way of verifying hosts for CSR autosigning * [#2609](https://github.com/Icinga/icinga2/issues/2609): udp check command is missing arguments. * [#2604](https://github.com/Icinga/icinga2/issues/2604) (CLI): Backup certificate files in 'node setup' * [#2601](https://github.com/Icinga/icinga2/issues/2601) (Configuration): Implement continue/break keywords * [#2600](https://github.com/Icinga/icinga2/issues/2600) (Configuration): Implement support for Json.encode and Json.decode * [#2591](https://github.com/Icinga/icinga2/issues/2591) (Performance Data): Add timestamp support for Graphite * [#2588](https://github.com/Icinga/icinga2/issues/2588) (Configuration): Add path information for objects in object list * [#2578](https://github.com/Icinga/icinga2/issues/2578) (Configuration): Implement Array\#join * [#2553](https://github.com/Icinga/icinga2/issues/2553) (Configuration): Implement validator support for function objects * [#2552](https://github.com/Icinga/icinga2/issues/2552) (Configuration): Make operators &&, || behave like in JavaScript * [#2546](https://github.com/Icinga/icinga2/issues/2546): Add macros $host.check\_source$ and $service.check\_source$ * [#2544](https://github.com/Icinga/icinga2/issues/2544) (Configuration): Implement the while keyword * [#2531](https://github.com/Icinga/icinga2/issues/2531) (Configuration): Implement keywords to explicitly access globals/locals * [#2522](https://github.com/Icinga/icinga2/issues/2522) (CLI): Make invalid log-severity option output an error instead of a warning * [#2509](https://github.com/Icinga/icinga2/issues/2509): Host/Service runtime macro downtime\_depth * [#2491](https://github.com/Icinga/icinga2/issues/2491) (Configuration): Assignments shouldn't have a "return" value * [#2488](https://github.com/Icinga/icinga2/issues/2488): Implement additional methods for strings * [#2487](https://github.com/Icinga/icinga2/issues/2487) (CLI): Figure out what to do about libreadline \(license\) * [#2486](https://github.com/Icinga/icinga2/issues/2486) (CLI): Figure out a better name for the repl command * [#2466](https://github.com/Icinga/icinga2/issues/2466) (Configuration): Implement line-continuation for the "console" command * [#2456](https://github.com/Icinga/icinga2/issues/2456) (CLI): feature enable should use relative symlinks * [#2439](https://github.com/Icinga/icinga2/issues/2439) (Configuration): Document the new language features in 2.3 * [#2437](https://github.com/Icinga/icinga2/issues/2437) (CLI): Implement readline support for the "console" CLI command * [#2432](https://github.com/Icinga/icinga2/issues/2432) (CLI): Backport i2tcl's error reporting functionality into "icinga2 console" * [#2429](https://github.com/Icinga/icinga2/issues/2429) (Configuration): Figure out how variable scopes should work * [#2426](https://github.com/Icinga/icinga2/issues/2426) (Configuration): Implement a way to call methods on objects * [#2421](https://github.com/Icinga/icinga2/issues/2421) (Configuration): Implement a way to remove dictionary keys * [#2418](https://github.com/Icinga/icinga2/issues/2418) (Plugins): Windows plugins should behave like their Linux cousins * [#2408](https://github.com/Icinga/icinga2/issues/2408) (Configuration): ConfigCompiler::HandleInclude should return an inline dictionary * [#2407](https://github.com/Icinga/icinga2/issues/2407) (Configuration): Implement a boolean sub-type for the Value class * [#2405](https://github.com/Icinga/icinga2/issues/2405): Disallow calling strings as functions * [#2396](https://github.com/Icinga/icinga2/issues/2396) (Configuration): Evaluate usage of function\(\) * [#2391](https://github.com/Icinga/icinga2/issues/2391): Improve output of ToString for type objects * [#2390](https://github.com/Icinga/icinga2/issues/2390): Register type objects as global variables * [#2367](https://github.com/Icinga/icinga2/issues/2367) (Configuration): The lexer shouldn't accept escapes for characters which don't have to be escaped * [#2365](https://github.com/Icinga/icinga2/issues/2365) (DB IDO): Implement socket\_path attribute for the IdoMysqlConnection class * [#2355](https://github.com/Icinga/icinga2/issues/2355) (Configuration): Implement official support for user-defined functions and the "for" keyword * [#2351](https://github.com/Icinga/icinga2/issues/2351) (Plugins): Windows agent is missing the standard plugin check\_ping * [#2348](https://github.com/Icinga/icinga2/issues/2348) (Plugins): Plugin Check Commands: Add icmp * [#2324](https://github.com/Icinga/icinga2/issues/2324) (Configuration): Implement the "if" and "else" keywords * [#2323](https://github.com/Icinga/icinga2/issues/2323) (Configuration): Figure out whether Number + String should implicitly convert the Number argument to a string * [#2322](https://github.com/Icinga/icinga2/issues/2322) (Configuration): Make the config parser thread-safe * [#2318](https://github.com/Icinga/icinga2/issues/2318) (Configuration): Implement the % operator * [#2312](https://github.com/Icinga/icinga2/issues/2312): Move the cast functions into libbase * [#2310](https://github.com/Icinga/icinga2/issues/2310) (Configuration): Implement unit tests for the config parser * [#2304](https://github.com/Icinga/icinga2/issues/2304): Implement an option to disable building the Demo component * [#2303](https://github.com/Icinga/icinga2/issues/2303): Implement an option to disable building the Livestatus module * [#2300](https://github.com/Icinga/icinga2/issues/2300) (Notifications): Implement the DISABLE\_HOST\_SVC\_NOTIFICATIONS and ENABLE\_HOST\_SVC\_NOTIFICATIONS commands * [#2298](https://github.com/Icinga/icinga2/issues/2298) (Plugins): Missing check\_disk output on Windows * [#2294](https://github.com/Icinga/icinga2/issues/2294) (Configuration): Implement an AST Expression for T\_CONST * [#2290](https://github.com/Icinga/icinga2/issues/2290): Rename \_DEBUG to I2\_DEBUG * [#2286](https://github.com/Icinga/icinga2/issues/2286) (Configuration): Redesign how stack frames work for scripts * [#2265](https://github.com/Icinga/icinga2/issues/2265): ConfigCompiler::Compile\* should return an AST node * [#2264](https://github.com/Icinga/icinga2/issues/2264) (Configuration): ConfigCompiler::HandleInclude\* should return an AST node * [#2262](https://github.com/Icinga/icinga2/issues/2262) (CLI): Add an option that hides CLI commands * [#2260](https://github.com/Icinga/icinga2/issues/2260) (Configuration): Evaluate apply/object rules when the parent objects are created * [#2211](https://github.com/Icinga/icinga2/issues/2211) (Configuration): Variable from for loop not usable in assign statement * [#2186](https://github.com/Icinga/icinga2/issues/2186) (Configuration): Access object runtime attributes in custom vars & command arguments * [#2176](https://github.com/Icinga/icinga2/issues/2176) (Configuration): Please add labels in SNMP checks * [#2043](https://github.com/Icinga/icinga2/issues/2043) (Livestatus): Livestatus: Add GroupBy tables: hostsbygroup, servicesbygroup, servicesbyhostgroup * [#2027](https://github.com/Icinga/icinga2/issues/2027) (Configuration): Add parent soft states option to Dependency object configuration * [#2000](https://github.com/Icinga/icinga2/issues/2000) (Performance Data): Add OpenTSDB Writer * [#1959](https://github.com/Icinga/icinga2/issues/1959) (Configuration): extended Manubulon SNMP Check Plugin Command * [#1890](https://github.com/Icinga/icinga2/issues/1890) (DB IDO): IDO should fill program\_end\_time on a clean shutdown * [#1866](https://github.com/Icinga/icinga2/issues/1866) (Notifications): Disable flapping detection by default * [#1859](https://github.com/Icinga/icinga2/issues/1859): Run CheckCommands with C locale \(workaround for comma vs dot and plugin api bug\) * [#1783](https://github.com/Icinga/icinga2/issues/1783) (Plugins): Plugin Check Commands: add check\_vmware\_esx * [#1733](https://github.com/Icinga/icinga2/issues/1733) (Configuration): Disallow side-effect-free r-value expressions in expression lists * [#1507](https://github.com/Icinga/icinga2/issues/1507): Don't spawn threads for network connections * [#404](https://github.com/Icinga/icinga2/issues/404) (CLI): Add troubleshooting collect cli command ### Bug * [#2707](https://github.com/Icinga/icinga2/issues/2707) (DB IDO): Crash when using ido-pgsql * [#2706](https://github.com/Icinga/icinga2/issues/2706): Icinga2 shuts down when service is reloaded * [#2703](https://github.com/Icinga/icinga2/issues/2703) (Configuration): Attribute hints don't work for nested attributes * [#2699](https://github.com/Icinga/icinga2/issues/2699) (Configuration): Dependency: Validate \*\_{host,service}\_name objects on their existance * [#2698](https://github.com/Icinga/icinga2/issues/2698) (Livestatus): Improve Livestatus query performance * [#2697](https://github.com/Icinga/icinga2/issues/2697) (Configuration): Memory leak in Expression::GetReference * [#2695](https://github.com/Icinga/icinga2/issues/2695) (Configuration): else if doesn't work without an else branch * [#2693](https://github.com/Icinga/icinga2/issues/2693): Check whether the new TimePeriod validator is working as expected * [#2692](https://github.com/Icinga/icinga2/issues/2692) (CLI): Resource leak in TroubleshootCommand::ObjectInfo * [#2691](https://github.com/Icinga/icinga2/issues/2691) (CLI): Resource leak in TroubleshootCommand::Run * [#2689](https://github.com/Icinga/icinga2/issues/2689): Check if scheduled downtimes work properly * [#2688](https://github.com/Icinga/icinga2/issues/2688) (Plugins): check\_memory tool shows incorrect memory size on windows * [#2685](https://github.com/Icinga/icinga2/issues/2685) (Cluster): Don't accept config updates for zones for which we have an authoritative copy of the config * [#2684](https://github.com/Icinga/icinga2/issues/2684) (Cluster): Icinga crashed on SocketEvent * [#2683](https://github.com/Icinga/icinga2/issues/2683) (Cluster): Crash in ApiClient::TimeoutTimerHandler * [#2680](https://github.com/Icinga/icinga2/issues/2680): Deadlock in TlsStream::Handshake * [#2679](https://github.com/Icinga/icinga2/issues/2679) (Cluster): Deadlock in ApiClient::Disconnect * [#2677](https://github.com/Icinga/icinga2/issues/2677): Crash in SocketEvents::Register * [#2676](https://github.com/Icinga/icinga2/issues/2676) (Livestatus): Windows build fails * [#2674](https://github.com/Icinga/icinga2/issues/2674) (DB IDO): Hosts: process\_performance\_data = 0 in database even though enable\_perfdata = 1 in config * [#2671](https://github.com/Icinga/icinga2/issues/2671) (DB IDO): Crash in DbObject::SendStatusUpdate * [#2670](https://github.com/Icinga/icinga2/issues/2670) (Compat): Valgrind warning for ExternalCommandListener::CommandPipeThread * [#2669](https://github.com/Icinga/icinga2/issues/2669): Crash in ApiEvents::RepositoryTimerHandler * [#2665](https://github.com/Icinga/icinga2/issues/2665) (Livestatus): livestatus limit header not working * [#2660](https://github.com/Icinga/icinga2/issues/2660) (Configuration): apply-for incorrectly converts loop var to string * [#2659](https://github.com/Icinga/icinga2/issues/2659) (Configuration): Config parser fails non-deterministic on Notification missing Checkable * [#2658](https://github.com/Icinga/icinga2/issues/2658) (CLI): Crash in icinga2 console * [#2654](https://github.com/Icinga/icinga2/issues/2654) (DB IDO): Deadlock with DB IDO dump and forcing a scheduled check * [#2650](https://github.com/Icinga/icinga2/issues/2650) (CLI): SIGSEGV in CLI * [#2647](https://github.com/Icinga/icinga2/issues/2647) (DB IDO): Icinga doesn't update long\_output in DB * [#2646](https://github.com/Icinga/icinga2/issues/2646) (Cluster): Misleading ApiListener connection log messages on a master \(Endpoint vs Zone\) * [#2644](https://github.com/Icinga/icinga2/issues/2644) (CLI): Figure out why 'node update-config' becomes slow over time * [#2642](https://github.com/Icinga/icinga2/issues/2642): Icinga 2 sometimes doesn't reconnect to the master * [#2641](https://github.com/Icinga/icinga2/issues/2641) (Cluster): ICINGA process crashes every night * [#2639](https://github.com/Icinga/icinga2/issues/2639) (CLI): Build fails on Debian squeeze * [#2636](https://github.com/Icinga/icinga2/issues/2636): Exception in WorkQueue::StatusTimerHandler * [#2631](https://github.com/Icinga/icinga2/issues/2631) (Cluster): deadlock in client connection * [#2630](https://github.com/Icinga/icinga2/issues/2630) (Cluster): Don't request heartbeat messages until after we've synced the log * [#2627](https://github.com/Icinga/icinga2/issues/2627) (Livestatus): Livestatus query on commands table with custom vars fails * [#2626](https://github.com/Icinga/icinga2/issues/2626) (DB IDO): Icinga2 segfaults when issuing postgresql queries * [#2622](https://github.com/Icinga/icinga2/issues/2622): "node wizard" crashes * [#2621](https://github.com/Icinga/icinga2/issues/2621): Don't attempt to restore program state from non-existing state file * [#2618](https://github.com/Icinga/icinga2/issues/2618) (DB IDO): DB IDO {host,service}checks command\_line value is "Object of type 'icinga::Array'" * [#2617](https://github.com/Icinga/icinga2/issues/2617) (DB IDO): Indicate that Icinga2 is shutting down in case of a fatal error * [#2615](https://github.com/Icinga/icinga2/issues/2615): Make the arguments for the stats functions const-ref * [#2613](https://github.com/Icinga/icinga2/issues/2613) (DB IDO): DB IDO: Duplicate entry icinga\_scheduleddowntime * [#2608](https://github.com/Icinga/icinga2/issues/2608) (Plugins): Ignore the -X option for check\_disk on Windows * [#2605](https://github.com/Icinga/icinga2/issues/2605): Compiler warnings * [#2599](https://github.com/Icinga/icinga2/issues/2599) (Cluster): Agent writes CR CR LF in synchronized config files * [#2598](https://github.com/Icinga/icinga2/issues/2598): Added downtimes must be triggered immediately if checkable is Not-OK * [#2597](https://github.com/Icinga/icinga2/issues/2597) (Cluster): Config sync authoritative file never created * [#2596](https://github.com/Icinga/icinga2/issues/2596) (Compat): StatusDataWriter: Wrong host notification filters \(broken fix in \#8192\) * [#2593](https://github.com/Icinga/icinga2/issues/2593) (Compat): last\_hard\_state missing in StatusDataWriter * [#2589](https://github.com/Icinga/icinga2/issues/2589) (Configuration): Stacktrace on Endpoint not belonging to a zone or multiple zones * [#2586](https://github.com/Icinga/icinga2/issues/2586): Icinga2 master doesn't change check-status when "accept\_commands = true" is not set at client node * [#2579](https://github.com/Icinga/icinga2/issues/2579) (Configuration): Apply rule '' for host does not match anywhere! * [#2572](https://github.com/Icinga/icinga2/issues/2572) (Cluster): Incorrectly formatted timestamp in .timestamp file * [#2570](https://github.com/Icinga/icinga2/issues/2570): Crash in ScheduledDowntime::CreateNextDowntime * [#2569](https://github.com/Icinga/icinga2/issues/2569): PidPath, VarsPath, ObjectsPath and StatePath no longer read from init.conf * [#2566](https://github.com/Icinga/icinga2/issues/2566) (Configuration): Don't allow comparison of strings and numbers * [#2562](https://github.com/Icinga/icinga2/issues/2562) (Cluster): ApiListener::ReplayLog shouldn't hold mutex lock during call to Socket::Poll * [#2560](https://github.com/Icinga/icinga2/issues/2560): notify flag is ignored in ACKNOWLEDGE\_\*\_PROBLEM commands * [#2559](https://github.com/Icinga/icinga2/issues/2559) (DB IDO): Duplicate entry on icinga\_hoststatus * [#2556](https://github.com/Icinga/icinga2/issues/2556) (CLI): Running icinga2 command as non privilged user raises error * [#2551](https://github.com/Icinga/icinga2/issues/2551) (Livestatus): Livestatus operator =~ is not case-insensitive * [#2542](https://github.com/Icinga/icinga2/issues/2542) (CLI): icinga2 node wizard: Create backups of certificates * [#2539](https://github.com/Icinga/icinga2/issues/2539) (Cluster): Report missing command objects on remote agent * [#2533](https://github.com/Icinga/icinga2/issues/2533) (Cluster): Problems using command\_endpoint inside HA zone * [#2529](https://github.com/Icinga/icinga2/issues/2529) (CLI): CLI console fails to report errors in included files * [#2526](https://github.com/Icinga/icinga2/issues/2526) (Configuration): Deadlock when accessing loop variable inside of the loop * [#2525](https://github.com/Icinga/icinga2/issues/2525) (Configuration): Lexer term for T\_ANGLE\_STRING is too aggressive * [#2513](https://github.com/Icinga/icinga2/issues/2513) (CLI): icinga2 node update should not write config for blacklisted zones/host * [#2503](https://github.com/Icinga/icinga2/issues/2503) (CLI): Argument auto-completion doesn't work for short options * [#2502](https://github.com/Icinga/icinga2/issues/2502): group assign fails with bad lexical cast when evaluating rules * [#2497](https://github.com/Icinga/icinga2/issues/2497): Exception on missing config files * [#2494](https://github.com/Icinga/icinga2/issues/2494) (Livestatus): Error messages when stopping Icinga * [#2493](https://github.com/Icinga/icinga2/issues/2493): Compiler warnings * [#2492](https://github.com/Icinga/icinga2/issues/2492): Segfault on icinga::String::operator= when compiling configuration * [#2485](https://github.com/Icinga/icinga2/issues/2485) (Configuration): parsing include\_recursive * [#2482](https://github.com/Icinga/icinga2/issues/2482) (Configuration): escaped backslash in string literals * [#2467](https://github.com/Icinga/icinga2/issues/2467) (CLI): Icinga crashes when config file name is invalid * [#2465](https://github.com/Icinga/icinga2/issues/2465) (Configuration): Debug info for indexer is incorrect * [#2457](https://github.com/Icinga/icinga2/issues/2457): Config file passing validation causes segfault * [#2452](https://github.com/Icinga/icinga2/issues/2452) (Cluster): Agent checks fail when there's already a host with the same name * [#2448](https://github.com/Icinga/icinga2/issues/2448) (Configuration): User::ValidateFilters isn't being used * [#2447](https://github.com/Icinga/icinga2/issues/2447) (Configuration): ConfigCompilerContext::WriteObject crashes after ConfigCompilerContext::FinishObjectsFile was called * [#2445](https://github.com/Icinga/icinga2/issues/2445) (Configuration): segfault on startup * [#2442](https://github.com/Icinga/icinga2/issues/2442) (DB IDO): POSTGRES IDO: invalid syntax for integer: "true" while trying to update table icinga\_hoststatus * [#2441](https://github.com/Icinga/icinga2/issues/2441) (CLI): console: Don't repeat line when we're reporting an error for the last line * [#2436](https://github.com/Icinga/icinga2/issues/2436) (Configuration): Modulo 0 crashes Icinga * [#2435](https://github.com/Icinga/icinga2/issues/2435) (Configuration): Location info for strings is incorrect * [#2434](https://github.com/Icinga/icinga2/issues/2434) (Configuration): Setting an attribute on an r-value fails * [#2433](https://github.com/Icinga/icinga2/issues/2433) (Configuration): Confusing error message when trying to set a field on a string * [#2431](https://github.com/Icinga/icinga2/issues/2431) (Configuration): icinga 2 Config Error needs to be more verbose * [#2428](https://github.com/Icinga/icinga2/issues/2428) (Configuration): Debug visualizer for the Value class is broken * [#2427](https://github.com/Icinga/icinga2/issues/2427) (Configuration): if doesn't work for non-boolean arguments * [#2423](https://github.com/Icinga/icinga2/issues/2423) (Configuration): Require at least one user for notification objects \(user or as member of user\_groups\) * [#2419](https://github.com/Icinga/icinga2/issues/2419) (Configuration): Confusing error message for import * [#2410](https://github.com/Icinga/icinga2/issues/2410): The Boolean type change broke set\_if * [#2406](https://github.com/Icinga/icinga2/issues/2406) (Configuration): len\(\) overflows * [#2395](https://github.com/Icinga/icinga2/issues/2395) (Configuration): operator precedence for % and \> is incorrect * [#2388](https://github.com/Icinga/icinga2/issues/2388): Value\(""\).IsEmpty\(\) should return true * [#2379](https://github.com/Icinga/icinga2/issues/2379) (Cluster): Windows Agent: Missing directory "zones" in setup * [#2375](https://github.com/Icinga/icinga2/issues/2375) (Configuration): Config validator doesn't show in which file the error was found * [#2362](https://github.com/Icinga/icinga2/issues/2362): Serialize\(\) fails to serialize objects which don't have a registered type * [#2361](https://github.com/Icinga/icinga2/issues/2361): Fix warnings when using CMake 3.1.0 * [#2346](https://github.com/Icinga/icinga2/issues/2346) (DB IDO): Missing persistent\_comment, notify\_contact columns for acknowledgement table * [#2329](https://github.com/Icinga/icinga2/issues/2329) (Configuration): - shouldn't be allowed in identifiers * [#2326](https://github.com/Icinga/icinga2/issues/2326): Compiler warnings * [#2320](https://github.com/Icinga/icinga2/issues/2320) (Configuration): - operator doesn't work in expressions * [#2319](https://github.com/Icinga/icinga2/issues/2319) (Configuration): Set expression should check whether LHS is a null pointer * [#2317](https://github.com/Icinga/icinga2/issues/2317) (Configuration): Validate array subscripts * [#2316](https://github.com/Icinga/icinga2/issues/2316) (Configuration): The \_\_return keyword is broken * [#2315](https://github.com/Icinga/icinga2/issues/2315) (Configuration): Return values for functions are broken * [#2314](https://github.com/Icinga/icinga2/issues/2314): Scoping rules for "for" are broken * [#2313](https://github.com/Icinga/icinga2/issues/2313) (Configuration): Unterminated string literals should cause parser to return an error * [#2308](https://github.com/Icinga/icinga2/issues/2308) (Configuration): Change parameter type for include and include\_recursive to T\_STRING * [#2307](https://github.com/Icinga/icinga2/issues/2307) (Configuration): Fix the shift/reduce conflicts in the parser * [#2289](https://github.com/Icinga/icinga2/issues/2289) (DB IDO): DB IDO: Duplicate entry icinga\_{host,service}dependencies * [#2274](https://github.com/Icinga/icinga2/issues/2274) (Notifications): Reminder notifications not being sent but logged every 5 secs * [#2234](https://github.com/Icinga/icinga2/issues/2234): Avoid rebuilding libbase when the version number changes * [#2232](https://github.com/Icinga/icinga2/issues/2232): Unity build doesn't work with MSVC * [#2194](https://github.com/Icinga/icinga2/issues/2194) (Configuration): validate configured legacy timeperiod ranges * [#2174](https://github.com/Icinga/icinga2/issues/2174) (Configuration): Update validators for CustomVarObject * [#2020](https://github.com/Icinga/icinga2/issues/2020) (Configuration): Invalid macro results in exception * [#1899](https://github.com/Icinga/icinga2/issues/1899): Scheduled start time will be ignored if the host or service is already in a problem state * [#1530](https://github.com/Icinga/icinga2/issues/1530): Remove name and return value for stats functions ### ITL * [#2705](https://github.com/Icinga/icinga2/issues/2705) (ITL): Add check commands for NSClient++ * [#2661](https://github.com/Icinga/icinga2/issues/2661) (ITL): ITL: The procs check command uses spaces instead of tabs * [#2652](https://github.com/Icinga/icinga2/issues/2652) (ITL): Rename PluginsContribDir to PluginContribDir * [#2649](https://github.com/Icinga/icinga2/issues/2649) (ITL): Snmp CheckCommand misses various options * [#2614](https://github.com/Icinga/icinga2/issues/2614) (ITL): add webinject checkcommand * [#2610](https://github.com/Icinga/icinga2/issues/2610) (ITL): Add ITL check command for check\_ipmi\_sensor * [#2573](https://github.com/Icinga/icinga2/issues/2573) (ITL): Extend disk checkcommand * [#2541](https://github.com/Icinga/icinga2/issues/2541) (ITL): The check "hostalive" is not working with ipv6 * [#2012](https://github.com/Icinga/icinga2/issues/2012) (ITL): ITL: ESXi-Hardware * [#2011](https://github.com/Icinga/icinga2/issues/2011) (ITL): ITL: Check\_Mem.pl * [#1984](https://github.com/Icinga/icinga2/issues/1984) (ITL): ITL: Interfacetable ### Documentation * [#2711](https://github.com/Icinga/icinga2/issues/2711) (Documentation): Document closures \('use'\) * [#2709](https://github.com/Icinga/icinga2/issues/2709) (Documentation): Fix a typo in documentation * [#2662](https://github.com/Icinga/icinga2/issues/2662) (Documentation): Update Remote Client/Distributed Monitoring Documentation * [#2595](https://github.com/Icinga/icinga2/issues/2595) (Documentation): Add documentation for cli command 'console' * [#2575](https://github.com/Icinga/icinga2/issues/2575) (Documentation): Remote Clients: Add manual setup cli commands * [#2555](https://github.com/Icinga/icinga2/issues/2555) (Documentation): The Zone::global attribute is not documented * [#2399](https://github.com/Icinga/icinga2/issues/2399) (Documentation): Allow name changed from inside the object * [#2387](https://github.com/Icinga/icinga2/issues/2387) (Documentation): Documentation enhancement for snmp traps and passive checks. * [#2321](https://github.com/Icinga/icinga2/issues/2321) (Documentation): Document operator precedence * [#2198](https://github.com/Icinga/icinga2/issues/2198) (Documentation): Variable expansion is single quoted. * [#1860](https://github.com/Icinga/icinga2/issues/1860) (Documentation): Add some more PNP details ### Support * [#2616](https://github.com/Icinga/icinga2/issues/2616) (Installation): Build fails on OpenBSD * [#2602](https://github.com/Icinga/icinga2/issues/2602) (Packages): Icinga2 config reset after package update \(centos6.6\) * [#2511](https://github.com/Icinga/icinga2/issues/2511) (Packages): '../features-available/checker.conf' does not exist \[Windows\] * [#2374](https://github.com/Icinga/icinga2/issues/2374) (Packages): Move the config file for the ido-\*sql features into the icinga2-ido-\* packages * [#2302](https://github.com/Icinga/icinga2/issues/2302) (Installation): Don't build db\_ido when both MySQL and PostgreSQL aren't enabled ## 2.2.4 (2015-02-05) ### Notes * Bugfixes ### Bug * [#2587](https://github.com/Icinga/icinga2/issues/2587) (CLI): Output in "node wizard" is confusing * [#2577](https://github.com/Icinga/icinga2/issues/2577) (Compat): enable\_event\_handlers attribute is missing in status.dat * [#2571](https://github.com/Icinga/icinga2/issues/2571): Segfault in Checkable::AddNotification * [#2561](https://github.com/Icinga/icinga2/issues/2561): Scheduling downtime for host and all services only schedules services * [#2558](https://github.com/Icinga/icinga2/issues/2558) (CLI): Restart of Icinga hangs * [#2550](https://github.com/Icinga/icinga2/issues/2550) (DB IDO): Crash in DbConnection::ProgramStatusHandler * [#2538](https://github.com/Icinga/icinga2/issues/2538) (CLI): Restart fails after deleting a Host * [#2508](https://github.com/Icinga/icinga2/issues/2508) (Compat): Feature statusdata shows wrong host notification options * [#2481](https://github.com/Icinga/icinga2/issues/2481) (CLI): Satellite doesn't use manually supplied 'local zone name' * [#2464](https://github.com/Icinga/icinga2/issues/2464): vfork\(\) hangs on OS X * [#2256](https://github.com/Icinga/icinga2/issues/2256) (Notifications): kUn-Bashify mail-{host,service}-notification.sh * [#2242](https://github.com/Icinga/icinga2/issues/2242): livestatus / nsca / etc submits are ignored during reload * [#1893](https://github.com/Icinga/icinga2/issues/1893): Configured recurring downtimes not applied on saturdays ### ITL * [#2532](https://github.com/Icinga/icinga2/issues/2532) (ITL): check\_ssmtp command does NOT support mail\_from ### Documentation * [#2521](https://github.com/Icinga/icinga2/issues/2521) (Documentation): Typos in readme file for windows plugins * [#2520](https://github.com/Icinga/icinga2/issues/2520) (Documentation): inconsistent URL http\(s\)://www.icinga.org * [#2512](https://github.com/Icinga/icinga2/issues/2512) (Documentation): Update Icinga Web 2 uri to /icingaweb2 ### Support * [#2517](https://github.com/Icinga/icinga2/issues/2517) (Packages): Fix YAJL detection on Debian squeeze * [#2462](https://github.com/Icinga/icinga2/issues/2462) (Packages): Icinga 2.2.2 build fails on SLES11SP3 because of changed boost dependency ## 2.2.3 (2015-01-12) ### Notes * Bugfixes ### Bug * [#2499](https://github.com/Icinga/icinga2/issues/2499) (CLI): Segfault on update-config old empty config * [#2498](https://github.com/Icinga/icinga2/issues/2498) (CLI): icinga2 node update config shows hex instead of human readable names * [#2496](https://github.com/Icinga/icinga2/issues/2496): Icinga 2.2.2 segfaults on FreeBSD * [#2477](https://github.com/Icinga/icinga2/issues/2477): DB IDO query queue limit reached on reload * [#2473](https://github.com/Icinga/icinga2/issues/2473) (CLI): check\_interval must be greater than 0 error on update-config * [#2471](https://github.com/Icinga/icinga2/issues/2471) (Cluster): Arguments without values are not used on plugin exec * [#2470](https://github.com/Icinga/icinga2/issues/2470) (Plugins): Windows plugin check\_service.exe can't find service NTDS * [#2459](https://github.com/Icinga/icinga2/issues/2459) (CLI): Incorrect ticket shouldn't cause "node wizard" to terminate * [#2420](https://github.com/Icinga/icinga2/issues/2420) (Notifications): Volatile checks trigger invalid notifications on OK-\>OK state changes ### Documentation * [#2490](https://github.com/Icinga/icinga2/issues/2490) (Documentation): Typo in example of StatusDataWriter ### Support * [#2460](https://github.com/Icinga/icinga2/issues/2460) (Packages): Icinga 2.2.2 doesn't build on i586 SUSE distributions ## 2.2.2 (2014-12-18) ### Notes * Bugfixes ### Bug * [#2446](https://github.com/Icinga/icinga2/issues/2446) (Compat): StatusDataWriter: Wrong export of event\_handler\_enabled * [#2444](https://github.com/Icinga/icinga2/issues/2444) (CLI): Remove usage info from --version * [#2416](https://github.com/Icinga/icinga2/issues/2416) (DB IDO): DB IDO: Missing last\_hard\_state column update in {host,service}status tables * [#2411](https://github.com/Icinga/icinga2/issues/2411): exception during config check * [#2394](https://github.com/Icinga/icinga2/issues/2394): typeof does not work for numbers * [#2381](https://github.com/Icinga/icinga2/issues/2381): SIGABRT while evaluating apply rules * [#2380](https://github.com/Icinga/icinga2/issues/2380) (Configuration): typeof\(\) seems to return null for arrays and dictionaries * [#2376](https://github.com/Icinga/icinga2/issues/2376) (Configuration): Apache 2.2 fails with new apache conf * [#2371](https://github.com/Icinga/icinga2/issues/2371) (Configuration): Test Classic UI config file with Apache 2.4 * [#2370](https://github.com/Icinga/icinga2/issues/2370) (Cluster): update\_config not updating configuration * [#2360](https://github.com/Icinga/icinga2/issues/2360): CLI `icinga2 node update-config` doesn't sync configs from remote clients as expected * [#2354](https://github.com/Icinga/icinga2/issues/2354) (DB IDO): Improve error reporting when libmysqlclient or libpq are missing * [#2350](https://github.com/Icinga/icinga2/issues/2350) (Cluster): Segfault on issuing node update-config * [#2341](https://github.com/Icinga/icinga2/issues/2341) (Cluster): execute checks locally if command\_endpoint == local endpoint * [#2283](https://github.com/Icinga/icinga2/issues/2283) (Cluster): Cluster heartbeats need to be more aggressive * [#2266](https://github.com/Icinga/icinga2/issues/2266) (CLI): "node wizard" shouldn't crash when SaveCert fails * [#2255](https://github.com/Icinga/icinga2/issues/2255) (DB IDO): If a parent host goes down, the child host isn't marked as unrechable in the db ido * [#2216](https://github.com/Icinga/icinga2/issues/2216) (Cluster): Repository does not support services which have a slash in their name * [#2202](https://github.com/Icinga/icinga2/issues/2202) (Configuration): CPU usage at 100% when check\_interval = 0 in host object definition * [#2154](https://github.com/Icinga/icinga2/issues/2154) (Cluster): update-config fails to create hosts * [#2148](https://github.com/Icinga/icinga2/issues/2148) (Compat): Feature `compatlog' should flush output buffer on every new line * [#2021](https://github.com/Icinga/icinga2/issues/2021): double macros in command arguments seems to lead to exception * [#2016](https://github.com/Icinga/icinga2/issues/2016) (Notifications): Docs: Better explaination of dependency state filters * [#1947](https://github.com/Icinga/icinga2/issues/1947) (Livestatus): Missing host downtimes/comments in Livestatus ### ITL * [#2430](https://github.com/Icinga/icinga2/issues/2430) (ITL): No option to specify timeout to check\_snmp and snmp manubulon commands ### Documentation * [#2422](https://github.com/Icinga/icinga2/issues/2422) (Documentation): Setting a dictionary key to null does not cause the key/value to be removed * [#2412](https://github.com/Icinga/icinga2/issues/2412) (Documentation): Update host examples in Dependencies for Network Reachability documentation * [#2409](https://github.com/Icinga/icinga2/issues/2409) (Documentation): Wrong command in documentation for installing Icinga 2 pretty printers. * [#2404](https://github.com/Icinga/icinga2/issues/2404) (Documentation): Livestatus: Replace unixcat with nc -U * [#2180](https://github.com/Icinga/icinga2/issues/2180) (Documentation): Documentation: Add note on default notification interval in getting started notifications.conf ### Support * [#2417](https://github.com/Icinga/icinga2/issues/2417) (Tests): Unit tests fail on FreeBSD * [#2369](https://github.com/Icinga/icinga2/issues/2369) (Packages): SUSE packages %set\_permissions post statement wasn't moved to common * [#2368](https://github.com/Icinga/icinga2/issues/2368) (Packages): /usr/lib/icinga2 is not owned by a package * [#2292](https://github.com/Icinga/icinga2/issues/2292) (Tests): The unit tests still crash sometimes * [#1942](https://github.com/Icinga/icinga2/issues/1942) (Packages): icinga2 init-script doesn't validate configuration on reload action ## 2.2.1 (2014-12-01) ### Notes * Support arrays in [command argument macros](#command-passing-parameters) #6709 * Allows to define multiple parameters for [nrpe -a](#plugin-check-command-nrpe), [nscp -l](#plugin-check-command-nscp), [disk -p](#plugin-check-command-disk), [dns -a](#plugin-check-command-dns). * Bugfixes ### Enhancement * [#2366](https://github.com/Icinga/icinga2/issues/2366): Release 2.2.1 * [#2277](https://github.com/Icinga/icinga2/issues/2277) (Configuration): The classicui Apache conf doesn't support Apache 2.4 * [#1790](https://github.com/Icinga/icinga2/issues/1790): Support for arrays in macros ### Bug * [#2340](https://github.com/Icinga/icinga2/issues/2340) (CLI): Segfault in CA handling * [#2328](https://github.com/Icinga/icinga2/issues/2328) (Cluster): Verify if master radio box is disabled in the Windows wizard * [#2311](https://github.com/Icinga/icinga2/issues/2311) (Configuration): !in operator returns incorrect result * [#2293](https://github.com/Icinga/icinga2/issues/2293) (Configuration): Objects created with node update-config can't be seen in Classic UI * [#2288](https://github.com/Icinga/icinga2/issues/2288) (Cluster): Incorrect error message for localhost * [#2282](https://github.com/Icinga/icinga2/issues/2282) (Cluster): Icinga2 node add failed with unhandled exception * [#2273](https://github.com/Icinga/icinga2/issues/2273): Restart Icinga - Error Restoring program state from file '/var/lib/icinga2/icinga2.state' * [#2272](https://github.com/Icinga/icinga2/issues/2272) (Cluster): Windows wizard is missing --zone argument * [#2271](https://github.com/Icinga/icinga2/issues/2271) (Cluster): Windows wizard uses incorrect CLI command * [#2267](https://github.com/Icinga/icinga2/issues/2267) (Cluster): Built-in commands shouldn't be run on the master instance in remote command execution mode * [#2207](https://github.com/Icinga/icinga2/issues/2207) (Livestatus): livestatus large amount of submitting unix socket command results in broken pipes ### ITL * [#2285](https://github.com/Icinga/icinga2/issues/2285) (ITL): Increase default timeout for NRPE checks ### Documentation * [#2344](https://github.com/Icinga/icinga2/issues/2344) (Documentation): Documentation: Explain how unresolved macros are handled * [#2343](https://github.com/Icinga/icinga2/issues/2343) (Documentation): Document how arrays in macros work * [#2336](https://github.com/Icinga/icinga2/issues/2336) (Documentation): Wrong information in section "Linux Client Setup Wizard for Remote Monitoring" * [#2275](https://github.com/Icinga/icinga2/issues/2275) (Documentation): 2.2.0 has out-of-date icinga2 man page * [#2251](https://github.com/Icinga/icinga2/issues/2251) (Documentation): object and template with the same name generate duplicate object error ### Support * [#2363](https://github.com/Icinga/icinga2/issues/2363) (Packages): Fix Apache config in the Debian package * [#2359](https://github.com/Icinga/icinga2/issues/2359) (Packages): Wrong permission in run directory after restart * [#2301](https://github.com/Icinga/icinga2/issues/2301) (Packages): Move the icinga2-prepare-dirs script elsewhere * [#2280](https://github.com/Icinga/icinga2/issues/2280) (Packages): Icinga 2.2 misses the build requirement libyajl-devel for SUSE distributions * [#2278](https://github.com/Icinga/icinga2/issues/2278) (Packages): /usr/sbin/icinga-prepare-dirs conflicts in the bin and common package * [#2276](https://github.com/Icinga/icinga2/issues/2276) (Packages): Systemd rpm scripts are run in wrong package * [#2212](https://github.com/Icinga/icinga2/issues/2212) (Packages): icinga2 checkconfig should fail if group given for command files does not exist * [#2117](https://github.com/Icinga/icinga2/issues/2117) (Packages): Update spec file to use yajl-devel * [#1968](https://github.com/Icinga/icinga2/issues/1968) (Packages): service icinga2 status gives wrong information when run as unprivileged user ## 2.2.0 (2014-11-17) ### Notes * DB IDO schema update to version `1.12.0` * schema files in `lib/db_ido_{mysql,pgsql}/schema` (source) * Table `programstatus`: New column `program_version` * Table `customvariables` and `customvariablestatus`: New column `is_json` (required for custom attribute array/dictionary support) * New features * [GelfWriter](#gelfwriter): Logging check results, state changes, notifications to GELF (graylog2, logstash) #7619 * Agent/Client/Node framework #7249 * Windows plugins for the client/agent parts #7242 #7243 * New CLI commands #7245 * `icinga2 feature {enable,disable}` replaces `icinga2-{enable,disable}-feature` script #7250 * `icinga2 object list` replaces `icinga2-list-objects` script #7251 * `icinga2 pki` replaces` icinga2-build-{ca,key}` scripts #7247 * `icinga2 repository` manages `/etc/icinga2/repository.d` which must be included in `icinga2.conf` #7255 * `icinga2 node` cli command provides node (master, satellite, agent) setup (wizard) and management functionality #7248 * `icinga2 daemon` for existing daemon arguments (`-c`, `-C`). Removed `-u` and `-g` parameters in favor of [init.conf](#init-conf). * bash auto-completion & terminal colors #7396 * Configuration * Former `localhost` example host is now defined in [hosts.conf](#hosts-conf) #7594 * All example services moved into advanced apply rules in [services.conf](#services-conf) * Updated downtimes configuration example in [downtimes.conf](#downtimes-conf) #7472 * Updated notification apply example in [notifications.conf](#notifications-conf) #7594 * Support for object attribute 'zone' #7400 * Support setting [object variables in apply rules](#dependencies-apply-custom-attributes) #7479 * Support arrays and dictionaries in [custom attributes](#custom-attributes-apply) #6544 #7560 * Add [apply for rules](#using-apply-for) for advanced dynamic object generation #7561 * New attribute `accept_commands` for [ApiListener](#objecttype-apilistener) #7559 * New [init.conf](#init-conf) file included first containing new constants `RunAsUser` and `RunAsGroup`. * Cluster * Add [CSR Auto-Signing support](#csr-autosigning-requirements) using generated ticket #7244 * Allow to [execute remote commands](#icinga2-remote-monitoring-client-command-execution) on endpoint clients #7559 * Perfdata * [PerfdataWriter](#writing-performance-data-files): Don't change perfdata, pass through from plugins #7268 * [GraphiteWriter](#graphite-carbon-cache-writer): Add warn/crit/min/max perfdata and downtime_depth stats values #7366 #6946 * Packages * `python-icinga2` package dropped in favor of integrated cli commands #7245 * Windows Installer for the agent parts #7243 > **Note** > > Please remove `conf.d/hosts/localhost*` after verifying your updated configuration! ### Enhancement * [#2219](https://github.com/Icinga/icinga2/issues/2219): Icinga 2 should use less RAM * [#2217](https://github.com/Icinga/icinga2/issues/2217) (Performance Data): Add GelfWriter for writing log events to graylog2/logstash * [#2213](https://github.com/Icinga/icinga2/issues/2213): Optimize class layout * [#2203](https://github.com/Icinga/icinga2/issues/2203) (Configuration): Revamp sample configuration: add NodeName host, move services into apply rules schema * [#2189](https://github.com/Icinga/icinga2/issues/2189) (Configuration): Refactor AST into multiple classes * [#2187](https://github.com/Icinga/icinga2/issues/2187) (Configuration): Implement support for arbitrarily complex indexers * [#2184](https://github.com/Icinga/icinga2/issues/2184) (Configuration): Generate objects using apply with foreach in arrays or dictionaries \(key =\> value\) * [#2183](https://github.com/Icinga/icinga2/issues/2183) (Configuration): Support dictionaries in custom attributes * [#2182](https://github.com/Icinga/icinga2/issues/2182) (Cluster): Execute remote commands on the agent w/o local objects by passing custom attributes * [#2179](https://github.com/Icinga/icinga2/issues/2179): Implement keys\(\) * [#2178](https://github.com/Icinga/icinga2/issues/2178) (CLI): Cli command Node: Disable notifications feature on client nodes * [#2161](https://github.com/Icinga/icinga2/issues/2161) (CLI): Cli Command: Rename 'agent' to 'node' * [#2158](https://github.com/Icinga/icinga2/issues/2158) (Cluster): Require --zone to be specified for "node setup" * [#2152](https://github.com/Icinga/icinga2/issues/2152) (Cluster): Rename --agent to --zone \(for blacklist/whitelist\) * [#2140](https://github.com/Icinga/icinga2/issues/2140) (CLI): Cli: Use Node Blacklist functionality in 'node update-config' * [#2138](https://github.com/Icinga/icinga2/issues/2138) (CLI): Find a better name for 'repository commit --clear' * [#2131](https://github.com/Icinga/icinga2/issues/2131) (Configuration): Set host/service variable in apply rules * [#2124](https://github.com/Icinga/icinga2/issues/2124) (Configuration): Update downtimes.conf example config * [#2119](https://github.com/Icinga/icinga2/issues/2119) (Cluster): Remove virtual agent name feature for localhost * [#2118](https://github.com/Icinga/icinga2/issues/2118) (CLI): Cli command: Node Setup Wizard \(for Satellites and Agents\) * [#2115](https://github.com/Icinga/icinga2/issues/2115) (CLI): Cli command: Repository remove host should remove host.conf host/ dir with services * [#2113](https://github.com/Icinga/icinga2/issues/2113) (CLI): validate repository config updates * [#2108](https://github.com/Icinga/icinga2/issues/2108): Only build YAJL when there's no system-provided version available * [#2107](https://github.com/Icinga/icinga2/issues/2107): Replace cJSON with a better JSON parser * [#2104](https://github.com/Icinga/icinga2/issues/2104) (CLI): Use "variable get" for "pki ticket" * [#2103](https://github.com/Icinga/icinga2/issues/2103) (CLI): Validate number of arguments * [#2098](https://github.com/Icinga/icinga2/issues/2098) (CLI): Support for writing api.conf * [#2096](https://github.com/Icinga/icinga2/issues/2096) (CLI): Cli command: pki needs option to define the algorithm * [#2092](https://github.com/Icinga/icinga2/issues/2092) (CLI): Rename PKI arguments * [#2088](https://github.com/Icinga/icinga2/issues/2088) (CLI): Cli command: Node Setup * [#2087](https://github.com/Icinga/icinga2/issues/2087) (CLI): "pki request" should ask user to verify the peer's certificate * [#2086](https://github.com/Icinga/icinga2/issues/2086) (CLI): Add -h next to --help * [#2085](https://github.com/Icinga/icinga2/issues/2085) (CLI): Remove "available features" list from "feature list" * [#2084](https://github.com/Icinga/icinga2/issues/2084) (CLI): Implement "feature disable" for Windows * [#2081](https://github.com/Icinga/icinga2/issues/2081) (CLI): CLI: List disabled features in feature list too * [#2079](https://github.com/Icinga/icinga2/issues/2079): Move WSAStartup call to INITIALIZE\_ONCE * [#2076](https://github.com/Icinga/icinga2/issues/2076) (CLI): Implement field attribute to hide fields in command auto-completion * [#2074](https://github.com/Icinga/icinga2/issues/2074) (CLI): Add autocomplete to 'host/service add' for object attributes \(e.g. --check\_interval\) * [#2073](https://github.com/Icinga/icinga2/issues/2073) (Configuration): Remove zone keyword and allow to use object attribute 'zone' * [#2071](https://github.com/Icinga/icinga2/issues/2071) (Configuration): Move localhost config into repository * [#2069](https://github.com/Icinga/icinga2/issues/2069) (CLI): Implement generic color support for terminals * [#2066](https://github.com/Icinga/icinga2/issues/2066) (CLI): Implement support for serial files * [#2064](https://github.com/Icinga/icinga2/issues/2064) (DB IDO): Add program\_version column to programstatus table * [#2062](https://github.com/Icinga/icinga2/issues/2062): Release 2.2 * [#2059](https://github.com/Icinga/icinga2/issues/2059) (CLI): Auto-completion for feature enable/disable * [#2055](https://github.com/Icinga/icinga2/issues/2055) (CLI): Windows support for cli command feature * [#2054](https://github.com/Icinga/icinga2/issues/2054) (CLI): CLI Commands: Remove timestamp prefix when logging output * [#2053](https://github.com/Icinga/icinga2/issues/2053) (CLI): autocomplete should support '--key value' * [#2050](https://github.com/Icinga/icinga2/issues/2050) (CLI): Cli command parser must support unregistered boost::program\_options * [#2049](https://github.com/Icinga/icinga2/issues/2049) (CLI): CLI command: variable * [#2046](https://github.com/Icinga/icinga2/issues/2046) (Graphite): GraphiteWriter: Add warn/crit/min/max perfdata values if existing * [#2031](https://github.com/Icinga/icinga2/issues/2031) (Graphite): GraphiteWriter: Add support for customized metric prefix names * [#2003](https://github.com/Icinga/icinga2/issues/2003): macro processor needs an array printer * [#1999](https://github.com/Icinga/icinga2/issues/1999) (CLI): Cli command: Repository * [#1997](https://github.com/Icinga/icinga2/issues/1997) (CLI): Cli Commands: Node Repository Blacklist & Whitelist * [#1996](https://github.com/Icinga/icinga2/issues/1996) (CLI): Cli command: SCM * [#1995](https://github.com/Icinga/icinga2/issues/1995) (CLI): Cli command: Object * [#1994](https://github.com/Icinga/icinga2/issues/1994) (CLI): Cli command: Feature * [#1993](https://github.com/Icinga/icinga2/issues/1993) (CLI): Node Repository * [#1992](https://github.com/Icinga/icinga2/issues/1992) (CLI): Cli command: Node * [#1991](https://github.com/Icinga/icinga2/issues/1991) (CLI): Cli command: pki * [#1990](https://github.com/Icinga/icinga2/issues/1990) (CLI): Cli command framework * [#1989](https://github.com/Icinga/icinga2/issues/1989) (CLI): Cli commands * [#1988](https://github.com/Icinga/icinga2/issues/1988) (Cluster): CSR auto-signing * [#1987](https://github.com/Icinga/icinga2/issues/1987) (Plugins): Windows plugins * [#1986](https://github.com/Icinga/icinga2/issues/1986) (Cluster): Windows Wizard * [#1977](https://github.com/Icinga/icinga2/issues/1977) (CLI): Cli commands: add filter capability to 'object list' * [#1901](https://github.com/Icinga/icinga2/issues/1901) (Cluster): Windows installer * [#1895](https://github.com/Icinga/icinga2/issues/1895) (Graphite): Add downtime depth as statistic metric for GraphiteWriter * [#1717](https://github.com/Icinga/icinga2/issues/1717) (Configuration): Support for array in custom variable. * [#894](https://github.com/Icinga/icinga2/issues/894): Add copyright header to .ti files and add support for comments in mkclass ### Bug * [#2258](https://github.com/Icinga/icinga2/issues/2258) (Configuration): Names for nested objects are evaluated at the wrong time * [#2257](https://github.com/Icinga/icinga2/issues/2257) (Configuration): DebugInfo is missing for nested dictionaries * [#2254](https://github.com/Icinga/icinga2/issues/2254): CreateProcess fails on Windows 7 * [#2241](https://github.com/Icinga/icinga2/issues/2241) (Cluster): node wizard uses incorrect path for the CA certificate * [#2237](https://github.com/Icinga/icinga2/issues/2237) (Configuration): Wrong set of dependency state when a host depends on a service * [#2235](https://github.com/Icinga/icinga2/issues/2235): Unit tests fail to run * [#2233](https://github.com/Icinga/icinga2/issues/2233): Get rid of static boost::mutex variables * [#2222](https://github.com/Icinga/icinga2/issues/2222) (DB IDO): IDO module crashes on Windows * [#2221](https://github.com/Icinga/icinga2/issues/2221): Installation on Windows fails * [#2220](https://github.com/Icinga/icinga2/issues/2220) (Notifications): Missing state filter 'OK' must not prevent recovery notifications being sent * [#2215](https://github.com/Icinga/icinga2/issues/2215): mkclass crashes when called without arguments * [#2214](https://github.com/Icinga/icinga2/issues/2214) (Cluster): Removing multiple services fails * [#2206](https://github.com/Icinga/icinga2/issues/2206): Plugin execution on Windows does not work * [#2205](https://github.com/Icinga/icinga2/issues/2205): Compilation Error with boost 1.56 under Windows * [#2201](https://github.com/Icinga/icinga2/issues/2201): Exception when executing check * [#2200](https://github.com/Icinga/icinga2/issues/2200) (Configuration): Nested templates do not work \(anymore\) * [#2199](https://github.com/Icinga/icinga2/issues/2199) (CLI): Typo in output of 'icinga2 object list' * [#2197](https://github.com/Icinga/icinga2/issues/2197) (Notifications): only notify users on recovery which have been notified before \(not-ok state\) * [#2195](https://github.com/Icinga/icinga2/issues/2195) (Cluster): Invalid checkresult object causes Icinga 2 to crash * [#2177](https://github.com/Icinga/icinga2/issues/2177) (CLI): 'pki request' fails with serial permission error * [#2172](https://github.com/Icinga/icinga2/issues/2172) (Configuration): There is no \_\_name available to nested objects * [#2171](https://github.com/Icinga/icinga2/issues/2171) (Configuration): Nesting an object in a template causes the template to become non-abstract * [#2170](https://github.com/Icinga/icinga2/issues/2170) (Configuration): Object list dump erraneously evaluates template definitions * [#2166](https://github.com/Icinga/icinga2/issues/2166) (Cluster): Error message is always shown even when the host exists * [#2165](https://github.com/Icinga/icinga2/issues/2165) (Cluster): Incorrect warning message for "node update-config" * [#2164](https://github.com/Icinga/icinga2/issues/2164) (Cluster): Error in migrate-hosts * [#2162](https://github.com/Icinga/icinga2/issues/2162) (CLI): Change blacklist/whitelist storage * [#2156](https://github.com/Icinga/icinga2/issues/2156) (Cluster): Use ScriptVariable::Get for RunAsUser/RunAsGroup * [#2155](https://github.com/Icinga/icinga2/issues/2155) (Cluster): Agent health check must not have zone attribute * [#2153](https://github.com/Icinga/icinga2/issues/2153) (Cluster): Misleading error messages for blacklist/whitelist remove * [#2142](https://github.com/Icinga/icinga2/issues/2142) (Configuration): Icinga2 fails to start due to configuration errors * [#2141](https://github.com/Icinga/icinga2/issues/2141): Build fails * [#2137](https://github.com/Icinga/icinga2/issues/2137): Utility::GetFQDN doesn't work on OS X * [#2134](https://github.com/Icinga/icinga2/issues/2134): Hosts/services should not have themselves as parents * [#2133](https://github.com/Icinga/icinga2/issues/2133): OnStateLoaded isn't called for objects which don't have any state * [#2132](https://github.com/Icinga/icinga2/issues/2132) (CLI): cli command 'node setup update-config' overwrites existing constants.conf * [#2128](https://github.com/Icinga/icinga2/issues/2128) (CLI): Cli: Node Setup/Wizard running as root must chown\(\) generated files to icinga daemon user * [#2127](https://github.com/Icinga/icinga2/issues/2127) (Configuration): can't assign Service to Host in nested HostGroup * [#2125](https://github.com/Icinga/icinga2/issues/2125) (Performance Data): Performance data via API is broken * [#2116](https://github.com/Icinga/icinga2/issues/2116) (CLI): Cli command: Repository should validate if object exists before add/remove * [#2106](https://github.com/Icinga/icinga2/issues/2106) (Cluster): When replaying logs the secobj attribute is ignored * [#2091](https://github.com/Icinga/icinga2/issues/2091) (CLI): Cli command: pki request throws exception on connection failure * [#2083](https://github.com/Icinga/icinga2/issues/2083): CMake warnings on OS X * [#2077](https://github.com/Icinga/icinga2/issues/2077) (CLI): CLI: Auto-completion with colliding arguments * [#2070](https://github.com/Icinga/icinga2/issues/2070) (DB IDO): CLI / MySQL error during vagrant provisioning * [#2068](https://github.com/Icinga/icinga2/issues/2068) (CLI): pki new-cert doesn't check whether the files were successfully written * [#2065](https://github.com/Icinga/icinga2/issues/2065) (DB IDO): Schema upgrade files are missing in /usr/share/icinga2-ido-{mysql,pgsql} * [#2063](https://github.com/Icinga/icinga2/issues/2063) (CLI): Cli commands: Integers in arrays are printed incorrectly * [#2057](https://github.com/Icinga/icinga2/issues/2057) (CLI): failed en/disable feature should return error * [#2056](https://github.com/Icinga/icinga2/issues/2056) (CLI): Commands are auto-completed when they shouldn't be * [#2051](https://github.com/Icinga/icinga2/issues/2051) (Configuration): custom attribute name 'type' causes empty vars dictionary * [#2048](https://github.com/Icinga/icinga2/issues/2048) (Compat): Fix reading perfdata in compat/checkresultreader * [#2042](https://github.com/Icinga/icinga2/issues/2042) (Plugins): Setting snmp\_v2 can cause snmp-manubulon-command derived checks to fail * [#2038](https://github.com/Icinga/icinga2/issues/2038) (Configuration): snmp-load checkcommand has a wrong "-T" param value * [#2034](https://github.com/Icinga/icinga2/issues/2034) (Configuration): Importing a CheckCommand in a NotificationCommand results in an exception without stacktrace. * [#2029](https://github.com/Icinga/icinga2/issues/2029) (Configuration): Error messages for invalid imports missing * [#2026](https://github.com/Icinga/icinga2/issues/2026) (Configuration): config parser crashes on unknown attribute in assign * [#2006](https://github.com/Icinga/icinga2/issues/2006) (Configuration): snmp-load checkcommand has wrong threshold syntax * [#2005](https://github.com/Icinga/icinga2/issues/2005) (Performance Data): icinga2 returns exponentail perfdata format with check\_nt * [#2004](https://github.com/Icinga/icinga2/issues/2004) (Performance Data): Icinga2 changes perfdata order and removes maximum * [#2001](https://github.com/Icinga/icinga2/issues/2001) (Notifications): default value for "disable\_notifications" in service dependencies is set to "false" * [#1950](https://github.com/Icinga/icinga2/issues/1950) (Configuration): Typo for "HTTP Checks" match in groups.conf * [#1720](https://github.com/Icinga/icinga2/issues/1720) (Notifications): delaying notifications with times.begin should postpone first notification into that window ### ITL * [#2204](https://github.com/Icinga/icinga2/issues/2204) (ITL): Plugin Check Commands: disk is missing '-p', 'x' parameter * [#2017](https://github.com/Icinga/icinga2/issues/2017) (ITL): ITL: check\_procs and check\_http are missing arguments ### Documentation * [#2218](https://github.com/Icinga/icinga2/issues/2218) (Documentation): Documentation: Update Icinga Web 2 installation * [#2191](https://github.com/Icinga/icinga2/issues/2191) (Documentation): link missing in documentation about livestatus * [#2175](https://github.com/Icinga/icinga2/issues/2175) (Documentation): Documentation for arrays & dictionaries in custom attributes and their usage in apply rules for * [#2160](https://github.com/Icinga/icinga2/issues/2160) (Documentation): Documentation: Explain how to manage agent config in central repository * [#2150](https://github.com/Icinga/icinga2/issues/2150) (Documentation): Documentation: Move troubleshooting after the getting started chapter * [#2143](https://github.com/Icinga/icinga2/issues/2143) (Documentation): Documentation: Revamp getting started with 1 host and multiple \(service\) applies * [#2130](https://github.com/Icinga/icinga2/issues/2130) (Documentation): Documentation: Mention 'icinga2 object list' in config validation * [#2129](https://github.com/Icinga/icinga2/issues/2129) (Documentation): Fix typos and other small corrections in documentation * [#2093](https://github.com/Icinga/icinga2/issues/2093) (Documentation): Documentation: 1-about contribute links to non-existing report a bug howto * [#2052](https://github.com/Icinga/icinga2/issues/2052) (Documentation): Wrong usermod command for external command pipe setup * [#2041](https://github.com/Icinga/icinga2/issues/2041) (Documentation): Documentation: Cli Commands * [#2037](https://github.com/Icinga/icinga2/issues/2037) (Documentation): Documentation: Wrong check command for snmp-int\(erface\) * [#2033](https://github.com/Icinga/icinga2/issues/2033) (Documentation): Docs: Default command timeout is 60s not 5m * [#2028](https://github.com/Icinga/icinga2/issues/2028) (Documentation): Icinga2 docs: link supported operators from sections about apply rules * [#2024](https://github.com/Icinga/icinga2/issues/2024) (Documentation): Documentation: Add support for locally-scoped variables for host/service in applied Dependency * [#2013](https://github.com/Icinga/icinga2/issues/2013) (Documentation): Documentation: Add host/services variables in apply rules * [#1998](https://github.com/Icinga/icinga2/issues/1998) (Documentation): Documentation: Agent/Satellite Setup * [#1972](https://github.com/Icinga/icinga2/issues/1972) (Documentation): Document how to use multiple assign/ignore statements with logical "and" & "or" ### Support * [#2253](https://github.com/Icinga/icinga2/issues/2253) (Packages): Conditionally enable MySQL and PostgresSQL, add support for FreeBSD and DragonFlyBSD * [#2236](https://github.com/Icinga/icinga2/issues/2236) (Packages): Enable parallel builds for the Debian package * [#2147](https://github.com/Icinga/icinga2/issues/2147) (Packages): Feature `checker' is not enabled when installing Icinga 2 using our lates RPM snapshot packages * [#2136](https://github.com/Icinga/icinga2/issues/2136) (Packages): Build fails on RHEL 6.6 * [#2123](https://github.com/Icinga/icinga2/issues/2123) (Packages): Post-update script \(migrate-hosts\) isn't run on RPM-based distributions * [#2095](https://github.com/Icinga/icinga2/issues/2095) (Packages): Unity build fails on RHEL 5 * [#2058](https://github.com/Icinga/icinga2/issues/2058) (Packages): Debian package root permissions interfere with icinga2 cli commands as icinga user * [#2007](https://github.com/Icinga/icinga2/issues/2007) (Packages): SLES \(Suse Linux Enterprise Server\) 11 SP3 package dependency failure ## 2.1.1 (2014-09-16) ### Enhancement * [#1938](https://github.com/Icinga/icinga2/issues/1938): Unity builds: Detect whether \_\_COUNTER\_\_ is available * [#1933](https://github.com/Icinga/icinga2/issues/1933): Implement support for unity builds * [#1932](https://github.com/Icinga/icinga2/issues/1932): Ensure that namespaces for INITIALIZE\_ONCE and REGISTER\_TYPE are truly unique * [#1931](https://github.com/Icinga/icinga2/issues/1931): Add include guards for mkclass files * [#1797](https://github.com/Icinga/icinga2/issues/1797): Change log message for checking/sending notifications ### Bug * [#1975](https://github.com/Icinga/icinga2/issues/1975): fix memory leak ido\_pgsql * [#1971](https://github.com/Icinga/icinga2/issues/1971) (Livestatus): Livestatus hangs from time to time * [#1967](https://github.com/Icinga/icinga2/issues/1967) (Plugins): fping4 doesn't work correctly with the shipped command-plugins.conf * [#1966](https://github.com/Icinga/icinga2/issues/1966) (Cluster): Segfault using cluster in TlsStream::IsEof * [#1958](https://github.com/Icinga/icinga2/issues/1958) (Configuration): Manubulon-Plugin conf Filename wrong * [#1957](https://github.com/Icinga/icinga2/issues/1957): Build fails on Haiku * [#1955](https://github.com/Icinga/icinga2/issues/1955) (Cluster): new SSL Errors with too many queued messages * [#1954](https://github.com/Icinga/icinga2/issues/1954): Missing differentiation between service and systemctl * [#1952](https://github.com/Icinga/icinga2/issues/1952) (Performance Data): GraphiteWriter should ignore empty perfdata value * [#1948](https://github.com/Icinga/icinga2/issues/1948): pipe2 returns ENOSYS on GNU Hurd and Debian kfreebsd * [#1946](https://github.com/Icinga/icinga2/issues/1946): Exit code is not initialized for some failed checks * [#1940](https://github.com/Icinga/icinga2/issues/1940): icinga2-list-objects complains about Umlauts and stops output * [#1935](https://github.com/Icinga/icinga2/issues/1935): icinga2-list-objects doesn't work with Python 3 * [#1934](https://github.com/Icinga/icinga2/issues/1934) (Configuration): Remove validator for the Script type * [#1930](https://github.com/Icinga/icinga2/issues/1930): "Error parsing performance data" in spite of "enable\_perfdata = false" * [#1910](https://github.com/Icinga/icinga2/issues/1910) (Cluster): SSL errors with interleaved SSL\_read/write * [#1862](https://github.com/Icinga/icinga2/issues/1862) (Cluster): SSL\_read errors during restart * [#1849](https://github.com/Icinga/icinga2/issues/1849) (Cluster): Too many queued messages * [#1782](https://github.com/Icinga/icinga2/issues/1782): make test fails on openbsd * [#1522](https://github.com/Icinga/icinga2/issues/1522): Link libcJSON against libm ### Documentation * [#1985](https://github.com/Icinga/icinga2/issues/1985) (Documentation): clarify on db ido upgrades * [#1962](https://github.com/Icinga/icinga2/issues/1962) (Documentation): Extend documentation for icinga-web on Debian systems * [#1949](https://github.com/Icinga/icinga2/issues/1949) (Documentation): Explain event commands and their integration by a real life example \(httpd restart via ssh\) * [#1927](https://github.com/Icinga/icinga2/issues/1927) (Documentation): Document how to use @ to escape keywords ### Support * [#1960](https://github.com/Icinga/icinga2/issues/1960) (Packages): GNUInstallDirs.cmake outdated * [#1944](https://github.com/Icinga/icinga2/issues/1944) (Packages): service icinga2 status - prints cat error if the service is stopped * [#1941](https://github.com/Icinga/icinga2/issues/1941) (Packages): icinga2 init-script terminates with exit code 0 if $DAEMON is not in place or not executable * [#1939](https://github.com/Icinga/icinga2/issues/1939) (Packages): Enable unity build for RPM/Debian packages * [#1937](https://github.com/Icinga/icinga2/issues/1937) (Packages): Figure out a better way to set the version for snapshot builds * [#1936](https://github.com/Icinga/icinga2/issues/1936) (Packages): Fix rpmlint errors * [#1928](https://github.com/Icinga/icinga2/issues/1928) (Packages): icinga2.spec: files-attr-not-set for python-icinga2 package ## 2.1.0 (2014-08-29) ### Notes * DB IDO schema upgrade ([MySQL](#upgrading-mysql-db),[PostgreSQL](#upgrading-postgresql-db) required! * new schema version: **1.11.7** * RPMs install the schema files into `/usr/share/icinga2-ido*` instead of `/usr/share/doc/icinga2-ido*` #6881 * [Information for config objects](#list-configuration-objects) using `icinga2-list-objects` script #6702 * Add Python 2.4 as requirement #6702 * Add search path: If `-c /etc/icinga2/icinga2.conf` is omitted, use `SysconfDir + "/icinga2/icinga2.conf"` #6874 * Change log level for failed commands #6751 * Notifications are load-balanced in a [High Availability cluster setup](#high-availability-notifications) #6203 * New config attribute: `enable_ha` * DB IDO "run once" or "run everywhere" mode in a [High Availability cluster setup](#high-availability-db-ido) #6203 #6827 * New config attributes: `enable_ha` and `failover_timeout` * RPMs use the `icingacmd` group for /var/{cache,log,run}/icinga2 #6948 ### Enhancement * [#1879](https://github.com/Icinga/icinga2/issues/1879): Enhance logging for perfdata/graphitewriter * [#1871](https://github.com/Icinga/icinga2/issues/1871) (Configuration): add search path for icinga2.conf * [#1843](https://github.com/Icinga/icinga2/issues/1843) (DB IDO): delay ido connect in ha cluster * [#1810](https://github.com/Icinga/icinga2/issues/1810): Change log level for failed commands * [#1788](https://github.com/Icinga/icinga2/issues/1788): Release 2.1 * [#1786](https://github.com/Icinga/icinga2/issues/1786) (Configuration): Information for config objects * [#1760](https://github.com/Icinga/icinga2/issues/1760) (Plugins): Plugin Check Commands: add manubulon snmp plugins * [#1548](https://github.com/Icinga/icinga2/issues/1548) (Cluster): Log replay sends messages to instances which shouldn't get those messages * [#1546](https://github.com/Icinga/icinga2/issues/1546) (Cluster): Better cluster support for notifications / IDO * [#1491](https://github.com/Icinga/icinga2/issues/1491) (Cluster): Better log messages for cluster changes * [#977](https://github.com/Icinga/icinga2/issues/977) (Cluster): Cluster support for modified attributes ### Bug * [#1916](https://github.com/Icinga/icinga2/issues/1916): Build fails with Boost 1.56 * [#1903](https://github.com/Icinga/icinga2/issues/1903) (Cluster): Host and service checks stuck in "pending" when hostname = localhost a parent/satellite setup * [#1902](https://github.com/Icinga/icinga2/issues/1902): Commands are processed multiple times * [#1896](https://github.com/Icinga/icinga2/issues/1896): check file permissions in /var/cache/icinga2 * [#1884](https://github.com/Icinga/icinga2/issues/1884): External command pipe: Too many open files * [#1819](https://github.com/Icinga/icinga2/issues/1819): ExternalCommandListener fails open pipe: Too many open files ### Documentation * [#1924](https://github.com/Icinga/icinga2/issues/1924) (Documentation): add example selinux policy for external command pipe * [#1915](https://github.com/Icinga/icinga2/issues/1915) (Documentation): how to add a new cluster node * [#1913](https://github.com/Icinga/icinga2/issues/1913) (Documentation): Keyword "required" used inconsistently for host and service "icon\_image\*" attributes * [#1905](https://github.com/Icinga/icinga2/issues/1905) (Documentation): Update command arguments 'set\_if' and beautify error message * [#1897](https://github.com/Icinga/icinga2/issues/1897) (Documentation): Add documentation for icinga2-list-objects * [#1889](https://github.com/Icinga/icinga2/issues/1889) (Documentation): Enhance Graphite Writer description * [#1881](https://github.com/Icinga/icinga2/issues/1881) (Documentation): clarify on which config tools are available * [#1872](https://github.com/Icinga/icinga2/issues/1872) (Documentation): Wrong parent in Load Distribution * [#1868](https://github.com/Icinga/icinga2/issues/1868) (Documentation): Wrong object attribute 'enable\_flap\_detection' * [#1867](https://github.com/Icinga/icinga2/issues/1867) (Documentation): Add systemd options: enable, journal * [#1865](https://github.com/Icinga/icinga2/issues/1865) (Documentation): add section about disabling re-notifications * [#1864](https://github.com/Icinga/icinga2/issues/1864) (Documentation): Add section for reserved keywords * [#1847](https://github.com/Icinga/icinga2/issues/1847) (Documentation): Explain how the order attribute works in commands * [#1807](https://github.com/Icinga/icinga2/issues/1807) (Documentation): Better explanation for HA config cluster * [#1787](https://github.com/Icinga/icinga2/issues/1787) (Documentation): Documentation for zones and cluster permissions * [#1761](https://github.com/Icinga/icinga2/issues/1761) (Documentation): Migration: note on check command timeouts ### Support * [#1923](https://github.com/Icinga/icinga2/issues/1923) (Packages): 64-bit RPMs are not installable * [#1888](https://github.com/Icinga/icinga2/issues/1888) (Packages): Recommend related packages on SUSE distributions * [#1887](https://github.com/Icinga/icinga2/issues/1887) (Installation): Clean up spec file * [#1885](https://github.com/Icinga/icinga2/issues/1885) (Packages): enforce /usr/lib as base for the cgi path on SUSE distributions * [#1883](https://github.com/Icinga/icinga2/issues/1883) (Installation): use \_rundir macro for configuring the run directory * [#1873](https://github.com/Icinga/icinga2/issues/1873) (Packages): make install does not install the db-schema ## 2.0.2 (2014-08-07) ### Notes * DB IDO schema upgrade required (new schema version: 1.11.6) ### Enhancement * [#1830](https://github.com/Icinga/icinga2/issues/1830) (Plugins): Plugin Check Commands: Add timeout option to check\_ssh * [#1826](https://github.com/Icinga/icinga2/issues/1826): Print application paths for --version * [#1785](https://github.com/Icinga/icinga2/issues/1785): Release 2.0.2 * [#1784](https://github.com/Icinga/icinga2/issues/1784) (Configuration): Require command to be an array when the arguments attribute is used * [#1781](https://github.com/Icinga/icinga2/issues/1781) (Plugins): Plugin Check Commands: Add expect option to check\_http ### Bug * [#1861](https://github.com/Icinga/icinga2/issues/1861): write startup error messages to error.log * [#1858](https://github.com/Icinga/icinga2/issues/1858): event command execution does not call finish handler * [#1855](https://github.com/Icinga/icinga2/issues/1855): Startup logfile is not flushed to disk * [#1853](https://github.com/Icinga/icinga2/issues/1853) (DB IDO): exit application if ido schema version does not match * [#1852](https://github.com/Icinga/icinga2/issues/1852): Error handler for getaddrinfo must use gai\_strerror * [#1848](https://github.com/Icinga/icinga2/issues/1848): Missing space in error message * [#1840](https://github.com/Icinga/icinga2/issues/1840): \[Patch\] Fix build issue and crash found on Solaris, potentially other Unix OSes * [#1839](https://github.com/Icinga/icinga2/issues/1839): Icinga 2 crashes during startup * [#1834](https://github.com/Icinga/icinga2/issues/1834) (Cluster): High Availablity does not synchronise the data like expected * [#1829](https://github.com/Icinga/icinga2/issues/1829): Service icinga2 reload command does not cause effect * [#1828](https://github.com/Icinga/icinga2/issues/1828): Fix notification definition if no host\_name / service\_description given * [#1816](https://github.com/Icinga/icinga2/issues/1816): Config validation without filename argument fails with unhandled exception * [#1813](https://github.com/Icinga/icinga2/issues/1813) (Performance Data): GraphiteWriter: Malformatted integer values * [#1800](https://github.com/Icinga/icinga2/issues/1800) (Cluster): TLS Connections still unstable in 2.0.1 * [#1796](https://github.com/Icinga/icinga2/issues/1796): "order" attribute doesn't seem to work as expected * [#1792](https://github.com/Icinga/icinga2/issues/1792) (Configuration): sample config: add check commands location hint \(itl/plugin check commands\) * [#1779](https://github.com/Icinga/icinga2/issues/1779) (Configuration): Remove superfluous quotes and commas in dictionaries * [#1778](https://github.com/Icinga/icinga2/issues/1778): Event Commands are triggered in OK HARD state everytime * [#1775](https://github.com/Icinga/icinga2/issues/1775): additional group rights missing when Icinga started with -u and -g * [#1774](https://github.com/Icinga/icinga2/issues/1774) (Cluster): Missing detailed error messages on ApiListener SSL Errors * [#1766](https://github.com/Icinga/icinga2/issues/1766): RPMLint security warning - missing-call-to-setgroups-before-setuid /usr/sbin/icinga2 * [#1757](https://github.com/Icinga/icinga2/issues/1757) (DB IDO): NULL vs empty string * [#1752](https://github.com/Icinga/icinga2/issues/1752) (Cluster): Infinite loop in TlsStream::Close * [#1744](https://github.com/Icinga/icinga2/issues/1744) (DB IDO): Two Custom Variables with same name, but Upper/Lowercase creating IDO duplicate entry * [#1741](https://github.com/Icinga/icinga2/issues/1741): Command pipe blocks when trying to open it more than once in parallel * [#1730](https://github.com/Icinga/icinga2/issues/1730): Check and retry intervals are incorrect * [#1729](https://github.com/Icinga/icinga2/issues/1729): $TOTALHOSTSERVICESWARNING$ and $TOTALHOSTSERVICESCRITICAL$ aren't getting converted * [#1728](https://github.com/Icinga/icinga2/issues/1728): Service dependencies aren't getting converted properly * [#1726](https://github.com/Icinga/icinga2/issues/1726): group names quoted twice in arrays * [#1723](https://github.com/Icinga/icinga2/issues/1723): add log message for invalid performance data * [#1722](https://github.com/Icinga/icinga2/issues/1722): GraphiteWriter regularly sends empty lines * [#1721](https://github.com/Icinga/icinga2/issues/1721) (Configuration): Add cmake constant for PluginDir * [#1684](https://github.com/Icinga/icinga2/issues/1684) (Notifications): Notifications not always triggered * [#1674](https://github.com/Icinga/icinga2/issues/1674): ipmi-sensors segfault due to stack size * [#1666](https://github.com/Icinga/icinga2/issues/1666) (DB IDO): objects and their ids are inserted twice ### ITL * [#1825](https://github.com/Icinga/icinga2/issues/1825) (ITL): The "ssl" check command always sets -D * [#1821](https://github.com/Icinga/icinga2/issues/1821) (ITL): Order doesn't work in check ssh command ### Documentation * [#1802](https://github.com/Icinga/icinga2/issues/1802) (Documentation): wrong path for the file 'localhost.conf' * [#1801](https://github.com/Icinga/icinga2/issues/1801) (Documentation): Missing documentation about implicit dependency * [#1791](https://github.com/Icinga/icinga2/issues/1791) (Documentation): icinga Web: wrong path to command pipe * [#1789](https://github.com/Icinga/icinga2/issues/1789) (Documentation): update installation with systemd usage * [#1762](https://github.com/Icinga/icinga2/issues/1762) (Documentation): clarify on which features are required for classic ui/web/web2 ### Support * [#1845](https://github.com/Icinga/icinga2/issues/1845) (Packages): Remove if\(NOT DEFINED ICINGA2\_SYSCONFIGFILE\) in etc/initsystem/CMakeLists.txt * [#1842](https://github.com/Icinga/icinga2/issues/1842) (Packages): incorrect sysconfig path on sles11 * [#1820](https://github.com/Icinga/icinga2/issues/1820) (Installation): Repo Error on RHEL 6.5 * [#1780](https://github.com/Icinga/icinga2/issues/1780) (Packages): Rename README to README.md * [#1763](https://github.com/Icinga/icinga2/issues/1763) (Packages): Build packages for el7 * [#1754](https://github.com/Icinga/icinga2/issues/1754) (Installation): Location of the run directory is hard coded and bound to "local\_state\_dir" * [#1699](https://github.com/Icinga/icinga2/issues/1699) (Packages): Classic UI Debian/Ubuntu: apache 2.4 requires 'a2enmod cgi' & apacheutils installed * [#1338](https://github.com/Icinga/icinga2/issues/1338) (Packages): SUSE packages ## 2.0.1 (2014-07-10) ### Notes Bugfix release ### Enhancement * [#1713](https://github.com/Icinga/icinga2/issues/1713) (Configuration): Add port option to check imap/pop/smtp and a new dig * [#1049](https://github.com/Icinga/icinga2/issues/1049) (Livestatus): OutputFormat python ### Bug * [#1773](https://github.com/Icinga/icinga2/issues/1773) (Notifications): Problem with enable\_notifications and retained state * [#1772](https://github.com/Icinga/icinga2/issues/1772) (Notifications): enable\_notifications = false for users has no effect * [#1771](https://github.com/Icinga/icinga2/issues/1771) (Cluster): Icinga crashes after "Too many queued messages" * [#1769](https://github.com/Icinga/icinga2/issues/1769): Build fails when MySQL is not installed * [#1767](https://github.com/Icinga/icinga2/issues/1767): Increase icinga.cmd Limit * [#1753](https://github.com/Icinga/icinga2/issues/1753) (Configuration): icinga2-sign-key creates ".crt" and ".key" files when the CA passphrase is invalid * [#1751](https://github.com/Icinga/icinga2/issues/1751) (Configuration): icinga2-build-ca shouldn't prompt for DN * [#1749](https://github.com/Icinga/icinga2/issues/1749): TLS connections are still unstable * [#1745](https://github.com/Icinga/icinga2/issues/1745): Icinga stops updating IDO after a while * [#1743](https://github.com/Icinga/icinga2/issues/1743) (Configuration): Please add --sni option to http check command * [#1740](https://github.com/Icinga/icinga2/issues/1740) (Notifications): Notifications causing segfault from exim * [#1737](https://github.com/Icinga/icinga2/issues/1737) (DB IDO): icinga2-ido-pgsql snapshot package missing dependecy dbconfig-common * [#1736](https://github.com/Icinga/icinga2/issues/1736): Remove line number information from stack traces * [#1734](https://github.com/Icinga/icinga2/issues/1734): Check command result doesn't match * [#1731](https://github.com/Icinga/icinga2/issues/1731): Dependencies should cache their parent and child object * [#1727](https://github.com/Icinga/icinga2/issues/1727): $SERVICEDESC$ isn't getting converted correctly * [#1724](https://github.com/Icinga/icinga2/issues/1724): Improve systemd service definition * [#1716](https://github.com/Icinga/icinga2/issues/1716) (Cluster): Icinga doesn't send SetLogPosition messages when one of the endpoints fails to connect * [#1712](https://github.com/Icinga/icinga2/issues/1712): parsing of double defined command can generate unexpected errors * [#1704](https://github.com/Icinga/icinga2/issues/1704): Reminder notifications are sent on disabled services * [#1698](https://github.com/Icinga/icinga2/issues/1698): icinga2 cannot be built with both systemd and init.d files * [#1697](https://github.com/Icinga/icinga2/issues/1697) (Livestatus): Thruk Panorama View cannot query Host Status * [#1695](https://github.com/Icinga/icinga2/issues/1695): icinga2.state could not be opened * [#1691](https://github.com/Icinga/icinga2/issues/1691): build warnings * [#1644](https://github.com/Icinga/icinga2/issues/1644) (Cluster): base64 on CentOS 5 fails to read certificate bundles * [#1639](https://github.com/Icinga/icinga2/issues/1639) (Cluster): Deadlock in ApiListener::RelayMessage * [#1609](https://github.com/Icinga/icinga2/issues/1609): application fails to start on wrong log file permissions but does not tell about it * [#1206](https://github.com/Icinga/icinga2/issues/1206) (DB IDO): PostgreSQL string escaping ### ITL * [#1739](https://github.com/Icinga/icinga2/issues/1739) (ITL): Add more options to snmp check ### Documentation * [#1777](https://github.com/Icinga/icinga2/issues/1777) (Documentation): event command execution cases are missing * [#1765](https://github.com/Icinga/icinga2/issues/1765) (Documentation): change docs.icinga.org/icinga2/latest to git master * [#1742](https://github.com/Icinga/icinga2/issues/1742) (Documentation): Documentation for || and && is missing * [#1702](https://github.com/Icinga/icinga2/issues/1702) (Documentation): Array section confusing ### Support * [#1764](https://github.com/Icinga/icinga2/issues/1764) (Installation): ICINGA2\_SYSCONFIGFILE should use full path using CMAKE\_INSTALL\_FULL\_SYSCONFDIR * [#1709](https://github.com/Icinga/icinga2/issues/1709) (Packages): htpasswd should be installed with icinga2-classicui on Ubuntu * [#1696](https://github.com/Icinga/icinga2/issues/1696) (Packages): Copyright problems * [#1655](https://github.com/Icinga/icinga2/issues/1655) (Packages): Debian package icinga2-classicui needs versioned dependency of icinga-cgi\* ## 2.0.0 (2014-06-16) ### Notes First official release ### Enhancement * [#1600](https://github.com/Icinga/icinga2/issues/1600): Prepare 2.0.0 release * [#1575](https://github.com/Icinga/icinga2/issues/1575) (Cluster): Cluster: global zone for all nodes * [#1348](https://github.com/Icinga/icinga2/issues/1348): move vagrant box into dedicated demo project * [#1341](https://github.com/Icinga/icinga2/issues/1341): Revamp migration script * [#1322](https://github.com/Icinga/icinga2/issues/1322): Update website for release * [#1320](https://github.com/Icinga/icinga2/issues/1320): Update documentation for 2.0 ### Bug * [#1694](https://github.com/Icinga/icinga2/issues/1694): Separate CMakeLists.txt for etc/initsystem * [#1682](https://github.com/Icinga/icinga2/issues/1682) (Configuration): logrotate.conf file should rotate log files as icinga user * [#1680](https://github.com/Icinga/icinga2/issues/1680) (Livestatus): Column 'host\_name' does not exist in table 'hosts' * [#1678](https://github.com/Icinga/icinga2/issues/1678) (Livestatus): Nagvis does not work with livestatus \(invalid format\) * [#1673](https://github.com/Icinga/icinga2/issues/1673): OpenSUSE Packages do not enable basic features * [#1669](https://github.com/Icinga/icinga2/issues/1669) (Cluster): Segfault with zones without endpoints on config compile * [#1642](https://github.com/Icinga/icinga2/issues/1642): Check if host recovery notifications work * [#1615](https://github.com/Icinga/icinga2/issues/1615) (Cluster): Subdirectories in the zone config are not synced * [#1427](https://github.com/Icinga/icinga2/issues/1427): fd-handling in Daemonize incorrect * [#1312](https://github.com/Icinga/icinga2/issues/1312): Permissions error on startup is only logged but not on stderr ### ITL * [#1690](https://github.com/Icinga/icinga2/issues/1690) (ITL): improve predefined command-plugins ### Documentation * [#1689](https://github.com/Icinga/icinga2/issues/1689) (Documentation): explain the icinga 2 reload * [#1681](https://github.com/Icinga/icinga2/issues/1681) (Documentation): Add instructions to install debug symbols on debian systems * [#1675](https://github.com/Icinga/icinga2/issues/1675) (Documentation): add a note on no length restrictions for plugin output / perfdata * [#1636](https://github.com/Icinga/icinga2/issues/1636) (Documentation): Update command definitions to use argument conditions * [#1572](https://github.com/Icinga/icinga2/issues/1572) (Documentation): change docs.icinga.org/icinga2/snapshot to 'latest' * [#1302](https://github.com/Icinga/icinga2/issues/1302) (Documentation): Replace Sphinx with Icinga Web 2 Doc Module ### Support * [#1686](https://github.com/Icinga/icinga2/issues/1686) (Installation): man pages for scripts * [#1685](https://github.com/Icinga/icinga2/issues/1685) (Installation): Cleanup installer for 2.0 supported features * [#1683](https://github.com/Icinga/icinga2/issues/1683) (Installation): remove 0.0.x schema upgrade files * [#1670](https://github.com/Icinga/icinga2/issues/1670) (Packages): Ubuntu package Release file lacks 'Suite' line * [#1645](https://github.com/Icinga/icinga2/issues/1645) (Packages): Packages are not installable on CentOS 5 * [#1342](https://github.com/Icinga/icinga2/issues/1342) (Installation): Less verbose start output using the initscript * [#1319](https://github.com/Icinga/icinga2/issues/1319) (Tests): Release tests * [#907](https://github.com/Icinga/icinga2/issues/907) (Packages): icinga2-classicui is not installable on Debian * [#788](https://github.com/Icinga/icinga2/issues/788) (Packages): add systemd support icinga2-2.8.1/CMakeLists.txt000066400000000000000000000327561322762156600156250ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. cmake_minimum_required(VERSION 2.6) set(BOOST_MIN_VERSION "1.41.0") project(icinga2) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third-party/cmake") if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() option(ICINGA2_WITH_MYSQL "Build the MySQL IDO module" ON) option(ICINGA2_WITH_PGSQL "Build the PostgreSQL IDO module" ON) option(ICINGA2_WITH_CHECKER "Build the checker module" ON) option(ICINGA2_WITH_COMPAT "Build the compat module" ON) option(ICINGA2_WITH_DEMO "Build the demo module" OFF) option(ICINGA2_WITH_HELLO "Build the hello module" OFF) option(ICINGA2_WITH_LIVESTATUS "Build the Livestatus module" ON) option(ICINGA2_WITH_NOTIFICATION "Build the notification module" ON) option(ICINGA2_WITH_PERFDATA "Build the perfdata module" ON) option(ICINGA2_WITH_STUDIO "Build the Icinga Studio application" OFF) option(ICINGA2_WITH_TESTS "Run unit tests" ON) file(STRINGS icinga2.spec VERSION_LINE REGEX "^Version: ") string(REPLACE "Version: " "" ICINGA2_VERSION ${VERSION_LINE}) include(GNUInstallDirs) include(InstallConfig) set(ICINGA2_USER "icinga" CACHE STRING "Icinga 2 user") set(ICINGA2_GROUP "icinga" CACHE STRING "Icinga 2 group") set(ICINGA2_COMMAND_GROUP "icingacmd" CACHE STRING "Icinga 2 command group") set(ICINGA2_RUNDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/run" CACHE STRING "/run directory") set(ICINGA2_PLUGINDIR "/usr/lib/nagios/plugins" CACHE STRING "Path for the check plugins") set(ICINGA2_GIT_VERSION_INFO ON CACHE BOOL "Whether to use git describe") set(ICINGA2_UNITY_BUILD ON CACHE BOOL "Whether to perform a unity build") set(ICINGA2_LTO_BUILD OFF CACHE BOOL "Whether to use LTO") site_name(ICINGA2_BUILD_HOST_NAME) set(ICINGA2_BUILD_COMPILER_NAME "${CMAKE_CXX_COMPILER_ID}") if(NOT CMAKE_CXX_COMPILER_VERSION) execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) endif() set(ICINGA2_BUILD_COMPILER_VERSION "${CMAKE_CXX_COMPILER_VERSION}") file(READ "${CMAKE_CURRENT_SOURCE_DIR}/COPYING" ICINGA2_LICENSE_GPL) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/COPYING.Exceptions" ICINGA2_LICENSE_ADDITIONS) set(ICINGA2_LICENSE "${ICINGA2_LICENSE_GPL}\n\n---\n\n${ICINGA2_LICENSE_ADDITIONS}") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt" ${ICINGA2_LICENSE}) file(STRINGS icinga2.spec SPEC_VERSION REGEX "^Version:") string(LENGTH "${SPEC_VERSION}" SPEC_VERSION_LENGTH) math(EXPR SPEC_VERSION_LENGTH "${SPEC_VERSION_LENGTH} - 9") string(SUBSTRING ${SPEC_VERSION} 9 ${SPEC_VERSION_LENGTH} SPEC_VERSION) configure_file(icinga-spec-version.h.cmake icinga-spec-version.h) include(GetGitRevisionDescription) git_describe(GIT_VERSION --tags) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/icinga-version.h.force) configure_file(icinga-version.h.force ${CMAKE_CURRENT_BINARY_DIR}/icinga-version.h COPYONLY) else() if(NOT ICINGA2_GIT_VERSION_INFO OR GIT_VERSION MATCHES "-NOTFOUND$") file(STRINGS icinga2.spec SPEC_REVISION REGEX "^%define revision ") string(LENGTH "${SPEC_REVISION}" SPEC_REVISION_LENGTH) math(EXPR SPEC_REVISION_LENGTH "${SPEC_REVISION_LENGTH} - 17") string(SUBSTRING ${SPEC_REVISION} 17 ${SPEC_REVISION_LENGTH} SPEC_REVISION) set(GIT_VERSION "r${SPEC_VERSION}-${SPEC_REVISION}") endif() configure_file(icinga-version.h.cmake icinga-version.h) endif() if(WIN32) set(Boost_USE_STATIC_LIBS ON) add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(/bigobj) endif() if(NOT DEFINED LOGROTATE_HAS_SU) set(LOGROTATE_HAS_SU OFF) find_program(LOGROTATE_BINARY logrotate) execute_process(COMMAND ${LOGROTATE_BINARY} ERROR_VARIABLE LOGROTATE_OUTPUT) if(LOGROTATE_OUTPUT) string(REGEX REPLACE "^logrotate ([0-9.]*).*" "\\1" LOGROTATE_VERSION ${LOGROTATE_OUTPUT}) message(STATUS "Found logrotate (found version \"${LOGROTATE_VERSION}\")") if("${LOGROTATE_VERSION}" VERSION_GREATER "3.7.9") set(LOGROTATE_HAS_SU ON) endif() endif() endif() if(LOGROTATE_HAS_SU) set(LOGROTATE_USE_SU "\n\tsu ${ICINGA2_USER} ${ICINGA2_GROUP}") endif() find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS thread system program_options regex REQUIRED) link_directories(${Boost_LIBRARY_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) find_package(OpenSSL REQUIRED) include_directories(${OPENSSL_INCLUDE_DIR}) find_package(YAJL) if(NOT YAJL_FOUND) include_directories(${icinga2_BINARY_DIR}/third-party/yajl/include) link_directories(${icinga2_BINARY_DIR}/third-party/yajl) set(YAJL_LIBRARIES "yajl") endif() find_package(Editline) set(HAVE_EDITLINE "${EDITLINE_FOUND}") find_package(Termcap) set(HAVE_TERMCAP "${TERMCAP_FOUND}") include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/lib ) set(CMAKE_MACOSX_RPATH 1) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -g") # Clang on Fedora requires -pthread, Apple Clang does not # AppleClang is available since CMake 3.0.0 if (NOT CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") endif() endif() if(CMAKE_C_COMPILER_ID STREQUAL "SunPro") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mt") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mt -library=stlport4") endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") if(CMAKE_SYSTEM_NAME MATCHES AIX) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -g -lpthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -lpthread") elseif(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -pthread") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpthread") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lpthread") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -pthread") endif() if(NOT CMAKE_SYSTEM_NAME MATCHES AIX AND NOT CMAKE_SYSTEM_NAME MATCHES OpenBSD AND NOT CMAKE_SYSTEM_NAME MATCHES SunOS) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -Wl,--no-export-dynamic -Bsymbolic-functions -Wl,--dynamic-list-cpp-typeinfo -Wl,--dynamic-list-data") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--no-export-dynamic -Bsymbolic-functions -Wl,--dynamic-list-cpp-typeinfo -Wl,--dynamic-list-data") endif() endif() include(CheckCXXCompilerFlag) if(ICINGA2_LTO_BUILD) check_cxx_compiler_flag("-flto" CXX_FLAG_LTO) if(NOT CXX_FLAG_LTO) message(WARNING "Compiler does not support LTO, falling back to non-LTO build") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto") endif() endif() include(CheckCCompilerFlag) check_c_compiler_flag(-fvisibility-inlines-hidden HAVE_VISIBILITY_INLINES_HIDDEN) if(HAVE_VISIBILITY_INLINES_HIDDEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility-inlines-hidden") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") endif() check_c_compiler_flag(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) if(HAVE_VISIBILITY_HIDDEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") endif() if(MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS) endif() set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/Bin/${CMAKE_BUILD_TYPE} CACHE PATH "Library output path") set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/Bin/${CMAKE_BUILD_TYPE} CACHE PATH "Executable output path") include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckIncludeFileCXX) check_symbol_exists(__COUNTER__ "" HAVE_COUNTER_MACRO) if(NOT HAVE_COUNTER_MACRO) message(FATAL_ERROR "Your C/C++ compiler does not support the __COUNTER__ macro.") endif() set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DI2_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DI2_DEBUG") check_function_exists(vfork HAVE_VFORK) check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS) check_function_exists(pipe2 HAVE_PIPE2) check_function_exists(nice HAVE_NICE) check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR) check_library_exists(execinfo backtrace_symbols "" HAVE_LIBEXECINFO) check_include_file_cxx(cxxabi.h HAVE_CXXABI_H) if(HAVE_LIBEXECINFO) set(HAVE_BACKTRACE_SYMBOLS TRUE) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") exec_program(${CMAKE_CXX_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE _ICINGA2_COMPILER_VERSION ) if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.7.0") message(FATAL_ERROR "Your version of GCC (${CMAKE_CXX_COMPILER_VERSION}) is too old for building Icinga 2 (GCC >= 4.7.0 is required).") endif() endif() if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") check_cxx_source_compiles("class Base { public: virtual void test(void) { } }; class Derived : public Base { virtual void test(void) override { } }; int main(){}" CXX_FEATURE_OVERRIDE) if(NOT CXX_FEATURE_OVERRIDE) add_definitions("-Doverride=") endif() endif() configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ESCAPE_QUOTES) install( FILES README.md COPYING COPYING.Exceptions AUTHORS CHANGELOG.md NEWS DESTINATION ${CMAKE_INSTALL_DOCDIR} ) include(CTest) enable_testing() set_property(GLOBAL PROPERTY USE_FOLDERS ON) add_subdirectory(third-party) add_subdirectory(tools) add_subdirectory(lib) add_subdirectory(icinga-app) add_subdirectory(etc) add_subdirectory(itl) add_subdirectory(doc) add_subdirectory(agent) add_subdirectory(plugins) add_subdirectory(choco) if(MSVC) add_subdirectory(icinga-installer) endif() if(ICINGA2_WITH_STUDIO) add_subdirectory(icinga-studio) endif() if(ICINGA2_WITH_TESTS) add_subdirectory(test) endif() set(CPACK_PACKAGE_NAME "Icinga 2") set(CPACK_PACKAGE_VENDOR "Icinga Development Team") set(CPACK_PACKAGE_VERSION ${ICINGA2_VERSION}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "ICINGA2") set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icinga-app\\\\icinga.ico") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt") set(CPACK_PACKAGE_EXECUTABLES "Icinga2SetupAgent;Icinga 2 Agent Wizard;icinga-studio;Icinga Studio") set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icinga-app\\\\icinga.ico") set(CPACK_WIX_UPGRADE_GUID "52F2BEAA-4DF0-4C3E-ABDC-C0F61DE4DF8A") set(CPACK_WIX_EXTENSIONS "WixUtilExtension") set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/icinga-installer/bannrbmp.bmp") set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/icinga-installer/dlgbmp.bmp") set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/icinga-installer/icinga2.wixpatch.Debug") set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/icinga-installer/icinga2.wixpatch") set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "sbin") set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE) include(InstallRequiredSystemLibraries) if(WIN32) if(CMAKE_VS_PLATFORM_NAME STREQUAL "x64") set(NSCP_URL "https://github.com/mickem/nscp/releases/download/0.5.0.62/NSCP-0.5.0.62-x64.msi") set(NSCP_SHA256 "1854de86ad4fda3391f273de0f9985b702c014bdec01b26ad28a1343177f537f") else() set(NSCP_URL "https://github.com/mickem/nscp/releases/download/0.5.0.62/NSCP-0.5.0.62-Win32.msi") set(NSCP_SHA256 "2186b60d588fa0811344ce709332f9c63670019c62ae92eae49698bf76205a95") endif() set(NSCP_SHA256SUM "") if (EXISTS ${CMAKE_CURRENT_BINARY_DIR}/NSCP.msi) file(SHA256 ${CMAKE_CURRENT_BINARY_DIR}/NSCP.msi NSCP_SHA256SUM) endif() if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/NSCP.msi OR NOT ${NSCP_SHA256SUM} STREQUAL ${NSCP_SHA256}) file(DOWNLOAD ${NSCP_URL} ${CMAKE_CURRENT_BINARY_DIR}/NSCP.msi SHOW_PROGRESS) endif() install(FILES ${CMAKE_CURRENT_BINARY_DIR}/NSCP.msi DESTINATION ${CMAKE_INSTALL_SBINDIR}) if (OPENSSL_VERSION_MINOR GREATER_EQUAL 1) if (CMAKE_VS_PLATFORM_NAME STREQUAL "x64") list (APPEND ICINGA2_OPENSSL_DLLS ${OPENSSL_INCLUDE_DIR}/../bin/libcrypto-1_1-x64.dll ${OPENSSL_INCLUDE_DIR}/../bin/libssl-1_1-x64.dll) else() list (APPEND ICINGA2_OPENSSL_DLLS ${OPENSSL_INCLUDE_DIR}/../bin/libcrypto-1_1.dll ${OPENSSL_INCLUDE_DIR}/../bin/libssl-1_1.dll) endif() else() list (APPEND ICINGA2_OPENSSL_DLLS ${OPENSSL_INCLUDE_DIR}/../bin/libeay32.dll ${OPENSSL_INCLUDE_DIR}/../bin/ssleay32.dll) endif() install( PROGRAMS ${ICINGA2_OPENSSL_DLLS} DESTINATION ${CMAKE_INSTALL_SBINDIR} ) endif() include(CPack) icinga2-2.8.1/CONTRIBUTING.md000066400000000000000000000367461322762156600153210ustar00rootroot00000000000000# Contributing Icinga is an open source project and lives from your ideas and contributions. There are many ways to contribute, from improving the documentation, submitting bug reports and features requests or writing code to add enhancements or fix bugs. #### Table of Contents 1. [Introduction](#contributing-intro) 2. [Fork the Project](#contributing-fork) 3. [Branches](#contributing-branches) 4. [Commits](#contributing-commits) 5. [Pull Requests](#contributing-pull-requests) 6. [Testing](#contributing-testing) 7. [Source Code Patches](#contributing-patches-source-code) 8. [Documentation Patches](#contributing-patches-documentation) 9. [Contribute CheckCommand Definitions](#contributing-patches-itl-checkcommands) 10. [Review](#contributing-review) ## Introduction Please consider our [roadmap](https://github.com/Icinga/icinga2/milestones) and [open issues](https://github.com/icinga/icinga2/issues) when you start contributing to the project. Before starting your work on Icinga 2, you should [fork the project](https://help.github.com/articles/fork-a-repo/) to your GitHub account. This allows you to freely experiment with your changes. When your changes are complete, submit a [pull request](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed and merged if they suit some general guidelines: * Changes are located in a topic branch * For new functionality, proper tests are written * Changes should follow the existing coding style and standards Please continue reading in the following sections for a step by step guide. ## Fork the Project [Fork the project](https://help.github.com/articles/fork-a-repo/) to your GitHub account and clone the repository: ``` git clone git@github.com:dnsmichi/icinga2.git cd icinga2 ``` Add a new remote `upstream` with this repository as value. ``` git remote add upstream https://github.com/icinga/icinga2.git ``` You can pull updates to your fork's master branch: ``` git fetch --all git pull upstream HEAD ``` Please continue to learn about [branches](CONTRIBUTING.md#contributing-branches). ## Branches Choosing a proper name for a branch helps us identify its purpose and possibly find an associated bug or feature. Generally a branch name should include a topic such as `fix` or `feature` followed by a description and an issue number if applicable. Branches should have only changes relevant to a specific issue. ``` git checkout -b fix/service-template-typo-1234 git checkout -b feature/config-handling-1235 ``` Continue to apply your changes and test them. More details on specific changes: * [Source Code Patches](#contributing-patches-source-code) * [Documentation Patches](#contributing-patches-documentation) * [Contribute CheckCommand Definitions](#contributing-patches-itl-checkcommands) ## Commits Once you've finished your work in a branch, please ensure to commit your changes. A good commit message includes a short topic, additional body and a reference to the issue you wish to solve (if existing). Fixes: ``` Fix problem with notifications in HA cluster There was a race condition when restarting. refs #4567 ``` Features: ``` Add ITL CheckCommand printer Requires the check_printer plugin. refs #1234 ``` You can add multiple commits during your journey to finish your patch. Don't worry, you can squash those changes into a single commit later on. ## Pull Requests Once you've commited your changes, please update your local master branch and rebase your fix/feature branch against it before submitting a PR. ``` git checkout master git pull upstream HEAD git checkout fix/notifications git rebase master ``` Once you've resolved any conflicts, push the branch to your remote repository. It might be necessary to force push after rebasing - use with care! New branch: ``` git push --set-upstream origin fix/notifications ``` Existing branch: ``` git push -f origin fix/notifications ``` You can now either use the [hub](https://hub.github.com) CLI tool to create a PR, or nagivate to your GitHub repository and create a PR there. The pull request should again contain a telling subject and a reference with `fixes` to an existing issue id if any. That allows developers to automatically resolve the issues once your PR gets merged. ``` hub pull-request fixes #1234 ``` Thanks a lot for your contribution! ### Rebase a Branch If you accidentally sent in a PR which was not rebased against the upstream master, developers might ask you to rebase your PR. First off, fetch and pull `upstream` master. ``` git checkout master git fetch --all git pull upstream HEAD ``` Then change to your working branch and start rebasing it against master: ``` git checkout fix/notifications git rebase master ``` If you are running into a conflict, rebase will stop and ask you to fix the problems. ``` git status both modified: path/to/conflict.cpp ``` Edit the file and search for `>>>`. Fix, build, test and save as needed. Add the modified file(s) and continue rebasing. ``` git add path/to/conflict.cpp git rebase --continue ``` Once succeeded ensure to push your changed history remotely. ``` git push -f origin fix/notifications ``` If you fear to break things, do the rebase in a backup branch first and later replace your current branch. ``` git checkout fix/notifications git checkout -b fix/notifications-rebase git rebase master git branch -D fix/notifications git checkout -b fix/notifications git push -f origin fix/notifications ``` ### Squash Commits > **Note:** > > Be careful with squashing. This might lead to non-recoverable mistakes. > > This is for advanced Git users. Say you want to squash the last 3 commits in your branch into a single one. Start an interactive (`-i`) rebase from current HEAD minus three commits (`HEAD~3`). ``` git rebase -i HEAD~3 ``` Git opens your preferred editor. `pick` the commit in the first line, change `pick` to `squash` on the other lines. ``` pick e4bf04e47 Fix notifications squash d7b939d99 Tests squash b37fd5377 Doc updates ``` Save and let rebase to its job. Then force push the changes to the remote origin. ``` git push -f origin fix/notifications ``` ## Testing Basic unit test coverage is provided by running `make test` during package builds. Read the [INSTALL.md](INSTALL.md) file for more information about development builds. Snapshot packages from the laster development branch are available inside the [package repository](https://packages.icinga.com). You can help test-drive the latest Icinga 2 snapshot packages inside the [Icinga 2 Vagrant boxes](https://github.com/icinga/icinga-vagrant). ## Source Code Patches Icinga 2 is written in C++ and uses the Boost libraries. We are also using the C++11 standard where applicable (please note the minimum required compiler versions in the [INSTALL.md](INSTALL.md) file. Icinga 2 can be built on Linux/Unix nodes and Windows clients. In order to develop patches for Icinga 2, you should prepare your own local build environment and know how to work with C++. More tips: * Requirements and source code installation for Linux/Unix is explained inside the [INSTALL.md](INSTALL.md) file. * Debug requirements and GDB instructions can be found in the [documentation](https://github.com/Icinga/icinga2/blob/master/doc/20-development.md). * If you are planning to develop and debug the Windows client, setup a Windows environment with [Visual Studio](https://www.visualstudio.com/vs/community/). An example can be found in [this blogpost](https://blog.netways.de/2015/08/24/developing-icinga-2-on-windows-10-using-visual-studio-2015/). ## Documentation Patches The documentation is written in GitHub flavored [Markdown](https://guides.github.com/features/mastering-markdown/). It is located in the `doc/` directory and can be edited with your preferred editor. You can also edit it online on GitHub. ``` vim doc/2-getting-started.md ``` In order to review and test changes, you can install the [mkdocs](http://www.mkdocs.org) Python library. ``` pip install mkdocs ``` This allows you to start a local mkdocs viewer instance on http://localhost:8000 ``` mkdocs serve ``` Changes on the chapter layout can be done inside the `mkdocs.yml` file in the main tree. There also is a script to ensure that relative URLs to other sections are updated. This script also checks for broken URLs. ``` ./doc/update-links.py doc/*.md ``` ## Contribute CheckCommand Definitions The Icinga Template Library (ITL) and its plugin check commands provide a variety of CheckCommand object definitions which can be included on-demand. Advantages of sending them upstream: * Everyone can use and update/fix them. * One single place for configuration and documentation. * Developers may suggest updates and help with best practices. * You don't need to care about copying the command definitions to your satellites and clients. #### Where do I start? Get to know the check plugin and its options. Read the general documentation on how to integrate your check plugins and how to create a good CheckCommand definition. A good command definition uses: * Command arguments including `value`, `description`, optional: `set_if`, `required`, etc. * Comments `/* ... */` to describe difficult parts. * Command name as prefix for the custom attributes referenced (e.g. `disk_`) * Default values * If `host.address` is involved, set a custom attribute (e.g. `ping_address`) to the default `$address$`. This allows users to override the host's address later on by setting the custom attribute inside the service apply definitions. * If the plugin is also capable to use ipv6, import the `ipv4-or-ipv6` template and use `$check_address$` instead of `$address$`. This allows to fall back to ipv6 if only this address is set. * If `set_if` is involved, ensure to specify a sane default value if required. * Templates if there are multiple plugins with the same basic behaviour (e.g. ping4 and ping6). * Your love and enthusiasm in making it the perfect CheckCommand. #### I have created a CheckCommand, what now? Icinga 2 developers love documentation. This isn't just because we want to annoy anyone sending a patch, it's a matter of making your contribution visible to the community. Your patch should consist of 2 parts: * The CheckCommand definition. * The documentation bits. [Fork the repository](https://help.github.com/articles/fork-a-repo/) and ensure that the master branch is up-to-date. Create a new fix or feature branch and start your work. ``` git checkout -b feature/itl-check-printer ``` #### Add CheckCommand Definition to Contrib Plugins There already exists a defined structure for contributed plugins. Navigate to `itl/plugins-contrib.d` and verify where your command definitions fits into. ``` cd itl/plugins-contrib.d/ ls ``` If you want to add or modify an existing Monitoring Plugin please use `itl/command-plugins.conf` instead. ``` vim itl/command-plugins-conf ``` ##### Existing Configuration File Just edit it, and add your CheckCommand definition. ``` vim operating-system.conf ``` Proceed to the documentation. ##### New type for CheckCommand Definition Create a new file with .conf suffix. ``` $ vim printer.conf ``` Add the file to `itl/CMakeLists.txt` in the FILES line in **alpha-numeric order**. This ensures that the installation and packages properly include your newly created file. ``` vim CMakeLists.txt -FILES ipmi.conf network-components.conf operating-system.conf virtualization.conf vmware.conf +FILES ipmi.conf network-components.conf operating-system.conf printer.conf virtualization.conf vmware.conf ``` Add the newly created file to your git commit. ``` git add printer.conf ``` Do not commit it yet but finish with the documentation. #### Create CheckCommand Documentation Edit the documentation file in the `doc/` directory. More details on documentation updates can be found [here](CONTRIBUTING.md#contributing-documentation). ``` vim doc/10-icinga-template-library.md ``` The CheckCommand documentation should be located in the same chapter similar to the configuration file you have just added/modified. Create a section for your plugin, add a description and a table of parameters. Each parameter should have at least: * optional or required * description of its purpose * the default value, if any Look at the existing documentation and "copy" the same style and layout. #### Send a Patch Commit your changes which includes a descriptive commit message. ``` git commit -av Add printer CheckCommand definition Explain its purpose and possible enhancements/shortcomings. refs #existingticketnumberifany ``` Push the branch to the remote origin and create a [pull request](https://help.github.com/articles/using-pull-requests/). ``` git push --set-upstream origin feature/itl-check-printer hub pull-request ``` In case developers ask for changes during review, please add them to the branch and push those changes. ## Review ### Pull Request Review This is only important for developers who will review pull requests. If you want to join the development team, kindly contact us. - Ensure that the style guide applies. - Verify that the patch fixes a problem or linked issue, if any. - Discuss new features with team members. - Test the patch in your local dev environment. If there are changes required, kindly ask for an updated patch. Once the review is completed, merge the PR via GitHub. #### Pull Request Review Fixes In order to amend the commit message, fix conflicts or add missing changes, you can add your changes to the PR. A PR is just a pointer to a different Git repository and branch. By default, pull requests allow to push into the repository of the PR creator. Example for [#4956](https://github.com/Icinga/icinga2/pull/4956): At the bottom it says "Add more commits by pushing to the fix/persistent-comments-are-not-persistent branch on TheFlyingCorpse/icinga2." First off, add the remote repository as additional origin and fetch its content: ``` git remote add theflyingcorpse https://github.com/TheFlyingCorpse/icinga2 git fetch --all ``` Checkout the mentioned remote branch into a local branch (Note: `theflyingcorpse` is the name of the remote): ``` git checkout theflyingcorpse/fix/persistent-comments-are-not-persistent -b fix/persistent-comments-are-not-persistent ``` Rebase, amend, squash or add your own commits on top. Once you are satisfied, push the changes to the remote `theflyingcorpse` and its branch `fix/persistent-comments-are-not-persistent`. The syntax here is `git push :`. ``` git push theflyingcorpse fix/persistent-comments-are-not-persistent:fix/persistent-comments-are-not-persistent ``` In case you've changed the commit history (rebase, amend, squash), you'll need to force push. Be careful, this can't be reverted! ``` git push -f theflyingcorpse fix/persistent-comments-are-not-persistent:fix/persistent-comments-are-not-persistent ``` icinga2-2.8.1/COPYING000066400000000000000000000431021322762156600141030ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.icinga2-2.8.1/COPYING.Exceptions000066400000000000000000000012741322762156600162270ustar00rootroot00000000000000In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. icinga2-2.8.1/INSTALL.md000066400000000000000000000315051322762156600145040ustar00rootroot00000000000000# Installing Icinga 2 The recommended way of installing Icinga 2 is to use packages. The Icinga project provides both release and development packages for a number of operating systems. Please check the documentation in the [doc/](doc/) directory for a current list of available packages and detailed installation instructions. The online documentation is available at [docs.icinga.com](https://docs.icinga.com) and will guide you step by step. There are a number of known caveats when installing from source such as incorrect directory and file permissions. So even if you're planning to not use the official packages it is advisable to build your own Debian or RPM packages. # Builds This information is intended for developers and packagers. ## Build Requirements The following requirements need to be fulfilled in order to build the application using a dist tarball (package names for RHEL and Debian in parentheses): * cmake >= 2.6 * GNU make (make) * C++ compiler which supports C++11 (gcc-c++ >= 4.7 on RHEL/SUSE, build-essential on Debian, alternatively clang++, build-base on Alpine) * RedHat Developer Tools on RHEL5/6 (details on building below) * pkg-config * OpenSSL library and header files >= 0.9.8 (openssl-devel on RHEL, libopenssl1-devel on SLES11, libopenssl-devel on SLES12, libssl-dev on Debian, libressl-dev on Alpine) * Boost library and header files >= 1.48.0 (boost148-devel on EPEL for RHEL / CentOS, libboost-all-dev on Debian, boost-dev on Alpine) * GNU bison (bison) * GNU flex (flex) >= 2.5.35 * recommended: libexecinfo on FreeBSD (automatically used when Icinga 2 is installed via port or package) * optional: MySQL (mysql-devel on RHEL, libmysqlclient-devel on SUSE, libmysqlclient-dev until Debian 8 jessie / default-libmysqlclient-dev from Debian 9 stretch, mariadb-dev on Alpine); set CMake variable `ICINGA2_WITH_MYSQL` to `OFF` to disable this module * optional: PostgreSQL (postgresql-devel on RHEL, libpq-dev on Debian, postgresql-dev on Alpine); set CMake variable `ICINGA2_WITH_PGSQL` to `OFF` to disable this module * optional: YAJL (yajl-devel on RHEL, libyajl-dev on Debian, yajl-dev on Alpine) * optional: libedit (libedit-devel on CentOS (RHEL requires rhel-7-server-optional-rpms repository for el7 e.g.), libedit-dev on Debian and Alpine) * optional: Termcap (libtermcap-devel on RHEL, not necessary on Debian) - only required if libedit doesn't already link against termcap/ncurses * optional: libwxgtk2.8-dev or newer (wxGTK-devel and wxBase) - only required when building the Icinga 2 Studio Note: RHEL5 ships an ancient flex version. Updated packages are available for example from the repoforge buildtools repository. * x86: https://mirror.hs-esslingen.de/repoforge/redhat/el5/en/i386/buildtools/ * x86\_64: https://mirror.hs-esslingen.de/repoforge/redhat/el5/en/x86\_64/buildtools/ ### User Requirements By default Icinga will run as user 'icinga' and group 'icinga'. Additionally the external command pipe and livestatus features require a dedicated command group 'icingacmd'. You can choose your own user/group names and pass them to CMake using the `ICINGA2_USER`, `ICINGA2_GROUP` and `ICINGA2_COMMAND_GROUP` variables. # groupadd icinga # groupadd icingacmd # useradd -c "icinga" -s /sbin/nologin -G icingacmd -g icinga icinga On Alpine (which uses ash busybox) you can run: # addgroup -S icinga # addgroup -S icingacmd # adduser -S -D -H -h /var/spool/icinga2 -s /sbin/nologin -G icinga -g icinga icinga # adduser icinga icingacmd Add the web server user to the icingacmd group in order to grant it write permissions to the external command pipe and livestatus socket: # usermod -a -G icingacmd www-data Make sure to replace "www-data" with the name of the user your web server is running as. ## Building Icinga 2 Once you have installed all the necessary build requirements you can build Icinga 2 using the following commands: $ mkdir build && cd build $ cmake .. $ make $ make install You can specify an alternative installation prefix using `-DCMAKE_INSTALL_PREFIX`: $ cmake .. -DCMAKE_INSTALL_PREFIX=/tmp/icinga2 In addition to `CMAKE_INSTALL_PREFIX` the following Icinga-specific cmake variables are supported: - `ICINGA2_USER`: The user Icinga 2 should run as; defaults to `icinga` - `ICINGA2_GROUP`: The group Icinga 2 should run as; defaults to `icinga` - `ICINGA2_GIT_VERSION_INFO`: Whether to use Git to determine the version number; defaults to `ON` - `ICINGA2_COMMAND_GROUP`: The command group Icinga 2 should use; defaults to `icingacmd` - `ICINGA2_UNITY_BUILD`: Whether to perform a unity build; defaults to `ON` - `ICINGA2_LTO_BUILD`: Whether to use link time optimization (LTO); defaults to `OFF` - `ICINGA2_PLUGINDIR`: The path for the Monitoring Plugins project binaries; defaults to `/usr/lib/nagios/plugins` - `ICINGA2_RUNDIR`: The location of the "run" directory; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/run` - `CMAKE_INSTALL_SYSCONFDIR`: The configuration directory; defaults to `CMAKE_INSTALL_PREFIX/etc` - `ICINGA2_SYSCONFIGFILE`: Where to put the config file the initscript/systemd pulls it's dirs from; defaults to `CMAKE_INSTALL_PREFIX/etc/sysconfig/icinga2` - `CMAKE_INSTALL_LOCALSTATEDIR`: The state directory; defaults to `CMAKE_INSTALL_PREFIX/var` - `USE_SYSTEMD=ON|OFF`: Use systemd or a classic SysV initscript; defaults to `OFF` - `INSTALL_SYSTEMD_SERVICE_AND_INITSCRIPT=ON|OFF` Force install both the systemd service definition file and the SysV initscript in parallel, regardless of how `USE_SYSTEMD` is set. Only use this for special packaging purposes and if you know what you are doing. Defaults to `OFF`. - `ICINGA2_WITH_MYSQL`: Determines whether the MySQL IDO module is built; defaults to `ON` - `ICINGA2_WITH_PGSQL`: Determines whether the PostgreSQL IDO module is built; defaults to `ON` - `ICINGA2_WITH_CHECKER`: Determines whether the checker module is built; defaults to `ON` - `ICINGA2_WITH_COMPAT`: Determines whether the compat module is built; defaults to `ON` - `ICINGA2_WITH_DEMO`: Determines whether the demo module is built; defaults to `OFF` - `ICINGA2_WITH_HELLO`: Determines whether the hello module is built; defaults to `OFF` - `ICINGA2_WITH_LIVESTATUS`: Determines whether the Livestatus module is built; defaults to `ON` - `ICINGA2_WITH_NOTIFICATION`: Determines whether the notification module is built; defaults to `ON` - `ICINGA2_WITH_PERFDATA`: Determines whether the perfdata module is built; defaults to `ON` - `ICINGA2_WITH_STUDIO`: Determines whether the Icinga Studio application is built; defaults to `OFF` - `ICINGA2_WITH_TESTS`: Determines whether the unit tests are built; defaults to `ON` CMake determines the Icinga 2 version number using `git describe` if the source directory is contained in a Git repository. Otherwise the version number is extracted from the [icinga2.spec](icinga2.spec) file. This behavior can be overridden by creating a file called `icinga-version.h.force` in the source directory. Alternatively the `-DICINGA2_GIT_VERSION_INFO=OFF` option for CMake can be used to disable the usage of `git describe`. ## Build Icinga 2 RPMs ### Build Environment on RHEL, CentOS, Fedora, Amazon Linux Setup your build environment: yum -y install rpmdevtools ### Build Environment on SuSE/SLES SLES: zypper addrepo http://download.opensuse.org/repositories/devel:tools/SLE_12_SP2/devel:tools.repo zypper refresh zypper install rpmdevtools spectool OpenSuSE: zypper addrepo http://download.opensuse.org/repositories/devel:tools/openSUSE_Leap_42.3/devel:tools.repo zypper refresh zypper install rpmdevtools spectool ### Package Builds Prepare the rpmbuild directory tree: cd $HOME rpmdev-setuptree Copy the icinga2.spec file to `rpmbuild/SPEC` or fetch the latest version: curl https://raw.githubusercontent.com/Icinga/icinga2/master/icinga2.spec -o $HOME/rpmbuild/SPECS/icinga2.spec Copy the tarball to `rpmbuild/SOURCES` e.g. by using the `spectool` binary provided with `rpmdevtools`: cd $HOME/rpmbuild/SOURCES spectool -g ../SPECS/icinga2.spec cd $HOME/rpmbuild Install the build dependencies. Example for CentOS 7: yum -y install libedit-devel ncurses-devel gcc-c++ libstdc++-devel openssl-devel \ cmake flex bison boost-devel systemd mysql-devel postgresql-devel httpd \ selinux-policy-devel checkpolicy selinux-policy selinux-policy-doc Note: If you are using Amazon Linux, systemd is not required. A shorter way is available using the `yum-builddep` command on RHEL based systems: yum-builddep SPECS/icinga2.spec Build the RPM: rpmbuild -ba SPECS/icinga2.spec ### Additional Hints #### SELinux policy module The following packages are required to build the SELinux policy module: * checkpolicy * selinux-policy (selinux-policy on CentOS 6, selinux-policy-devel on CentOS 7) * selinux-policy-doc #### RHEL/CentOS 5 and 6 The RedHat Developer Toolset is required for building Icinga 2 beforehand. This contains a modern version of flex and a C++ compiler which supports C++11 features. cat >/etc/yum.repos.d/devtools-2.repo <$HOME/.rpmmacros <227, you'll also need to package and install the `etc/initsystem/icinga2.service.limits.conf` file into `/etc/systemd/system/icinga2.service.d`. ### openrc Or if your distribution uses openrc (like Alpine): # rc-service icinga2 Usage: /etc/init.d/icinga2 {start|stop|restart|reload|checkconfig|status} Note: the openrc's init.d is not shipped by default. A working init.d with openrc can be found here: (https://git.alpinelinux.org/cgit/aports/plain/community/icinga2/icinga2.initd). If you have customized some path, edit the file and adjust it according with your setup. Those few steps can be followed: # wget https://git.alpinelinux.org/cgit/aports/plain/community/icinga2/icinga2.initd # mv icinga2.initd /etc/init.d/icinga2 # chmod +x /etc/init.d/icinga2 Icinga 2 reads a single configuration file which is used to specify all configuration settings (global settings, hosts, services, etc.). The configuration format is explained in detail in the [doc/](doc/) directory. By default `make install` installs example configuration files in `/usr/local/etc/icinga2` unless you have specified a different prefix or sysconfdir. icinga2-2.8.1/NEWS000066400000000000000000000001301322762156600135410ustar00rootroot00000000000000News for this application can be found on the project website at https://www.icinga.com icinga2-2.8.1/README.md000066400000000000000000000041201322762156600143240ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/Icinga/icinga2.svg?branch=master)](https://travis-ci.org/Icinga/icinga2) # Icinga 2 ![Icinga Logo](https://www.icinga.com/wp-content/uploads/2014/06/icinga_logo.png) #### Table of Contents 1. [About][About] 2. [License][License] 3. [Installation][Installation] 4. [Documentation][Documentation] 5. [Support][Support] 6. [Contributing][Contributing] ## About Icinga 2 is an open source monitoring system which checks the availability of your network resources, notifies users of outages, and generates performance data for reporting. Scalable and extensible, Icinga 2 can monitor large, complex environments across multiple locations. Icinga 2 as monitoring core works best with [Icinga Web 2](https://www.icinga.com/products/icinga-web-2/) as web interface. More information can be found at [www.icinga.com](https://www.icinga.com/products/icinga-2/) and inside the [documentation](doc/1-about.md). ## License Icinga 2 and the Icinga 2 documentation are licensed under the terms of the GNU General Public License Version 2, you will find a copy of this license in the COPYING file included in the source package. ## Installation Read the [INSTALL.md](INSTALL.md) file for more information about how to install it. ## Documentation The documentation is located in the [doc/](doc/) directory. The latest documentation is also available on https://docs.icinga.com ## Support Check the project website at https://www.icinga.com for status updates. Join the [community channels](https://www.icinga.com/community/get-involved/) for questions or ask an Icinga partner for [professional support](https://www.icinga.com/services/support/). ## Contributing There are many ways to contribute to Icinga -- whether it be sending patches, testing, reporting bugs, or reviewing and updating the documentation. Every contribution is appreciated! Please continue reading in the [contributing chapter](CONTRIBUTING.md). [About]: #about [License]: #license [Installation]: #installation [Documentation]: #documentation [Support]: #support [Contributing]: #contributing icinga2-2.8.1/RELEASE.md000066400000000000000000000073611322762156600144610ustar00rootroot00000000000000# Release Workflow Specify the release version. ``` VERSION=2.7.2 ``` ## Issues Check issues at https://github.com/Icinga/icinga2 ## Backport Commits For minor versions you need to manually backports any and all commits from the master branch which should be part of this release. ## Authors Update the [.mailmap](.mailmap) and [AUTHORS](AUTHORS) files: ``` git checkout master git log --use-mailmap | grep '^Author:' | cut -f2- -d' ' | sort | uniq > AUTHORS ``` ## Version Update the version in the spec file: ``` gsed -i "s/Version: .*/Version: $VERSION/g" icinga2.spec ``` ## Changelog Update the [CHANGELOG.md](CHANGELOG.md) file. Export these environment variables: ``` export ICINGA_GITHUB_AUTH_USERNAME='user' export ICINGA_GITHUB_AUTH_TOKEN='token' export ICINGA_GITHUB_PROJECT='icinga/icinga2' ``` Run the script which updates the [CHANGELOG.md](CHANGELOG.md) file. ``` ./changelog.py git diff ``` ## Git Tag Commit these changes to the "master" branch: ``` git commit -v -a -m "Release version $VERSION" ``` For minor releases: Cherry-pick this commit into the "support" branch: ``` git checkout support/2.7 git cherry-pick master ``` Create a signed tag (tags/v) on the "master" branch (for major releases) or the "support" branch (for minor releases). GB: ``` git tag -u EE8E0720 -m "Version $VERSION" v$VERSION ``` MF: ``` git tag -u D14A1F16 -m "Version $VERSION" v$VERSION ``` NH: ``` git tag -u 630F89D9 -m "Version $VERSION" v$VERSION ``` Push the tag: ``` git push --tags ``` For major releases: Create a new "support" branch: ``` git checkout master git checkout -b support/2.7 git push -u origin support/2.7 ``` For minor releases: Push the support branch, cherry-pick the release commit into master and merge the support branch: ``` git push -u origin support/2.7 git checkout master git cherry-pick support/2.7 git merge --strategy=ours support/2.7 git push origin master ``` # External Dependencies ## Build Server * Verify package build changes for this version. * Test the snapshot packages for all distributions beforehand. * Build the newly created Git tag for Debian/RHEL/SuSE. * Build the newly created Git tag for Windows. ## Release Tests * Test DB IDO with MySQL and PostgreSQL. * Provision the vagrant boxes and test the release packages. * Test the [setup wizard](https://packages.icinga.com/windows/) inside a Windows VM. * Start a new docker container and install/run icinga2. Example for CentOS7: ``` docker run -ti centos:latest bash yum -y install https://packages.icinga.com/epel/icinga-rpm-release-7-latest.noarch.rpm yum -y install icinga2 icinga2 daemon -C ``` ## GitHub Release Create a new release for the newly created Git tag. https://github.com/Icinga/icinga2/releases ## Chocolatey Navigate to the git repository on your Windows box which already has chocolatey installed. Pull/checkout the release. Create the nupkg package: ``` cpack ``` Install the created icinga2 package locally: ``` choco install icinga2 -version 2.7.0 -fdv "%cd%" -source "'%cd%;https://chocolatey.org/api/v2/'" ``` Upload the package to [chocolatey](https://chocolatey.org/packages/upload). ## Online Documentation Ask @bobapple to update the documentation at docs.icinga.com. ## Announcement * Create a new blog post on www.icinga.com/blog * Social media: [Twitter](https://twitter.com/icinga), [Facebook](https://www.facebook.com/icinga), [G+](https://plus.google.com/+icinga), [Xing](https://www.xing.com/communities/groups/icinga-da4b-1060043), [LinkedIn](https://www.linkedin.com/groups/Icinga-1921830/about) * Update IRC channel topic # After the release * Add new minor version on [GitHub](https://github.com/Icinga/icinga2/milestones). * Close the released version on [GitHub](https://github.com/Icinga/icinga2/milestones). icinga2-2.8.1/agent/000077500000000000000000000000001322762156600141465ustar00rootroot00000000000000icinga2-2.8.1/agent/CMakeLists.txt000066400000000000000000000024061322762156600167100ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. if(MSVC) include_external_msproject( icinga2setupagent ${CMAKE_CURRENT_SOURCE_DIR}/windows-setup-agent/Icinga2SetupAgent.csproj TYPE FAE04EC0-301F-11D3-BF4B-00C04F79EFBC PLATFORM Win32 ) install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/windows-setup-agent/bin/\${CMAKE_INSTALL_CONFIG_NAME}/Icinga2SetupAgent.exe ${CMAKE_CURRENT_SOURCE_DIR}/windows-setup-agent/bin/\${CMAKE_INSTALL_CONFIG_NAME}/Icinga2SetupAgent.exe.config DESTINATION ${CMAKE_INSTALL_SBINDIR} ) endif() icinga2-2.8.1/agent/windows-setup-agent/000077500000000000000000000000001322762156600200725ustar00rootroot00000000000000icinga2-2.8.1/agent/windows-setup-agent/.gitignore000066400000000000000000000000071322762156600220570ustar00rootroot00000000000000bin objicinga2-2.8.1/agent/windows-setup-agent/App.config000066400000000000000000000002771322762156600220070ustar00rootroot00000000000000 icinga2-2.8.1/agent/windows-setup-agent/EndpointInputBox.Designer.cs000066400000000000000000000140351322762156600254340ustar00rootroot00000000000000namespace Icinga { partial class EndpointInputBox { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.btnOK = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.txtHost = new System.Windows.Forms.TextBox(); this.txtPort = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.lblHost = new System.Windows.Forms.Label(); this.lblPort = new System.Windows.Forms.Label(); this.lblInstanceName = new System.Windows.Forms.Label(); this.txtInstanceName = new System.Windows.Forms.TextBox(); this.chkConnect = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // btnOK // this.btnOK.Location = new System.Drawing.Point(196, 171); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(75, 23); this.btnOK.TabIndex = 4; this.btnOK.Text = "OK"; this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // // btnCancel // this.btnCancel.CausesValidation = false; this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(277, 171); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(75, 23); this.btnCancel.TabIndex = 5; this.btnCancel.Text = "Cancel"; this.btnCancel.UseVisualStyleBackColor = true; // // txtHost // this.txtHost.Location = new System.Drawing.Point(101, 103); this.txtHost.Name = "txtHost"; this.txtHost.Size = new System.Drawing.Size(251, 20); this.txtHost.TabIndex = 2; // // txtPort // this.txtPort.Location = new System.Drawing.Point(101, 134); this.txtPort.Name = "txtPort"; this.txtPort.Size = new System.Drawing.Size(100, 20); this.txtPort.TabIndex = 3; this.txtPort.Text = "5665"; // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(12, 9); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(276, 13); this.label1.TabIndex = 4; this.label1.Text = "Please enter the connection details for the new endpoint:"; // // lblHost // this.lblHost.AutoSize = true; this.lblHost.Location = new System.Drawing.Point(15, 106); this.lblHost.Name = "lblHost"; this.lblHost.Size = new System.Drawing.Size(32, 13); this.lblHost.TabIndex = 5; this.lblHost.Text = "Host:"; // // lblPort // this.lblPort.AutoSize = true; this.lblPort.Location = new System.Drawing.Point(15, 137); this.lblPort.Name = "lblPort"; this.lblPort.Size = new System.Drawing.Size(29, 13); this.lblPort.TabIndex = 6; this.lblPort.Text = "Port:"; // // lblInstanceName // this.lblInstanceName.AutoSize = true; this.lblInstanceName.Location = new System.Drawing.Point(15, 41); this.lblInstanceName.Name = "lblInstanceName"; this.lblInstanceName.Size = new System.Drawing.Size(82, 13); this.lblInstanceName.TabIndex = 7; this.lblInstanceName.Text = "Instance Name:"; // // txtInstanceName // this.txtInstanceName.Location = new System.Drawing.Point(101, 37); this.txtInstanceName.Name = "txtInstanceName"; this.txtInstanceName.Size = new System.Drawing.Size(251, 20); this.txtInstanceName.TabIndex = 0; // // chkConnect // this.chkConnect.AutoSize = true; this.chkConnect.Checked = true; this.chkConnect.CheckState = System.Windows.Forms.CheckState.Checked; this.chkConnect.Location = new System.Drawing.Point(18, 73); this.chkConnect.Name = "chkConnect"; this.chkConnect.Size = new System.Drawing.Size(141, 17); this.chkConnect.TabIndex = 1; this.chkConnect.Text = "Connect to this endpoint"; this.chkConnect.UseVisualStyleBackColor = true; this.chkConnect.CheckedChanged += new System.EventHandler(this.chkConnect_CheckedChanged); // // EndpointInputBox // this.AcceptButton = this.btnOK; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(360, 202); this.Controls.Add(this.chkConnect); this.Controls.Add(this.txtInstanceName); this.Controls.Add(this.lblInstanceName); this.Controls.Add(this.lblPort); this.Controls.Add(this.lblHost); this.Controls.Add(this.label1); this.Controls.Add(this.txtPort); this.Controls.Add(this.txtHost); this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnOK); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "EndpointInputBox"; this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Add Endpoint"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button btnOK; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label lblHost; private System.Windows.Forms.Label lblPort; public System.Windows.Forms.TextBox txtHost; public System.Windows.Forms.TextBox txtPort; public System.Windows.Forms.TextBox txtInstanceName; private System.Windows.Forms.Label lblInstanceName; public System.Windows.Forms.CheckBox chkConnect; } }icinga2-2.8.1/agent/windows-setup-agent/EndpointInputBox.cs000066400000000000000000000020271322762156600236730ustar00rootroot00000000000000using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace Icinga { public partial class EndpointInputBox : Form { public EndpointInputBox() { InitializeComponent(); } private void Warning(string message) { MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); } private void chkConnect_CheckedChanged(object sender, EventArgs e) { txtHost.Enabled = chkConnect.Checked; txtPort.Enabled = chkConnect.Checked; } private void btnOK_Click(object sender, EventArgs e) { if (txtInstanceName.Text.Length == 0) { Warning("Please enter an instance name."); return; } if (chkConnect.Checked) { if (txtHost.Text.Length == 0) { Warning("Please enter a host name."); return; } if (txtPort.Text.Length == 0) { Warning("Please enter a port."); return; } } DialogResult = DialogResult.OK; Close(); } } } icinga2-2.8.1/agent/windows-setup-agent/EndpointInputBox.resx000066400000000000000000000131021322762156600242430ustar00rootroot00000000000000 text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 icinga2-2.8.1/agent/windows-setup-agent/Icinga2SetupAgent.csproj000066400000000000000000000201451322762156600245720ustar00rootroot00000000000000 Debug x86 {A86F1159-66E8-4BDB-BF28-A2BDAF76517C} WinExe Properties Icinga Icinga2SetupAgent v2.0 512 publish\ true Disk false Foreground 7 Days false false true 0 1.0.0.%2a false false true x86 true full false bin\Debug\ DEBUG;TRACE prompt 4 x86 pdbonly true bin\Release\ TRACE prompt 4 x86 pdbonly true bin\RelWithDebInfo\ TRACE prompt 4 x86 pdbonly true bin\MinSizeRel\ TRACE prompt 4 x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 x64 pdbonly true bin\RelWithDebInfo\ TRACE prompt 4 x64 pdbonly true bin\MinSizeRel\ TRACE prompt 4 icinga.ico app.manifest Form ServiceStatus.cs Form SetupWizard.cs Form EndpointInputBox.cs ServiceStatus.cs SetupWizard.cs EndpointInputBox.cs ResXFileCodeGenerator Resources.Designer.cs Designer True Resources.resx True SettingsSingleFileGenerator Settings.Designer.cs True Settings.settings True False Microsoft .NET Framework 4.5 %28x86 and x64%29 true False .NET Framework 3.5 SP1 Client Profile false False .NET Framework 3.5 SP1 false icinga2-2.8.1/agent/windows-setup-agent/Program.cs000066400000000000000000000050511322762156600220310ustar00rootroot00000000000000using System; using System.IO; using System.Windows.Forms; using Microsoft.Win32; using System.Runtime.InteropServices; using System.Text; namespace Icinga { static class Program { [DllImport("msi.dll", SetLastError = true)] static extern int MsiEnumProducts(int iProductIndex, StringBuilder lpProductBuf); [DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern Int32 MsiGetProductInfo(string product, string property, [Out] StringBuilder valueBuf, ref Int32 len); public static string Icinga2InstallDir { get { StringBuilder szProduct; for (int index = 0; ; index++) { szProduct = new StringBuilder(39); if (MsiEnumProducts(index, szProduct) != 0) break; int cbName = 128; StringBuilder szName = new StringBuilder(cbName); if (MsiGetProductInfo(szProduct.ToString(), "ProductName", szName, ref cbName) != 0) continue; if (szName.ToString() != "Icinga 2") continue; int cbLocation = 1024; StringBuilder szLocation = new StringBuilder(cbLocation); if (MsiGetProductInfo(szProduct.ToString(), "InstallLocation", szLocation, ref cbLocation) == 0) return szLocation.ToString(); } return ""; } } public static string Icinga2DataDir { get { return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\icinga2"; } } public static string Icinga2User { get { if (!File.Exists(Icinga2DataDir + "\\etc\\icinga2\\user")) return "NT AUTHORITY\\NetworkService"; System.IO.StreamReader file = new System.IO.StreamReader(Icinga2DataDir + "\\etc\\icinga2\\user"); string line = file.ReadLine(); file.Close(); if (line != null) return line; else return "NT AUTHORITY\\NetworkService"; } } public static void FatalError(Form owner, string message) { MessageBox.Show(owner, message, "Icinga 2 Setup Wizard", MessageBoxButtons.OK, MessageBoxIcon.Error); Application.Exit(); } /// /// The main entry point for the application. /// [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); string installDir = Program.Icinga2InstallDir; if (installDir == "") { FatalError(null, "Icinga 2 does not seem to be installed properly."); return; } Form form; if (File.Exists(Program.Icinga2DataDir + "\\etc\\icinga2\\features-enabled\\api.conf")) form = new ServiceStatus(); else form = new SetupWizard(); Application.Run(form); } } } icinga2-2.8.1/agent/windows-setup-agent/Properties/000077500000000000000000000000001322762156600222265ustar00rootroot00000000000000icinga2-2.8.1/agent/windows-setup-agent/Properties/AssemblyInfo.cs000066400000000000000000000026601322762156600251540ustar00rootroot00000000000000using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Icinga 2 Agent Wizard")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Icinga Development Team")] [assembly: AssemblyProduct("Icinga 2")] [assembly: AssemblyCopyright("Copyright © 2014-2015 Icinga Development Team")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("51f4fcaf-8cf8-4d1c-9fde-61526c17a0d8")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] icinga2-2.8.1/agent/windows-setup-agent/Properties/Resources.Designer.cs000066400000000000000000000061231322762156600262700ustar00rootroot00000000000000//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Icinga.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Icinga.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// internal static System.Drawing.Bitmap icinga_banner { get { object obj = ResourceManager.GetObject("icinga-banner", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } } } icinga2-2.8.1/agent/windows-setup-agent/Properties/Resources.resx000066400000000000000000000137001322762156600251040ustar00rootroot00000000000000 text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\icinga-banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a icinga2-2.8.1/agent/windows-setup-agent/Properties/Settings.Designer.cs000066400000000000000000000020471322762156600261170ustar00rootroot00000000000000//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Icinga.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } } } icinga2-2.8.1/agent/windows-setup-agent/Properties/Settings.settings000066400000000000000000000003621322762156600256110ustar00rootroot00000000000000 icinga2-2.8.1/agent/windows-setup-agent/ServiceStatus.Designer.cs000066400000000000000000000130471322762156600247710ustar00rootroot00000000000000namespace Icinga { partial class ServiceStatus { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceStatus)); this.picBanner = new System.Windows.Forms.PictureBox(); this.lblStatus = new System.Windows.Forms.Label(); this.txtStatus = new System.Windows.Forms.TextBox(); this.btnReconfigure = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button(); this.btnOpenConfigDir = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit(); this.SuspendLayout(); // // picBanner // this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner; this.picBanner.Location = new System.Drawing.Point(0, 0); this.picBanner.Name = "picBanner"; this.picBanner.Size = new System.Drawing.Size(625, 77); this.picBanner.TabIndex = 2; this.picBanner.TabStop = false; // // lblStatus // this.lblStatus.AutoSize = true; this.lblStatus.Location = new System.Drawing.Point(12, 105); this.lblStatus.Name = "lblStatus"; this.lblStatus.Size = new System.Drawing.Size(79, 13); this.lblStatus.TabIndex = 3; this.lblStatus.Text = "Service Status:"; // // txtStatus // this.txtStatus.Location = new System.Drawing.Point(97, 102); this.txtStatus.Name = "txtStatus"; this.txtStatus.ReadOnly = true; this.txtStatus.Size = new System.Drawing.Size(278, 20); this.txtStatus.TabIndex = 3; // // btnReconfigure // this.btnReconfigure.Location = new System.Drawing.Point(195, 143); this.btnReconfigure.Name = "btnReconfigure"; this.btnReconfigure.Size = new System.Drawing.Size(89, 23); this.btnReconfigure.TabIndex = 1; this.btnReconfigure.Text = "Reconfigure"; this.btnReconfigure.UseVisualStyleBackColor = true; this.btnReconfigure.Click += new System.EventHandler(this.btnReconfigure_Click); // // btnOK // this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnOK.Location = new System.Drawing.Point(290, 143); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(89, 23); this.btnOK.TabIndex = 0; this.btnOK.Text = "OK"; this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // // btnOpenConfigDir // this.btnOpenConfigDir.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnOpenConfigDir.Location = new System.Drawing.Point(100, 143); this.btnOpenConfigDir.Name = "btnOpenConfigDir"; this.btnOpenConfigDir.Size = new System.Drawing.Size(89, 23); this.btnOpenConfigDir.TabIndex = 2; this.btnOpenConfigDir.Text = "Examine Config"; this.btnOpenConfigDir.UseVisualStyleBackColor = true; this.btnOpenConfigDir.Click += new System.EventHandler(this.btnOpenConfigDir_Click); // // ServiceStatus // this.AcceptButton = this.btnOK; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btnOK; this.ClientSize = new System.Drawing.Size(391, 186); this.Controls.Add(this.btnOpenConfigDir); this.Controls.Add(this.btnOK); this.Controls.Add(this.btnReconfigure); this.Controls.Add(this.txtStatus); this.Controls.Add(this.lblStatus); this.Controls.Add(this.picBanner); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.Name = "ServiceStatus"; this.Text = "Icinga 2 Service Status"; ((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.PictureBox picBanner; private System.Windows.Forms.Label lblStatus; private System.Windows.Forms.TextBox txtStatus; private System.Windows.Forms.Button btnReconfigure; private System.Windows.Forms.Button btnOK; private System.Windows.Forms.Button btnOpenConfigDir; } }icinga2-2.8.1/agent/windows-setup-agent/ServiceStatus.cs000066400000000000000000000015471322762156600232340ustar00rootroot00000000000000using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.ServiceProcess; using System.Diagnostics; namespace Icinga { public partial class ServiceStatus : Form { public ServiceStatus() { InitializeComponent(); try { ServiceController sc = new ServiceController("icinga2"); txtStatus.Text = sc.Status.ToString(); } catch (InvalidOperationException) { txtStatus.Text = "Not Available"; } } private void btnReconfigure_Click(object sender, EventArgs e) { new SetupWizard().ShowDialog(this); } private void btnOK_Click(object sender, EventArgs e) { Close(); } private void btnOpenConfigDir_Click(object sender, EventArgs e) { Process.Start("explorer.exe", Program.Icinga2DataDir); } } } icinga2-2.8.1/agent/windows-setup-agent/ServiceStatus.resx000066400000000000000000000157321322762156600236110ustar00rootroot00000000000000 text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 AAABAAEAICAQAAAABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAAAIAAAAAAAAAAAAAEAAAABAA AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP// AAD///8AAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAcAAAcAB3AAAAAAAAAAAAAAcABwB///cA AAAAAAAAAAAAcAAA////AAAAAAAAAAAAAAAAAP///3AAAAAAAAAAAAAAAAD///9wAAAAAAAAAAAAAAAA j//4AAAAB3AAAAAAAAAAAAj/jwAAAA/4AAAAAAAAAAAAAAiAAAAP9wAAAAAAAAAAAAAH9wAAf3AAAAAA AAAAAAAAAH93d/cAAAAAAAAAAAAAAAB////3AAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAB/////9w AAAAAAAAAAAAAAf/////gAAAAAAAAAAAAAAH//////h3AAAAAAAAAAAAB/////+I//h3eHAAAAAAAAD/ ////AAB3j//3AAAAAAB4////9wAAAAf/+AAAAAf/+AB4iPAAAAAAj/cAAAAH//AAAAD3AAAAAAcAAAAA B/+AAAAAjwAAAAAAAAAAAAB3AAAAAA9wAAAAAAAAAAAAAAAAAAAIh3AAAAAAAAAAAAAAAAAAD//wAAAA AAAAAAAAAAAAAH//9wAAAAAAAAAAAAAAAAB///cAAAAAAAcAAAAAAAAACP+AAAAAAHAAcAAAAAAAAAB3 AAAAAAcAAAcAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAD/////4AAAB8AAAAOAAAABgAAAAYAA AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAA AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAcAAAAPgAAAH/////w== icinga2-2.8.1/agent/windows-setup-agent/SetupWizard.Designer.cs000066400000000000000000000742501322762156600244510ustar00rootroot00000000000000namespace Icinga { partial class SetupWizard { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SetupWizard)); this.btnBack = new System.Windows.Forms.Button(); this.btnNext = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.tabFinish = new System.Windows.Forms.TabPage(); this.lblSetupCompleted = new System.Windows.Forms.Label(); this.tabConfigure = new System.Windows.Forms.TabPage(); this.lblConfigStatus = new System.Windows.Forms.Label(); this.prgConfig = new System.Windows.Forms.ProgressBar(); this.tabParameters = new System.Windows.Forms.TabPage(); this.groupBox3 = new System.Windows.Forms.GroupBox(); this.txtUser = new System.Windows.Forms.TextBox(); this.chkRunServiceAsThisUser = new System.Windows.Forms.CheckBox(); this.chkInstallNSCP = new System.Windows.Forms.CheckBox(); this.chkAcceptConfig = new System.Windows.Forms.CheckBox(); this.chkAcceptCommands = new System.Windows.Forms.CheckBox(); this.txtTicket = new System.Windows.Forms.TextBox(); this.lblTicket = new System.Windows.Forms.Label(); this.txtInstanceName = new System.Windows.Forms.TextBox(); this.lblInstanceName = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.rdoNoListener = new System.Windows.Forms.RadioButton(); this.txtListenerPort = new System.Windows.Forms.TextBox(); this.lblListenerPort = new System.Windows.Forms.Label(); this.rdoListener = new System.Windows.Forms.RadioButton(); this.groupBox1 = new System.Windows.Forms.GroupBox(); this.btnEditEndpoint = new System.Windows.Forms.Button(); this.btnRemoveEndpoint = new System.Windows.Forms.Button(); this.btnAddEndpoint = new System.Windows.Forms.Button(); this.lvwEndpoints = new System.Windows.Forms.ListView(); this.colInstanceName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colHost = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colPort = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.tbcPages = new System.Windows.Forms.TabControl(); this.tabRetrieveCertificate = new System.Windows.Forms.TabPage(); this.lblRetrieveCertificate = new System.Windows.Forms.Label(); this.prgRetrieveCertificate = new System.Windows.Forms.ProgressBar(); this.tabVerifyCertificate = new System.Windows.Forms.TabPage(); this.grpX509Fields = new System.Windows.Forms.GroupBox(); this.txtX509Field = new System.Windows.Forms.TextBox(); this.lvwX509Fields = new System.Windows.Forms.ListView(); this.colField = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colValue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.txtX509Subject = new System.Windows.Forms.TextBox(); this.txtX509Issuer = new System.Windows.Forms.TextBox(); this.lblX509Subject = new System.Windows.Forms.Label(); this.lblX509Issuer = new System.Windows.Forms.Label(); this.lblX509Prompt = new System.Windows.Forms.Label(); this.tabError = new System.Windows.Forms.TabPage(); this.txtError = new System.Windows.Forms.TextBox(); this.lblError = new System.Windows.Forms.Label(); this.picBanner = new System.Windows.Forms.PictureBox(); this.introduction1 = new System.Windows.Forms.Label(); this.tabFinish.SuspendLayout(); this.tabConfigure.SuspendLayout(); this.tabParameters.SuspendLayout(); this.groupBox3.SuspendLayout(); this.groupBox2.SuspendLayout(); this.groupBox1.SuspendLayout(); this.tbcPages.SuspendLayout(); this.tabRetrieveCertificate.SuspendLayout(); this.tabVerifyCertificate.SuspendLayout(); this.grpX509Fields.SuspendLayout(); this.tabError.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit(); this.SuspendLayout(); // // btnBack // this.btnBack.Enabled = false; this.btnBack.Location = new System.Drawing.Point(367, 592); this.btnBack.Name = "btnBack"; this.btnBack.Size = new System.Drawing.Size(75, 23); this.btnBack.TabIndex = 1; this.btnBack.Text = "< &Back"; this.btnBack.UseVisualStyleBackColor = true; this.btnBack.Click += new System.EventHandler(this.btnBack_Click); // // btnNext // this.btnNext.Location = new System.Drawing.Point(448, 592); this.btnNext.Name = "btnNext"; this.btnNext.Size = new System.Drawing.Size(75, 23); this.btnNext.TabIndex = 2; this.btnNext.Text = "&Next >"; this.btnNext.UseVisualStyleBackColor = true; this.btnNext.Click += new System.EventHandler(this.btnNext_Click); // // btnCancel // this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(538, 592); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(75, 23); this.btnCancel.TabIndex = 3; this.btnCancel.Text = "Cancel"; this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); // // tabFinish // this.tabFinish.Controls.Add(this.lblSetupCompleted); this.tabFinish.Location = new System.Drawing.Point(4, 5); this.tabFinish.Name = "tabFinish"; this.tabFinish.Padding = new System.Windows.Forms.Padding(3); this.tabFinish.Size = new System.Drawing.Size(617, 500); this.tabFinish.TabIndex = 5; this.tabFinish.Text = "Finish"; this.tabFinish.UseVisualStyleBackColor = true; // // lblSetupCompleted // this.lblSetupCompleted.AutoSize = true; this.lblSetupCompleted.Location = new System.Drawing.Point(34, 35); this.lblSetupCompleted.Name = "lblSetupCompleted"; this.lblSetupCompleted.Size = new System.Drawing.Size(259, 13); this.lblSetupCompleted.TabIndex = 0; this.lblSetupCompleted.Text = "The Icinga 2 Windows client was set up successfully."; // // tabConfigure // this.tabConfigure.Controls.Add(this.lblConfigStatus); this.tabConfigure.Controls.Add(this.prgConfig); this.tabConfigure.Location = new System.Drawing.Point(4, 5); this.tabConfigure.Name = "tabConfigure"; this.tabConfigure.Padding = new System.Windows.Forms.Padding(3); this.tabConfigure.Size = new System.Drawing.Size(617, 500); this.tabConfigure.TabIndex = 4; this.tabConfigure.Text = "Configure Icinga 2"; this.tabConfigure.UseVisualStyleBackColor = true; // // lblConfigStatus // this.lblConfigStatus.AutoSize = true; this.lblConfigStatus.Location = new System.Drawing.Point(184, 204); this.lblConfigStatus.Name = "lblConfigStatus"; this.lblConfigStatus.Size = new System.Drawing.Size(141, 13); this.lblConfigStatus.TabIndex = 1; this.lblConfigStatus.Text = "Updating the configuration..."; // // prgConfig // this.prgConfig.Location = new System.Drawing.Point(184, 223); this.prgConfig.Name = "prgConfig"; this.prgConfig.Size = new System.Drawing.Size(289, 23); this.prgConfig.TabIndex = 0; // // tabParameters // this.tabParameters.Controls.Add(this.introduction1); this.tabParameters.Controls.Add(this.groupBox3); this.tabParameters.Controls.Add(this.txtTicket); this.tabParameters.Controls.Add(this.lblTicket); this.tabParameters.Controls.Add(this.txtInstanceName); this.tabParameters.Controls.Add(this.lblInstanceName); this.tabParameters.Controls.Add(this.groupBox2); this.tabParameters.Controls.Add(this.groupBox1); this.tabParameters.Location = new System.Drawing.Point(4, 5); this.tabParameters.Name = "tabParameters"; this.tabParameters.Padding = new System.Windows.Forms.Padding(3); this.tabParameters.Size = new System.Drawing.Size(617, 500); this.tabParameters.TabIndex = 3; this.tabParameters.Text = "Agent Parameters"; this.tabParameters.UseVisualStyleBackColor = true; // // groupBox3 // this.groupBox3.Controls.Add(this.txtUser); this.groupBox3.Controls.Add(this.chkRunServiceAsThisUser); this.groupBox3.Controls.Add(this.chkInstallNSCP); this.groupBox3.Controls.Add(this.chkAcceptConfig); this.groupBox3.Controls.Add(this.chkAcceptCommands); this.groupBox3.Location = new System.Drawing.Point(308, 291); this.groupBox3.Name = "groupBox3"; this.groupBox3.Size = new System.Drawing.Size(301, 188); this.groupBox3.TabIndex = 5; this.groupBox3.TabStop = false; this.groupBox3.Text = "Advanced Options"; // // txtUser // this.txtUser.Enabled = false; this.txtUser.Location = new System.Drawing.Point(28, 88); this.txtUser.Name = "txtUser"; this.txtUser.Size = new System.Drawing.Size(178, 20); this.txtUser.TabIndex = 8; this.txtUser.Text = "NT AUTHORITY\\NetworkService"; // // chkRunServiceAsThisUser // this.chkRunServiceAsThisUser.AutoSize = true; this.chkRunServiceAsThisUser.Location = new System.Drawing.Point(9, 65); this.chkRunServiceAsThisUser.Name = "chkRunServiceAsThisUser"; this.chkRunServiceAsThisUser.Size = new System.Drawing.Size(183, 17); this.chkRunServiceAsThisUser.TabIndex = 7; this.chkRunServiceAsThisUser.Text = "Run Icinga 2 service as this user:"; this.chkRunServiceAsThisUser.UseVisualStyleBackColor = true; this.chkRunServiceAsThisUser.CheckedChanged += new System.EventHandler(this.chkRunServiceAsThisUser_CheckedChanged); // // chkInstallNSCP // this.chkInstallNSCP.AutoSize = true; this.chkInstallNSCP.Location = new System.Drawing.Point(9, 114); this.chkInstallNSCP.Name = "chkInstallNSCP"; this.chkInstallNSCP.Size = new System.Drawing.Size(190, 17); this.chkInstallNSCP.TabIndex = 6; this.chkInstallNSCP.Text = "Install/Update bundled NSClient++"; this.chkInstallNSCP.UseVisualStyleBackColor = true; // // chkAcceptConfig // this.chkAcceptConfig.AutoSize = true; this.chkAcceptConfig.Location = new System.Drawing.Point(9, 42); this.chkAcceptConfig.Name = "chkAcceptConfig"; this.chkAcceptConfig.Size = new System.Drawing.Size(284, 17); this.chkAcceptConfig.TabIndex = 1; this.chkAcceptConfig.Text = "Accept config updates from master/satellite instance(s)"; this.chkAcceptConfig.UseVisualStyleBackColor = true; // // chkAcceptCommands // this.chkAcceptCommands.AutoSize = true; this.chkAcceptCommands.Location = new System.Drawing.Point(9, 19); this.chkAcceptCommands.Name = "chkAcceptCommands"; this.chkAcceptCommands.Size = new System.Drawing.Size(265, 17); this.chkAcceptCommands.TabIndex = 0; this.chkAcceptCommands.Text = "Accept commands from master/satellite instance(s)"; this.chkAcceptCommands.UseVisualStyleBackColor = true; // // txtTicket // this.txtTicket.Location = new System.Drawing.Point(136, 56); this.txtTicket.Name = "txtTicket"; this.txtTicket.Size = new System.Drawing.Size(378, 20); this.txtTicket.TabIndex = 1; // // lblTicket // this.lblTicket.AutoSize = true; this.lblTicket.Location = new System.Drawing.Point(9, 59); this.lblTicket.Name = "lblTicket"; this.lblTicket.Size = new System.Drawing.Size(117, 13); this.lblTicket.TabIndex = 4; this.lblTicket.Text = "Setup Ticket (optional):"; // // txtInstanceName // this.txtInstanceName.Location = new System.Drawing.Point(136, 27); this.txtInstanceName.Name = "txtInstanceName"; this.txtInstanceName.Size = new System.Drawing.Size(378, 20); this.txtInstanceName.TabIndex = 0; // // lblInstanceName // this.lblInstanceName.AutoSize = true; this.lblInstanceName.Location = new System.Drawing.Point(11, 30); this.lblInstanceName.Name = "lblInstanceName"; this.lblInstanceName.Size = new System.Drawing.Size(121, 13); this.lblInstanceName.TabIndex = 3; this.lblInstanceName.Text = "Instance Name (FQDN):"; // // groupBox2 // this.groupBox2.Controls.Add(this.rdoNoListener); this.groupBox2.Controls.Add(this.txtListenerPort); this.groupBox2.Controls.Add(this.lblListenerPort); this.groupBox2.Controls.Add(this.rdoListener); this.groupBox2.Location = new System.Drawing.Point(8, 291); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(298, 188); this.groupBox2.TabIndex = 2; this.groupBox2.TabStop = false; this.groupBox2.Text = "TCP Listener"; // // rdoNoListener // this.rdoNoListener.AutoSize = true; this.rdoNoListener.Checked = true; this.rdoNoListener.Location = new System.Drawing.Point(11, 82); this.rdoNoListener.Name = "rdoNoListener"; this.rdoNoListener.Size = new System.Drawing.Size(163, 17); this.rdoNoListener.TabIndex = 9; this.rdoNoListener.TabStop = true; this.rdoNoListener.Text = "Do not listen for connections."; this.rdoNoListener.UseVisualStyleBackColor = true; this.rdoNoListener.CheckedChanged += new System.EventHandler(this.RadioListener_CheckedChanged); // // txtListenerPort // this.txtListenerPort.Enabled = false; this.txtListenerPort.Location = new System.Drawing.Point(66, 47); this.txtListenerPort.Name = "txtListenerPort"; this.txtListenerPort.Size = new System.Drawing.Size(84, 20); this.txtListenerPort.TabIndex = 8; this.txtListenerPort.Text = "5665"; // // lblListenerPort // this.lblListenerPort.AutoSize = true; this.lblListenerPort.Location = new System.Drawing.Point(31, 51); this.lblListenerPort.Name = "lblListenerPort"; this.lblListenerPort.Size = new System.Drawing.Size(29, 13); this.lblListenerPort.TabIndex = 1; this.lblListenerPort.Text = "Port:"; // // rdoListener // this.rdoListener.AutoSize = true; this.rdoListener.Location = new System.Drawing.Point(11, 24); this.rdoListener.Name = "rdoListener"; this.rdoListener.Size = new System.Drawing.Size(283, 17); this.rdoListener.TabIndex = 7; this.rdoListener.Text = "Listen for connections from master/satellite instance(s):"; this.rdoListener.UseVisualStyleBackColor = true; this.rdoListener.CheckedChanged += new System.EventHandler(this.RadioListener_CheckedChanged); // // groupBox1 // this.groupBox1.Controls.Add(this.btnEditEndpoint); this.groupBox1.Controls.Add(this.btnRemoveEndpoint); this.groupBox1.Controls.Add(this.btnAddEndpoint); this.groupBox1.Controls.Add(this.lvwEndpoints); this.groupBox1.Location = new System.Drawing.Point(8, 94); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(601, 191); this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "Parent master/satellite instance(s) for this client"; // // btnEditEndpoint // this.btnEditEndpoint.Enabled = false; this.btnEditEndpoint.Location = new System.Drawing.Point(520, 48); this.btnEditEndpoint.Name = "btnEditEndpoint"; this.btnEditEndpoint.Size = new System.Drawing.Size(75, 23); this.btnEditEndpoint.TabIndex = 7; this.btnEditEndpoint.Text = "Edit"; this.btnEditEndpoint.UseVisualStyleBackColor = true; this.btnEditEndpoint.Click += new System.EventHandler(this.btnEditEndpoint_Click); // // btnRemoveEndpoint // this.btnRemoveEndpoint.Enabled = false; this.btnRemoveEndpoint.Location = new System.Drawing.Point(520, 77); this.btnRemoveEndpoint.Name = "btnRemoveEndpoint"; this.btnRemoveEndpoint.Size = new System.Drawing.Size(75, 23); this.btnRemoveEndpoint.TabIndex = 6; this.btnRemoveEndpoint.Text = "Remove"; this.btnRemoveEndpoint.UseVisualStyleBackColor = true; this.btnRemoveEndpoint.Click += new System.EventHandler(this.btnRemoveEndpoint_Click); // // btnAddEndpoint // this.btnAddEndpoint.Location = new System.Drawing.Point(520, 19); this.btnAddEndpoint.Name = "btnAddEndpoint"; this.btnAddEndpoint.Size = new System.Drawing.Size(75, 23); this.btnAddEndpoint.TabIndex = 5; this.btnAddEndpoint.Text = "Add"; this.btnAddEndpoint.UseVisualStyleBackColor = true; this.btnAddEndpoint.Click += new System.EventHandler(this.btnAddEndpoint_Click); // // lvwEndpoints // this.lvwEndpoints.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.colInstanceName, this.colHost, this.colPort}); this.lvwEndpoints.FullRowSelect = true; this.lvwEndpoints.Location = new System.Drawing.Point(6, 19); this.lvwEndpoints.Name = "lvwEndpoints"; this.lvwEndpoints.Size = new System.Drawing.Size(500, 166); this.lvwEndpoints.TabIndex = 4; this.lvwEndpoints.UseCompatibleStateImageBehavior = false; this.lvwEndpoints.View = System.Windows.Forms.View.Details; this.lvwEndpoints.SelectedIndexChanged += new System.EventHandler(this.lvwEndpoints_SelectedIndexChanged); // // colInstanceName // this.colInstanceName.Text = "Instance Name"; this.colInstanceName.Width = 200; // // colHost // this.colHost.Text = "Host"; this.colHost.Width = 200; // // colPort // this.colPort.Text = "Port"; this.colPort.Width = 80; // // tbcPages // this.tbcPages.Appearance = System.Windows.Forms.TabAppearance.FlatButtons; this.tbcPages.Controls.Add(this.tabParameters); this.tbcPages.Controls.Add(this.tabRetrieveCertificate); this.tbcPages.Controls.Add(this.tabVerifyCertificate); this.tbcPages.Controls.Add(this.tabConfigure); this.tbcPages.Controls.Add(this.tabFinish); this.tbcPages.Controls.Add(this.tabError); this.tbcPages.ItemSize = new System.Drawing.Size(0, 1); this.tbcPages.Location = new System.Drawing.Point(0, 80); this.tbcPages.Margin = new System.Windows.Forms.Padding(0); this.tbcPages.Name = "tbcPages"; this.tbcPages.SelectedIndex = 0; this.tbcPages.Size = new System.Drawing.Size(625, 509); this.tbcPages.SizeMode = System.Windows.Forms.TabSizeMode.Fixed; this.tbcPages.TabIndex = 0; this.tbcPages.SelectedIndexChanged += new System.EventHandler(this.tbcPages_SelectedIndexChanged); // // tabRetrieveCertificate // this.tabRetrieveCertificate.Controls.Add(this.lblRetrieveCertificate); this.tabRetrieveCertificate.Controls.Add(this.prgRetrieveCertificate); this.tabRetrieveCertificate.Location = new System.Drawing.Point(4, 5); this.tabRetrieveCertificate.Name = "tabRetrieveCertificate"; this.tabRetrieveCertificate.Padding = new System.Windows.Forms.Padding(3); this.tabRetrieveCertificate.Size = new System.Drawing.Size(617, 500); this.tabRetrieveCertificate.TabIndex = 7; this.tabRetrieveCertificate.Text = "Checking Certificate"; this.tabRetrieveCertificate.UseVisualStyleBackColor = true; // // lblRetrieveCertificate // this.lblRetrieveCertificate.AutoSize = true; this.lblRetrieveCertificate.Location = new System.Drawing.Point(164, 229); this.lblRetrieveCertificate.Name = "lblRetrieveCertificate"; this.lblRetrieveCertificate.Size = new System.Drawing.Size(110, 13); this.lblRetrieveCertificate.TabIndex = 3; this.lblRetrieveCertificate.Text = "Checking certificate..."; // // prgRetrieveCertificate // this.prgRetrieveCertificate.Location = new System.Drawing.Point(164, 248); this.prgRetrieveCertificate.Name = "prgRetrieveCertificate"; this.prgRetrieveCertificate.Size = new System.Drawing.Size(289, 23); this.prgRetrieveCertificate.TabIndex = 2; // // tabVerifyCertificate // this.tabVerifyCertificate.Controls.Add(this.grpX509Fields); this.tabVerifyCertificate.Controls.Add(this.txtX509Subject); this.tabVerifyCertificate.Controls.Add(this.txtX509Issuer); this.tabVerifyCertificate.Controls.Add(this.lblX509Subject); this.tabVerifyCertificate.Controls.Add(this.lblX509Issuer); this.tabVerifyCertificate.Controls.Add(this.lblX509Prompt); this.tabVerifyCertificate.Location = new System.Drawing.Point(4, 5); this.tabVerifyCertificate.Name = "tabVerifyCertificate"; this.tabVerifyCertificate.Padding = new System.Windows.Forms.Padding(3); this.tabVerifyCertificate.Size = new System.Drawing.Size(617, 500); this.tabVerifyCertificate.TabIndex = 6; this.tabVerifyCertificate.Text = "Verify Certificate"; this.tabVerifyCertificate.UseVisualStyleBackColor = true; // // grpX509Fields // this.grpX509Fields.Controls.Add(this.txtX509Field); this.grpX509Fields.Controls.Add(this.lvwX509Fields); this.grpX509Fields.Location = new System.Drawing.Point(11, 115); this.grpX509Fields.Name = "grpX509Fields"; this.grpX509Fields.Size = new System.Drawing.Size(598, 369); this.grpX509Fields.TabIndex = 8; this.grpX509Fields.TabStop = false; this.grpX509Fields.Text = "X509 Fields"; // // txtX509Field // this.txtX509Field.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtX509Field.Location = new System.Drawing.Point(6, 197); this.txtX509Field.Multiline = true; this.txtX509Field.Name = "txtX509Field"; this.txtX509Field.ReadOnly = true; this.txtX509Field.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.txtX509Field.Size = new System.Drawing.Size(586, 166); this.txtX509Field.TabIndex = 9; // // lvwX509Fields // this.lvwX509Fields.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.colField, this.colValue}); this.lvwX509Fields.Location = new System.Drawing.Point(6, 19); this.lvwX509Fields.Name = "lvwX509Fields"; this.lvwX509Fields.Size = new System.Drawing.Size(586, 172); this.lvwX509Fields.TabIndex = 8; this.lvwX509Fields.UseCompatibleStateImageBehavior = false; this.lvwX509Fields.View = System.Windows.Forms.View.Details; this.lvwX509Fields.SelectedIndexChanged += new System.EventHandler(this.lvwX509Fields_SelectedIndexChanged); // // colField // this.colField.Text = "Field"; this.colField.Width = 200; // // colValue // this.colValue.Text = "Value"; this.colValue.Width = 350; // // txtX509Subject // this.txtX509Subject.Location = new System.Drawing.Point(71, 73); this.txtX509Subject.Name = "txtX509Subject"; this.txtX509Subject.ReadOnly = true; this.txtX509Subject.Size = new System.Drawing.Size(532, 20); this.txtX509Subject.TabIndex = 4; // // txtX509Issuer // this.txtX509Issuer.Location = new System.Drawing.Point(71, 47); this.txtX509Issuer.Name = "txtX509Issuer"; this.txtX509Issuer.ReadOnly = true; this.txtX509Issuer.Size = new System.Drawing.Size(532, 20); this.txtX509Issuer.TabIndex = 3; // // lblX509Subject // this.lblX509Subject.AutoSize = true; this.lblX509Subject.Location = new System.Drawing.Point(8, 77); this.lblX509Subject.Name = "lblX509Subject"; this.lblX509Subject.Size = new System.Drawing.Size(46, 13); this.lblX509Subject.TabIndex = 2; this.lblX509Subject.Text = "Subject:"; // // lblX509Issuer // this.lblX509Issuer.AutoSize = true; this.lblX509Issuer.Location = new System.Drawing.Point(8, 50); this.lblX509Issuer.Name = "lblX509Issuer"; this.lblX509Issuer.Size = new System.Drawing.Size(38, 13); this.lblX509Issuer.TabIndex = 1; this.lblX509Issuer.Text = "Issuer:"; // // lblX509Prompt // this.lblX509Prompt.AutoSize = true; this.lblX509Prompt.Location = new System.Drawing.Point(8, 15); this.lblX509Prompt.Name = "lblX509Prompt"; this.lblX509Prompt.Size = new System.Drawing.Size(201, 13); this.lblX509Prompt.TabIndex = 0; this.lblX509Prompt.Text = "Please verify the master/satellite\'s SSL certificate:"; // // tabError // this.tabError.Controls.Add(this.txtError); this.tabError.Controls.Add(this.lblError); this.tabError.Location = new System.Drawing.Point(4, 5); this.tabError.Name = "tabError"; this.tabError.Padding = new System.Windows.Forms.Padding(3); this.tabError.Size = new System.Drawing.Size(617, 500); this.tabError.TabIndex = 8; this.tabError.Text = "Error"; this.tabError.UseVisualStyleBackColor = true; // // txtError // this.txtError.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtError.Location = new System.Drawing.Point(11, 38); this.txtError.Multiline = true; this.txtError.Name = "txtError"; this.txtError.ReadOnly = true; this.txtError.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.txtError.Size = new System.Drawing.Size(598, 397); this.txtError.TabIndex = 1; // // lblError // this.lblError.AutoSize = true; this.lblError.Location = new System.Drawing.Point(8, 12); this.lblError.Name = "lblError"; this.lblError.Size = new System.Drawing.Size(209, 13); this.lblError.TabIndex = 0; this.lblError.Text = "An error occurred while setting up Icinga 2:"; // // picBanner // this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner; this.picBanner.Location = new System.Drawing.Point(0, 0); this.picBanner.Name = "picBanner"; this.picBanner.Size = new System.Drawing.Size(625, 77); this.picBanner.TabIndex = 1; this.picBanner.TabStop = false; // // introduction1 // this.introduction1.AutoSize = true; this.introduction1.Location = new System.Drawing.Point(11, 3); this.introduction1.Name = "introduction1"; this.introduction1.Size = new System.Drawing.Size(269, 13); this.introduction1.TabIndex = 6; this.introduction1.Text = "Welcome to the Icinga 2 Windows Client Setup Wizard!"; // // SetupWizard // this.AcceptButton = this.btnNext; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(625, 624); this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnNext); this.Controls.Add(this.btnBack); this.Controls.Add(this.picBanner); this.Controls.Add(this.tbcPages); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.Name = "SetupWizard"; this.Text = "Icinga 2 Setup Wizard"; this.tabFinish.ResumeLayout(false); this.tabFinish.PerformLayout(); this.tabConfigure.ResumeLayout(false); this.tabConfigure.PerformLayout(); this.tabParameters.ResumeLayout(false); this.tabParameters.PerformLayout(); this.groupBox3.ResumeLayout(false); this.groupBox3.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); this.groupBox1.ResumeLayout(false); this.tbcPages.ResumeLayout(false); this.tabRetrieveCertificate.ResumeLayout(false); this.tabRetrieveCertificate.PerformLayout(); this.tabVerifyCertificate.ResumeLayout(false); this.tabVerifyCertificate.PerformLayout(); this.grpX509Fields.ResumeLayout(false); this.grpX509Fields.PerformLayout(); this.tabError.ResumeLayout(false); this.tabError.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit(); this.ResumeLayout(false); } #endregion private System.Windows.Forms.PictureBox picBanner; private System.Windows.Forms.Button btnBack; private System.Windows.Forms.Button btnNext; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.TabPage tabFinish; private System.Windows.Forms.Label lblSetupCompleted; private System.Windows.Forms.TabPage tabConfigure; private System.Windows.Forms.Label lblConfigStatus; private System.Windows.Forms.ProgressBar prgConfig; private System.Windows.Forms.TabPage tabParameters; private System.Windows.Forms.TextBox txtInstanceName; private System.Windows.Forms.Label lblInstanceName; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.RadioButton rdoNoListener; private System.Windows.Forms.TextBox txtListenerPort; private System.Windows.Forms.Label lblListenerPort; private System.Windows.Forms.RadioButton rdoListener; private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.Button btnRemoveEndpoint; private System.Windows.Forms.Button btnAddEndpoint; private System.Windows.Forms.ListView lvwEndpoints; private System.Windows.Forms.ColumnHeader colHost; private System.Windows.Forms.ColumnHeader colPort; private System.Windows.Forms.TabControl tbcPages; private System.Windows.Forms.TabPage tabVerifyCertificate; private System.Windows.Forms.Label lblX509Prompt; private System.Windows.Forms.TextBox txtX509Subject; private System.Windows.Forms.TextBox txtX509Issuer; private System.Windows.Forms.Label lblX509Subject; private System.Windows.Forms.Label lblX509Issuer; private System.Windows.Forms.GroupBox grpX509Fields; private System.Windows.Forms.ListView lvwX509Fields; private System.Windows.Forms.ColumnHeader colField; private System.Windows.Forms.ColumnHeader colValue; private System.Windows.Forms.TextBox txtX509Field; private System.Windows.Forms.TabPage tabRetrieveCertificate; private System.Windows.Forms.Label lblRetrieveCertificate; private System.Windows.Forms.ProgressBar prgRetrieveCertificate; private System.Windows.Forms.TabPage tabError; private System.Windows.Forms.TextBox txtError; private System.Windows.Forms.Label lblError; private System.Windows.Forms.TextBox txtTicket; private System.Windows.Forms.Label lblTicket; private System.Windows.Forms.ColumnHeader colInstanceName; private System.Windows.Forms.GroupBox groupBox3; private System.Windows.Forms.CheckBox chkAcceptConfig; private System.Windows.Forms.CheckBox chkAcceptCommands; private System.Windows.Forms.CheckBox chkInstallNSCP; private System.Windows.Forms.TextBox txtUser; private System.Windows.Forms.CheckBox chkRunServiceAsThisUser; private System.Windows.Forms.Button btnEditEndpoint; private System.Windows.Forms.Label introduction1; } } icinga2-2.8.1/agent/windows-setup-agent/SetupWizard.cs000066400000000000000000000342221322762156600227050ustar00rootroot00000000000000using System; using System.IO; using System.Text; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Net.NetworkInformation; using System.IO.Compression; using System.Diagnostics; using System.ServiceProcess; using System.Security.AccessControl; namespace Icinga { public partial class SetupWizard : Form { private string _TrustedFile; private string Icinga2User; public SetupWizard() { InitializeComponent(); txtInstanceName.Text = Icinga2InstanceName; Icinga2User = Program.Icinga2User; txtUser.Text = Icinga2User; } private void Warning(string message) { MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); } private string Icinga2InstanceName { get { IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties(); string fqdn = props.HostName; if (props.DomainName != "") fqdn += "." + props.DomainName; return fqdn; } } private bool GetMasterHostPort(out string host, out string port) { foreach (ListViewItem lvi in lvwEndpoints.Items) { if (lvi.SubItems.Count > 1) { host = lvi.SubItems[1].Text.Trim(); port = lvi.SubItems[2].Text.Trim(); return true; } } host = null; port = null; return false; } private void EnableFeature(string feature) { FileStream fp = null; try { fp = File.Open(Program.Icinga2DataDir + String.Format("\\etc\\icinga2\\features-enabled\\{0}.conf", feature), FileMode.Create); using (StreamWriter sw = new StreamWriter(fp, Encoding.ASCII)) { fp = null; sw.Write(String.Format("include \"../features-available/{0}.conf\"\n", feature)); } } finally { if (fp != null) fp.Dispose(); } } private void SetRetrievalStatus(int pct) { if (InvokeRequired) { Invoke((MethodInvoker)delegate { SetRetrievalStatus(pct); }); return; } prgRetrieveCertificate.Value = pct; } private void SetConfigureStatus(int pct, string message) { if (InvokeRequired) { Invoke((MethodInvoker)delegate { SetConfigureStatus(pct, message); }); return; } prgConfig.Value = pct; lblConfigStatus.Text = message; } private void ShowErrorText(string text) { if (InvokeRequired) { Invoke((MethodInvoker)delegate { ShowErrorText(text); }); return; } txtError.Text = text; tbcPages.SelectedTab = tabError; } private bool RunProcess(string filename, string arguments, out string output) { ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = filename; psi.Arguments = arguments; psi.CreateNoWindow = true; psi.UseShellExecute = false; psi.RedirectStandardOutput = true; psi.RedirectStandardError = true; String result = ""; using (Process proc = Process.Start(psi)) { proc.ErrorDataReceived += delegate (object sender, DataReceivedEventArgs args) { result += args.Data + "\r\n"; }; proc.OutputDataReceived += delegate (object sender, DataReceivedEventArgs args) { result += args.Data + "\r\n"; }; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); output = result; if (proc.ExitCode != 0) return false; } return true; } private void VerifyCertificate(string host, string port) { SetRetrievalStatus(25); string pathPrefix = Program.Icinga2DataDir + "\\etc\\icinga2\\pki\\" + txtInstanceName.Text; string processArguments = "pki new-cert --cn \"" + txtInstanceName.Text + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\""; string output; if (!File.Exists(pathPrefix + ".crt")) { if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", processArguments, out output)) { ShowErrorText("Running command 'icinga2.exe " + processArguments + "' produced the following output:\n" + output); return; } } SetRetrievalStatus(50); _TrustedFile = Path.GetTempFileName(); processArguments = "pki save-cert --host \"" + host + "\" --port \"" + port + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\" --trustedcert \"" + _TrustedFile + "\""; if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", processArguments, out output)) { ShowErrorText("Running command 'icinga2.exe " + processArguments + "' produced the following output:\n" + output); return; } SetRetrievalStatus(100); X509Certificate2 cert = new X509Certificate2(_TrustedFile); Invoke((MethodInvoker)delegate { ShowCertificatePrompt(cert); }); } private void ConfigureService() { SetConfigureStatus(0, "Updating configuration files..."); string output; string args = ""; Invoke((MethodInvoker)delegate { string master_host, master_port; GetMasterHostPort(out master_host, out master_port); args += " --master_host " + master_host + "," + master_port; foreach (ListViewItem lvi in lvwEndpoints.Items) { args += " --endpoint " + lvi.SubItems[0].Text.Trim(); if (lvi.SubItems.Count > 1) { args += "," + lvi.SubItems[1].Text.Trim() + "," + lvi.SubItems[2].Text.Trim(); } } }); if (rdoListener.Checked) args += " --listen ::," + txtListenerPort.Text.Trim(); if (chkAcceptConfig.Checked) args += " --accept-config"; if (chkAcceptCommands.Checked) args += " --accept-commands"; string ticket = txtTicket.Text.Trim(); if (ticket.Length > 0) args += " --ticket \"" + ticket + "\""; args += " --trustedcert \"" + _TrustedFile + "\""; args += " --cn \"" + txtInstanceName.Text.Trim() + "\""; args += " --zone \"" + txtInstanceName.Text.Trim() + "\""; if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", "node setup" + args, out output)) { ShowErrorText("Running command 'icinga2.exe " + "node setup" + args + "' produced the following output:\n" + output); return; } SetConfigureStatus(50, "Setting ACLs for the Icinga 2 directory..."); string serviceUser = txtUser.Text.Trim(); DirectoryInfo di = new DirectoryInfo(Program.Icinga2InstallDir); DirectorySecurity ds = di.GetAccessControl(); FileSystemAccessRule rule = new FileSystemAccessRule(serviceUser, FileSystemRights.Modify, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow); try { ds.AddAccessRule(rule); di.SetAccessControl(ds); } catch (System.Security.Principal.IdentityNotMappedException) { ShowErrorText("Could not set ACLs for user \"" + serviceUser + "\". Identitiy is not mapped.\n"); return; } SetConfigureStatus(75, "Installing the Icinga 2 service..."); RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", "--scm-uninstall", out output); if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", "daemon --validate", out output)) { ShowErrorText("Running command 'icinga2.exe daemon --validate' produced the following output:\n" + output); return; } if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe", "--scm-install --scm-user \"" + serviceUser + "\" daemon", out output)) { ShowErrorText("\nRunning command 'icinga2.exe --scm-install --scm-user \"" + serviceUser + "\" daemon' produced the following output:\n" + output); return; } if (chkInstallNSCP.Checked) { SetConfigureStatus(85, "Waiting for NSClient++ installation to complete..."); Process proc = new Process(); proc.StartInfo.FileName = "msiexec.exe"; proc.StartInfo.Arguments = "/i \"" + Program.Icinga2InstallDir + "\\sbin\\NSCP.msi\""; proc.Start(); proc.WaitForExit(); } SetConfigureStatus(100, "Finished."); // Override the completed text lblSetupCompleted.Text = "The Icinga 2 Windows client was set up successfully."; // Add a note for the user for ticket-less signing if (ticket.Length == 0) { lblSetupCompleted.Text += "\n\nTicket was not specified. Please sign the certificate request on the Icinga 2 master node (requires v2.8+)."; } FinishConfigure(); } private void FinishConfigure() { if (InvokeRequired) { Invoke((MethodInvoker)FinishConfigure); return; } tbcPages.SelectedTab = tabFinish; } private void btnBack_Click(object sender, EventArgs e) { if (tbcPages.SelectedTab == tabError) { tbcPages.SelectedIndex = 0; return; } int offset = 1; if (tbcPages.SelectedTab == tabVerifyCertificate) offset++; tbcPages.SelectedIndex -= offset; } private void btnNext_Click(object sender, EventArgs e) { if (tbcPages.SelectedTab == tabParameters) { if (txtInstanceName.Text.Length == 0) { Warning("Please enter an instance name."); return; } if (lvwEndpoints.Items.Count == 0) { Warning("You need to add at least one master/satellite endpoint."); return; } string host, port; if (!GetMasterHostPort(out host, out port)) { Warning("Please enter a remote host and port for at least one of your endpoints."); return; } if (rdoListener.Checked && (txtListenerPort.Text == "")) { Warning("You need to specify a listener port."); return; } if (txtUser.Text.Length == 0) { Warning("Icinga 2 service user may not be empty."); return; } } if (tbcPages.SelectedTab == tabFinish || tbcPages.SelectedTab == tabError) Application.Exit(); tbcPages.SelectedIndex++; } private void btnCancel_Click(object sender, EventArgs e) { Application.Exit(); } private void tbcPages_SelectedIndexChanged(object sender, EventArgs e) { Refresh(); btnBack.Enabled = (tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabError); btnNext.Enabled = (tbcPages.SelectedTab == tabParameters || tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabFinish); if (tbcPages.SelectedTab == tabFinish) { btnNext.Text = "&Finish >"; btnCancel.Enabled = false; } if (tbcPages.SelectedTab == tabRetrieveCertificate) { ListViewItem lvi = lvwEndpoints.Items[0]; string master_host, master_port; GetMasterHostPort(out master_host, out master_port); Thread thread = new Thread((ThreadStart)delegate { VerifyCertificate(master_host, master_port); }); thread.Start(); } if (tbcPages.SelectedTab == tabConfigure) { Thread thread = new Thread(ConfigureService); thread.Start(); } } private void RadioListener_CheckedChanged(object sender, EventArgs e) { txtListenerPort.Enabled = rdoListener.Checked; } private void AddCertificateField(string name, string shortValue, string longValue = null) { ListViewItem lvi = new ListViewItem(); lvi.Text = name; lvi.SubItems.Add(shortValue); if (longValue == null) longValue = shortValue; lvi.Tag = longValue; lvwX509Fields.Items.Add(lvi); } private string PadText(string input) { string output = ""; for (int i = 0; i < input.Length; i += 2) { if (output != "") output += " "; int len = 2; if (input.Length - i < 2) len = input.Length - i; output += input.Substring(i, len); } return output; } private void ShowCertificatePrompt(X509Certificate2 certificate) { txtX509Issuer.Text = certificate.Issuer; txtX509Subject.Text = certificate.Subject; lvwX509Fields.Items.Clear(); AddCertificateField("Version", "V" + certificate.Version.ToString()); AddCertificateField("Serial number", certificate.SerialNumber); AddCertificateField("Signature algorithm", certificate.SignatureAlgorithm.FriendlyName); AddCertificateField("Valid from", certificate.NotBefore.ToString()); AddCertificateField("Valid to", certificate.NotAfter.ToString()); string pkey = BitConverter.ToString(certificate.PublicKey.EncodedKeyValue.RawData).Replace("-", " "); AddCertificateField("Public key", certificate.PublicKey.Oid.FriendlyName + " (" + certificate.PublicKey.Key.KeySize + " bits)", pkey); string thumbprint = PadText(certificate.Thumbprint); AddCertificateField("Thumbprint", thumbprint); tbcPages.SelectedTab = tabVerifyCertificate; } private void btnAddEndpoint_Click(object sender, EventArgs e) { EndpointInputBox eib = new EndpointInputBox(); if (eib.ShowDialog(this) == DialogResult.Cancel) return; ListViewItem lvi = new ListViewItem(); lvi.Text = eib.txtInstanceName.Text; if (eib.chkConnect.Checked) { lvi.SubItems.Add(eib.txtHost.Text); lvi.SubItems.Add(eib.txtPort.Text); } lvwEndpoints.Items.Add(lvi); } private void lvwEndpoints_SelectedIndexChanged(object sender, EventArgs e) { btnRemoveEndpoint.Enabled = lvwEndpoints.SelectedItems.Count > 0; btnEditEndpoint.Enabled = lvwEndpoints.SelectedItems.Count > 0; } private void lvwX509Fields_SelectedIndexChanged(object sender, EventArgs e) { if (lvwX509Fields.SelectedItems.Count == 0) return; ListViewItem lvi = lvwX509Fields.SelectedItems[0]; txtX509Field.Text = Convert.ToString(lvi.Tag); } private void btnRemoveEndpoint_Click(object sender, EventArgs e) { while (lvwEndpoints.SelectedItems.Count > 0) { lvwEndpoints.Items.Remove(lvwEndpoints.SelectedItems[0]); } } private void chkRunServiceAsThisUser_CheckedChanged(object sender, EventArgs e) { txtUser.Enabled = !txtUser.Enabled; if (!txtUser.Enabled) txtUser.Text = Icinga2User; } private void btnEditEndpoint_Click(object sender, EventArgs e) { ListViewItem lvi = lvwEndpoints.SelectedItems[0]; EndpointInputBox eib = new EndpointInputBox(); eib.Text = "Edit Endpoint"; eib.txtInstanceName.Text = lvi.SubItems[0].Text; if (lvi.SubItems.Count >= 2) { eib.txtHost.Text = lvi.SubItems[1].Text; eib.txtPort.Text = lvi.SubItems[2].Text; eib.chkConnect.Checked = true; } if (eib.ShowDialog(this) == DialogResult.Cancel) return; lvwEndpoints.Items.Remove(lvi); ListViewItem lvi2 = new ListViewItem(); lvi2.Text = eib.txtInstanceName.Text; if (eib.chkConnect.Checked) { lvi2.SubItems.Add(eib.txtHost.Text); lvi2.SubItems.Add(eib.txtPort.Text); } lvwEndpoints.Items.Add(lvi2); } } } icinga2-2.8.1/agent/windows-setup-agent/SetupWizard.resx000066400000000000000000000157321322762156600232660ustar00rootroot00000000000000 text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 AAABAAEAICAQAAAABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAAAIAAAAAAAAAAAAAEAAAABAA AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP// AAD///8AAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAcAAAcAB3AAAAAAAAAAAAAAcABwB///cA AAAAAAAAAAAAcAAA////AAAAAAAAAAAAAAAAAP///3AAAAAAAAAAAAAAAAD///9wAAAAAAAAAAAAAAAA j//4AAAAB3AAAAAAAAAAAAj/jwAAAA/4AAAAAAAAAAAAAAiAAAAP9wAAAAAAAAAAAAAH9wAAf3AAAAAA AAAAAAAAAH93d/cAAAAAAAAAAAAAAAB////3AAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAB/////9w AAAAAAAAAAAAAAf/////gAAAAAAAAAAAAAAH//////h3AAAAAAAAAAAAB/////+I//h3eHAAAAAAAAD/ ////AAB3j//3AAAAAAB4////9wAAAAf/+AAAAAf/+AB4iPAAAAAAj/cAAAAH//AAAAD3AAAAAAcAAAAA B/+AAAAAjwAAAAAAAAAAAAB3AAAAAA9wAAAAAAAAAAAAAAAAAAAIh3AAAAAAAAAAAAAAAAAAD//wAAAA AAAAAAAAAAAAAH//9wAAAAAAAAAAAAAAAAB///cAAAAAAAcAAAAAAAAACP+AAAAAAHAAcAAAAAAAAAB3 AAAAAAcAAAcAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAD/////4AAAB8AAAAOAAAABgAAAAYAA AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAA AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAcAAAAPgAAAH/////w== icinga2-2.8.1/agent/windows-setup-agent/app.manifest000066400000000000000000000053631322762156600224110ustar00rootroot00000000000000 icinga2-2.8.1/agent/windows-setup-agent/icinga-banner.png000066400000000000000000000045101322762156600232750ustar00rootroot00000000000000PNG  IHDRrN+kl= pHYs  tEXtSoftwareAdobe ImageReadyqe<IDATxkت`W0 ogΥb"sCJwB]uah JʒB .z 4DNILAsuq?1{<Ϗcl' yd23ssr_/d[+ x)**** V V V V UUUU@@@$\Oe֧*+wkV1l ez/uǪu#b_nl`l@^m<'e*8j5^.{T,l;({`d*XM3xe3:1 @Px$G3G ?l>Z|iFMD=zPovZP'Ť?Kݶ녢gbgפ\vl}lE##.B9mt3Lfk7(X/>~{|'6k^4\h#Sg#_*^*V]iwUf~a.{PeRunR_O $ao \{+EU) BӏäIw[D6ha9vR)8qN7Sg4yȷ?55] B1rRKEC(^5O_jchٕ#<ҩ:7?NUWsFz XU߿קwYDo ^m ŭԉYz콇F_b?˻Z->|4?VTtWӃz'r+[וVZZ]ODYŪ?=\i/׾8b=]wj]r{Wl@jX2j*uۛ0"-VzCw֌-W)KO$g;- AT iկ՝~y9q϶, th~_T2 ]Idڮ4> HyUkst(w(Vu!+܊:߾{ꊜR`׶kwk+5׻Tgpkq\@TWd$Ցܑq =rl>[AeD=n.sjNZ#BJ9j` @ŪOUWwqq%ؚy}~onN-.Am=}=;/ԮFu :noGU)WjwVSza:[U`ٺ+֫_*XJD|k6+mz5a-V]TLwphfk?nsYU8.c r5~Կ&}xub_0:II?͏q3uʔ% :Hp}[KUFm85{r쇟`%_nZ=TGFkczCNu p*H]՞ɿFZE콇Frd)2[+k,m^zS{{įGS1]@G) XǫN!V V V V UUU@@@@bbb`8UIENDB`icinga2-2.8.1/agent/windows-setup-agent/icinga.ico000066400000000000000000000013761322762156600220270ustar00rootroot00000000000000 ( @ppwpppppwwpwwxpwxxwppppwpicinga2-2.8.1/changelog.py000077500000000000000000000146171322762156600153650ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding:utf-8 -*- import requests import re import pickle import sys import os from datetime import datetime from collections import defaultdict from collections import OrderedDict ################################# ## Env Config try: github_auth_username = os.environ['ICINGA_GITHUB_AUTH_USERNAME'] except KeyError: print "ERROR: Environment variable 'ICINGA_GITHUB_AUTH_USERNAME' is not set." sys.exit(1) try: github_auth_token = os.environ['ICINGA_GITHUB_AUTH_TOKEN'] except: print "ERROR: Environment variable 'ICINGA_GITHUB_AUTH_TOKEN' is not set." sys.exit(1) try: project_name = os.environ['ICINGA_GITHUB_PROJECT'] except: print "ERROR: Environment variable 'ICINGA_GITHUB_PROJECT' is not set." sys.exit(1) ################################# ## Config changelog_file = "CHANGELOG.md" # TODO: config param debug = 1 # Keep this in sync with GitHub labels. ignored_labels = [ "high-priority", "low-priority", "bug", "enhancement", "needs-feedback", "question", "duplicate", "invalid", "wontfix", "backported", "build-fix" ] # Selectively show and collect specific categories # # (category, list of case sensitive matching labels) # The order is important! # Keep this in sync with GitHub labels. categories = OrderedDict( [ ("Enhancement", ["enhancement"]), ("Bug", ["bug", "crash"]), ("ITL", ["ITL"]), ("Documentation", ["Documentation"]), ("Support", ["code-quality", "Tests", "Packages", "Installation"]) ] ) ################################# ## Helpers def write_changelog(line): clfp.write(line + "\n") def log(level, msg): if level <= debug: print " " + msg def fetch_github_resources(uri, params = {}): resources = [] url = 'https://api.github.com/repos/' + project_name + uri + "?per_page=100" # 100 is the maximum while True: log(2, "Requesting URL: " + url) resp = requests.get(url, auth=(github_auth_username, github_auth_token), params=params) try: resp.raise_for_status() except requests.exceptions.HTTPError as e: raise e data = resp.json() if len(data) == 0: break resources.extend(data) # fetch the next page from headers, do not count pages # http://engineering.hackerearth.com/2014/08/21/python-requests-module/ if "next" in resp.links: url = resp.links['next']['url'] log(2, "Found next link for Github pagination: " + url) else: break # no link found, we are done log(2, "No more pages to fetch, stop.") return resources def issue_type(issue): issue_labels = [label["name"] for label in issue["labels"]] # start with the least important first (e.g. "Support", "Documentation", "Bug", "Enhancement" as order) for category in reversed(categories): labels = categories[category] for label in labels: if label in issue_labels: return category return "Support" def escape_markdown(text): #tmp = text.replace('&', '&').replace('<', '<').replace('>', '>') tmp = text tmp.replace('\\', '\\\\') return re.sub("([<>*_()\[\]#])", r"\\\1", tmp) def format_labels(issue): labels = filter(lambda label: label not in ignored_labels, [label["name"] for label in issue["labels"]]) # Mark PRs as custom label if "pull_request" in issue: labels.append("PR") if len(labels): return " (" + ", ".join(labels) + ")" else: return "" def format_title(title): # Fix encoding try: issue_title = str(title.encode('ascii', 'ignore').encode('utf-8')) except Error: log(1, "Error: Cannot convert " + title + " to UTF-8") # Remove dev.icinga.com tag issue_title = re.sub('\[dev\.icinga\.com #\d+\] ', '', issue_title) #log(1, "Issue title: " + issue_title + "Type: " + str(type(issue_title))) return escape_markdown(issue_title) ################################# ## MAIN milestones = {} issues = defaultdict(lambda: defaultdict(list)) log(1, "Fetching data from GitHub API for project " + project_name) try: tickets = fetch_github_resources("/issues", { "state": "all" }) except requests.exceptions.HTTPError as e: log(1, "ERROR " + str(e.response.status_code) + ": " + e.response.text) sys.exit(1) clfp = open(changelog_file, "w+") with open('tickets.pickle', 'wb') as fp: pickle.dump(tickets, fp) with open('tickets.pickle', 'rb') as fp: cached_issues = pickle.load(fp) for issue in cached_issues: #fetch_github_resources("/issues", { "state": "all" }): milestone = issue["milestone"] if not milestone: continue ms_title = milestone["title"] if not re.match('^\d+\.\d+\.\d+$', ms_title): continue if ms_title.split(".")[0] != "2": continue milestones[ms_title] = milestone ms_tickets = issues[ms_title][issue_type(issue)] ms_tickets.append(issue) # TODO: Generic header based on project_name write_changelog("# Icinga 2.x CHANGELOG") write_changelog("") for milestone in sorted(milestones.values(), key=lambda ms: (ms["due_on"], ms["title"]), reverse=True): if milestone["state"] != "closed": continue if milestone["due_on"] == None: print "Milestone", milestone["title"], "does not have a due date." sys.exit(1) ms_due_on = datetime.strptime(milestone["due_on"], "%Y-%m-%dT%H:%M:%SZ") write_changelog("## %s (%s)" % (milestone["title"], ms_due_on.strftime("%Y-%m-%d"))) write_changelog("") ms_description = milestone["description"] ms_description = re.sub('\r\n', '\n', ms_description) if len(ms_description) > 0: write_changelog("### Notes\n\n" + ms_description + "\n") # Don't escape anything, we take care on Github for valid Markdown for category, labels in categories.iteritems(): try: ms_issues = issues[milestone["title"]][category] except KeyError: continue if len(ms_issues) == 0: continue write_changelog("### " + category) write_changelog("") for issue in ms_issues: write_changelog("* [#" + str(issue["number"]) + "](https://github.com/" + project_name + "/issues/" + str(issue["number"]) + ")" + format_labels(issue) + ": " + format_title(issue["title"])) write_changelog("") clfp.close() log(1, "Finished writing " + changelog_file) icinga2-2.8.1/choco/000077500000000000000000000000001322762156600141435ustar00rootroot00000000000000icinga2-2.8.1/choco/CMakeLists.txt000066400000000000000000000023631322762156600167070ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. if(WIN32) find_program(CHOCO_BINARY choco) configure_file(icinga2.nuspec.cmake icinga2.nuspec) configure_file(chocolateyInstall.ps1.cmake chocolateyInstall.ps1) add_custom_target(choco-pkg ALL COMMAND choco pack COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/icinga2.${SPEC_VERSION}.nupkg ${CMAKE_CURRENT_BINARY_DIR}/icinga2.nupkg DEPENDS icinga2.nuspec ${CMAKE_CURRENT_BINARY_DIR}/chocolateyInstall.ps1 chocolateyUninstall.ps1 ) endif() icinga2-2.8.1/choco/chocolateyInstall.ps1.cmake000077500000000000000000000006171322762156600213370ustar00rootroot00000000000000$packageName = 'icinga2' $installerType = 'msi' $url32 = 'https://packages.icinga.com/windows/Icinga2-v${SPEC_VERSION}-x86.msi' $url64 = 'https://packages.icinga.com/windows/Icinga2-v${SPEC_VERSION}-x86_64.msi' $silentArgs = '/qn /norestart' $validExitCodes = @(0) Install-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "$url32" "$url64" -validExitCodes $validExitCodes icinga2-2.8.1/choco/chocolateyUninstall.ps1000066400000000000000000000017601322762156600206200ustar00rootroot00000000000000$packageName = "Icinga 2"; $fileType = 'msi'; $silentArgs = '/qr /norestart' $validExitCodes = @(0) try { $packageGuid = Get-ChildItem HKLM:\SOFTWARE\Classes\Installer\Products | Get-ItemProperty -Name 'ProductName' | ? { $_.ProductName -like $packageName + "*"} | Select -ExpandProperty PSChildName -First 1 $properties = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packageGuid\InstallProperties $file = $properties.LocalPackage # Would like to use the following, but looks like there is a bug in this method when uninstalling MSI's # Uninstall-ChocolateyPackage $packageName $fileType $silentArgs $file -validExitCodes $validExitCodes # Use this instead $msiArgs = "/x $file $silentArgs"; Start-ChocolateyProcessAsAdmin "$msiArgs" 'msiexec' -validExitCodes $validExitCodes Write-ChocolateySuccess $package } catch { Write-ChocolateyFailure $package "$($_.Exception.Message)" throw } icinga2-2.8.1/choco/icinga2.nuspec.cmake000077500000000000000000000035171322762156600177660ustar00rootroot00000000000000 icinga2 Icinga 2 ${SPEC_VERSION} The Icinga Project Icinga Development Team icinga2 - Monitoring Agent for Windows Icinga 2 is an open source monitoring platform which notifies users about host and service outages. https://www.icinga.com/ icinga2 agent monitoring admin https://www.icinga.com/resources/faq/ https://github.com/Icinga/icinga2/blob/master/ChangeLog https://docs.icinga.com/icinga2/ https://github.com/Icinga/icinga2/issues https://github.com/Icinga/icinga2 https://github.com/Icinga/icinga2 false https://www.icinga.com/wp-content/uploads/2015/05/icinga_icon_128x128.png icinga2-2.8.1/cmake/000077500000000000000000000000001322762156600141305ustar00rootroot00000000000000icinga2-2.8.1/cmake/FindYAJL.cmake000066400000000000000000000017571322762156600165040ustar00rootroot00000000000000# - Try to find libyajl # Once done this will define # YAJL_FOUND - System has YAJL # YAJL_INCLUDE_DIRS - The YAJL include directories # YAJL_LIBRARIES - The libraries needed to use YAJL # YAJL_DEFINITIONS - Compiler switches required for using YAJL find_package(PkgConfig) pkg_check_modules(PC_YAJL QUIET yajl) set(YAJL_DEFINITIONS ${PC_YAJL_CFLAGS_OTHER}) find_path(YAJL_INCLUDE_DIR yajl/yajl_version.h HINTS ${PC_YAJL_INCLUDEDIR} ${PC_YAJL_INCLUDE_DIRS} PATH_SUFFIXES libyajl) find_library(YAJL_LIBRARY NAMES yajl libyajl HINTS ${PC_YAJL_LIBDIR} ${PC_YAJL_LIBRARY_DIRS}) set(YAJL_LIBRARIES ${YAJL_LIBRARY} ) set(YAJL_INCLUDE_DIRS ${YAJL_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set YAJL_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(yajl DEFAULT_MSG YAJL_LIBRARY YAJL_INCLUDE_DIR) mark_as_advanced(YAJL_INCLUDE_DIR YAJL_LIBRARY) icinga2-2.8.1/cmake/InstallConfig.cmake000066400000000000000000000043031322762156600176660ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.com) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. function(install_if_not_exists src dest) set(real_dest "${dest}") if(NOT IS_ABSOLUTE "${src}") set(src "${CMAKE_CURRENT_SOURCE_DIR}/${src}") endif() get_filename_component(src_name "${src}" NAME) get_filename_component(basename_dest "${src}" NAME) string(REPLACE "/" "\\\\" nsis_src "${src}") string(REPLACE "/" "\\\\" nsis_dest_dir "${real_dest}") string(REPLACE "/" "\\\\" nsis_dest "${real_dest}/${basename_dest}") install(CODE " if(\"\$ENV{DESTDIR}\" STREQUAL \"\") set(target_dir \${CMAKE_INSTALL_PREFIX}) else() set(target_dir \$ENV{DESTDIR}) endif() if(\${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.* OR NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${skel_prefix}${dest}/${src_name}\") message(STATUS \"Installing: \$ENV{DESTDIR}${dest}/${src_name}\") if(\${CMAKE_INSTALL_PREFIX} MATCHES .*/_CPack_Packages/.*) set(skel_prefix \"share/skel/\") else() set(skel_prefix \"\") endif() execute_process(COMMAND \${CMAKE_COMMAND} -E copy \"${src}\" \"\${target_dir}/\${skel_prefix}${dest}/${src_name}\" RESULT_VARIABLE copy_result ERROR_VARIABLE error_output) if(copy_result) message(FATAL_ERROR \${error_output}) endif() else() message(STATUS \"Skipping : \${target_dir}/${dest}/${src_name}\") endif() ") endfunction(install_if_not_exists) icinga2-2.8.1/config.h.cmake000066400000000000000000000016701322762156600155510ustar00rootroot00000000000000#ifndef CONFIG_H #define CONFIG_H #cmakedefine HAVE_BACKTRACE_SYMBOLS #cmakedefine HAVE_PIPE2 #cmakedefine HAVE_VFORK #cmakedefine HAVE_DLADDR #cmakedefine HAVE_LIBEXECINFO #cmakedefine HAVE_CXXABI_H #cmakedefine HAVE_NICE #cmakedefine HAVE_EDITLINE #cmakedefine ICINGA2_UNITY_BUILD #define ICINGA_PREFIX "${CMAKE_INSTALL_PREFIX}" #define ICINGA_SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}" #define ICINGA_RUNDIR "${ICINGA2_RUNDIR}" #define ICINGA_LOCALSTATEDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}" #define ICINGA_PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2" #define ICINGA_INCLUDECONFDIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2/include" #define ICINGA_USER "${ICINGA2_USER}" #define ICINGA_GROUP "${ICINGA2_GROUP}" #define ICINGA_BUILD_HOST_NAME "${ICINGA2_BUILD_HOST_NAME}" #define ICINGA_BUILD_COMPILER_NAME "${ICINGA2_BUILD_COMPILER_NAME}" #define ICINGA_BUILD_COMPILER_VERSION "${ICINGA2_BUILD_COMPILER_VERSION}" #endif /* CONFIG_H */ icinga2-2.8.1/contrib/000077500000000000000000000000001322762156600145105ustar00rootroot00000000000000icinga2-2.8.1/contrib/GPLHeader000066400000000000000000000026421322762156600161720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ icinga2-2.8.1/contrib/README000066400000000000000000000003461322762156600153730ustar00rootroot00000000000000Icinga 2 Contrib files ====================== This directory contains various unsupported scripts. Chances are that they're either completely broken or at least need some changes to work with the most recent version of Icinga 2. icinga2-2.8.1/contrib/discover-api.py000077500000000000000000000101201322762156600174440ustar00rootroot00000000000000#!/usr/bin/env python # Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. import sys import subprocess import socket import urlparse import requests import json from xml.dom.minidom import parse api_url = "https://localhost:5665/" api_user = "root" api_password = "root" if len(sys.argv) < 2: print "Syntax: %s [ ...]" % (sys.argv[0]) sys.exit(1) tcp_service_commands = { 'ssh': 'ssh', 'http': 'http', 'smtp': 'smtp', 'ssmtp': 'ssmtp' } udp_service_commands = { 'ntp': 'ntp_time', 'snmp': 'snmp-uptime' } hosts = {} def process_host(host_element): global hosts status = "down" for status_element in host_element.getElementsByTagName("status"): status = status_element.getAttribute("state") if status != "up": return for address_element in host_element.getElementsByTagName("address"): if not address_element.getAttribute("addrtype") in [ "ipv4", "ipv6" ]: continue address = address_element.getAttribute("addr") break name = address for hostname_element in host_element.getElementsByTagName("hostname"): name = hostname_element.getAttribute("name") try: services = hosts[name]["services"] except: services = {} for port_element in host_element.getElementsByTagName("port"): state = "closed" for state_element in port_element.getElementsByTagName("state"): state = state_element.getAttribute("state") if state != "open": continue port = int(port_element.getAttribute("portid")) protocol = port_element.getAttribute("protocol") try: serv = socket.getservbyport(port, protocol) except: serv = str(port) try: if protocol == "tcp": command = tcp_service_commands[serv] elif protocol == "udp": command = udp_service_commands[serv] else: raise "Unknown protocol." except: command = protocol if command == "udp": continue services[serv] = { "command": command, "port": port } hosts[name] = { "name": name, "address": address, "services": services } def create_host(host): global api_url, api_user, api_password req = { "templates": [ "discovered-host" ], "attrs": { "address": host["address"] } } headers = {"Accept": "application/json"} url = urlparse.urljoin(api_url, "v1/objects/hosts/%s" % (host["name"])) requests.put(url, headers=headers, auth=(api_user, api_password), data=json.dumps(req), verify=False) for serv, service in host["services"].iteritems(): req = { "templates": [ "discovered-service" ], "attrs": { "vars.%s_port" % (service["command"]): service["port"], "check_command": service["command"], } } headers = {"Accept": "application/json"} url = urlparse.urljoin(api_url, "v1/objects/services/%s!%s" % (host["name"], serv)) requests.put(url, headers=headers, auth=(api_user, api_password), data=json.dumps(req), verify=False) for arg in sys.argv[1:]: # Expects XML output from 'nmap -oX' dom = parse(arg) for host in dom.getElementsByTagName("host"): process_host(host) for host in hosts.values(): create_host(host) icinga2-2.8.1/contrib/discover.py000077500000000000000000000072211322762156600167050ustar00rootroot00000000000000#!/usr/bin/env python # Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. import sys import subprocess import socket from xml.dom.minidom import parse if len(sys.argv) < 2: print "Syntax: %s [ ...]" % (sys.argv[0]) sys.exit(1) tcp_service_commands = { 'ssh': 'ssh', 'http': 'http_ip', 'https': 'https_ip', 'smtp': 'smtp', 'ssmtp': 'ssmtp' } udp_service_commands = { 'ntp': 'ntp_time', 'snmp': 'snmp-uptime' } hosts = {} def process_host(host_element): global hosts status = "down" for status_element in host_element.getElementsByTagName("status"): status = status_element.getAttribute("state") if status != "up": return for address_element in host_element.getElementsByTagName("address"): if not address_element.getAttribute("addrtype") in [ "ipv4", "ipv6" ]: continue address = address_element.getAttribute("addr") break name = address for hostname_element in host_element.getElementsByTagName("hostname"): name = hostname_element.getAttribute("name") try: services = hosts[name]["services"] except: services = {} for port_element in host_element.getElementsByTagName("port"): state = "closed" for state_element in port_element.getElementsByTagName("state"): state = state_element.getAttribute("state") if state != "open": continue port = int(port_element.getAttribute("portid")) protocol = port_element.getAttribute("protocol") try: serv = socket.getservbyport(port, protocol) except: serv = str(port) try: if protocol == "tcp": command = tcp_service_commands[serv] elif protocol == "udp": command = udp_service_commands[serv] else: raise "Unknown protocol." except: command = protocol if command == "udp": continue services[serv] = { "command": command, "port": port } hosts[name] = { "name": name, "address": address, "services": services } def print_host(host): print "object Host \"%s\" {" % (host["name"]) print "\timport \"discovered-host\"," print "" print "\taddress = \"%s\"," % (host["address"]) print "}" print "" for serv, service in host["services"].iteritems(): print "object Service \"%s\" {" % (serv) print "\timport \"discovered-service\"," print "" print "\thost_name = \"%s\"" % (host["name"]) print "\tcheck_command = \"%s\"," % (service["command"]) print "" print "\tvars.port = %s" % (service["port"]) print "}" print "" for arg in sys.argv[1:]: # Expects XML output from 'nmap -oX' dom = parse(arg) for host in dom.getElementsByTagName("host"): process_host(host) for host in hosts.values(): print_host(host) icinga2-2.8.1/contrib/i2eval/000077500000000000000000000000001322762156600156725ustar00rootroot00000000000000icinga2-2.8.1/contrib/i2eval/Makefile000066400000000000000000000004421322762156600173320ustar00rootroot00000000000000i2tcl.so: i2tcl.cpp i2tcl.hpp swig -c++ -o i2tcl_wrap.cpp i2tcl.hpp g++ -g -std=c++11 -I/usr/include/tcl8.5 -shared -fpic -Iicinga2/lib -Iicinga2/build -Iicinga2/build/lib -L/opt/icinga2/lib/icinga2 -lbase -lconfig -Wl,-rpath=/opt/icinga2/lib/icinga2 -o i2tcl.so i2tcl_wrap.cpp i2tcl.cpp icinga2-2.8.1/contrib/i2eval/README000066400000000000000000000001261322762156600165510ustar00rootroot00000000000000This is the source code for the 'i2eval' IRC bot that's on #icinga and #icinga-devel. icinga2-2.8.1/contrib/i2eval/i2tcl.cpp000066400000000000000000000107671322762156600174260ustar00rootroot00000000000000#include "i2tcl.hpp" #include "config/configcompiler.hpp" #include "config/configcompilercontext.hpp" #include "base/function.hpp" #include "base/json.hpp" #include "base/application.hpp" #include using namespace icinga; static bool l_Init_Called; static Tcl_Interp *l_Interp; static Tcl_Encoding l_Encoding; static std::map l_Lines; static int l_NextLine = 1; static Value i2_call_tcl(const String& command, const String& mtype, const std::vector& args) { Tcl_Obj **objv = new Tcl_Obj *[args.size() + 1]; objv[0] = Tcl_NewStringObj(command.CStr(), -1); Tcl_IncrRefCount(objv[0]); for (size_t i = 0; i < args.size(); i++) { Tcl_DString dsText; String arg = static_cast(args[i]); Tcl_ExternalToUtfDString(l_Encoding, arg.CStr(), -1, &dsText); objv[i + 1] = Tcl_NewStringObj(Tcl_DStringValue(&dsText), Tcl_DStringLength(&dsText)); Tcl_DStringFree(&dsText); Tcl_IncrRefCount(objv[i + 1]); } int code = Tcl_EvalObjv(l_Interp, args.size() + 1, objv, TCL_EVAL_GLOBAL); Tcl_Obj *result = Tcl_GetObjResult(l_Interp); for (size_t i = 0; i < args.size() + 1; i++) Tcl_DecrRefCount(objv[i]); delete [] objv; if (code == TCL_ERROR) BOOST_THROW_EXCEPTION(std::runtime_error("An error occurred in the TCL script")); Value vresult; if (mtype == "list") { Array::Ptr arr = new Array(); int len; if (Tcl_ListObjLength(l_Interp, result, &len) != TCL_OK) BOOST_THROW_EXCEPTION(std::invalid_argument("TCL proc returned something that is not a list")); for (size_t i = 0; i < len; i++) { Tcl_Obj *obj; Tcl_ListObjIndex(l_Interp, result, i, &obj); const char* strObj = Tcl_GetString(obj); Tcl_DString dsObj; arr->Add(Tcl_UtfToExternalDString(l_Encoding, strObj, -1, &dsObj)); Tcl_DStringFree(&dsObj); } vresult = arr; } else if (mtype == "null") { /* Nothing to do here */ } else if (mtype == "number") { const char* strResult = Tcl_GetString(result); vresult = Convert::ToDouble(strResult); } else if (mtype == "bool") { const char* strResult = Tcl_GetString(result); vresult = Convert::ToBool(Convert::ToLong(strResult)); } else { const char* strResult = Tcl_GetString(result); Tcl_DString dsResult; vresult = Tcl_UtfToExternalDString(l_Encoding, strResult, -1, &dsResult); Tcl_DStringFree(&dsResult); } return vresult; } void i2_register_command(const char *icmd, const char *tcmd, const char *mtype, Tcl_Interp *interp) { Function::Ptr sf = new Function(icmd, boost::bind(i2_call_tcl, String(tcmd), String(mtype), _1)); ScriptGlobal::Set(icmd, sf); } void *i2_new_frame(Tcl_Interp *interp) { if (!l_Init_Called) { l_Init_Called = true; l_Encoding = Tcl_GetEncoding(l_Interp, "ISO8859-1"); Application::InitializeBase(); } ScriptFrame *frame = new ScriptFrame(); frame->Self = ScriptGlobal::GetGlobals(); return frame; } void i2_free_frame(void *frame, Tcl_Interp *interp) { delete reinterpret_cast(frame); } char *i2_eval(void *uframe, const char *text, Tcl_Interp *interp) { std::ostringstream msgbuf; Expression *expr; ScriptFrame *frame = reinterpret_cast(uframe); l_Interp = interp; try { String lineNum = Convert::ToString(l_NextLine); l_NextLine++; String fileName = "<" + lineNum + ">"; l_Lines[fileName] = text; expr = ConfigCompiler::CompileText(fileName, text); if (expr) { Value result = expr->Evaluate(*frame); if (!result.IsObject() || result.IsObjectType() || result.IsObjectType()) msgbuf << JsonEncode(result); else msgbuf << result; } } catch (const ScriptError& ex) { DebugInfo di = ex.GetDebugInfo(); if (di.FirstLine != 0) { String text = l_Lines[di.Path]; std::vector lines; boost::algorithm::split(lines, text, boost::is_any_of("\n")); for (int i = di.FirstLine; i <= di.LastLine; i++) { int start, len; if (i == di.FirstLine) start = di.FirstColumn; else start = 0; if (i == di.LastLine) len = di.LastColumn - di.FirstColumn + 1; else len = lines[i].GetLength(); String pathInfo = di.Path; if (i != 1) pathInfo += "(" + Convert::ToString(i) + ")"; pathInfo += ": "; msgbuf << pathInfo << lines[i - 1] << "\n"; msgbuf << String(pathInfo.GetLength(), ' '); msgbuf << String(start, ' ') << String(len, '^') << "\n"; } } msgbuf << ex.what(); } catch (const std::exception& ex) { msgbuf << "Error: " << DiagnosticInformation(ex); } delete expr; std::string str = msgbuf.str(); return strdup(str.c_str()); } icinga2-2.8.1/contrib/i2eval/i2tcl.hpp000066400000000000000000000007271322762156600174260ustar00rootroot00000000000000#ifdef SWIG %module i2tcl %{ #include "i2tcl.hpp" %} %typemap(in,numinputs=0) Tcl_Interp *interp { $1 = interp; } #endif /* SWIG */ #include #ifndef I2TCL_H #define I2TCL_H void i2_register_command(const char *icmd, const char *tcmd, const char *mtype, Tcl_Interp *interp); void *i2_new_frame(Tcl_Interp *interp); void i2_free_frame(void *frame, Tcl_Interp *interp); char *i2_eval(void *frame, const char *text, Tcl_Interp *interp); #endif /* I2TCL_H */ icinga2-2.8.1/contrib/i2eval/i2tcl.tcl000066400000000000000000000047201322762156600174160ustar00rootroot00000000000000package require http package require tls http::register https 443 [list ::tls::socket -tls1 1] load /home/gunnar/i2tcl.so i2tcl bind pub - > i2tcl bind pub - >u i2tcl_url bind pub - ^ i2tcl bind pub - ^u i2tcl_url if {![info exists ::i2frame]} { set ::i2frame [i2_new_frame] } set ::i2chan "" set ::i2nick "" i2_register_command irc i2_irc null i2_register_command channels channels list i2_register_command chanlist internalchanlist list i2_register_command getnick getcurrentnick string i2_register_command onchan onchan bool i2_register_command topic topic string i2_register_command topicnick topicnick string i2_register_command topicstamp topicstamp number i2_register_command chanmodes getchanmode string i2_register_command isop isop bool i2_register_command isvoice isvoice bool i2_register_command ishop ishop bool i2_register_command chanhost getchanhost string i2_register_command chanbans chanbans list i2_register_command getnick i2_getnick string i2_register_command getchan i2_getchan string i2_register_command "Internal.run_with_activation_context" i2_null null i2_register_command exit i2_null null proc i2_null {} { } proc i2_getnick {} { global i2nick return $i2nick } proc i2_getchan {} { global i2chan return $i2chan } proc i2_irc {message} { global i2chan if {[string first "\n" $message] != -1 || [string first "\r" $message] != -1} { return } putserv "PRIVMSG $i2chan :$message" } proc i2tcl {nick host hand chan arg} { global i2frame i2chan i2nick set i2chan $chan set i2nick $nick set result [i2_eval $i2frame $arg] if {$result == ""} { set result "" } foreach sline [split $result \n] { putserv "PRIVMSG $chan :( $arg ) = $sline" } } proc i2tcl_url {nick host hand chan arg} { global i2frame i2chan i2nick set i2chan $chan set i2nick $nick if {[catch {set token [http::geturl $arg]} msg]} { putserv "PRIVMSG $chan :HTTP request failed: $msg" http::cleanup $token return } if {[http::status $token] != "ok"} { putserv "PRIVMSG $chan :HTTP request failed: [http::error $token]" http::cleanup $token return } set rpl [split [http::code $token] " "] if {[lindex $rpl 1] != 200} { putserv "PRIVMSG $chan :HTTP request failed: [join [lrange $rpl 1 end]]" http::cleanup $token return } set code [http::data $token] http::cleanup $token set result [i2_eval $i2frame $code] if {$result == ""} { set result "" } foreach sline [split $result \n] { putserv "PRIVMSG $chan :( $arg ) = $sline" } } icinga2-2.8.1/contrib/icinga2clr.cs000066400000000000000000000034101322762156600170520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ using System; using System.Collections; namespace Icinga { public enum ServiceState { ServiceOK, ServiceWarning, ServiceCritical, ServiceUnknown } public class CheckResult { public ServiceState State; public String Output; public String PerformanceData; } public interface ICheckPlugin { CheckResult Check(Hashtable args); } } icinga2-2.8.1/contrib/make-agent-config.py000077500000000000000000000047741322762156600203550ustar00rootroot00000000000000#!/usr/bin/env python # Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. import subprocess, json inventory_json = subprocess.check_output(["icinga2", "agent", "list", "--batch"]) inventory = json.loads(inventory_json) for agent, agent_info in inventory.items(): print "object Endpoint \"%s\" {" % (agent) print " host = \"%s\"" % (agent) print "}" print "" print "object Zone \"%s\" {" % (agent_info["zone"]) if "parent_zone" in agent_info: print " parent = \"%s\"" % (agent_info["parent_zone"]) print " endpoints = [ \"%s\" ]" % (agent) print "}" print "" print "object Host \"%s\" {" % (agent_info["zone"]) print " check_command = \"cluster-zone\"" print "}" print "" print "apply Dependency \"host-zone-%s\" to Host {" % (agent_info["zone"]) print " parent_host_name = \"%s\"" % (agent_info["zone"]) print " assign where host.zone == \"%s\"" % (agent_info["zone"]) print "}" print "" print "apply Dependency \"service-zone-%s\" to Service {" % (agent_info["zone"]) print " parent_host_name = \"%s\"" % (agent_info["zone"]) print " assign where service.zone == \"%s\"" % (agent_info["zone"]) print "}" print "" for host, services in agent_info["repository"].items(): if host != agent_info["zone"]: print "object Host \"%s\" {" % (host) print " check_command = \"dummy\"" print " zone = \"%s\"" % (agent_info["zone"]) print "}" print "" for service in services: print "object Service \"%s\" {" % (service) print " check_command = \"dummy\"" print " host_name = \"%s\"" % (host) print " zone = \"%s\"" % (agent_info["zone"]) print "}" print "" icinga2-2.8.1/doc/000077500000000000000000000000001322762156600136155ustar00rootroot00000000000000icinga2-2.8.1/doc/.gitignore000066400000000000000000000000141322762156600156000ustar00rootroot00000000000000build *.rst icinga2-2.8.1/doc/01-about.md000066400000000000000000000034211322762156600154670ustar00rootroot00000000000000# About Icinga 2 ## What is Icinga 2? Icinga 2 is an open source monitoring system which checks the availability of your network resources, notifies users of outages and generates performance data for reporting. Scalable and extensible, Icinga 2 can monitor large, complex environments across multiple locations. ## Licensing Icinga 2 and the Icinga 2 documentation are licensed under the terms of the GNU General Public License Version 2. You will find a copy of this license in the LICENSE file included in the source package. ## Support Check the project website at https://www.icinga.com for status updates. Join the [community channels](https://www.icinga.com/community/get-involved/) for questions or ask an Icinga partner for [professional support](https://www.icinga.com/services/support/). ## Contribute There are many ways to contribute to Icinga -- whether it be sending patches, testing, reporting bugs or reviewing and updating the documentation. Every contribution is appreciated! Please continue reading in the [Contributing chapter](https://github.com/Icinga/icinga2/blob/master/CONTRIBUTING.md). ### Icinga 2 Development The Git repository is located on [GitHub](https://github.com/Icinga/icinga2). Icinga 2 is written in C++ and can be built on Linux/Unix and Windows. Read more about development builds in the [INSTALL.md](https://github.com/Icinga/icinga2/blob/master/INSTALL.md) file. ## What's New The Icinga 2 Changelog is located [here](https://github.com/Icinga/icinga2/blob/master/CHANGELOG.md). Please follow our release announcements on [icinga.com](https://www.icinga.com/blog/) too. icinga2-2.8.1/doc/02-getting-started.md000066400000000000000000001004651322762156600174710ustar00rootroot00000000000000# Getting Started This tutorial is a step-by-step introduction to installing [Icinga 2](02-getting-started.md#setting-up-icinga2) and [Icinga Web 2](02-getting-started.md#setting-up-icingaweb2). It assumes that you are familiar with the operating system you're using to install Icinga 2. In case you are upgrading an existing setup, please ensure to follow the [upgrade documentation](16-upgrading-icinga-2.md#upgrading-icinga-2). ## Setting up Icinga 2 First off you have to install Icinga 2. The preferred way of doing this is to use the official package repositories depending on which operating system and distribution you are running. Distribution | Repository ------------------------|--------------------------- Debian | [Icinga Repository](https://packages.icinga.com/debian/) Ubuntu | [Icinga Repository](https://packages.icinga.com/ubuntu/) RHEL/CentOS | [Icinga Repository](https://packages.icinga.com/epel/) openSUSE | [Icinga Repository](https://packages.icinga.com/openSUSE/) SLES | [Icinga Repository](https://packages.icinga.com/SUSE/) Gentoo | [Upstream](https://packages.gentoo.org/package/net-analyzer/icinga2) FreeBSD | [Upstream](https://www.freshports.org/net-mgmt/icinga2) OpenBSD | [Upstream](http://ports.su/net/icinga/core2,-main) ArchLinux | [Upstream](https://aur.archlinux.org/packages/icinga2) Alpine Linux | [Upstream](https://pkgs.alpinelinux.org/package/edge/community/x86_64/icinga2) Packages for distributions other than the ones listed above may also be available. Please contact your distribution packagers. ### Package Repositories You need to add the Icinga repository to your package management configuration. Below is a list with examples for the various distributions. Debian: # wget -O - https://packages.icinga.com/icinga.key | apt-key add - # echo 'deb https://packages.icinga.com/debian icinga-stretch main' >/etc/apt/sources.list.d/icinga.list # apt-get update Ubuntu: # wget -O - https://packages.icinga.com/icinga.key | apt-key add - # echo 'deb https://packages.icinga.com/ubuntu icinga-xenial main' >/etc/apt/sources.list.d/icinga.list # apt-get update RHEL/CentOS 7: yum install https://packages.icinga.com/epel/icinga-rpm-release-7-latest.noarch.rpm RHEL/CentOS 6: yum install https://packages.icinga.com/epel/icinga-rpm-release-6-latest.noarch.rpm Fedora 26: dnf install https://packages.icinga.com/fedora/icinga-rpm-release-26-latest.noarch.rpm Fedora 25: dnf install https://packages.icinga.com/fedora/icinga-rpm-release-25-latest.noarch.rpm SLES 11: # zypper ar https://packages.icinga.com/SUSE/ICINGA-release-11.repo # zypper ref SLES 12: # zypper ar https://packages.icinga.com/SUSE/ICINGA-release.repo # zypper ref openSUSE: # zypper ar https://packages.icinga.com/openSUSE/ICINGA-release.repo # zypper ref Alpine Linux: # echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories # apk update #### RHEL/CentOS EPEL Repository The packages for RHEL/CentOS depend on other packages which are distributed as part of the [EPEL repository](https://fedoraproject.org/wiki/EPEL). CentOS 7/6: yum install epel-release If you are using RHEL you need to enable the `optional` repository and then install the [EPEL rpm package](https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F). #### SLES Security Repository The packages for SLES 11 depend on the `openssl1` package which is distributed as part of the [SLES 11 Security Module](https://www.suse.com/communities/conversations/introducing-the-suse-linux-enterprise-11-security-module/). #### SLES 12 SDK Icinga 2 requires the `libboost_chrono1_54_0` package from the `SLES 12 SDK` repository. Refer to the SUSE Enterprise Linux documentation for further information. #### Alpine Linux Notes The example provided assumes that you are running Alpine edge, which is the -dev branch and is a rolling release. If you are using a stable version please "pin" the edge repository on the latest Icinga 2 package version. In order to correctly manage your repository, please follow [these instructions](https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management) ### Installing Icinga 2 You can install Icinga 2 by using your distribution's package manager to install the `icinga2` package. Debian/Ubuntu: # apt-get install icinga2 RHEL/CentOS 6: # yum install icinga2 # chkconfig icinga2 on # service icinga2 start RHEL/CentOS 7 and Fedora: # yum install icinga2 # systemctl enable icinga2 # systemctl start icinga2 SLES/openSUSE: # zypper install icinga2 FreeBSD: # pkg install icinga2 Alpine Linux: # apk add icinga2 ### Enabled Features during Installation The default installation will enable three features required for a basic Icinga 2 installation: * `checker` for executing checks * `notification` for sending notifications * `mainlog` for writing the `icinga2.log` file You can verify that by calling `icinga2 feature list` [CLI command](11-cli-commands.md#cli-command-feature) to see which features are enabled and disabled. # icinga2 feature list Disabled features: api command compatlog debuglog gelf graphite icingastatus ido-mysql ido-pgsql influxdb livestatus opentsdb perfdata statusdata syslog Enabled features: checker mainlog notification ### Installation Paths By default Icinga 2 uses the following files and directories: Path | Description ----------------------------------------------|------------------------------------ /etc/icinga2 | Contains Icinga 2 configuration files. /usr/lib/systemd/system/icinga2.service | The Icinga 2 Systemd service file on systems using Systemd. /etc/systemd/system/icinga2.service.d/limits.conf | On distributions with Systemd >227, additional service limits are required. /etc/init.d/icinga2 | The Icinga 2 init script on systems using SysVinit or OpenRC. /usr/sbin/icinga2 | Shell wrapper for the Icinga 2 binary. /usr/lib\*/icinga2 | Libraries and the Icinga 2 binary (use `find /usr -type f -name icinga2` to locate the binary path). /usr/share/doc/icinga2 | Documentation files that come with Icinga 2. /usr/share/icinga2/include | The Icinga Template Library and plugin command configuration. /var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api). /var/run/icinga2 | PID file. /var/run/icinga2/cmd | Command pipe and Livestatus socket. /var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files. /var/spool/icinga2 | Used for performance data spool files. /var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature. FreeBSD uses slightly different paths: By default Icinga 2 uses the following files and directories: Path | Description ------------------------------------|------------------------------------ /usr/local/etc/icinga2 | Contains Icinga 2 configuration files. /usr/local/etc/rc.d/icinga2 | The Icinga 2 init script. /usr/local/sbin/icinga2 | Shell wrapper for the Icinga 2 binary. /usr/local/lib/icinga2 | Libraries and the Icinga 2 binary. /usr/local/share/doc/icinga2 | Documentation files that come with Icinga 2. /usr/local/share/icinga2/include | The Icinga Template Library and plugin command configuration. /var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api). /var/run/icinga2 | PID file. /var/run/icinga2/cmd | Command pipe and Livestatus socket. /var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files. /var/spool/icinga2 | Used for performance data spool files. /var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature. ## Setting up Check Plugins Without plugins Icinga 2 does not know how to check external services. The [Monitoring Plugins Project](https://www.monitoring-plugins.org/) provides an extensive set of plugins which can be used with Icinga 2 to check whether services are working properly. These plugins are required to make the [example configuration](04-configuring-icinga-2.md#configuring-icinga2-overview) work out-of-the-box. For your convenience here is a list of package names for some of the more popular operating systems/distributions: OS/Distribution | Package Name | Repository | Installation Path -----------------------|--------------------|---------------------------|---------------------------- RHEL/CentOS | nagios-plugins-all | [EPEL](https://fedoraproject.org/wiki/EPEL) | /usr/lib/nagios/plugins or /usr/lib64/nagios/plugins SLES/OpenSUSE | monitoring-plugins | [server:monitoring](https://build.opensuse.org/project/repositories/server:monitoring) | /usr/lib/nagios/plugins Debian/Ubuntu | monitoring-plugins | - | /usr/lib/nagios/plugins FreeBSD | monitoring-plugins | - | /usr/local/libexec/nagios Alpine Linux | monitoring-plugins | - | /usr/lib/monitoring-plugins OS X | nagios-plugins | [MacPorts](https://www.macports.org), [Homebrew](https://brew.sh) | /opt/local/libexec or /usr/local/sbin The recommended way of installing these standard plugins is to use your distribution's package manager. Debian/Ubuntu: # apt-get install monitoring-plugins RHEL/CentOS: # yum install nagios-plugins-all The packages for RHEL/CentOS depend on other packages which are distributed as part of the [EPEL repository](https://fedoraproject.org/wiki/EPEL). Please make sure to enable this repository by following [these instructions](https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F). Fedora: # dnf install nagios-plugins-all SLES/openSUSE: # zypper install monitoring-plugins The packages for SLES/OpenSUSE depend on other packages which are distributed as part of the [server:monitoring repository](https://build.opensuse.org/project/repositories/server:monitoring). Please make sure to enable this repository beforehand. FreeBSD: # pkg install monitoring-plugins Alpine Linux: # apk add monitoring-plugins Note: For Alpine you don't need to explicitly add the `monitoring-plugins` package since it is a dependency of `icinga2` and is pulled automatically. Depending on which directory your plugins are installed into you may need to update the global `PluginDir` constant in your [Icinga 2 configuration](04-configuring-icinga-2.md#constants-conf). This constant is used by the check command definitions contained in the Icinga Template Library to determine where to find the plugin binaries. > **Note** > > Please refer to the [service monitoring](05-service-monitoring.md#service-monitoring-plugins) chapter for details about how to integrate > additional check plugins into your Icinga 2 setup. ## Running Icinga 2 ### Init Script Icinga 2's init script is installed in `/etc/init.d/icinga2` (`/usr/local/etc/rc.d/icinga2` on FreeBSD) by default: # /etc/init.d/icinga2 Usage: /etc/init.d/icinga2 {start|stop|restart|reload|checkconfig|status} The init script supports the following actions: Command | Description --------------------|------------------------ start | The `start` action starts the Icinga 2 daemon. stop | The `stop` action stops the Icinga 2 daemon. restart | The `restart` action is a shortcut for running the `stop` action followed by `start`. reload | The `reload` action sends the `HUP` signal to Icinga 2 which causes it to restart. Unlike the `restart` action `reload` does not wait until Icinga 2 has restarted. checkconfig | The `checkconfig` action checks if the `/etc/icinga2/icinga2.conf` configuration file contains any errors. status | The `status` action checks if Icinga 2 is running. By default, the Icinga 2 daemon is running as `icinga` user and group using the init script. Using Debian packages the user and group are set to `nagios` for historical reasons. ### Systemd Service Some distributions (e.g. Fedora, openSUSE and RHEL/CentOS 7) use Systemd. The Icinga 2 packages automatically install the necessary Systemd unit files. The Icinga 2 Systemd service can be (re-)started, reloaded, stopped and also queried for its current status. # systemctl status icinga2 icinga2.service - Icinga host/service/network monitoring system Loaded: loaded (/usr/lib/systemd/system/icinga2.service; disabled) Active: active (running) since Mi 2014-07-23 13:39:38 CEST; 15s ago Process: 21692 ExecStart=/usr/sbin/icinga2 -c ${ICINGA2_CONFIG_FILE} -d -e ${ICINGA2_ERROR_LOG} -u ${ICINGA2_USER} -g ${ICINGA2_GROUP} (code=exited, status=0/SUCCESS) Process: 21674 ExecStartPre=/usr/sbin/icinga2-prepare-dirs /etc/sysconfig/icinga2 (code=exited, status=0/SUCCESS) Main PID: 21727 (icinga2) CGroup: /system.slice/icinga2.service 21727 /usr/sbin/icinga2 -c /etc/icinga2/icinga2.conf -d -e /var/log/icinga2/error.log -u icinga -g icinga --no-stack-rlimit Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 309 Service(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 1 User(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 15 Notification(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 4 ScheduledDowntime(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 1 UserGroup(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 1 IcingaApplication(s). Jul 23 13:39:38 nbmif icinga2[21692]: [2014-07-23 13:39:38 +0200] information/ConfigItem: Checked 8 Dependency(s). Jul 23 13:39:38 nbmif systemd[1]: Started Icinga host/service/network monitoring system. The `systemctl` command supports the following actions: Command | Description --------------------|------------------------ start | The `start` action starts the Icinga 2 daemon. stop | The `stop` action stops the Icinga 2 daemon. restart | The `restart` action is a shortcut for running the `stop` action followed by `start`. reload | The `reload` action sends the `HUP` signal to Icinga 2 which causes it to restart. Unlike the `restart` action `reload` does not wait until Icinga 2 has restarted. status | The `status` action checks if Icinga 2 is running. enable | The `enable` action enables the service being started at system boot time (similar to `chkconfig`) Examples: # systemctl enable icinga2 # systemctl restart icinga2 Job for icinga2.service failed. See 'systemctl status icinga2.service' and 'journalctl -xn' for details. If you're stuck with configuration errors, you can manually invoke the [configuration validation](11-cli-commands.md#config-validation). Usually Icinga 2 is a mission critical part of infrastructure and should be online at all times. In case of a recoverable crash (e.g. OOM) you may want to restart Icinga 2 automatically. With Systemd it is as easy as overriding some settings of the Icinga 2 Systemd service by creating `/etc/systemd/system/icinga2.service.d/override.conf` with the following content: [Service] Restart=always RestartSec=1 StartLimitInterval=10 StartLimitBurst=3 Run `systemctl daemon-reload && systemctl restart icinga2` to apply the changes. Now Systemd will always try to restart Icinga 2 (except if you run `systemctl stop icinga2`). After three failures in ten seconds it will stop trying because you probably have a problem that requires manual intervention. > **Tip** > > If you are running into fork errors with Systemd enabled distributions, > please check the [troubleshooting chapter](15-troubleshooting.md#check-fork-errors). ### FreeBSD On FreeBSD you need to enable icinga2 in your rc.conf # sysrc icinga2_enable=yes # service icinga2 restart ### SELinux SELinux is a mandatory access control (MAC) system on Linux which adds a fine-grained permission system for access to all system resources such as files, devices, networks and inter-process communication. Icinga 2 provides its own SELinux policy. `icinga2-selinux` is a policy package for Red Hat Enterprise Linux 7 and derivatives. The package runs the targeted policy which confines Icinga 2 including enabled features and running commands. RHEL/CentOS 7: ``` yum install icinga2-selinux ``` Fedora: ``` dnf install icinga2-selinux ``` Read more about SELinux in [this chapter](22-selinux.md#selinux). ## Configuration Syntax Highlighting Icinga 2 ships configuration examples for syntax highlighting using the `vim` and `nano` editors. The RHEL and SUSE package `icinga2-common` installs these files into `/usr/share/doc/icinga2-common-[x.x.x]/syntax` (where `[x.x.x]` is the version number, e.g. `2.4.3` or `2.4.4`). Sources provide these files in `tools/syntax`. On Debian systems the `icinga2-common` package provides only the Nano configuration file (`/usr/share/nano/icinga2.nanorc`); to obtain the Vim configuration, please install the extra package `vim-icinga2`. The files are located in `/usr/share/vim/addons`. ### Configuration Syntax Highlighting using Vim Install the package `vim-icinga2` with your distribution's package manager. Debian/Ubuntu: # apt-get install vim-icinga2 vim-addon-manager # vim-addon-manager -w install icinga2 Info: installing removed addon 'icinga2' to /var/lib/vim/addons RHEL/CentOS/Fedora: # yum install vim-icinga2 SLES/openSUSE: # zypper install vim-icinga2 Alpine Linux: # apk add icinga2-vim Ensure that syntax highlighting is enabled e.g. by editing the user's `vimrc` configuration file: # vim ~/.vimrc syntax on Test it: # vim /etc/icinga2/conf.d/templates.conf ![Vim with syntax highlighting](images/getting-started/vim-syntax.png "Vim with Icinga 2 syntax highlighting") ### Configuration Syntax Highlighting using Nano Install the package `nano-icinga2` with your distribution's package manager. Debian/Ubuntu: **Note:** The syntax files are installed with the `icinga2-common` package already. RHEL/CentOS/Fedora: # yum install nano-icinga2 SLES/openSUSE: # zypper install nano-icinga2 Copy the `/etc/nanorc` sample file to your home directory. $ cp /etc/nanorc ~/.nanorc Include the `icinga2.nanorc` file. $ vim ~/.nanorc ## Icinga 2 include "/usr/share/nano/icinga2.nanorc" Test it: $ nano /etc/icinga2/conf.d/templates.conf ![Nano with syntax highlighting](images/getting-started/nano-syntax.png "Nano with Icinga 2 syntax highlighting") ## Setting up Icinga Web 2 Icinga 2 can be used with Icinga Web 2 and a number of other web interfaces. This chapter explains how to set up Icinga Web 2. The DB IDO (Database Icinga Data Output) modules for Icinga 2 take care of exporting all configuration and status information into a database. The IDO database is used by a number of projects including [Icinga Web 2](02-getting-started.md#setting-up-icingaweb2), Icinga Reporting or Icinga Web 1.x. There is a separate module for each database backend. At present support for both MySQL and PostgreSQL has been implemented. Please choose whether to install [MySQL](02-getting-started.md#configuring-db-ido-mysql) or [PostgreSQL](02-getting-started.md#configuring-db-ido-postgresql). ### Configuring DB IDO MySQL #### Installing MySQL database server Debian/Ubuntu: # apt-get install mysql-server mysql-client # mysql_secure_installation RHEL/CentOS 6: # yum install mysql-server mysql # chkconfig mysqld on # service mysqld start # mysql_secure_installation RHEL/CentOS 7 and Fedora: # yum install mariadb-server mariadb # systemctl enable mariadb # systemctl start mariadb # mysql_secure_installation SUSE: # zypper install mysql mysql-client # chkconfig mysqld on # service mysqld start FreeBSD: # pkg install mysql56-server # sysrc mysql_enable=yes # service mysql-server restart # mysql_secure_installation Alpine Linux: # apk add mariadb # rc-service mariadb setup # rc-update add mariadb default # rc-service mariadb start #### Installing the IDO modules for MySQL The next step is to install the `icinga2-ido-mysql` package using your distribution's package manager. Debian/Ubuntu: # apt-get install icinga2-ido-mysql RHEL/CentOS: # yum install icinga2-ido-mysql SUSE: # zypper install icinga2-ido-mysql FreeBSD: On FreeBSD the IDO modules for MySQL are included with the icinga2 package and located at /usr/local/share/icinga2-ido-mysql/schema/mysql.sql Alpine Linux: On Alpine Linux the IDO modules for MySQL are included with the `icinga2` package and located at /usr/share/icinga2-ido-mysql/schema/mysql.sql > **Note** > > The Debian/Ubuntu packages provide a database configuration wizard by > default. You can skip the automated setup and install/upgrade the > database manually if you prefer that. #### Setting up the MySQL database Set up a MySQL database for Icinga 2: # mysql -u root -p mysql> CREATE DATABASE icinga; mysql> GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icinga.* TO 'icinga'@'localhost' IDENTIFIED BY 'icinga'; mysql> quit ![setting up the database on CentOS 7](images/getting-started/mariadb-centos7.png "Setting up the database on CentOS 7") After creating the database you can import the Icinga 2 IDO schema using the following command: # mysql -u root -p icinga < /usr/share/icinga2-ido-mysql/schema/mysql.sql #### Enabling the IDO MySQL module The package provides a new configuration file that is installed in `/etc/icinga2/features-available/ido-mysql.conf`. You will need to update the database credentials in this file. All available attributes are explained in the [IdoMysqlConnection object](09-object-types.md#objecttype-idomysqlconnection) chapter. You can enable the `ido-mysql` feature configuration file using `icinga2 feature enable`: # icinga2 feature enable ido-mysql Module 'ido-mysql' was enabled. Make sure to restart Icinga 2 for these changes to take effect. After enabling the ido-mysql feature you have to restart Icinga 2: RHEL/CentOS 7/Fedora, SLES 12/openSUSE > 12.2, Debian Jessie/Stretch, Ubuntu Xenial: # systemctl restart icinga2 Debian/Ubuntu, RHEL/CentOS 6, SLES 11/openSUSE < 12.3 and FreeBSD: # service icinga2 restart Alpine Linux: # rc-service icinga2 restart Continue with the [webserver setup](02-getting-started.md#icinga2-user-interface-webserver). ### Configuring DB IDO PostgreSQL #### Installing PostgreSQL database server Debian/Ubuntu: # apt-get install postgresql RHEL/CentOS 6: # yum install postgresql-server postgresql # chkconfig postgresql on # service postgresql initdb # service postgresql start RHEL/CentOS 7: # yum install postgresql-server postgresql # postgresql-setup initdb # systemctl enable postgresql # systemctl start postgresql SUSE: # zypper install postgresql postgresql-server # chkconfig postgresql on # service postgresql initdb # service postgresql start FreeBSD: # pkg install postgresql93-server # sysrc postgresql_enable=yes # service postgresql initdb # service postgresql start Alpine Linux: # apk add postgresql # rc-update add postgresql default # rc-service postgresql setup # rc-service postgresql start #### Installing the IDO modules for PostgreSQL The next step is to install the `icinga2-ido-pgsql` package using your distribution's package manager. Debian/Ubuntu: # apt-get install icinga2-ido-pgsql RHEL/CentOS: # yum install icinga2-ido-pgsql SUSE: # zypper install icinga2-ido-pgsql FreeBSD: On FreeBSD the IDO modules for PostgreSQL are included with the icinga2 package and located at /usr/local/share/icinga2-ido-pgsql/schema/pgsql.sql Alpine Linux: On Alpine Linux the IDO modules for PostgreSQL are included with the `icinga2` package and located at /usr/share/icinga2-ido-pgsql/schema/pgsql.sql > **Note** > > Upstream Debian packages provide a database configuration wizard by default. > You can skip the automated setup and install/upgrade the database manually > if you prefer that. #### Setting up the PostgreSQL database Set up a PostgreSQL database for Icinga 2: # cd /tmp # sudo -u postgres psql -c "CREATE ROLE icinga WITH LOGIN PASSWORD 'icinga'" # sudo -u postgres createdb -O icinga -E UTF8 icinga # sudo -u postgres createlang plpgsql icinga > **Note** > > When using PostgreSQL 9.x you can omit the `createlang` command. > Also it is assumed here that your locale is set to utf-8, you may run into > problems otherwise. Locate your pg\_hba.conf (Debian: `/etc/postgresql/*/main/pg_hba.conf`, RHEL/SUSE: `/var/lib/pgsql/data/pg_hba.conf`), add the icinga user with md5 authentication method and restart the postgresql server. # icinga local icinga icinga md5 host icinga icinga 127.0.0.1/32 md5 host icinga icinga ::1/128 md5 # "local" is for Unix domain socket connections only local all all ident # IPv4 local connections: host all all 127.0.0.1/32 ident # IPv6 local connections: host all all ::1/128 ident # service postgresql restart After creating the database and permissions you can import the Icinga 2 IDO schema using the following command: # export PGPASSWORD=icinga # psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/pgsql.sql ![importing the Icinga 2 IDO schema](images/getting-started/postgr-import-ido.png "Importing the Icinga 2 IDO schema on Debian Jessie") #### Enabling the IDO PostgreSQL module The package provides a new configuration file that is installed in `/etc/icinga2/features-available/ido-pgsql.conf`. You will need to update the database credentials in this file. All available attributes are explained in the [IdoPgsqlConnection object](09-object-types.md#objecttype-idopgsqlconnection) chapter. You can enable the `ido-pgsql` feature configuration file using `icinga2 feature enable`: # icinga2 feature enable ido-pgsql Module 'ido-pgsql' was enabled. Make sure to restart Icinga 2 for these changes to take effect. After enabling the ido-pgsql feature you have to restart Icinga 2: RHEL/CentOS 7/Fedora, SLES 12/openSUSE > 12.2, Debian Jessie/Stretch, Ubuntu Xenial: # systemctl restart icinga2 Debian/Ubuntu, RHEL/CentOS 6, SLES 11/openSUSE < 12.3 and FreeBSD: # service icinga2 restart Alpine Linux: # rc-service icinga2 restart Continue with the [webserver setup](02-getting-started.md#icinga2-user-interface-webserver). ### Webserver Debian/Ubuntu: # apt-get install apache2 RHEL/CentOS 6: # yum install httpd # chkconfig httpd on # service httpd start RHEL/CentOS 7, Fedora: # yum install httpd # systemctl enable httpd # systemctl start httpd SUSE: # zypper install apache2 # chkconfig on # service apache2 start FreeBSD (nginx, but you could also use the apache24 package): # pkg install nginx php56-gettext php56-ldap php56-openssl php56-mysql php56-pdo_mysql php56-pgsql php56-pdo_pgsql php56-sockets php56-gd pecl-imagick pecl-intl # sysrc php_fpm_enable=yes # sysrc nginx_enable=yes # sed -i '' "s/listen\ =\ 127.0.0.1:9000/listen\ =\ \/var\/run\/php5-fpm.sock/" /usr/local/etc/php-fpm.conf # sed -i '' "s/;listen.owner/listen.owner/" /usr/local/etc/php-fpm.conf # sed -i '' "s/;listen.group/listen.group/" /usr/local/etc/php-fpm.conf # sed -i '' "s/;listen.mode/listen.mode/" /usr/local/etc/php-fpm.conf # service php-fpm start # service nginx start Alpine Linux: # apk add apache2 php7-apache2 # sed -i -e "s/^#LoadModule rewrite_module/LoadModule rewrite_module/" /etc/apache2/httpd.conf # rc-update add apache2 default # rc-service apache2 start ### Firewall Rules Example: # iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # service iptables save RHEL/CentOS 7 specific: # firewall-cmd --add-service=http # firewall-cmd --permanent --add-service=http FreeBSD: Please consult the [FreeBSD Handbook](https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/firewalls.html) how to configure one of FreeBSD's firewalls. ### Setting Up Icinga 2 REST API Icinga Web 2 and other web interfaces require the [REST API](12-icinga2-api.md#icinga2-api-setup) to send actions (reschedule check, etc.) and query object details. You can run the CLI command `icinga2 api setup` to enable the `api` [feature](11-cli-commands.md#enable-features) and set up certificates as well as a new API user `root` with an auto-generated password in the `/etc/icinga2/conf.d/api-users.conf` configuration file: # icinga2 api setup Edit the `api-users.conf` file and add a new ApiUser object. Specify the [permissions](12-icinga2-api.md#icinga2-api-permissions) attribute with minimal permissions required by Icinga Web 2. # vim /etc/icinga2/conf.d/api-users.conf object ApiUser "icingaweb2" { password = "Wijsn8Z9eRs5E25d" permissions = [ "status/query", "actions/*", "objects/modify/*", "objects/query/*" ] } Make sure to restart Icinga 2 to activate the configuration. RHEL/CentOS 7/Fedora, SLES 12/openSUSE > 12.2, Debian Jessie/Stretch, Ubuntu Xenial: # systemctl restart icinga2 Debian/Ubuntu, RHEL/CentOS 6, SLES 11/openSUSE < 12.3 and FreeBSD: # service icinga2 restart Alpine Linux: # rc-service icinga2 restart ### Installing Icinga Web 2 Please consult the [installation documentation](https://www.icinga.com/docs/icingaweb2/latest/doc/02-Installation/) for further instructions on how to install Icinga Web 2. The Icinga 2 API can be defined as [command transport](https://www.icinga.com/docs/icingaweb2/latest/modules/monitoring/doc/05-Command-Transports/) in Icinga Web 2 >= 2.4. ## Addons A number of additional features are available in the form of addons. A list of popular addons is available in the [Addons and Plugins](13-addons.md#addons) chapter. ## Backup Ensure to include the following in your backups: * Configuration files in `/etc/icinga2` * Certificate files in `/var/lib/icinga2/ca` (Master CA key pair) and `/var/lib/icinga2/certs` (node certificates) * Runtime files in `/var/lib/icinga2` * Optional: IDO database backup icinga2-2.8.1/doc/03-monitoring-basics.md000066400000000000000000003135771322762156600200260ustar00rootroot00000000000000# Monitoring Basics This part of the Icinga 2 documentation provides an overview of all the basic monitoring concepts you need to know to run Icinga 2. Keep in mind these examples are made with a Linux server. If you are using Windows, you will need to change the services accordingly. See the [ITL reference](10-icinga-template-library.md#windows-plugins) for further information. ## Attribute Value Types The Icinga 2 configuration uses different value types for attributes. Type | Example -------------------------------------------------------|--------------------------------------------------------- [Number](17-language-reference.md#numeric-literals) | `5` [Duration](17-language-reference.md#duration-literals) | `1m` [String](17-language-reference.md#string-literals) | `"These are notes"` [Boolean](17-language-reference.md#boolean-literals) | `true` [Array](17-language-reference.md#array) | `[ "value1", "value2" ]` [Dictionary](17-language-reference.md#dictionary) | `{ "key1" = "value1", "key2" = false }` It is important to use the correct value type for object attributes as otherwise the [configuration validation](11-cli-commands.md#config-validation) will fail. ## Hosts and Services Icinga 2 can be used to monitor the availability of hosts and services. Hosts and services can be virtually anything which can be checked in some way: * Network services (HTTP, SMTP, SNMP, SSH, etc.) * Printers * Switches or routers * Temperature sensors * Other local or network-accessible services Host objects provide a mechanism to group services that are running on the same physical device. Here is an example of a host object which defines two child services: ``` object Host "my-server1" { address = "10.0.0.1" check_command = "hostalive" } object Service "ping4" { host_name = "my-server1" check_command = "ping4" } object Service "http" { host_name = "my-server1" check_command = "http" } ``` The example creates two services `ping4` and `http` which belong to the host `my-server1`. It also specifies that the host should perform its own check using the `hostalive` check command. The `address` attribute is used by check commands to determine which network address is associated with the host object. Details on troubleshooting check problems can be found [here](15-troubleshooting.md#troubleshooting). ### Host States Hosts can be in any one of the following states: Name | Description ------------|-------------- UP | The host is available. DOWN | The host is unavailable. ### Service States Services can be in any one of the following states: Name | Description ------------|-------------- OK | The service is working properly. WARNING | The service is experiencing some problems but is still considered to be in working condition. CRITICAL | The service is in a critical state. UNKNOWN | The check could not determine the service's state. ### Check Result State Mapping [Check plugins](05-service-monitoring.md#service-monitoring-plugins) return with an exit code which is converted into a state number. Services map the states directly while hosts will treat `0` or `1` as `UP` for example. Value | Host State | Service State ------|------------|-------------- 0 | Up | OK 1 | Up | Warning 2 | Down | Critical 3 | Down | Unknown ### Hard and Soft States When detecting a problem with a host/service, Icinga re-checks the object a number of times (based on the `max_check_attempts` and `retry_interval` settings) before sending notifications. This ensures that no unnecessary notifications are sent for transient failures. During this time the object is in a `SOFT` state. After all re-checks have been executed and the object is still in a non-OK state, the host/service switches to a `HARD` state and notifications are sent. Name | Description ------------|-------------- HARD | The host/service's state hasn't recently changed. `check_interval` applies here. SOFT | The host/service has recently changed state and is being re-checked with `retry_interval`. ### Host and Service Checks Hosts and services determine their state by running checks in a regular interval. ``` object Host "router" { check_command = "hostalive" address = "10.0.0.1" } ``` The `hostalive` command is one of several built-in check commands. It sends ICMP echo requests to the IP address specified in the `address` attribute to determine whether a host is online. > **Tip** > > `hostalive` is the same as `ping` but with different default thresholds. > Both use the `ping` CLI command to execute sequential checks. > > If you need faster ICMP checks, look into the [icmp](10-icinga-template-library.md#plugin-check-command-icmp) CheckCommand. A number of other [built-in check commands](10-icinga-template-library.md#icinga-template-library) are also available. In addition to these commands the next few chapters will explain in detail how to set up your own check commands. #### Host Check Alternatives If the host is not reachable with ICMP, HTTP, etc. you can also use the [dummy](10-icinga-template-library.md#plugin-check-command-dummy) CheckCommand to set a default state. ``` object Host "dummy-host" { check_command = "dummy" vars.dummy_state = 0 //Up vars.dummy_text = "Everything OK." } ``` This method is also used when you send in [external check results](08-advanced-topics.md#external-check-results). A more advanced technique is to calculate an overall state based on all services. This is described [here](08-advanced-topics.md#access-object-attributes-at-runtime-cluster-check). ## Templates Templates may be used to apply a set of identical attributes to more than one object: ``` template Service "generic-service" { max_check_attempts = 3 check_interval = 5m retry_interval = 1m enable_perfdata = true } apply Service "ping4" { import "generic-service" check_command = "ping4" assign where host.address } apply Service "ping6" { import "generic-service" check_command = "ping6" assign where host.address6 } ``` In this example the `ping4` and `ping6` services inherit properties from the template `generic-service`. Objects as well as templates themselves can import an arbitrary number of other templates. Attributes inherited from a template can be overridden in the object if necessary. You can also import existing non-template objects. > **Note** > > Templates and objects share the same namespace, i.e. you can't define a template > that has the same name like an object. ### Multiple Templates The following example uses [custom attributes](03-monitoring-basics.md#custom-attributes) which are provided in each template. The `web-server` template is used as the base template for any host providing web services. In addition to that it specifies the custom attribute `webserver_type`, e.g. `apache`. Since this template is also the base template, we import the `generic-host` template here. This provides the `check_command` attribute by default and we don't need to set it anywhere later on. ``` template Host "web-server" { import "generic-host" vars = { webserver_type = "apache" } } ``` The `wp-server` host template specifies a Wordpress instance and sets the `application_type` custom attribute. Please note the `+=` [operator](17-language-reference.md#dictionary-operators) which adds [dictionary](17-language-reference.md#dictionary) items, but does not override any previous `vars` attribute. ``` template Host "wp-server" { vars += { application_type = "wordpress" } } ``` The final host object imports both templates. The order is important here: First the base template `web-server` is added to the object, then additional attributes are imported from the `wp-server` object. ``` object Host "wp.example.com" { import "web-server" import "wp-server" address = "192.168.56.200" } ``` If you want to override specific attributes inherited from templates, you can specify them on the host object. ``` object Host "wp1.example.com" { import "web-server" import "wp-server" vars.webserver_type = "nginx" //overrides attribute from base template address = "192.168.56.201" } ``` ## Custom Attributes In addition to built-in attributes you can define your own attributes inside the `vars` attribute: ``` object Host "localhost" { check_command = "ssh" vars.ssh_port = 2222 } ``` `vars` is a [dictionary](17-language-reference.md#dictionary) where you can set specific keys to values. The example above uses the shorter [indexer](17-language-reference.md#indexer) syntax. An alternative representation can be written like this: ``` vars = { ssh_port = 2222 } ``` or ``` vars["ssh_port"] = 2222 ``` ### Custom Attribute Values Valid values for custom attributes include: * [Strings](17-language-reference.md#string-literals), [numbers](17-language-reference.md#numeric-literals) and [booleans](17-language-reference.md#boolean-literals) * [Arrays](17-language-reference.md#array) and [dictionaries](17-language-reference.md#dictionary) * [Functions](03-monitoring-basics.md#custom-attributes-functions) You can also define nested values such as dictionaries in dictionaries. This example defines the custom attribute `disks` as dictionary. The first key is set to `disk /` is itself set to a dictionary with one key-value pair. ``` vars.disks["disk /"] = { disk_partitions = "/" } ``` This can be written as resolved structure like this: ``` vars = { disks = { "disk /" = { disk_partitions = "/" } } } ``` Keep this in mind when trying to access specific sub-keys in apply rules or functions. Another example which is shown in the example configuration: ``` vars.notification["mail"] = { groups = [ "icingaadmins" ] } ``` This defines the `notification` custom attribute as dictionary with the key `mail`. Its value is a dictionary with the key `groups` which itself has an array as value. Note: This array is the exact same as the `user_groups` attribute for [notification apply rules](#03-monitoring-basics.md#using-apply-notifications) expects. ``` vars.notification = { mail = { groups = [ "icingaadmins" ] } } ``` ### Functions as Custom Attributes Icinga 2 lets you specify [functions](17-language-reference.md#functions) for custom attributes. The special case here is that whenever Icinga 2 needs the value for such a custom attribute it runs the function and uses whatever value the function returns: ``` object CheckCommand "random-value" { command = [ PluginDir + "/check_dummy", "0", "$text$" ] vars.text = {{ Math.random() * 100 }} } ``` This example uses the [abbreviated lambda syntax](17-language-reference.md#nullary-lambdas). These functions have access to a number of variables: Variable | Description -------------|--------------- user | The User object (for notifications). service | The Service object (for service checks/notifications/event handlers). host | The Host object. command | The command object (e.g. a CheckCommand object for checks). Here's an example: ``` vars.text = {{ host.check_interval }} ``` In addition to these variables the [macro](18-library-reference.md#scoped-functions-macro) function can be used to retrieve the value of arbitrary macro expressions: ``` vars.text = {{ if (macro("$address$") == "127.0.0.1") { log("Running a check for localhost!") } return "Some text" }} ``` The `resolve_arguments` function can be used to resolve a command and its arguments much in the same fashion Icinga does this for the `command` and `arguments` attributes for commands. The `by_ssh` command uses this functionality to let users specify a command and arguments that should be executed via SSH: ``` arguments = { "-C" = {{ var command = macro("$by_ssh_command$") var arguments = macro("$by_ssh_arguments$") if (typeof(command) == String && !arguments) { return command } var escaped_args = [] for (arg in resolve_arguments(command, arguments)) { escaped_args.add(escape_shell_arg(arg)) } return escaped_args.join(" ") }} ... } ``` Accessing object attributes at runtime inside these functions is described in the [advanced topics](08-advanced-topics.md#access-object-attributes-at-runtime) chapter. ## Runtime Macros Macros can be used to access other objects' attributes at runtime. For example they are used in command definitions to figure out which IP address a check should be run against: ``` object CheckCommand "my-ping" { command = [ PluginDir + "/check_ping", "-H", "$ping_address$" ] arguments = { "-w" = "$ping_wrta$,$ping_wpl$%" "-c" = "$ping_crta$,$ping_cpl$%" "-p" = "$ping_packets$" } vars.ping_address = "$address$" vars.ping_wrta = 100 vars.ping_wpl = 5 vars.ping_crta = 250 vars.ping_cpl = 10 vars.ping_packets = 5 } object Host "router" { check_command = "my-ping" address = "10.0.0.1" } ``` In this example we are using the `$address$` macro to refer to the host's `address` attribute. We can also directly refer to custom attributes, e.g. by using `$ping_wrta$`. Icinga automatically tries to find the closest match for the attribute you specified. The exact rules for this are explained in the next section. > **Note** > > When using the `$` sign as single character you must escape it with an > additional dollar character (`$$`). ### Evaluation Order When executing commands Icinga 2 checks the following objects in this order to look up macros and their respective values: 1. User object (only for notifications) 2. Service object 3. Host object 4. Command object 5. Global custom attributes in the `Vars` constant This execution order allows you to define default values for custom attributes in your command objects. Here's how you can override the custom attribute `ping_packets` from the previous example: ``` object Service "ping" { host_name = "localhost" check_command = "my-ping" vars.ping_packets = 10 // Overrides the default value of 5 given in the command } ``` If a custom attribute isn't defined anywhere, an empty value is used and a warning is written to the Icinga 2 log. You can also directly refer to a specific attribute -- thereby ignoring these evaluation rules -- by specifying the full attribute name: ``` $service.vars.ping_wrta$ ``` This retrieves the value of the `ping_wrta` custom attribute for the service. This returns an empty value if the service does not have such a custom attribute no matter whether another object such as the host has this attribute. ### Host Runtime Macros The following host custom attributes are available in all commands that are executed for hosts or services: Name | Description -----------------------------|-------------- host.name | The name of the host object. host.display\_name | The value of the `display_name` attribute. host.state | The host's current state. Can be one of `UNREACHABLE`, `UP` and `DOWN`. host.state\_id | The host's current state. Can be one of `0` (up), `1` (down) and `2` (unreachable). host.state\_type | The host's current state type. Can be one of `SOFT` and `HARD`. host.check\_attempt | The current check attempt number. host.max\_check\_attempts | The maximum number of checks which are executed before changing to a hard state. host.last\_state | The host's previous state. Can be one of `UNREACHABLE`, `UP` and `DOWN`. host.last\_state\_id | The host's previous state. Can be one of `0` (up), `1` (down) and `2` (unreachable). host.last\_state\_type | The host's previous state type. Can be one of `SOFT` and `HARD`. host.last\_state\_change | The last state change's timestamp. host.downtime\_depth | The number of active downtimes. host.duration\_sec | The time since the last state change. host.latency | The host's check latency. host.execution\_time | The host's check execution time. host.output | The last check's output. host.perfdata | The last check's performance data. host.last\_check | The timestamp when the last check was executed. host.check\_source | The monitoring instance that performed the last check. host.num\_services | Number of services associated with the host. host.num\_services\_ok | Number of services associated with the host which are in an `OK` state. host.num\_services\_warning | Number of services associated with the host which are in a `WARNING` state. host.num\_services\_unknown | Number of services associated with the host which are in an `UNKNOWN` state. host.num\_services\_critical | Number of services associated with the host which are in a `CRITICAL` state. In addition to these specific runtime macros [host object](09-object-types.md#objecttype-host) attributes can be accessed too. ### Service Runtime Macros The following service macros are available in all commands that are executed for services: Name | Description -----------------------------|-------------- service.name | The short name of the service object. service.display\_name | The value of the `display_name` attribute. service.check\_command | The short name of the command along with any arguments to be used for the check. service.state | The service's current state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`. service.state\_id | The service's current state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown). service.state\_type | The service's current state type. Can be one of `SOFT` and `HARD`. service.check\_attempt | The current check attempt number. service.max\_check\_attempts | The maximum number of checks which are executed before changing to a hard state. service.last\_state | The service's previous state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`. service.last\_state\_id | The service's previous state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown). service.last\_state\_type | The service's previous state type. Can be one of `SOFT` and `HARD`. service.last\_state\_change | The last state change's timestamp. service.downtime\_depth | The number of active downtimes. service.duration\_sec | The time since the last state change. service.latency | The service's check latency. service.execution\_time | The service's check execution time. service.output | The last check's output. service.perfdata | The last check's performance data. service.last\_check | The timestamp when the last check was executed. service.check\_source | The monitoring instance that performed the last check. In addition to these specific runtime macros [service object](09-object-types.md#objecttype-service) attributes can be accessed too. ### Command Runtime Macros The following custom attributes are available in all commands: Name | Description -----------------------|-------------- command.name | The name of the command object. ### User Runtime Macros The following custom attributes are available in all commands that are executed for users: Name | Description -----------------------|-------------- user.name | The name of the user object. user.display\_name | The value of the `display_name` attribute. In addition to these specific runtime macros [user object](09-object-types.md#objecttype-user) attributes can be accessed too. ### Notification Runtime Macros Name | Description -----------------------|-------------- notification.type | The type of the notification. notification.author | The author of the notification comment if existing. notification.comment | The comment of the notification if existing. In addition to these specific runtime macros [notification object](09-object-types.md#objecttype-notification) attributes can be accessed too. ### Global Runtime Macros The following macros are available in all executed commands: Name | Description -------------------------|-------------- icinga.timet | Current UNIX timestamp. icinga.long\_date\_time | Current date and time including timezone information. Example: `2014-01-03 11:23:08 +0000` icinga.short\_date\_time | Current date and time. Example: `2014-01-03 11:23:08` icinga.date | Current date. Example: `2014-01-03` icinga.time | Current time including timezone information. Example: `11:23:08 +0000` icinga.uptime | Current uptime of the Icinga 2 process. The following macros provide global statistics: Name | Description ------------------------------------|------------------------------------ icinga.num\_services\_ok | Current number of services in state 'OK'. icinga.num\_services\_warning | Current number of services in state 'Warning'. icinga.num\_services\_critical | Current number of services in state 'Critical'. icinga.num\_services\_unknown | Current number of services in state 'Unknown'. icinga.num\_services\_pending | Current number of pending services. icinga.num\_services\_unreachable | Current number of unreachable services. icinga.num\_services\_flapping | Current number of flapping services. icinga.num\_services\_in\_downtime | Current number of services in downtime. icinga.num\_services\_acknowledged | Current number of acknowledged service problems. icinga.num\_hosts\_up | Current number of hosts in state 'Up'. icinga.num\_hosts\_down | Current number of hosts in state 'Down'. icinga.num\_hosts\_unreachable | Current number of unreachable hosts. icinga.num\_hosts\_pending | Current number of pending hosts. icinga.num\_hosts\_flapping | Current number of flapping hosts. icinga.num\_hosts\_in\_downtime | Current number of hosts in downtime. icinga.num\_hosts\_acknowledged | Current number of acknowledged host problems. ## Apply Rules Several object types require an object relation, e.g. [Service](09-object-types.md#objecttype-service), [Notification](09-object-types.md#objecttype-notification), [Dependency](09-object-types.md#objecttype-dependency), [ScheduledDowntime](09-object-types.md#objecttype-scheduleddowntime) objects. The object relations are documented in the linked chapters. If you for example create a service object you have to specify the [host_name](09-object-types.md#objecttype-service) attribute and reference an existing host attribute. ``` object Service "ping4" { check_command = "ping4" host_name = "icinga2-client1.localdomain" } ``` This isn't comfortable when managing a huge set of configuration objects which could [match](03-monitoring-basics.md#using-apply-expressions) on a common pattern. Instead you want to use **[apply](17-language-reference.md#apply) rules**. If you want basic monitoring for all your hosts, add a `ping4` service apply rule for all hosts which have the `address` attribute specified. Just one rule for 1000 hosts instead of 1000 service objects. Apply rules will automatically generate them for you. ``` apply Service "ping4" { check_command = "ping4" assign where host.address } ``` More explanations on assign where expressions can be found [here](03-monitoring-basics.md#using-apply-expressions). ### Apply Rules: Prerequisites Before you start with apply rules keep the following in mind: * Define the best match. * A set of unique [custom attributes](03-monitoring-basics.md#custom-attributes) for these hosts/services? * Or [group](03-monitoring-basics.md#groups) memberships, e.g. a host being a member of a hostgroup which should have a service set? * A generic pattern [match](18-library-reference.md#global-functions-match) on the host/service name? * [Multiple expressions combined](03-monitoring-basics.md#using-apply-expressions) with `&&` or `||` [operators](17-language-reference.md#expression-operators) * All expressions must return a boolean value (an empty string is equal to `false` e.g.) More specific object type requirements are described in these chapters: * [Apply services to hosts](03-monitoring-basics.md#using-apply-services) * [Apply notifications to hosts and services](03-monitoring-basics.md#using-apply-notifications) * [Apply dependencies to hosts and services](03-monitoring-basics.md#using-apply-dependencies) * [Apply scheduled downtimes to hosts and services](03-monitoring-basics.md#using-apply-scheduledowntimes) ### Apply Rules: Usage Examples You can set/override object attributes in apply rules using the respectively available objects in that scope (host and/or service objects). ``` vars.application_type = host.vars.application_type ``` [Custom attributes](03-monitoring-basics.md#custom-attributes) can also store nested dictionaries and arrays. That way you can use them for not only matching for their existence or values in apply expressions, but also assign ("inherit") their values into the generated objected from apply rules. Remember the examples shown for [custom attribute values](03-monitoring-basics.md#custom-attributes-values): ``` vars.notification["mail"] = { groups = [ "icingaadmins" ] } ``` You can do two things here: * Check for the existence of the `notification` custom attribute and its nested dictionary key `mail`. If this is boolean true, the notification object will be generated. * Assign the value of the `groups` key to the `user_groups` attribute. ``` apply Notification "mail-icingaadmin" to Host { [...] user_groups = host.vars.notification.mail.groups assign where host.vars.notification.mail } ``` A more advanced example is to use [apply rules with for loops on arrays or dictionaries](03-monitoring-basics.md#using-apply-for) provided by [custom atttributes](03-monitoring-basics.md#custom-attributes) or groups. Remember the examples shown for [custom attribute values](03-monitoring-basics.md#custom-attributes-values): ``` vars.disks["disk /"] = { disk_partitions = "/" } ``` You can iterate over all dictionary keys defined in `disks`. You can optionally use the value to specify additional object attributes. ``` apply Service for (disk => config in host.vars.disks) { [...] vars.disk_partitions = config.disk_partitions } ``` Please read the [apply for chapter](03-monitoring-basics.md#using-apply-for) for more specific insights. > **Tip** > > Building configuration in that dynamic way requires detailed information > of the generated objects. Use the `object list` [CLI command](11-cli-commands.md#cli-command-object) > after successful [configuration validation](11-cli-commands.md#config-validation). ### Apply Rules Expressions You can use simple or advanced combinations of apply rule expressions. Each expression must evaluate into the boolean `true` value. An empty string will be for instance interpreted as `false`. In a similar fashion undefined attributes will return `false`. Returns `false`: ``` assign where host.vars.attribute_does_not_exist ``` Multiple `assign where` condition rows are evaluated as `OR` condition. You can combine multiple expressions for matching only a subset of objects. In some cases, you want to be able to add more than one assign/ignore where expression which matches a specific condition. To achieve this you can use the logical `and` and `or` operators. #### Apply Rules Expressions Examples Assign a service to a specific host in a host group [array](18-library-reference.md#array-type) using the [in operator](17-language-reference.md#expression-operators): ``` assign where "hostgroup-dev" in host.groups ``` Assign an object when a custom attribute is [equal](17-language-reference.md#expression-operators) to a value: ``` assign where host.vars.application_type == "database" assign where service.vars.sms_notify == true ``` Assign an object if a dictionary [contains](18-library-reference.md#dictionary-contains) a given key: ``` assign where host.vars.app_dict.contains("app") ``` Match the host name by either using a [case insensitive match](18-library-reference.md#global-functions-match): ``` assign where match("webserver*", host.name) ``` Match the host name by using a [regular expression](18-library-reference.md#global-functions-regex). Please note the [escaped](17-language-reference.md#string-literals-escape-sequences) backslash character: ``` assign where regex("^webserver-[\\d+]", host.name) ``` [Match](18-library-reference.md#global-functions-match) all `*mysql*` patterns in the host name and (`&&`) custom attribute `prod_mysql_db` matches the `db-*` pattern. All hosts with the custom attribute `test_server` set to `true` should be ignored, or any host name ending with `*internal` pattern. ``` object HostGroup "mysql-server" { display_name = "MySQL Server" assign where match("*mysql*", host.name) && match("db-*", host.vars.prod_mysql_db) ignore where host.vars.test_server == true ignore where match("*internal", host.name) } ``` Similar example for advanced notification apply rule filters: If the service attribute `notes` [matches](18-library-reference.md#global-functions-match) the `has gold support 24x7` string `AND` one of the two condition passes, either the `customer` host custom attribute is set to `customer-xy` `OR` the host custom attribute `always_notify` is set to `true`. The notification is ignored for services whose host name ends with `*internal` `OR` the `priority` custom attribute is [less than](17-language-reference.md#expression-operators) `2`. ``` template Notification "cust-xy-notification" { users = [ "noc-xy", "mgmt-xy" ] command = "mail-service-notification" } apply Notification "notify-cust-xy-mysql" to Service { import "cust-xy-notification" assign where match("*has gold support 24x7*", service.notes) && (host.vars.customer == "customer-xy" || host.vars.always_notify == true) ignore where match("*internal", host.name) || (service.vars.priority < 2 && host.vars.is_clustered == true) } ``` More advanced examples are covered [here](08-advanced-topics.md#use-functions-assign-where). ### Apply Services to Hosts The sample configuration already includes a detailed example in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) and [services.conf](04-configuring-icinga-2.md#services-conf) for this use case. The example for `ssh` applies a service object to all hosts with the `address` attribute being defined and the custom attribute `os` set to the string `Linux` in `vars`. ``` apply Service "ssh" { import "generic-service" check_command = "ssh" assign where host.address && host.vars.os == "Linux" } ``` Other detailed examples are used in their respective chapters, for example [apply services with custom command arguments](03-monitoring-basics.md#command-passing-parameters). ### Apply Notifications to Hosts and Services Notifications are applied to specific targets (`Host` or `Service`) and work in a similar manner: ``` apply Notification "mail-noc" to Service { import "mail-service-notification" user_groups = [ "noc" ] assign where host.vars.notification.mail } ``` In this example the `mail-noc` notification will be created as object for all services having the `notification.mail` custom attribute defined. The notification command is set to `mail-service-notification` and all members of the user group `noc` will get notified. It is also possible to generally apply a notification template and dynamically overwrite values from the template by checking for custom attributes. This can be achieved by using [conditional statements](17-language-reference.md#conditional-statements): ``` apply Notification "host-mail-noc" to Host { import "mail-host-notification" // replace interval inherited from `mail-host-notification` template with new notfication interval set by a host custom attribute if (host.vars.notification_interval) { interval = host.vars.notification_interval } // same with notification period if (host.vars.notification_period) { period = host.vars.notification_period } // Send SMS instead of email if the host's custom attribute `notification_type` is set to `sms` if (host.vars.notification_type == "sms") { command = "sms-host-notification" } else { command = "mail-host-notification" } user_groups = [ "noc" ] assign where host.address } ``` In the example above the notification template `mail-host-notification` contains all relevant notification settings. The apply rule is applied on all host objects where the `host.address` is defined. If the host object as a specific custom attributed set, its value is inherited into the local notification object scope, e.g. `host.vars.notification_interval`, `host.vars.notification_period` and `host.vars.notification_type`. This overwrites attributes already specified in the imported `mail-host-notification` template. The corresponding host object could look like this: ``` object Host "host1" { import "host-linux-prod" display_name = "host1" address = "192.168.1.50" vars.notification_interval = 1h vars.notification_period = "24x7" vars.notification_type = "sms" } ``` ### Apply Dependencies to Hosts and Services Detailed examples can be found in the [dependencies](03-monitoring-basics.md#dependencies) chapter. ### Apply Recurring Downtimes to Hosts and Services The sample configuration includes an example in [downtimes.conf](04-configuring-icinga-2.md#downtimes-conf). Detailed examples can be found in the [recurring downtimes](08-advanced-topics.md#recurring-downtimes) chapter. ### Using Apply For Rules Next to the standard way of using [apply rules](03-monitoring-basics.md#using-apply) there is the requirement of applying objects based on a set (array or dictionary) using [apply for](17-language-reference.md#apply-for) expressions. The sample configuration already includes a detailed example in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) and [services.conf](04-configuring-icinga-2.md#services-conf) for this use case. Take the following example: A host provides the snmp oids for different service check types. This could look like the following example: ``` object Host "router-v6" { check_command = "hostalive" address6 = "::1" vars.oids["if01"] = "1.1.1.1.1" vars.oids["temp"] = "1.1.1.1.2" vars.oids["bgp"] = "1.1.1.1.5" } ``` The idea is to create service objects for `if01` and `temp` but not `bgp`. The oid value should also be used as service custom attribute `snmp_oid`. This is the command argument required by the [snmp](10-icinga-template-library.md#plugin-check-command-snmp) check command. The service's `display_name` should be set to the identifier inside the dictionary, e.g. `if01`. ``` apply Service for (identifier => oid in host.vars.oids) { check_command = "snmp" display_name = identifier vars.snmp_oid = oid ignore where identifier == "bgp" //don't generate service for bgp checks } ``` Icinga 2 evaluates the `apply for` rule for all objects with the custom attribute `oids` set. It iterates over all dictionary items inside the `for` loop and evaluates the `assign/ignore where` expressions. You can access the loop variable in these expressions, e.g. to ignore specific values. In this example the `bgp` identifier is ignored. This avoids to generate unwanted services. A different approach would be to match the `oid` value with a [regex](18-library-reference.md#global-functions-regex)/[wildcard match](18-library-reference.md#global-functions-match) pattern for example. ``` ignore where regex("^\d.\d.\d.\d.5$", oid) ``` > **Note** > > You don't need an `assign where` expression which checks for the existence of the > `oids` custom attribute. This method saves you from creating multiple apply rules. It also moves the attribute specification logic from the service to the host. #### Apply For and Custom Attribute Override Imagine a different more advanced example: You are monitoring your network device (host) with many interfaces (services). The following requirements/problems apply: * Each interface service should be named with a prefix and a name defined in your host object (which could be generated from your CMDB, etc.) * Each interface has its own VLAN tag * Some interfaces have QoS enabled * Additional attributes such as `display_name` or `notes`, `notes_url` and `action_url` must be dynamically generated. > **Tip** > > Define the SNMP community as global constant in your [constants.conf](04-configuring-icinga-2.md#constants-conf) file. ``` const IftrafficSnmpCommunity = "public" ``` Define the `interfaces` [custom attribute](03-monitoring-basics.md#custom-attributes) on the `cisco-catalyst-6509-34` host object and add three example interfaces as dictionary keys. Specify additional attributes inside the nested dictionary as learned with [custom attribute values](03-monitoring-basics.md#custom-attributes-values): ``` object Host "cisco-catalyst-6509-34" { import "generic-host" display_name = "Catalyst 6509 #34 VIE21" address = "127.0.1.4" /* "GigabitEthernet0/2" is the interface name, * and key name in service apply for later on */ vars.interfaces["GigabitEthernet0/2"] = { /* define all custom attributes with the * same name required for command parameters/arguments * in service apply (look into your CheckCommand definition) */ iftraffic_units = "g" iftraffic_community = IftrafficSnmpCommunity iftraffic_bandwidth = 1 vlan = "internal" qos = "disabled" } vars.interfaces["GigabitEthernet0/4"] = { iftraffic_units = "g" //iftraffic_community = IftrafficSnmpCommunity iftraffic_bandwidth = 1 vlan = "renote" qos = "enabled" } vars.interfaces["MgmtInterface1"] = { iftraffic_community = IftrafficSnmpCommunity vlan = "mgmt" interface_address = "127.99.0.100" #special management ip } } ``` Start with the apply for definition and iterate over `host.vars.interfaces`. This is a dictionary and should use the variables `interface_name` as key and `interface_config` as value for each generated object scope. `"if-"` specifies the object name prefix for each service which results in `if-` for each iteration. ``` /* loop over the host.vars.interfaces dictionary * for (key => value in dict) means `interface_name` as key * and `interface_config` as value. Access config attributes * with the indexer (`.`) character. */ apply Service "if-" for (interface_name => interface_config in host.vars.interfaces) { ``` Import the `generic-service` template, assign the [iftraffic](10-icinga-template-library.md#plugin-contrib-command-iftraffic) `check_command`. Use the dictionary key `interface_name` to set a proper `display_name` string for external interfaces. ``` import "generic-service" check_command = "iftraffic" display_name = "IF-" + interface_name ``` The `interface_name` key's value is the same string used as command parameter for `iftraffic`: ``` /* use the key as command argument (no duplication of values in host.vars.interfaces) */ vars.iftraffic_interface = interface_name ``` Remember that `interface_config` is a nested dictionary. In the first iteration it looks like this: ``` interface_config = { iftraffic_units = "g" iftraffic_community = IftrafficSnmpCommunity iftraffic_bandwidth = 1 vlan = "internal" qos = "disabled" } ``` Access the dictionary keys with the [indexer](17-language-reference.md#indexer) syntax and assign them to custom attributes used as command parameters for the `iftraffic` check command. ``` /* map the custom attributes as command arguments */ vars.iftraffic_units = interface_config.iftraffic_units vars.iftraffic_community = interface_config.iftraffic_community ``` If you just want to inherit all attributes specified inside the `interface_config` dictionary, add it to the generated service custom attributes like this: ``` /* the above can be achieved in a shorter fashion if the names inside host.vars.interfaces * are the _exact_ same as required as command parameter by the check command * definition. */ vars += interface_config ``` If the user did not specify default values for required service custom attributes, add them here. This also helps to avoid unwanted configuration validation errors or runtime failures. Please read more about conditional statements [here](17-language-reference.md#conditional-statements). ``` /* set a default value for units and bandwidth */ if (interface_config.iftraffic_units == "") { vars.iftraffic_units = "m" } if (interface_config.iftraffic_bandwidth == "") { vars.iftraffic_bandwidth = 1 } if (interface_config.vlan == "") { vars.vlan = "not set" } if (interface_config.qos == "") { vars.qos = "not set" } ``` If the host object did not specify a custom SNMP community, set a default value specified by the [global constant](17-language-reference.md#constants) `IftrafficSnmpCommunity`. ``` /* set the global constant if not explicitely * not provided by the `interfaces` dictionary on the host */ if (len(interface_config.iftraffic_community) == 0 || len(vars.iftraffic_community) == 0) { vars.iftraffic_community = IftrafficSnmpCommunity } ``` Use the provided values to [calculate](17-language-reference.md#expression-operators) more object attributes which can be e.g. seen in external interfaces. ``` /* Calculate some additional object attributes after populating the `vars` dictionary */ notes = "Interface check for " + interface_name + " (units: '" + interface_config.iftraffic_units + "') in VLAN '" + vars.vlan + "' with ' QoS '" + vars.qos + "'" notes_url = "https://foreman.company.com/hosts/" + host.name action_url = "http://snmp.checker.company.com/" + host.name + "/if-" + interface_name } ``` > **Tip** > > Building configuration in that dynamic way requires detailed information > of the generated objects. Use the `object list` [CLI command](11-cli-commands.md#cli-command-object) > after successful [configuration validation](11-cli-commands.md#config-validation). Verify that the apply-for-rule successfully created the service objects with the inherited custom attributes: ``` # icinga2 daemon -C # icinga2 object list --type Service --name *catalyst* Object 'cisco-catalyst-6509-34!if-GigabitEthernet0/2' of type 'Service': ...... * vars % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 59:3-59:26 * iftraffic_bandwidth = 1 * iftraffic_community = "public" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 53:3-53:65 * iftraffic_interface = "GigabitEthernet0/2" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 49:3-49:43 * iftraffic_units = "g" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 52:3-52:57 * qos = "disabled" * vlan = "internal" Object 'cisco-catalyst-6509-34!if-GigabitEthernet0/4' of type 'Service': ... * vars % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 59:3-59:26 * iftraffic_bandwidth = 1 * iftraffic_community = "public" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 53:3-53:65 % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 79:5-79:53 * iftraffic_interface = "GigabitEthernet0/4" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 49:3-49:43 * iftraffic_units = "g" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 52:3-52:57 * qos = "enabled" * vlan = "renote" Object 'cisco-catalyst-6509-34!if-MgmtInterface1' of type 'Service': ... * vars % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 59:3-59:26 * iftraffic_bandwidth = 1 % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 66:5-66:32 * iftraffic_community = "public" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 53:3-53:65 * iftraffic_interface = "MgmtInterface1" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 49:3-49:43 * iftraffic_units = "m" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 52:3-52:57 % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 63:5-63:30 * interface_address = "127.99.0.100" * qos = "not set" % = modified in '/etc/icinga2/conf.d/iftraffic.conf', lines 72:5-72:24 * vlan = "mgmt" ``` ### Use Object Attributes in Apply Rules Since apply rules are evaluated after the generic objects, you can reference existing host and/or service object attributes as values for any object attribute specified in that apply rule. ``` object Host "opennebula-host" { import "generic-host" address = "10.1.1.2" vars.hosting["cust1"] = { http_uri = "/shop" customer_name = "Customer 1" customer_id = "7568" support_contract = "gold" } vars.hosting["cust2"] = { http_uri = "/" customer_name = "Customer 2" customer_id = "7569" support_contract = "silver" } } ``` `hosting` is a custom attribute with the Dictionary value type. This is mandatory to iterate with the `key => value` notation in the below apply for rule. ``` apply Service for (customer => config in host.vars.hosting) { import "generic-service" check_command = "ping4" vars.qos = "disabled" vars += config vars.http_uri = "/" + customer + "/" + config.http_uri display_name = "Shop Check for " + vars.customer_name + "-" + vars.customer_id notes = "Support contract: " + vars.support_contract + " for Customer " + vars.customer_name + " (" + vars.customer_id + ")." notes_url = "https://foreman.company.com/hosts/" + host.name action_url = "http://snmp.checker.company.com/" + host.name + "/" + vars.customer_id } ``` Each loop iteration has different values for `customer` and config` in the local scope. 1. ``` customer = "cust 1" config = { http_uri = "/shop" customer_name = "Customer 1" customer_id = "7568" support_contract = "gold" } ``` 2. ``` customer = "cust2" config = { http_uri = "/" customer_name = "Customer 2" customer_id = "7569" support_contract = "silver" } ``` You can now add the `config` dictionary into `vars`. ``` vars += config ``` Now it looks like the following in the first iteration: ``` customer = "cust 1" vars = { http_uri = "/shop" customer_name = "Customer 1" customer_id = "7568" support_contract = "gold" } ``` Remember, you know this structure already. Custom attributes can also be accessed by using the [indexer](17-language-reference.md#indexer) syntax. ``` vars.http_uri = ... + config.http_uri ``` can also be written as ``` vars += config vars.http_uri = ... + vars.http_uri ``` ## Groups A group is a collection of similar objects. Groups are primarily used as a visualization aid in web interfaces. Group membership is defined at the respective object itself. If you have a hostgroup name `windows` for example, and want to assign specific hosts to this group for later viewing the group on your alert dashboard, first create a HostGroup object: ``` object HostGroup "windows" { display_name = "Windows Servers" } ``` Then add your hosts to this group: ``` template Host "windows-server" { groups += [ "windows" ] } object Host "mssql-srv1" { import "windows-server" vars.mssql_port = 1433 } object Host "mssql-srv2" { import "windows-server" vars.mssql_port = 1433 } ``` This can be done for service and user groups the same way: ``` object UserGroup "windows-mssql-admins" { display_name = "Windows MSSQL Admins" } template User "generic-windows-mssql-users" { groups += [ "windows-mssql-admins" ] } object User "win-mssql-noc" { import "generic-windows-mssql-users" email = "noc@example.com" } object User "win-mssql-ops" { import "generic-windows-mssql-users" email = "ops@example.com" } ``` ### Group Membership Assign Instead of manually assigning each object to a group you can also assign objects to a group based on their attributes: ``` object HostGroup "prod-mssql" { display_name = "Production MSSQL Servers" assign where host.vars.mssql_port && host.vars.prod_mysql_db ignore where host.vars.test_server == true ignore where match("*internal", host.name) } ``` In this example all hosts with the `vars` attribute `mssql_port` will be added as members to the host group `mssql`. However, all hosts [matching](18-library-reference.md#global-functions-match) the string `\*internal` or with the `test_server` attribute set to `true` are **not** added to this group. Details on the `assign where` syntax can be found in the [Language Reference](17-language-reference.md#apply). ## Notifications Notifications for service and host problems are an integral part of your monitoring setup. When a host or service is in a downtime, a problem has been acknowledged or the dependency logic determined that the host/service is unreachable, no notifications are sent. You can configure additional type and state filters refining the notifications being actually sent. There are many ways of sending notifications, e.g. by email, XMPP, IRC, Twitter, etc. On its own Icinga 2 does not know how to send notifications. Instead it relies on external mechanisms such as shell scripts to notify users. More notification methods are listed in the [addons and plugins](13-addons.md#notification-scripts-interfaces) chapter. A notification specification requires one or more users (and/or user groups) who will be notified in case of problems. These users must have all custom attributes defined which will be used in the `NotificationCommand` on execution. The user `icingaadmin` in the example below will get notified only on `Warning` and `Critical` problems. In addition to that `Recovery` notifications are sent (they require the `OK` state). ``` object User "icingaadmin" { display_name = "Icinga 2 Admin" enable_notifications = true states = [ OK, Warning, Critical ] types = [ Problem, Recovery ] email = "icinga@localhost" } ``` If you don't set the `states` and `types` configuration attributes for the `User` object, notifications for all states and types will be sent. Details on troubleshooting notification problems can be found [here](15-troubleshooting.md#troubleshooting). > **Note** > > Make sure that the [notification](11-cli-commands.md#enable-features) feature is enabled > in order to execute notification commands. You should choose which information you (and your notified users) are interested in case of emergency, and also which information does not provide any value to you and your environment. An example notification command is explained [here](03-monitoring-basics.md#notification-commands). You can add all shared attributes to a `Notification` template which is inherited to the defined notifications. That way you'll save duplicated attributes in each `Notification` object. Attributes can be overridden locally. ``` template Notification "generic-notification" { interval = 15m command = "mail-service-notification" states = [ Warning, Critical, Unknown ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] period = "24x7" } ``` The time period `24x7` is included as example configuration with Icinga 2. Use the `apply` keyword to create `Notification` objects for your services: ``` apply Notification "notify-cust-xy-mysql" to Service { import "generic-notification" users = [ "noc-xy", "mgmt-xy" ] assign where match("*has gold support 24x7*", service.notes) && (host.vars.customer == "customer-xy" || host.vars.always_notify == true ignore where match("*internal", host.name) || (service.vars.priority < 2 && host.vars.is_clustered == true) } ``` Instead of assigning users to notifications, you can also add the `user_groups` attribute with a list of user groups to the `Notification` object. Icinga 2 will send notifications to all group members. > **Note** > > Only users who have been notified of a problem before (`Warning`, `Critical`, `Unknown` states for services, `Down` for hosts) will receive `Recovery` notifications. ### Notifications: Users from Host/Service A common pattern is to store the users and user groups on the host or service objects instead of the notification object itself. The sample configuration provided in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) and [notifications.conf](notifications-conf) already provides an example for this question. > **Tip** > > Please make sure to read the [apply](03-monitoring-basics.md#using-apply) and > [custom attribute values](03-monitoring-basics.md#custom-attributes-values) chapter to > fully understand these examples. Specify the user and groups as nested custom attribute on the host object: ``` object Host "icinga2-client1.localdomain" { [...] vars.notification["mail"] = { groups = [ "icingaadmins" ] users = [ "icingaadmin" ] } vars.notification["sms"] = { users = [ "icingaadmin" ] } } ``` As you can see, there is the option to use two different notification apply rules here: One for `mail` and one for `sms`. This example assigns the `users` and `groups` nested keys from the `notification` custom attribute to the actual notification object attributes. Since errors are hard to debug if host objects don't specify the required configuration attributes, you can add a safety condition which logs which host object is affected. ``` critical/config: Host 'icinga2-client3.localdomain' does not specify required user/user_groups configuration attributes for notification 'mail-icingaadmin'. ``` You can also use the [script debugger](20-script-debugger.md#script-debugger) for more advanced insights. ``` apply Notification "mail-host-notification" to Host { [...] /* Log which host does not specify required user/user_groups attributes. This will fail immediately during config validation and help a lot. */ if (len(host.vars.notification.mail.users) == 0 && len(host.vars.notification.mail.user_groups) == 0) { log(LogCritical, "config", "Host '" + host.name + "' does not specify required user/user_groups configuration attributes for notification '" + name + "'.") } users = host.vars.notification.mail.users user_groups = host.vars.notification.mail.groups assign where host.vars.notification.mail && typeof(host.vars.notification.mail) == Dictionary } apply Notification "sms-host-notification" to Host { [...] /* Log which host does not specify required user/user_groups attributes. This will fail immediately during config validation and help a lot. */ if (len(host.vars.notification.sms.users) == 0 && len(host.vars.notification.sms.user_groups) == 0) { log(LogCritical, "config", "Host '" + host.name + "' does not specify required user/user_groups configuration attributes for notification '" + name + "'.") } users = host.vars.notification.sms.users user_groups = host.vars.notification.sms.groups assign where host.vars.notification.sms && typeof(host.vars.notification.sms) == Dictionary } ``` The example above uses [typeof](18-library-reference.md#global-functions-typeof) as safety function to ensure that the `mail` key really provides a dictionary as value. Otherwise the configuration validation could fail if an admin adds something like this on another host: ``` vars.notification.mail = "yes" ``` You can also do a more fine granular assignment on the service object: ``` apply Service "http" { [...] vars.notification["mail"] = { groups = [ "icingaadmins" ] users = [ "icingaadmin" ] } [...] } ``` This notification apply rule is different to the one above. The service notification users and groups are inherited from the service and if not set, from the host object. A default user is set too. ``` apply Notification "mail-host-notification" to Service { [...] if (service.vars.notification.mail.users) { users = service.vars.notification.mail.users } else if (host.vars.notification.mail.users) { users = host.vars.notification.mail.users } else { /* Default user who receives everything. */ users = [ "icingaadmin" ] } if (service.vars.notification.mail.groups) { user_groups = service.vars.notification.mail.groups } else {host.vars.notification.mail.groups) { user_groups = host.vars.notification.mail.groups } assign where host.vars.notification.mail && typeof(host.vars.notification.mail) == Dictionary } ``` ### Notification Escalations When a problem notification is sent and a problem still exists at the time of re-notification you may want to escalate the problem to the next support level. A different approach is to configure the default notification by email, and escalate the problem via SMS if not already solved. You can define notification start and end times as additional configuration attributes making the `Notification` object a so-called `notification escalation`. Using templates you can share the basic notification attributes such as users or the `interval` (and override them for the escalation then). Using the example from above, you can define additional users being escalated for SMS notifications between start and end time. ``` object User "icinga-oncall-2nd-level" { display_name = "Icinga 2nd Level" vars.mobile = "+1 555 424642" } object User "icinga-oncall-1st-level" { display_name = "Icinga 1st Level" vars.mobile = "+1 555 424642" } ``` Define an additional [NotificationCommand](03-monitoring-basics.md#notification-commands) for SMS notifications. > **Note** > > The example is not complete as there are many different SMS providers. > Please note that sending SMS notifications will require an SMS provider > or local hardware with an active SIM card. ``` object NotificationCommand "sms-notification" { command = [ PluginDir + "/send_sms_notification", "$mobile$", "..." } ``` The two new notification escalations are added onto the local host and its service `ping4` using the `generic-notification` template. The user `icinga-oncall-2nd-level` will get notified by SMS (`sms-notification` command) after `30m` until `1h`. > **Note** > > The `interval` was set to 15m in the `generic-notification` > template example. Lower that value in your escalations by using a secondary > template or by overriding the attribute directly in the `notifications` array > position for `escalation-sms-2nd-level`. If the problem does not get resolved nor acknowledged preventing further notifications, the `escalation-sms-1st-level` user will be escalated `1h` after the initial problem was notified, but only for one hour (`2h` as `end` key for the `times` dictionary). ``` apply Notification "mail" to Service { import "generic-notification" command = "mail-notification" users = [ "icingaadmin" ] assign where service.name == "ping4" } apply Notification "escalation-sms-2nd-level" to Service { import "generic-notification" command = "sms-notification" users = [ "icinga-oncall-2nd-level" ] times = { begin = 30m end = 1h } assign where service.name == "ping4" } apply Notification "escalation-sms-1st-level" to Service { import "generic-notification" command = "sms-notification" users = [ "icinga-oncall-1st-level" ] times = { begin = 1h end = 2h } assign where service.name == "ping4" } ``` ### Notification Delay Sometimes the problem in question should not be announced when the notification is due (the object reaching the `HARD` state), but after a certain period. In Icinga 2 you can use the `times` dictionary and set `begin = 15m` as key and value if you want to postpone the notification window for 15 minutes. Leave out the `end` key -- if not set, Icinga 2 will not check against any end time for this notification. Make sure to specify a relatively low notification `interval` to get notified soon enough again. ``` apply Notification "mail" to Service { import "generic-notification" command = "mail-notification" users = [ "icingaadmin" ] interval = 5m times.begin = 15m // delay notification window assign where service.name == "ping4" } ``` ### Disable Re-notifications If you prefer to be notified only once, you can disable re-notifications by setting the `interval` attribute to `0`. ``` apply Notification "notify-once" to Service { import "generic-notification" command = "mail-notification" users = [ "icingaadmin" ] interval = 0 // disable re-notification assign where service.name == "ping4" } ``` ### Notification Filters by State and Type If there are no notification state and type filter attributes defined at the `Notification` or `User` object, Icinga 2 assumes that all states and types are being notified. Available state and type filters for notifications are: ``` template Notification "generic-notification" { states = [ OK, Warning, Critical, Unknown ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] } ``` ## Commands Icinga 2 uses three different command object types to specify how checks should be performed, notifications should be sent, and events should be handled. ### Check Commands [CheckCommand](09-object-types.md#objecttype-checkcommand) objects define the command line how a check is called. [CheckCommand](09-object-types.md#objecttype-checkcommand) objects are referenced by [Host](09-object-types.md#objecttype-host) and [Service](09-object-types.md#objecttype-service) objects using the `check_command` attribute. > **Note** > > Make sure that the [checker](11-cli-commands.md#enable-features) feature is enabled in order to > execute checks. #### Integrate the Plugin with a CheckCommand Definition Unless you have done so already, download your check plugin and put it into the [PluginDir](04-configuring-icinga-2.md#constants-conf) directory. The following example uses the `check_mysql` plugin contained in the Monitoring Plugins package. The plugin path and all command arguments are made a list of double-quoted string arguments for proper shell escaping. Call the `check_disk` plugin with the `--help` parameter to see all available options. Our example defines warning (`-w`) and critical (`-c`) thresholds for the disk usage. Without any partition defined (`-p`) it will check all local partitions. ``` icinga@icinga2 $ /usr/lib64/nagios/plugins/check_mysql --help ... This program tests connections to a MySQL server Usage: check_mysql [-d database] [-H host] [-P port] [-s socket] [-u user] [-p password] [-S] [-l] [-a cert] [-k key] [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group] ``` Next step is to understand how [command parameters](03-monitoring-basics.md#command-passing-parameters) are being passed from a host or service object, and add a [CheckCommand](09-object-types.md#objecttype-checkcommand) definition based on these required parameters and/or default values. Please continue reading in the [plugins section](05-service-monitoring.md#service-monitoring-plugins) for additional integration examples. #### Passing Check Command Parameters from Host or Service Check command parameters are defined as custom attributes which can be accessed as runtime macros by the executed check command. The check command parameters for ITL provided plugin check command definitions are documented [here](10-icinga-template-library.md#icinga-template-library), for example [disk](10-icinga-template-library.md#plugin-check-command-disk). In order to practice passing command parameters you should [integrate your own plugin](03-monitoring-basics.md#command-plugin-integration). The following example will use `check_mysql` provided by the [Monitoring Plugins installation](02-getting-started.md#setting-up-check-plugins). Define the default check command custom attributes, for example `mysql_user` and `mysql_password` (freely definable naming schema) and optional their default threshold values. You can then use these custom attributes as runtime macros for [command arguments](03-monitoring-basics.md#command-arguments) on the command line. > **Tip** > > Use a common command type as prefix for your command arguments to increase > readability. `mysql_user` helps understanding the context better than just > `user` as argument. The default custom attributes can be overridden by the custom attributes defined in the host or service using the check command `my-mysql`. The custom attributes can also be inherited from a parent template using additive inheritance (`+=`). ``` # vim /etc/icinga2/conf.d/commands.conf object CheckCommand "my-mysql" { command = [ PluginDir + "/check_mysql" ] //constants.conf -> const PluginDir arguments = { "-H" = "$mysql_host$" "-u" = { required = true value = "$mysql_user$" } "-p" = "$mysql_password$" "-P" = "$mysql_port$" "-s" = "$mysql_socket$" "-a" = "$mysql_cert$" "-d" = "$mysql_database$" "-k" = "$mysql_key$" "-C" = "$mysql_ca_cert$" "-D" = "$mysql_ca_dir$" "-L" = "$mysql_ciphers$" "-f" = "$mysql_optfile$" "-g" = "$mysql_group$" "-S" = { set_if = "$mysql_check_slave$" description = "Check if the slave thread is running properly." } "-l" = { set_if = "$mysql_ssl$" description = "Use ssl encryption" } } vars.mysql_check_slave = false vars.mysql_ssl = false vars.mysql_host = "$address$" } ``` The check command definition also sets `mysql_host` to the `$address$` default value. You can override this command parameter if for example your MySQL host is not running on the same server's ip address. Make sure pass all required command parameters, such as `mysql_user`, `mysql_password` and `mysql_database`. `MysqlUsername` and `MysqlPassword` are specified as [global constants](04-configuring-icinga-2.md#constants-conf) in this example. ``` # vim /etc/icinga2/conf.d/services.conf apply Service "mysql-icinga-db-health" { import "generic-service" check_command = "my-mysql" vars.mysql_user = MysqlUsername vars.mysql_password = MysqlPassword vars.mysql_database = "icinga" vars.mysql_host = "192.168.33.11" assign where match("icinga2*", host.name) ignore where host.vars.no_health_check == true } ``` Take a different example: The example host configuration in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) also applies an `ssh` service check. Your host's ssh port is not the default `22`, but set to `2022`. You can pass the command parameter as custom attribute `ssh_port` directly inside the service apply rule inside [services.conf](04-configuring-icinga-2.md#services-conf): ``` apply Service "ssh" { import "generic-service" check_command = "ssh" vars.ssh_port = 2022 //custom command parameter assign where (host.address || host.address6) && host.vars.os == "Linux" } ``` If you prefer this being configured at the host instead of the service, modify the host configuration object instead. The runtime macro resolving order is described [here](03-monitoring-basics.md#macro-evaluation-order). ``` object Host "icinga2-client1.localdomain { ... vars.ssh_port = 2022 } ``` #### Passing Check Command Parameters Using Apply For The host `localhost` with the generated services from the `basic-partitions` dictionary (see [apply for](03-monitoring-basics.md#using-apply-for) for details) checks a basic set of disk partitions with modified custom attributes (warning thresholds at `10%`, critical thresholds at `5%` free disk space). The custom attribute `disk_partition` can either hold a single string or an array of string values for passing multiple partitions to the `check_disk` check plugin. ``` object Host "my-server" { import "generic-host" address = "127.0.0.1" address6 = "::1" vars.local_disks["basic-partitions"] = { disk_partitions = [ "/", "/tmp", "/var", "/home" ] } } apply Service for (disk => config in host.vars.local_disks) { import "generic-service" check_command = "my-disk" vars += config vars.disk_wfree = "10%" vars.disk_cfree = "5%" } ``` More details on using arrays in custom attributes can be found in [this chapter](03-monitoring-basics.md#custom-attributes). #### Command Arguments By defining a check command line using the `command` attribute Icinga 2 will resolve all macros in the static string or array. Sometimes it is required to extend the arguments list based on a met condition evaluated at command execution. Or making arguments optional -- only set if the macro value can be resolved by Icinga 2. ``` object CheckCommand "http" { command = [ PluginDir + "/check_http" ] arguments = { "-H" = "$http_vhost$" "-I" = "$http_address$" "-u" = "$http_uri$" "-p" = "$http_port$" "-S" = { set_if = "$http_ssl$" } "--sni" = { set_if = "$http_sni$" } "-a" = { value = "$http_auth_pair$" description = "Username:password on sites with basic authentication" } "--no-body" = { set_if = "$http_ignore_body$" } "-r" = "$http_expect_body_regex$" "-w" = "$http_warn_time$" "-c" = "$http_critical_time$" "-e" = "$http_expect$" } vars.http_address = "$address$" vars.http_ssl = false vars.http_sni = false } ``` The example shows the `check_http` check command defining the most common arguments. Each of them is optional by default and is omitted if the value is not set. For example, if the service calling the check command does not have `vars.http_port` set, it won't get added to the command line. If the `vars.http_ssl` custom attribute is set in the service, host or command object definition, Icinga 2 will add the `-S` argument based on the `set_if` numeric value to the command line. String values are not supported. If the macro value cannot be resolved, Icinga 2 will not add the defined argument to the final command argument array. Empty strings for macro values won't omit the argument. That way you can use the `check_http` command definition for both, with and without SSL enabled checks saving you duplicated command definitions. Details on all available options can be found in the [CheckCommand object definition](09-object-types.md#objecttype-checkcommand). ##### Command Arguments: set_if The `set_if` attribute in command arguments can be used to only add this parameter if the runtime macro value is boolean `true`. Best practice is to define and pass only [boolean](17-language-reference.md#boolean-literals) values here. [Numeric](17-language-reference.md#numeric-literals) values are allowed too. Examples: ``` vars.test_b = true vars.test_n = 3.0 arguments = { "-x" = { set_if = "$test_b$" } "-y" = { set_if = "$test_n$" } } ``` If you accidentally used a [String](17-language-reference.md#string-literals) value, this could lead into an undefined behaviour. If you still want to work with String values and other variants, you can also use runtime evaluated functions for `set_if`. ``` vars.test_s = "1.1.2.1" arguments = { "-z" = { set_if = {{ var str = macro("$test_s$") return regex("^\d.\d.\d.\d$", str) }} } ``` References: [abbreviated lambda syntax](17-language-reference.md#nullary-lambdas), [macro](18-library-reference.md#scoped-functions-macro), [regex](18-library-reference.md#global-functions-regex). #### Environment Variables The `env` command object attribute specifies a list of environment variables with values calculated from either runtime macros or custom attributes which should be exported as environment variables prior to executing the command. This is useful for example for hiding sensitive information on the command line output when passing credentials to database checks: ``` object CheckCommand "mysql-health" { command = [ PluginDir + "/check_mysql" ] arguments = { "-H" = "$mysql_address$" "-d" = "$mysql_database$" } vars.mysql_address = "$address$" vars.mysql_database = "icinga" vars.mysql_user = "icinga_check" vars.mysql_pass = "password" env.MYSQLUSER = "$mysql_user$" env.MYSQLPASS = "$mysql_pass$" } ``` ### Notification Commands [NotificationCommand](09-object-types.md#objecttype-notificationcommand) objects define how notifications are delivered to external interfaces (email, XMPP, IRC, Twitter, etc.). [NotificationCommand](09-object-types.md#objecttype-notificationcommand) objects are referenced by [Notification](09-object-types.md#objecttype-notification) objects using the `command` attribute. > **Note** > > Make sure that the [notification](11-cli-commands.md#enable-features) feature is enabled > in order to execute notification commands. While it's possible to specify an entire notification command right in the NotificationCommand object it is generally advisable to create a shell script in the `/etc/icinga2/scripts` directory and have the NotificationCommand object refer to that. A fresh Icinga 2 install comes with with two example scripts for host and service notifications by email. Based on the Icinga 2 runtime macros (such as `$service.output$` for the current check output) it's possible to send email to the user(s) associated with the notification itself (`$user.email$`). Feel free to take these scripts as a starting point for your own individual notification solution - and keep in mind that nearly everything is technically possible. Information needed to generate notifications is passed to the scripts as arguments. The NotificationCommand objects `mail-host-notification` and `mail-service-notification` correspond to the shell scripts `mail-host-notification.sh` and `mail-service-notification.sh` in `/etc/icinga2/scripts` and define default values for arguments. These defaults can always be overwritten locally. > **Note** > > This example requires the `mail` binary installed on the Icinga 2 > master. #### Notification Commands in 2.7 Icinga 2 v2.7.0 introduced new notification scripts which support both environment variables and command line parameters. Therefore the `NotificationCommand` objects inside the [commands.conf](04-configuring-icinga-2.md#commands-conf) and `Notification` apply rules inside the [notifications.conf](04-configuring-icinga-2.md#notifications-conf) configuration files have been updated. Your configuration needs to be updated next to the notification scripts themselves. > **Note** > > Several parameters have been changed. Please review the notification > script parameters and configuration objects before updating your production > environment. The safest way is to incorporate the configuration updates from v2.7.0 inside the [commands.conf](04-configuring-icinga-2.md#commands-conf) and [notifications.conf](04-configuring-icinga-2.md#notifications-conf) configuration files. A quick-fix is shown below: ``` @@ -5,7 +5,8 @@ object NotificationCommand "mail-host-notification" { env = { NOTIFICATIONTYPE = "$notification.type$" - HOSTALIAS = "$host.display_name$" + HOSTNAME = "$host.name$" + HOSTDISPLAYNAME = "$host.display_name$" HOSTADDRESS = "$address$" HOSTSTATE = "$host.state$" LONGDATETIME = "$icinga.long_date_time$" @@ -22,8 +23,9 @@ object NotificationCommand "mail-service-notification" { env = { NOTIFICATIONTYPE = "$notification.type$" - SERVICEDESC = "$service.name$" - HOSTALIAS = "$host.display_name$" + SERVICENAME = "$service.name$" + HOSTNAME = "$host.name$" + HOSTDISPLAYNAME = "$host.display_name$" HOSTADDRESS = "$address$" SERVICESTATE = "$service.state$" LONGDATETIME = "$icinga.long_date_time$" ``` #### mail-host-notification The `mail-host-notification` NotificationCommand object uses the example notification script located in `/etc/icinga2/scripts/mail-host-notification.sh`. Here is a quick overview of the arguments that can be used. See also [host runtime macros](03-monitoring-basics.md#-host-runtime-macros) for further information. Name | Description -------------------------------|--------------------------------------- `notification_date` | **Required.** Date and time. Defaults to `$icinga.long_date_time$`. `notification_hostname` | **Required.** The host's `FQDN`. Defaults to `$host.name$`. `notification_hostdisplayname` | **Required.** The host's display name. Defaults to `$host.display_name$`. `notification_hostoutput` | **Required.** Output from host check. Defaults to `$host.output$`. `notification_useremail` | **Required.** The notification's recipient(s). Defaults to `$user.email$`. `notification_hoststate` | **Required.** Current state of host. Defaults to `$host.state$`. `notification_type` | **Required.** Type of notification. Defaults to `$notification.type$`. `notification_address` | **Optional.** The host's IPv4 address. Defaults to `$address$`. `notification_address6` | **Optional.** The host's IPv6 address. Defaults to `$address6$`. `notification_author` | **Optional.** Comment author. Defaults to `$notification.author$`. `notification_comment` | **Optional.** Comment text. Defaults to `$notification.comment$`. `notification_from` | **Optional.** Define a valid From: string (e.g. `"Icinga 2 Host Monitoring "`). Requires `GNU mailutils` (Debian/Ubuntu) or `mailx` (RHEL/SUSE). `notification_icingaweb2url` | **Optional.** Define URL to your Icinga Web 2 (e.g. `"https://www.example.com/icingaweb2"`) `notification_logtosyslog` | **Optional.** Set `true` to log notification events to syslog; useful for debugging. Defaults to `false`. #### mail-service-notification The `mail-service-notification` NotificationCommand object uses the example notification script located in `/etc/icinga2/scripts/mail-service-notification.sh`. Here is a quick overview of the arguments that can be used. See also [service runtime macros](03-monitoring-basics.md#-service-runtime-macros) for further information. Name | Description ----------------------------------|--------------------------------------- `notification_date` | **Required.** Date and time. Defaults to `$icinga.long_date_time$`. `notification_hostname` | **Required.** The host's `FQDN`. Defaults to `$host.name$`. `notification_servicename` | **Required.** The service name. Defaults to `$service.name$`. `notification_hostdisplayname` | **Required.** Host display name. Defaults to `$host.display_name$`. `notification_servicedisplayname` | **Required.** Service display name. Defaults to `$service.display_name$`. `notification_serviceoutput` | **Required.** Output from service check. Defaults to `$service.output$`. `notification_useremail` | **Required.** The notification's recipient(s). Defaults to `$user.email$`. `notification_servicestate` | **Required.** Current state of host. Defaults to `$service.state$`. `notification_type` | **Required.** Type of notification. Defaults to `$notification.type$`. `notification_address` | **Optional.** The host's IPv4 address. Defaults to `$address$`. `notification_address6` | **Optional.** The host's IPv6 address. Defaults to `$address6$`. `notification_author` | **Optional.** Comment author. Defaults to `$notification.author$`. `notification_comment` | **Optional.** Comment text. Defaults to `$notification.comment$`. `notification_from` | **Optional.** Define a valid From: string (e.g. `"Icinga 2 Host Monitoring "`). Requires `GNU mailutils` (Debian/Ubuntu) or `mailx` (RHEL/SUSE). `notification_icingaweb2url` | **Optional.** Define URL to your Icinga Web 2 (e.g. `"https://www.example.com/icingaweb2"`) `notification_logtosyslog` | **Optional.** Set `true` to log notification events to syslog; useful for debugging. Defaults to `false`. ## Dependencies Icinga 2 uses host and service [Dependency](09-object-types.md#objecttype-dependency) objects for determining their network reachability. A service can depend on a host, and vice versa. A service has an implicit dependency (parent) to its host. A host to host dependency acts implicitly as host parent relation. When dependencies are calculated, not only the immediate parent is taken into account but all parents are inherited. The `parent_host_name` and `parent_service_name` attributes are mandatory for service dependencies, `parent_host_name` is required for host dependencies. [Apply rules](03-monitoring-basics.md#using-apply) will allow you to [determine these attributes](03-monitoring-basics.md#dependencies-apply-custom-attributes) in a more dynamic fashion if required. ``` parent_host_name = "core-router" parent_service_name = "uplink-port" ``` Notifications are suppressed by default if a host or service becomes unreachable. You can control that option by defining the `disable_notifications` attribute. ``` disable_notifications = false ``` If the dependency should be triggered in the parent object's soft state, you need to set `ignore_soft_states` to `false`. The dependency state filter must be defined based on the parent object being either a host (`Up`, `Down`) or a service (`OK`, `Warning`, `Critical`, `Unknown`). The following example will make the dependency fail and trigger it if the parent object is **not** in one of these states: ``` states = [ OK, Critical, Unknown ] ``` > **In other words** > > If the parent service object changes into the `Warning` state, this > dependency will fail and render all child objects (hosts or services) unreachable. You can determine the child's reachability by querying the `is_reachable` attribute in for example [DB IDO](24-appendix.md#schema-db-ido-extensions). ### Implicit Dependencies for Services on Host Icinga 2 automatically adds an implicit dependency for services on their host. That way service notifications are suppressed when a host is `DOWN` or `UNREACHABLE`. This dependency does not overwrite other dependencies and implicitely sets `disable_notifications = true` and `states = [ Up ]` for all service objects. Service checks are still executed. If you want to prevent them from happening, you can apply the following dependency to all services setting their host as `parent_host_name` and disabling the checks. `assign where true` matches on all `Service` objects. ``` apply Dependency "disable-host-service-checks" to Service { disable_checks = true assign where true } ``` ### Dependencies for Network Reachability A common scenario is the Icinga 2 server behind a router. Checking internet access by pinging the Google DNS server `google-dns` is a common method, but will fail in case the `dsl-router` host is down. Therefore the example below defines a host dependency which acts implicitly as parent relation too. Furthermore the host may be reachable but ping probes are dropped by the router's firewall. In case the `dsl-router`'s `ping4` service check fails, all further checks for the `ping4` service on host `google-dns` service should be suppressed. This is achieved by setting the `disable_checks` attribute to `true`. ``` object Host "dsl-router" { import "generic-host" address = "192.168.1.1" } object Host "google-dns" { import "generic-host" address = "8.8.8.8" } apply Service "ping4" { import "generic-service" check_command = "ping4" assign where host.address } apply Dependency "internet" to Host { parent_host_name = "dsl-router" disable_checks = true disable_notifications = true assign where host.name != "dsl-router" } apply Dependency "internet" to Service { parent_host_name = "dsl-router" parent_service_name = "ping4" disable_checks = true assign where host.name != "dsl-router" } ``` ### Apply Dependencies based on Custom Attributes You can use [apply rules](03-monitoring-basics.md#using-apply) to set parent or child attributes, e.g. `parent_host_name` to other objects' attributes. A common example are virtual machines hosted on a master. The object name of that master is auto-generated from your CMDB or VMWare inventory into the host's custom attributes (or a generic template for your cloud). Define your master host object: ``` /* your master */ object Host "master.example.com" { import "generic-host" } ``` Add a generic template defining all common host attributes: ``` /* generic template for your virtual machines */ template Host "generic-vm" { import "generic-host" } ``` Add a template for all hosts on your example.com cloud setting custom attribute `vm_parent` to `master.example.com`: ``` template Host "generic-vm-example.com" { import "generic-vm" vars.vm_parent = "master.example.com" } ``` Define your guest hosts: ``` object Host "www.example1.com" { import "generic-vm-master.example.com" } object Host "www.example2.com" { import "generic-vm-master.example.com" } ``` Apply the host dependency to all child hosts importing the `generic-vm` template and set the `parent_host_name` to the previously defined custom attribute `host.vars.vm_parent`. ``` apply Dependency "vm-host-to-parent-master" to Host { parent_host_name = host.vars.vm_parent assign where "generic-vm" in host.templates } ``` You can extend this example, and make your services depend on the `master.example.com` host too. Their local scope allows you to use `host.vars.vm_parent` similar to the example above. ``` apply Dependency "vm-service-to-parent-master" to Service { parent_host_name = host.vars.vm_parent assign where "generic-vm" in host.templates } ``` That way you don't need to wait for your guest hosts becoming unreachable when the master host goes down. Instead the services will detect their reachability immediately when executing checks. > **Note** > > This method with setting locally scoped variables only works in > apply rules, but not in object definitions. ### Dependencies for Agent Checks Another classic example are agent based checks. You would define a health check for the agent daemon responding to your requests, and make all other services querying that daemon depend on that health check. The following configuration defines two nrpe based service checks `nrpe-load` and `nrpe-disk` applied to the host `nrpe-server` [matched](18-library-reference.md#global-functions-match) by its name. The health check is defined as `nrpe-health` service. ``` apply Service "nrpe-health" { import "generic-service" check_command = "nrpe" assign where match("nrpe-*", host.name) } apply Service "nrpe-load" { import "generic-service" check_command = "nrpe" vars.nrpe_command = "check_load" assign where match("nrpe-*", host.name) } apply Service "nrpe-disk" { import "generic-service" check_command = "nrpe" vars.nrpe_command = "check_disk" assign where match("nrpe-*", host.name) } object Host "nrpe-server" { import "generic-host" address = "192.168.1.5" } apply Dependency "disable-nrpe-checks" to Service { parent_service_name = "nrpe-health" states = [ OK ] disable_checks = true disable_notifications = true assign where service.check_command == "nrpe" ignore where service.name == "nrpe-health" } ``` The `disable-nrpe-checks` dependency is applied to all services on the `nrpe-service` host using the `nrpe` check_command attribute but not the `nrpe-health` service itself. ### Event Commands Unlike notifications, event commands for hosts/services are called on every check execution if one of these conditions matches: * The host/service is in a [soft state](03-monitoring-basics.md#hard-soft-states) * The host/service state changes into a [hard state](03-monitoring-basics.md#hard-soft-states) * The host/service state recovers from a [soft or hard state](03-monitoring-basics.md#hard-soft-states) to [OK](03-monitoring-basics.md#service-states)/[Up](03-monitoring-basics.md#host-states) [EventCommand](09-object-types.md#objecttype-eventcommand) objects are referenced by [Host](09-object-types.md#objecttype-host) and [Service](09-object-types.md#objecttype-service) objects with the `event_command` attribute. Therefore the `EventCommand` object should define a command line evaluating the current service state and other service runtime attributes available through runtime variables. Runtime macros such as `$service.state_type$` and `$service.state$` will be processed by Icinga 2 and help with fine-granular triggered events If the host/service is located on a client as [command endpoint](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) the event command will be executed on the client itself (similar to the check command). Common use case scenarios are a failing HTTP check which requires an immediate restart via event command. Another example would be an application that is not responding and therefore requires a restart. You can also use event handlers to forward more details on state changes and events than the typical notification alerts provide. #### Use Event Commands to Send Information from the Master This example sends a web request from the master node to an external tool for every event triggered on a `businessprocess` service. Define an [EventCommand](09-object-types.md#objecttype-eventcommand) object `send_to_businesstool` which sends state changes to the external tool. ``` object EventCommand "send_to_businesstool" { command = [ "/usr/bin/curl", "-s", "-X PUT" ] arguments = { "-H" = { value ="$businesstool_url$" skip_key = true } "-d" = "$businesstool_message$" } vars.businesstool_url = "http://localhost:8080/businesstool" vars.businesstool_message = "$host.name$ $service.name$ $service.state$ $service.state_type$ $service.check_attempt$" } ``` Set the `event_command` attribute to `send_to_businesstool` on the Service. ``` object Service "businessprocess" { host_name = "businessprocess" check_command = "icingacli-businessprocess" vars.icingacli_businessprocess_process = "icinga" vars.icingacli_businessprocess_config = "training" event_command = "send_to_businesstool" } ``` In order to test this scenario you can run: ``` nc -l 8080 ``` This allows to catch the web request. You can also enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) and search for the event command execution log message. ``` tail -f /var/log/icinga2/debug.log | grep EventCommand ``` Feed in a check result via REST API action [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result) or via Icinga Web 2. Expected Result: ``` # nc -l 8080 PUT /businesstool HTTP/1.1 User-Agent: curl/7.29.0 Host: localhost:8080 Accept: */* Content-Length: 47 Content-Type: application/x-www-form-urlencoded businessprocess businessprocess CRITICAL SOFT 1 ``` #### Use Event Commands to Restart Service Daemon via Command Endpoint on Linux This example triggers a restart of the `httpd` service on the local system when the `procs` service check executed via Command Endpoint fails. It only triggers if the service state is `Critical` and attempts to restart the service before a notification is sent. Requirements: * Icinga 2 as client on the remote node * icinga user with sudo permissions to the httpd daemon Example on CentOS 7: ``` # visudo icinga ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart httpd ``` Note: Distributions might use a different name. On Debian/Ubuntu the service is called `apache2`. Define an [EventCommand](09-object-types.md#objecttype-eventcommand) object `restart_service` which allows to trigger local service restarts. Put it into a [global zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) to sync its configuration to all clients. ``` [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/global-templates/eventcommands.conf object EventCommand "restart_service" { command = [ PluginDir + "/restart_service" ] arguments = { "-s" = "$service.state$" "-t" = "$service.state_type$" "-a" = "$service.check_attempt$" "-S" = "$restart_service$" } vars.restart_service = "$procs_command$" } ``` This event command triggers the following script which restarts the service. The script only is executed if the service state is `CRITICAL`. Warning and Unknown states are ignored as they indicate not an immediate failure. ``` [root@icinga2-client1.localdomain /]# vim /usr/lib64/nagios/plugins/restart_service #!/bin/bash while getopts "s:t:a:S:" opt; do case $opt in s) servicestate=$OPTARG ;; t) servicestatetype=$OPTARG ;; a) serviceattempt=$OPTARG ;; S) service=$OPTARG ;; esac done if ( [ -z $servicestate ] || [ -z $servicestatetype ] || [ -z $serviceattempt ] || [ -z $service ] ); then echo "USAGE: $0 -s servicestate -z servicestatetype -a serviceattempt -S service" exit 3; else # Only restart on the third attempt of a critical event if ( [ $servicestate == "CRITICAL" ] && [ $servicestatetype == "SOFT" ] && [ $serviceattempt -eq 3 ] ); then sudo /usr/bin/systemctl restart $service fi fi [root@icinga2-client1.localdomain /]# chmod +x /usr/lib64/nagios/plugins/restart_service ``` Add a service on the master node which is executed via command endpoint on the client. Set the `event_command` attribute to `restart_service`, the name of the previously defined EventCommand object. ``` [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/icinga2-client1.localdomain.conf object Service "Process httpd" { check_command = "procs" event_command = "restart_service" max_check_attempts = 4 host_name = "icinga2-client1.localdomain" command_endpoint = "icinga2-client1.localdomain" vars.procs_command = "httpd" vars.procs_warning = "1:10" vars.procs_critical = "1:" } ``` In order to test this configuration just stop the `httpd` on the remote host `icinga2-client1.localdomain`. ``` [root@icinga2-client1.localdomain /]# systemctl stop httpd ``` You can enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) and search for the executed command line. ``` [root@icinga2-client1.localdomain /]# tail -f /var/log/icinga2/debug.log | grep restart_service ``` #### Use Event Commands to Restart Service Daemon via Command Endpoint on Windows This example triggers a restart of the `httpd` service on the remote system when the `service-windows` service check executed via Command Endpoint fails. It only triggers if the service state is `Critical` and attempts to restart the service before a notification is sent. Requirements: * Icinga 2 as client on the remote node * Icinga 2 service with permissions to execute Powershell scripts (which is the default) Define an [EventCommand](09-object-types.md#objecttype-eventcommand) object `restart_service-windows` which allows to trigger local service restarts. Put it into a [global zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) to sync its configuration to all clients. ``` [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/global-templates/eventcommands.conf object EventCommand "restart_service-windows" { command = [ "C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe", PluginDir + "/restart_service.ps1" ] arguments = { "-ServiceState" = "$service.state$" "-ServiceStateType" = "$service.state_type$" "-ServiceAttempt" = "$service.check_attempt$" "-Service" = "$restart_service$" "; exit" = { order = 99 value = "$$LASTEXITCODE" } } vars.restart_service = "$service_win_service$" } ``` This event command triggers the following script which restarts the service. The script only is executed if the service state is `CRITICAL`. Warning and Unknown states are ignored as they indicate not an immediate failure. Add the `restart_service.ps1` Powershell script into `C:\Program Files\Icinga2\sbin`: ``` param( [string]$Service = '', [string]$ServiceState = '', [string]$ServiceStateType = '', [int]$ServiceAttempt = '' ) if (!$Service -Or !$ServiceState -Or !$ServiceStateType -Or !$ServiceAttempt) { $scriptName = GCI $MyInvocation.PSCommandPath | Select -Expand Name; Write-Host "USAGE: $scriptName -ServiceState servicestate -ServiceStateType servicestatetype -ServiceAttempt serviceattempt -Service service" -ForegroundColor red; exit 3; } # Only restart on the third attempt of a critical event if ($ServiceState -eq "CRITICAL" -And $ServiceStateType -eq "SOFT" -And $ServiceAttempt -eq 3) { Restart-Service $Service; } exit 0; ``` Add a service on the master node which is executed via command endpoint on the client. Set the `event_command` attribute to `restart_service-windows`, the name of the previously defined EventCommand object. ``` [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/icinga2-client2.localdomain.conf object Service "Service httpd" { check_command = "service-windows" event_command = "restart_service-windows" max_check_attempts = 4 host_name = "icinga2-client2.localdomain" command_endpoint = "icinga2-client2.localdomain" vars.service_win_service = "httpd" } ``` In order to test this configuration just stop the `httpd` on the remote host `icinga2-client1.localdomain`. ``` C:> net stop httpd ``` You can enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) and search for the executed command line in `C:\ProgramData\icinga2\var\log\icinga2\debug.log`. #### Use Event Commands to Restart Service Daemon via SSH This example triggers a restart of the `httpd` daemon via SSH when the `http` service check fails. Requirements: * SSH connection allowed (firewall, packet filters) * icinga user with public key authentication * icinga user with sudo permissions to restart the httpd daemon. Example on Debian: ``` # ls /home/icinga/.ssh/ authorized_keys # visudo icinga ALL=(ALL) NOPASSWD: /etc/init.d/apache2 restart ``` Define a generic [EventCommand](09-object-types.md#objecttype-eventcommand) object `event_by_ssh` which can be used for all event commands triggered using SSH: ``` [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/local_eventcommands.conf /* pass event commands through ssh */ object EventCommand "event_by_ssh" { command = [ PluginDir + "/check_by_ssh" ] arguments = { "-H" = "$event_by_ssh_address$" "-p" = "$event_by_ssh_port$" "-C" = "$event_by_ssh_command$" "-l" = "$event_by_ssh_logname$" "-i" = "$event_by_ssh_identity$" "-q" = { set_if = "$event_by_ssh_quiet$" } "-w" = "$event_by_ssh_warn$" "-c" = "$event_by_ssh_crit$" "-t" = "$event_by_ssh_timeout$" } vars.event_by_ssh_address = "$address$" vars.event_by_ssh_quiet = false } ``` The actual event command only passes the `event_by_ssh_command` attribute. The `event_by_ssh_service` custom attribute takes care of passing the correct daemon name, while `test $service.state_id$ -gt 0` makes sure that the daemon is only restarted when the service is not in an `OK` state. ``` object EventCommand "event_by_ssh_restart_service" { import "event_by_ssh" //only restart the daemon if state > 0 (not-ok) //requires sudo permissions for the icinga user vars.event_by_ssh_command = "test $service.state_id$ -gt 0 && sudo systemctl restart $event_by_ssh_service$" } ``` Now set the `event_command` attribute to `event_by_ssh_restart_service` and tell it which service should be restarted using the `event_by_ssh_service` attribute. ``` apply Service "http" { import "generic-service" check_command = "http" event_command = "event_by_ssh_restart_service" vars.event_by_ssh_service = "$host.vars.httpd_name$" //vars.event_by_ssh_logname = "icinga" //vars.event_by_ssh_identity = "/home/icinga/.ssh/id_rsa.pub" assign where host.vars.httpd_name } ``` Specify the `httpd_name` custom attribute on the host to assign the service and set the event handler service. ``` object Host "remote-http-host" { import "generic-host" address = "192.168.1.100" vars.httpd_name = "apache2" } ``` In order to test this configuration just stop the `httpd` on the remote host `icinga2-client1.localdomain`. ``` [root@icinga2-client1.localdomain /]# systemctl stop httpd ``` You can enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) and search for the executed command line. ``` [root@icinga2-client1.localdomain /]# tail -f /var/log/icinga2/debug.log | grep by_ssh ``` icinga2-2.8.1/doc/04-configuring-icinga-2.md000066400000000000000000000706461322762156600202760ustar00rootroot00000000000000# Configuring Icinga 2: First Steps This chapter provides an introduction into best practices for your Icinga 2 configuration. The configuration files which are automatically created when installing the Icinga 2 packages are a good way to start with Icinga 2. The [Language Reference](17-language-reference.md#language-reference) chapter explains details on value types (string, number, dictionaries, etc.) and the general configuration syntax. ## Configuration Best Practice If you are ready to configure additional hosts, services, notifications, dependencies, etc., you should think about the requirements first and then decide for a possible strategy. There are many ways of creating Icinga 2 configuration objects: * Manually with your preferred editor, for example vi(m), nano, notepad, etc. * A configuration tool for Icinga 2 e.g. the [Icinga Director](https://github.com/Icinga/icingaweb2-module-director) * Generated by a [configuration management tool](13-addons.md#configuration-tools) such as Puppet, Chef, Ansible, etc. * A custom exporter script from your CMDB or inventory tool * etc. Find the best strategy for your own configuration and ask yourself the following questions: * Do your hosts share a common group of services (for example linux hosts with disk, load, etc. checks)? * Only a small set of users receives notifications and escalations for all hosts/services? If you can at least answer one of these questions with yes, look for the [apply rules](03-monitoring-basics.md#using-apply) logic instead of defining objects on a per host and service basis. * You are required to define specific configuration for each host/service? * Does your configuration generation tool already know about the host-service-relationship? Then you should look for the object specific configuration setting `host_name` etc. accordingly. You decide on the "best" layout for configuration files and directories. Ensure that the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file includes them. Consider these ideas: * tree-based on locations, host groups, specific host attributes with sub levels of directories. * flat `hosts.conf`, `services.conf`, etc. files for rule based configuration. * generated configuration with one file per host and a global configuration for groups, users, etc. * one big file generated from an external application (probably a bad idea for maintaining changes). * your own. In either way of choosing the right strategy you should additionally check the following: * Are there any specific attributes describing the host/service you could set as `vars` custom attributes? You can later use them for applying assign/ignore rules, or export them into external interfaces. * Put hosts into hostgroups, services into servicegroups and use these attributes for your apply rules. * Use templates to store generic attributes for your objects and apply rules making your configuration more readable. Details can be found in the [using templates](03-monitoring-basics.md#object-inheritance-using-templates) chapter. * Apply rules may overlap. Keep a central place (for example, [services.conf](04-configuring-icinga-2.md#services-conf) or [notifications.conf](04-configuring-icinga-2.md#notifications-conf)) storing the configuration instead of defining apply rules deep in your configuration tree. * Every plugin used as check, notification or event command requires a `Command` definition. Further details can be looked up in the [check commands](03-monitoring-basics.md#check-commands) chapter. If you are planning to use a distributed monitoring setup with master, satellite and client installations take the configuration location into account too. Everything configured on the master, synced to all other nodes? Or any specific local configuration (e.g. health checks)? There is a detailed chapter on [distributed monitoring scenarios](06-distributed-monitoring.md#distributed-monitoring-scenarios). Please ensure to have read the [introduction](06-distributed-monitoring.md#distributed-monitoring) at first glance. If you happen to have further questions, do not hesitate to join the [community support channels](https://www.icinga.com/community/get-involved/) and ask community members for their experience and best practices. ## Your Configuration If you prefer to organize your own local object tree, you can also remove `include_recursive "conf.d"` from your icinga2.conf file. Create a new configuration directory, e.g. `objects.d` and include it in your icinga2.conf file. [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/objects.d [root@icinga2-master1.localdomain /]# vim /etc/icinga2/icinga2.conf /* Local object configuration on our master instance. */ include_recursive "objects.d" This approach is used by the [Icinga 2 Puppet module](https://github.com/Icinga/puppet-icinga2). If you plan to setup a distributed setup with HA clusters and clients, please refer to [this chapter](#06-distributed-monitoring.md#distributed-monitoring-top-down) for examples with `zones.d` as configuration directory. ## Configuration Overview ### icinga2.conf An example configuration file is installed for you in `/etc/icinga2/icinga2.conf`. Here's a brief description of the example configuration: /** * Icinga 2 configuration file * -- this is where you define settings for the Icinga application including * which hosts/services to check. * * For an overview of all available configuration options please refer * to the documentation that is distributed as part of Icinga 2. */ Icinga 2 supports [C/C++-style comments](17-language-reference.md#comments). /** * The constants.conf defines global constants. */ include "constants.conf" The `include` directive can be used to include other files. /** * The zones.conf defines zones for a cluster setup. * Not required for single instance setups. */ include "zones.conf" The [Icinga Template Library](10-icinga-template-library.md#icinga-template-library) provides a set of common templates and [CheckCommand](03-monitoring-basics.md#check-commands) definitions. /** * The Icinga Template Library (ITL) provides a number of useful templates * and command definitions. * Common monitoring plugin command definitions are included separately. */ include include include include /** * This includes the Icinga 2 Windows plugins. These command definitions * are required on a master node when a client is used as command endpoint. */ include /** * This includes the NSClient++ check commands. These command definitions * are required on a master node when a client is used as command endpoint. */ include /** * The features-available directory contains a number of configuration * files for features which can be enabled and disabled using the * icinga2 feature enable / icinga2 feature disable CLI commands. * These commands work by creating and removing symbolic links in * the features-enabled directory. */ include "features-enabled/*.conf" This `include` directive takes care of including the configuration files for all the features which have been enabled with `icinga2 feature enable`. See [Enabling/Disabling Features](11-cli-commands.md#enable-features) for more details. /** * Although in theory you could define all your objects in this file * the preferred way is to create separate directories and files in the conf.d * directory. Each of these files must have the file extension ".conf". */ include_recursive "conf.d" You can put your own configuration files in the [conf.d](04-configuring-icinga-2.md#conf-d) directory. This directive makes sure that all of your own configuration files are included. ### constants.conf The `constants.conf` configuration file can be used to define global constants. By default, you need to make sure to set these constants: * The `PluginDir` constant must be set to the path where the [Monitoring Project plugins](02-getting-started.md#setting-up-check-plugins) are installed. This constant is used by a number of [built-in check command definitions](10-icinga-template-library.md#icinga-template-library). * The `NodeName` constant defines your local node name. Should be set to FQDN which is the default if not set. This constant is required for local host configuration, monitoring remote clients and cluster setup. Example: /* The directory which contains the plugins from the Monitoring Plugins project. */ const PluginDir = "/usr/lib64/nagios/plugins" /* The directory which contains the Manubulon plugins. * Check the documentation, chapter "SNMP Manubulon Plugin Check Commands", for details. */ const ManubulonPluginDir = "/usr/lib64/nagios/plugins" /* Our local instance name. By default this is the server's hostname as returned by `hostname --fqdn`. * This should be the common name from the API certificate. */ //const NodeName = "localhost" /* Our local zone name. */ const ZoneName = NodeName /* Secret key for remote node tickets */ const TicketSalt = "" The `ZoneName` and `TicketSalt` constants are required for remote client and distributed setups only. ### zones.conf This file can be used to specify the required [Zone](09-object-types.md#objecttype-zone) and [Endpoint](09-object-types.md#objecttype-endpoint) configuration object for [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring). By default the `NodeName` and `ZoneName` [constants](04-configuring-icinga-2.md#constants-conf) will be used. It also contains several [global zones](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) for distributed monitoring environments. Please ensure to modify this configuration with real names i.e. use the FQDN mentioned in [this chapter](06-distributed-monitoring.md#distributed-monitoring-conventions) for your `Zone` and `Endpoint` object names. ### The conf.d Directory This directory contains **example configuration** which should help you get started with monitoring the local host and its services. It is included in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file by default. It can be used as reference example for your own configuration strategy. Just keep in mind to include the main directories in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) file. > **Note** > > You can remove the include directive in [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) > if you prefer your own way of deploying Icinga 2 configuration. Further details on configuration best practice and how to build your own strategy is described in [this chapter](04-configuring-icinga-2.md#configuration-best-practice). Available configuration files which are installed by default: * [hosts.conf](04-configuring-icinga-2.md#hosts-conf) * [services.conf](04-configuring-icinga-2.md#services-conf) * [users.conf](04-configuring-icinga-2.md#users-conf) * [notifications.conf](04-configuring-icinga-2.md#notifications-conf) * [commands.conf](04-configuring-icinga-2.md#commands-conf) * [groups.conf](04-configuring-icinga-2.md#groups-conf) * [templates.conf](04-configuring-icinga-2.md#templates-conf) * [downtimes.conf](04-configuring-icinga-2.md#downtimes-conf) * [timeperiods.conf](04-configuring-icinga-2.md#timeperiods-conf) * [api-users.conf](04-configuring-icinga-2.md#api-users-conf) * [app.conf](04-configuring-icinga-2.md#app-conf) #### hosts.conf The `hosts.conf` file contains an example host based on your `NodeName` setting in [constants.conf](04-configuring-icinga-2.md#constants-conf). You can use global constants for your object names instead of string values. The `import` keyword is used to import the `generic-host` template which takes care of setting up the host check command to `hostalive`. If you require a different check command, you can override it in the object definition. The `vars` attribute can be used to define custom attributes which are available for check and notification commands. Most of the [Plugin Check Commands](10-icinga-template-library.md#icinga-template-library) in the Icinga Template Library require an `address` attribute. The custom attribute `os` is evaluated by the `linux-servers` group in [groups.conf](04-configuring-icinga-2.md#groups-conf) making the local host a member. The example host will show you how to: * define http vhost attributes for the `http` service apply rule defined in [services.conf](04-configuring-icinga-2.md#services-conf). * define disks (all, specific `/`) and their attributes for the `disk` service apply rule defined in [services.conf](04-configuring-icinga-2.md#services-conf). * define notification types (`mail`) and set the groups attribute. This will be used by notification apply rules in [notifications.conf](04-configuring-icinga-2.md#notifications-conf). If you've installed [Icinga Web 2](02-getting-started.md#setting-up-icingaweb2), you can uncomment the http vhost attributes and reload Icinga 2. The apply rules in [services.conf](04-configuring-icinga-2.md#services-conf) will automatically generate a new service checking the `/icingaweb2` URI using the `http` check. /* * Host definitions with object attributes * used for apply rules for Service, Notification, * Dependency and ScheduledDowntime objects. * * Tip: Use `icinga2 object list --type Host` to * list all host objects after running * configuration validation (`icinga2 daemon -C`). */ /* * This is an example host based on your * local host's FQDN. Specify the NodeName * constant in `constants.conf` or use your * own description, e.g. "db-host-1". */ object Host NodeName { /* Import the default host template defined in `templates.conf`. */ import "generic-host" /* Specify the address attributes for checks e.g. `ssh` or `http`. */ address = "127.0.0.1" address6 = "::1" /* Set custom attribute `os` for hostgroup assignment in `groups.conf`. */ vars.os = "Linux" /* Define http vhost attributes for service apply rules in `services.conf`. */ vars.http_vhosts["http"] = { http_uri = "/" } /* Uncomment if you've sucessfully installed Icinga Web 2. */ //vars.http_vhosts["Icinga Web 2"] = { // http_uri = "/icingaweb2" //} /* Define disks and attributes for service apply rules in `services.conf`. */ vars.disks["disk"] = { /* No parameters. */ } vars.disks["disk /"] = { disk_partitions = "/" } /* Define notification mail attributes for notification apply rules in `notifications.conf`. */ vars.notification["mail"] = { /* The UserGroup `icingaadmins` is defined in `users.conf`. */ groups = [ "icingaadmins" ] } } This is only the host object definition. Now we'll need to make sure that this host and your additional hosts are getting [services](04-configuring-icinga-2.md#services-conf) applied. > **Tip** > > If you don't understand all the attributes and how to use [apply rules](17-language-reference.md#apply), > don't worry -- the [monitoring basics](03-monitoring-basics.md#monitoring-basics) chapter will explain > that in detail. #### services.conf These service [apply rules](17-language-reference.md#apply) will show you how to monitor the local host, but also allow you to re-use or modify them for your own requirements. You should define all your service apply rules in `services.conf` or any other central location keeping them organized. By default, the local host will be monitored by the following services Service(s) | Applied on host(s) --------------------------------------------|------------------------ `load`, `procs`, `swap`, `users`, `icinga` | The `NodeName` host only. `ping4`, `ping6` | All hosts with `address` resp. `address6` attribute. `ssh` | All hosts with `address` and `vars.os` set to `Linux` `http`, optional: `Icinga Web 2` | All hosts with custom attribute `http_vhosts` defined as dictionary. `disk`, `disk /` | All hosts with custom attribute `disks` defined as dictionary. The Debian packages also include an additional `apt` service check applied to the local host. The command object `icinga` for the embedded health check is provided by the [Icinga Template Library (ITL)](10-icinga-template-library.md#icinga-template-library) while `http_ip`, `ssh`, `load`, `processes`, `users` and `disk` are all provided by the [Plugin Check Commands](10-icinga-template-library.md#icinga-template-library) which we enabled earlier by including the `itl` and `plugins` configuration file. Example `load` service apply rule: apply Service "load" { import "generic-service" check_command = "load" /* Used by the ScheduledDowntime apply rule in `downtimes.conf`. */ vars.backup_downtime = "02:00-03:00" assign where host.name == NodeName } The `apply` keyword can be used to create new objects which are associated with another group of objects. You can `import` existing templates, define (custom) attributes. The custom attribute `backup_downtime` is defined to a specific timerange string. This variable value will be used for applying a `ScheduledDowntime` object to these services in [downtimes.conf](04-configuring-icinga-2.md#downtimes-conf). In this example the `assign where` condition is a boolean expression which is evaluated for all objects of type `Host` and a new service with name "load" is created for each matching host. [Expression operators](17-language-reference.md#expression-operators) may be used in `assign where` conditions. Multiple `assign where` condition can be combined with `AND` using the `&&` operator as shown in the `ssh` example: apply Service "ssh" { import "generic-service" check_command = "ssh" assign where host.address && host.vars.os == "Linux" } In this example, the service `ssh` is applied to all hosts having the `address` attribute defined `AND` having the custom attribute `os` set to the string `Linux`. You can modify this condition to match multiple expressions by combining `AND` and `OR` using `&&` and `||` [operators](17-language-reference.md#expression-operators), for example `assign where host.address && (vars.os == "Linux" || vars.os == "Windows")`. A more advanced example is shown by the `http` and `disk` service apply rules. While one `apply` rule for `ssh` will only create a service for matching hosts, you can go one step further: Generate apply rules based on array items or dictionary key-value pairs. The idea is simple: Your host in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) defines the `disks` dictionary as custom attribute in `vars`. Remember the example from [hosts.conf](04-configuring-icinga-2.md#hosts-conf): ... /* Define disks and attributes for service apply rules in `services.conf`. */ vars.disks["disk"] = { /* No parameters. */ } vars.disks["disk /"] = { disk_partition = "/" } ... This dictionary contains multiple service names we want to monitor. `disk` should just check all available disks, while `disk /` will pass an additional parameter `disk_partition` to the check command. You'll recognize that the naming is important -- that's the very same name as it is passed from a service to a check command argument. Read about services and passing check commands in [this chapter](03-monitoring-basics.md#command-passing-parameters). Using `apply Service for` omits the service name, it will take the key stored in the `disk` variable in `key => config` as new service object name. The `for` keyword expects a loop definition, for example `key => value in dictionary` as known from Perl and other scripting languages. Once defined like this, the `apply` rule defined below will do the following: * only match hosts with `host.vars.disks` defined through the `assign where` condition * loop through all entries in the `host.vars.disks` dictionary. That's `disk` and `disk /` as keys. * call `apply` on each, and set the service object name from the provided key * inside apply, the `generic-service` template is imported * defining the [disk](10-icinga-template-library.md#plugin-check-command-disk) check command requiring command arguments like `disk_partition` * adding the `config` dictionary items to `vars`. Simply said, there's now `vars.disk_partition` defined for the generated service Configuration example: apply Service for (disk => config in host.vars.disks) { import "generic-service" check_command = "disk" vars += config } A similar example is used for the `http` services. That way you can make your host the information provider for all apply rules. Define them once, and only manage your hosts. Look into [notifications.conf](04-configuring-icinga-2.md#notifications-conf) how this technique is used for applying notifications to hosts and services using their type and user attributes. Don't forget to install the [check plugins](02-getting-started.md#setting-up-check-plugins) required by the hosts and services and their check commands. Further details on the monitoring configuration can be found in the [monitoring basics](03-monitoring-basics.md#monitoring-basics) chapter. #### users.conf Defines the `icingaadmin` User and the `icingaadmins` UserGroup. The latter is used in [hosts.conf](04-configuring-icinga-2.md#hosts-conf) for defining a custom host attribute later used in [notifications.conf](04-configuring-icinga-2.md#notifications-conf) for notification apply rules. object User "icingaadmin" { import "generic-user" display_name = "Icinga 2 Admin" groups = [ "icingaadmins" ] email = "icinga@localhost" } object UserGroup "icingaadmins" { display_name = "Icinga 2 Admin Group" } #### notifications.conf Notifications for check alerts are an integral part or your Icinga 2 monitoring stack. The examples in this file define two notification apply rules for hosts and services. Both `apply` rules match on the same condition: They are only applied if the nested dictionary attribute `notification.mail` is set. Please note that the `to` keyword is important in [notification apply rules](03-monitoring-basics.md#using-apply-notifications) defining whether these notifications are applies to hosts or services. The `import` keyword imports the specific mail templates defined in [templates.conf](04-configuring-icinga-2.md#templates-conf). The `interval` attribute is not explicitly set -- it [defaults to 30 minutes](09-object-types.md#objecttype-notification). By setting the `user_groups` to the value provided by the respective [host.vars.notification.mail](04-configuring-icinga-2.md#hosts-conf) attribute we'll implicitely use the `icingaadmins` UserGroup defined in [users.conf](04-configuring-icinga-2.md#users-conf). apply Notification "mail-icingaadmin" to Host { import "mail-host-notification" user_groups = host.vars.notification.mail.groups users = host.vars.notification.mail.users assign where host.vars.notification.mail } apply Notification "mail-icingaadmin" to Service { import "mail-service-notification" user_groups = host.vars.notification.mail.groups users = host.vars.notification.mail.users assign where host.vars.notification.mail } More details on defining notifications and their additional attributes such as filters can be read in [this chapter](03-monitoring-basics.md#alert-notifications). #### commands.conf This is the place where your own command configuration can be defined. By default only the notification commands used by the notification templates defined in [templates.conf](04-configuring-icinga-2.md#templates-conf). You can freely customize these notification commands, and adapt them for your needs. Read more on that topic [here](03-monitoring-basics.md#notification-commands). #### groups.conf The example host defined in [hosts.conf](hosts-conf) already has the custom attribute `os` set to `Linux` and is therefore automatically a member of the host group `linux-servers`. This is done by using the [group assign](17-language-reference.md#group-assign) expressions similar to previously seen [apply rules](03-monitoring-basics.md#using-apply). object HostGroup "linux-servers" { display_name = "Linux Servers" assign where host.vars.os == "Linux" } object HostGroup "windows-servers" { display_name = "Windows Servers" assign where host.vars.os == "Windows" } Service groups can be grouped together by similar pattern matches. The [match function](18-library-reference.md#global-functions-match) expects a wildcard match string and the attribute string to match with. object ServiceGroup "ping" { display_name = "Ping Checks" assign where match("ping*", service.name) } object ServiceGroup "http" { display_name = "HTTP Checks" assign where match("http*", service.check_command) } object ServiceGroup "disk" { display_name = "Disk Checks" assign where match("disk*", service.check_command) } #### templates.conf Most of the example configuration objects use generic global templates by default: template Host "generic-host" { max_check_attempts = 5 check_interval = 1m retry_interval = 30s check_command = "hostalive" } template Service "generic-service" { max_check_attempts = 3 check_interval = 1m retry_interval = 30s } The `hostalive` check command is part of the [Plugin Check Commands](10-icinga-template-library.md#icinga-template-library). template Notification "mail-host-notification" { command = "mail-host-notification" states = [ Up, Down ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] period = "24x7" } template Notification "mail-service-notification" { command = "mail-service-notification" states = [ OK, Warning, Critical, Unknown ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] period = "24x7" } More details on `Notification` object attributes can be found [here](09-object-types.md#objecttype-notification). #### downtimes.conf The `load` service apply rule defined in [services.conf](04-configuring-icinga-2.md#services-conf) defines the `backup_downtime` custom attribute. The [ScheduledDowntime](09-object-types.md#objecttype-scheduleddowntime) apply rule uses this attribute to define the default value for the time ranges required for recurring downtime slots. apply ScheduledDowntime "backup-downtime" to Service { author = "icingaadmin" comment = "Scheduled downtime for backup" ranges = { monday = service.vars.backup_downtime tuesday = service.vars.backup_downtime wednesday = service.vars.backup_downtime thursday = service.vars.backup_downtime friday = service.vars.backup_downtime saturday = service.vars.backup_downtime sunday = service.vars.backup_downtime } assign where service.vars.backup_downtime != "" } #### timeperiods.conf This file contains the default timeperiod definitions for `24x7`, `9to5` and `never`. TimePeriod objects are referenced by `*period` objects such as hosts, services or notifications. #### api-users.conf Provides the default [ApiUser](09-object-types.md#objecttype-apiuser) object named "root" for the [API authentication](12-icinga2-api.md#icinga2-api-authentication). #### app.conf Provides the default [IcingaApplication](09-object-types.md#objecttype-icingaapplication) object named "app" for additional settings such as disabling notifications globally, etc. icinga2-2.8.1/doc/05-service-monitoring.md000066400000000000000000000342521322762156600202120ustar00rootroot00000000000000# Service Monitoring The power of Icinga 2 lies in its modularity. There are thousands of community plugins available next to the standard plugins provided by the [Monitoring Plugins project](https://www.monitoring-plugins.org). ## Requirements ### Plugins All existing Nagios or Icinga 1.x plugins work with Icinga 2. Community plugins can be found for example on [Icinga Exchange](https://exchange.icinga.com). The recommended way of setting up these plugins is to copy them to a common directory and create a new global constant, e.g. `CustomPluginDir` in your [constants.conf](04-configuring-icinga-2.md#constants-conf) configuration file: # cp check_snmp_int.pl /opt/monitoring/plugins # chmod +x /opt/plugins/check_snmp_int.pl # cat /etc/icinga2/constants.conf /** * This file defines global constants which can be used in * the other configuration files. At a minimum the * PluginDir constant should be defined. */ const PluginDir = "/usr/lib/nagios/plugins" const CustomPluginDir = "/opt/monitoring/plugins" Prior to using the check plugin with Icinga 2 you should ensure that it is working properly by trying to run it on the console using whichever user Icinga 2 is running as: # su - icinga -s /bin/bash $ /opt/monitoring/plugins/check_snmp_int.pl --help Additional libraries may be required for some plugins. Please consult the plugin documentation and/or the included README file for installation instructions. Sometimes plugins contain hard-coded paths to other components. Instead of changing the plugin it might be easier to create a symbolic link to make sure it doesn't get overwritten during the next update. Sometimes there are plugins which do not exactly fit your requirements. In that case you can modify an existing plugin or just write your own. ### CheckCommand Definition Each plugin requires a [CheckCommand](09-object-types.md#objecttype-checkcommand) object in your configuration which can be used in the [Service](09-object-types.md#objecttype-service) or [Host](09-object-types.md#objecttype-host) object definition. Please check if the Icinga 2 package already provides an [existing CheckCommand definition](10-icinga-template-library.md#icinga-template-library). If that's the case, throroughly check the required parameters and integrate the check command into your host and service objects. Please make sure to follow these conventions when adding a new command object definition: * Use [command arguments](03-monitoring-basics.md#command-arguments) whenever possible. The `command` attribute must be an array in `[ ... ]` for shell escaping. * Define a unique `prefix` for the command's specific arguments. That way you can safely set them on host/service level and you'll always know which command they control. * Use command argument default values, e.g. for thresholds. * Use [advanced conditions](09-object-types.md#objecttype-checkcommand) like `set_if` definitions. This is an example for a custom `my-snmp-int` check command: object CheckCommand "my-snmp-int" { command = [ CustomPluginDir + "/check_snmp_int.pl" ] arguments = { "-H" = "$snmp_address$" "-C" = "$snmp_community$" "-p" = "$snmp_port$" "-2" = { set_if = "$snmp_v2$" } "-n" = "$snmp_interface$" "-f" = { set_if = "$snmp_perf$" } "-w" = "$snmp_warn$" "-c" = "$snmp_crit$" } vars.snmp_v2 = true vars.snmp_perf = true vars.snmp_warn = "300,400" vars.snmp_crit = "0,600" } For further information on your monitoring configuration read the [Monitoring Basics](03-monitoring-basics.md#monitoring-basics) chapter. If you have created your own `CheckCommand` definition, please kindly [send it upstream](https://www.icinga.com/community/get-involved/). ### Plugin API Currently Icinga 2 supports the native plugin API specification from the Monitoring Plugins project. It is defined in the [Monitoring Plugins Development Guidelines](https://www.monitoring-plugins.org/doc/guidelines.html). ### Create a new Plugin Sometimes an existing plugin does not satisfy your requirements. You can either kindly contact the original author about plans to add changes and/or create a patch. If you just want to format the output and state of an existing plugin it might also be helpful to write a wrapper script. This script could pass all configured parameters, call the plugin script, parse its output/exit code and return your specified output/exit code. On the other hand plugins for specific services and hardware might not yet exist. Common best practices when creating a new plugin are for example: * Choose the programming language wisely * Scripting languages (Bash, Python, Perl, Ruby, PHP, etc.) are easier to write and setup but their check execution might take longer (invoking the script interpreter as overhead, etc.). * Plugins written in C/C++, Go, etc. improve check execution time but may generate an overhead with installation and packaging. * Use a modern VCS such as Git for developing the plugin (e.g. share your plugin on GitHub). * Add parameters with key-value pairs to your plugin. They should allow long names (e.g. `--host localhost`) and also short parameters (e.g. `-H localhost`) * `-h|--help` should print the version and all details about parameters and runtime invocation. * Add a verbose/debug output functionality for detailed on-demand logging. * Respect the exit codes required by the [Plugin API](05-service-monitoring.md#service-monitoring-plugin-api). * Always add performance data to your plugin output Example skeleton: # 1. include optional libraries # 2. global variables # 3. helper functions and/or classes # 4. define timeout condition if () then print "UNKNOWN - Timeout (...) reached | 'time'=30.0 endif # 5. main method if () then print "CRITICAL - ... | 'time'=0.1 'myperfdatavalue'=5.0 exit(2) else if () then print "WARNING - ... | 'time'=0.1 'myperfdatavalue'=3.0 exit(1) else print "OK - ... | 'time'=0.2 'myperfdatavalue'=1.0 endif There are various plugin libraries available which will help with plugin execution and output formatting too, for example [nagiosplugin from Python](https://pypi.python.org/pypi/nagiosplugin/). > **Note** > > Ensure to test your plugin properly with special cases before putting it > into production! Once you've finished your plugin please upload/sync it to [Icinga Exchange](https://exchange.icinga.com/new). Thanks in advance! ## Service Monitoring Overview The following examples should help you to start implementing your own ideas. There is a variety of plugins available. This collection is not complete -- if you have any updates, please send a documentation patch upstream. ### General Monitoring If the remote service is available (via a network protocol and port), and if a check plugin is also available, you don't necessarily need a local client. Instead, choose a plugin and configure its parameters and thresholds. The following examples are included in the [Icinga 2 Template Library](10-icinga-template-library.md#icinga-template-library): * [ping4](10-icinga-template-library.md#plugin-check-command-ping4), [ping6](10-icinga-template-library.md#plugin-check-command-ping6), [fping4](10-icinga-template-library.md#plugin-check-command-fping4), [fping6](10-icinga-template-library.md#plugin-check-command-fping6), [hostalive](10-icinga-template-library.md#plugin-check-command-hostalive) * [tcp](10-icinga-template-library.md#plugin-check-command-tcp), [udp](10-icinga-template-library.md#plugin-check-command-udp), [ssl](10-icinga-template-library.md#plugin-check-command-ssl) * [ntp_time](10-icinga-template-library.md#plugin-check-command-ntp-time) ### Linux Monitoring * [disk](10-icinga-template-library.md#plugin-check-command-disk) * [mem](10-icinga-template-library.md#plugin-contrib-command-mem), [swap](10-icinga-template-library.md#plugin-check-command-swap) * [procs](10-icinga-template-library.md#plugin-check-command-processes) * [users](10-icinga-template-library.md#plugin-check-command-users) * [running_kernel](10-icinga-template-library.md#plugin-contrib-command-running_kernel) * package management: [apt](10-icinga-template-library.md#plugin-check-command-apt), [yum](10-icinga-template-library.md#plugin-contrib-command-yum), etc. * [ssh](10-icinga-template-library.md#plugin-check-command-ssh) * performance: [iostat](10-icinga-template-library.md#plugin-contrib-command-iostat), [check_sar_perf](https://github.com/dnsmichi/icinga-plugins/blob/master/scripts/check_sar_perf.py) ### Windows Monitoring * [check_wmi_plus](http://www.edcint.co.nz/checkwmiplus/) * [NSClient++](https://www.nsclient.org) (in combination with the Icinga 2 client and either [check_nscp_api](10-icinga-template-library.md#nscp-check-api) or [nscp-local](10-icinga-template-library.md#nscp-plugin-check-commands) check commands) * [Icinga 2 Windows Plugins](10-icinga-template-library.md#windows-plugins) (disk, load, memory, network, performance counters, ping, procs, service, swap, updates, uptime, users * vbs and Powershell scripts ### Database Monitoring * MySQL/MariaDB: [mysql_health](10-icinga-template-library.md#plugin-contrib-command-mysql_health), [mysql](10-icinga-template-library.md#plugin-check-command-mysql), [mysql_query](10-icinga-template-library.md#plugin-check-command-mysql-query) * PostgreSQL: [postgres](10-icinga-template-library.md#plugin-contrib-command-postgres) * Oracle: [oracle_health](10-icinga-template-library.md#plugin-contrib-command-oracle_health) * MSSQL: [mssql_health](10-icinga-template-library.md#plugin-contrib-command-mssql_health) * DB2: [db2_health](10-icinga-template-library.md#plugin-contrib-command-db2_health) * MongoDB: [mongodb](10-icinga-template-library.md#plugin-contrib-command-mongodb) * Elasticsearch: [elasticsearch](10-icinga-template-library.md#plugin-contrib-command-elasticsearch) * Redis: [redis](10-icinga-template-library.md#plugin-contrib-command-redis) ### SNMP Monitoring * [Manubulon plugins](10-icinga-template-library.md#snmp-manubulon-plugin-check-commands) (interface, storage, load, memory, process) * [snmp](10-icinga-template-library.md#plugin-check-command-snmp), [snmpv3](10-icinga-template-library.md#plugin-check-command-snmpv3) ### Network Monitoring * [nwc_health](10-icinga-template-library.md#plugin-contrib-command-nwc_health) * [interfaces](10-icinga-template-library.md#plugin-contrib-command-interfaces) * [interfacetable](10-icinga-template-library.md#plugin-contrib-command-interfacetable) * [iftraffic](10-icinga-template-library.md#plugin-contrib-command-iftraffic), [iftraffic64](10-icinga-template-library.md#plugin-contrib-command-iftraffic64) ### Web Monitoring * [http](10-icinga-template-library.md#plugin-check-command-http) * [ftp](10-icinga-template-library.md#plugin-check-command-ftp) * [webinject](10-icinga-template-library.md#plugin-contrib-command-webinject) * [squid](10-icinga-template-library.md#plugin-contrib-command-squid) * [apache_status](10-icinga-template-library.md#plugin-contrib-command-apache_status) * [nginx_status](10-icinga-template-library.md#plugin-contrib-command-nginx_status) * [kdc](10-icinga-template-library.md#plugin-contrib-command-kdc) * [rbl](10-icinga-template-library.md#plugin-contrib-command-rbl) ### Java Monitoring * [jmx4perl](10-icinga-template-library.md#plugin-contrib-command-jmx4perl) ### DNS Monitoring * [dns](10-icinga-template-library.md#plugin-check-command-dns) * [dig](10-icinga-template-library.md#plugin-check-command-dig) * [dhcp](10-icinga-template-library.md#plugin-check-command-dhcp) ### Backup Monitoring * [check_bareos](https://github.com/widhalmt/check_bareos) ### Log Monitoring * [check_logfiles](https://labs.consol.de/nagios/check_logfiles/) * [check_logstash](https://github.com/widhalmt/check_logstash) * [check_graylog2_stream](https://github.com/Graylog2/check-graylog2-stream) ### Virtualization Monitoring ### VMware Monitoring * [esxi_hardware](10-icinga-template-library.md#plugin-contrib-command-esxi-hardware) * [VMware](10-icinga-template-library.md#plugin-contrib-vmware) **Tip**: If you are encountering timeouts using the VMware Perl SDK, check [this blog entry](https://www.claudiokuenzler.com/blog/650/slow-vmware-perl-sdk-soap-request-error-libwww-version). ### SAP Monitoring * [check_sap_health](https://labs.consol.de/nagios/check_sap_health/index.html) * [SAP CCMS](https://sourceforge.net/projects/nagios-sap-ccms/) ### Mail Monitoring * [smtp](10-icinga-template-library.md#plugin-check-command-smtp), [ssmtp](10-icinga-template-library.md#plugin-check-command-ssmtp) * [imap](10-icinga-template-library.md#plugin-check-command-imap), [simap](10-icinga-template-library.md#plugin-check-command-simap) * [pop](10-icinga-template-library.md#plugin-check-command-pop), [spop](10-icinga-template-library.md#plugin-check-command-spop) * [mailq](10-icinga-template-library.md#plugin-check-command-mailq) ### Hardware Monitoring * [hpasm](10-icinga-template-library.md#plugin-contrib-command-hpasm) * [ipmi-sensor](10-icinga-template-library.md#plugin-contrib-command-ipmi-sensor) ### Metrics Monitoring * [graphite](10-icinga-template-library.md#plugin-contrib-command-graphite) icinga2-2.8.1/doc/06-distributed-monitoring.md000066400000000000000000003424341322762156600211010ustar00rootroot00000000000000# Distributed Monitoring with Master, Satellites, and Clients This chapter will guide you through the setup of a distributed monitoring environment, including high-availability clustering and setup details for the Icinga 2 client. ## Roles: Master, Satellites, and Clients Icinga 2 nodes can be given names for easier understanding: * A `master` node which is on top of the hierarchy. * A `satellite` node which is a child of a `satellite` or `master` node. * A `client` node which works as an `agent` connected to `master` and/or `satellite` nodes. ![Icinga 2 Distributed Roles](images/distributed-monitoring/icinga2_distributed_roles.png) Rephrasing this picture into more details: * A `master` node has no parent node. * A `master`node is where you usually install Icinga Web 2. * A `master` node can combine executed checks from child nodes into backends and notifications. * A `satellite` node has a parent and a child node. * A `satellite` node may execute checks on its own or delegate check execution to child nodes. * A `satellite` node can receive configuration for hosts/services, etc. from the parent node. * A `satellite` node continues to run even if the master node is temporarily unavailable. * A `client` node only has a parent node. * A `client` node will either run its own configured checks or receive command execution events from the parent node. The following sections will refer to these roles and explain the differences and the possibilities this kind of setup offers. **Tip**: If you just want to install a single master node that monitors several hosts (i.e. Icinga 2 clients), continue reading -- we'll start with simple examples. In case you are planning a huge cluster setup with multiple levels and lots of clients, read on -- we'll deal with these cases later on. The installation on each system is the same: You need to install the [Icinga 2 package](02-getting-started.md#setting-up-icinga2) and the required [plugins](02-getting-started.md#setting-up-check-plugins). The required configuration steps are mostly happening on the command line. You can also [automate the setup](06-distributed-monitoring.md#distributed-monitoring-automation). The first thing you need learn about a distributed setup is the hierarchy of the single components. ## Zones The Icinga 2 hierarchy consists of so-called [zone](09-object-types.md#objecttype-zone) objects. Zones depend on a parent-child relationship in order to trust each other. ![Icinga 2 Distributed Zones](images/distributed-monitoring/icinga2_distributed_zones.png) Have a look at this example for the `satellite` zones which have the `master` zone as a parent zone: object Zone "master" { //... } object Zone "satellite region 1" { parent = "master" //... } object Zone "satellite region 2" { parent = "master" //... } There are certain limitations for child zones, e.g. their members are not allowed to send configuration commands to the parent zone members. Vice versa, the trust hierarchy allows for example the `master` zone to send configuration files to the `satellite` zone. Read more about this in the [security section](06-distributed-monitoring.md#distributed-monitoring-security). `client` nodes also have their own unique zone. By convention you can use the FQDN for the zone name. ## Endpoints Nodes which are a member of a zone are so-called [Endpoint](09-object-types.md#objecttype-endpoint) objects. ![Icinga 2 Distributed Endpoints](images/distributed-monitoring/icinga2_distributed_endpoints.png) Here is an example configuration for two endpoints in different zones: object Endpoint "icinga2-master1.localdomain" { host = "192.168.56.101" } object Endpoint "icinga2-satellite1.localdomain" { host = "192.168.56.105" } object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] } object Zone "satellite" { endpoints = [ "icinga2-satellite1.localdomain" ] parent = "master" } All endpoints in the same zone work as high-availability setup. For example, if you have two nodes in the `master` zone, they will load-balance the check execution. Endpoint objects are important for specifying the connection information, e.g. if the master should actively try to connect to a client. The zone membership is defined inside the `Zone` object definition using the `endpoints` attribute with an array of `Endpoint` names. If you want to check the availability (e.g. ping checks) of the node you still need a [Host](09-object-types.md#objecttype-host) object. ## ApiListener In case you are using the CLI commands later, you don't have to write this configuration from scratch in a text editor. The [ApiListener](09-object-types.md#objecttype-apilistener) object is used to load the SSL certificates and specify restrictions, e.g. for accepting configuration commands. It is also used for the [Icinga 2 REST API](12-icinga2-api.md#icinga2-api) which shares the same host and port with the Icinga 2 Cluster protocol. The object configuration is stored in the `/etc/icinga2/features-enabled/api.conf` file. Depending on the configuration mode the attributes `accept_commands` and `accept_config` can be configured here. In order to use the `api` feature you need to enable it and restart Icinga 2. icinga2 feature enable api ## Conventions By convention all nodes should be configured using their FQDN. Furthermore, you must ensure that the following names are exactly the same in all configuration files: * Host certificate common name (CN). * Endpoint configuration object for the host. * NodeName constant for the local host. Setting this up on the command line will help you to minimize the effort. Just keep in mind that you need to use the FQDN for endpoints and for common names when asked. ## Security While there are certain mechanisms to ensure a secure communication between all nodes (firewalls, policies, software hardening, etc.), Icinga 2 also provides additional security: * SSL certificates are mandatory for communication between nodes. The CLI commands help you create those certificates. * Child zones only receive updates (check results, commands, etc.) for their configured objects. * Child zones are not allowed to push configuration updates to parent zones. * Zones cannot interfere with other zones and influence each other. Each checkable host or service object is assigned to **one zone** only. * All nodes in a zone trust each other. * [Config sync](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync) and [remote command endpoint execution](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) is disabled by default. The underlying protocol uses JSON-RPC event notifications exchanged by nodes. The connection is secured by TLS. The message protocol uses an internal API, and as such message types and names may change internally and are not documented. Zones build the trust relationship in a distributed environment. If you do not specify a zone for a client and specify the parent zone, its zone members e.g. the master instance won't trust the client. Building this trust is key in your distributed environment. That way the parent node knows that it is able to send messages to the child zone, e.g. configuration objects, configuration in global zones, commands to be executed in this zone/for this endpoint. It also receives check results from the child zone for checkable objects (host/service). Vice versa, the client trusts the master and accepts configuration and commands if enabled in the api feature. If the client would send configuration to the parent zone, the parent nodes will deny it. The parent zone is the configuration entity, and does not trust clients in this matter. A client could attempt to modify a different client for example, or inject a check command with malicious code. While it may sound complicated for client setups, it removes the problem with different roles and configurations for a master and a client. Both of them work the same way, are configured in the same way (Zone, Endpoint, ApiListener), and you can troubleshoot and debug them in just one go. ## Master Setup This section explains how to install a central single master node using the `node wizard` command. If you prefer to do an automated installation, please refer to the [automated setup](06-distributed-monitoring.md#distributed-monitoring-automation) section. Install the [Icinga 2 package](02-getting-started.md#setting-up-icinga2) and setup the required [plugins](02-getting-started.md#setting-up-check-plugins) if you haven't done so already. **Note**: Windows is not supported for a master node setup. The next step is to run the `node wizard` CLI command. Prior to that ensure to collect the required information: Parameter | Description --------------------|-------------------- Common name (CN) | **Required.** By convention this should be the host's FQDN. Defaults to the FQDN. API bind host | **Optional.** Allows to specify the address the ApiListener is bound to. For advanced usage only. API bind port | **Optional.** Allows to specify the port the ApiListener is bound to. For advanced usage only (requires changing the default port 5665 everywhere). The setup wizard will ensure that the following steps are taken: * Enable the `api` feature. * Generate a new certificate authority (CA) in `/var/lib/icinga2/ca` if it doesn't exist. * Create a certificate for this node signed by the CA key. * Update the [zones.conf](04-configuring-icinga-2.md#zones-conf) file with the new zone hierarchy. * Update the [ApiListener](06-distributed-monitoring.md#distributed-monitoring-apilistener) and [constants](04-configuring-icinga-2.md#constants-conf) configuration. Here is an example of a master setup for the `icinga2-master1.localdomain` node on CentOS 7: ``` [root@icinga2-master1.localdomain /]# icinga2 node wizard Welcome to the Icinga 2 Setup Wizard! We will guide you through all required configuration details. Please specify if this is a satellite/client setup ('n' installs a master setup) [Y/n]: n Starting the Master setup routine... Please specify the common name (CN) [icinga2-master1.localdomain]: icinga2-master1.localdomain Reconfiguring Icinga... Checking for existing certificates for common name 'master1'... Generating master configuration for Icinga 2. Please specify the API bind host/port (optional): Bind Host []: Bind Port []: Done. Now restart your Icinga 2 daemon to finish the installation! ``` You can verify that the CA public and private keys are stored in the `/var/lib/icinga2/ca` directory. Keep this path secure and include it in your [backups](02-getting-started.md#install-backup). In case you lose the CA private key you have to generate a new CA for signing new client certificate requests. You then have to also re-create new signed certificates for all existing nodes. Once the master setup is complete, you can also use this node as primary [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing) master. The following section will explain how to use the CLI commands in order to fetch their signed certificate from this master node. ## Signing Certificates on the Master All certificates must be signed by the same certificate authority (CA). This ensures that all nodes trust each other in a distributed monitoring environment. This CA is generated during the [master setup](06-distributed-monitoring.md#distributed-monitoring-setup-master) and should be the same on all master instances. You can avoid signing and deploying certificates [manually](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-certificates-manual) by using built-in methods for auto-signing certificate signing requests (CSR): * [CSR Auto-Signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing) which uses a client ticket generated on the master as trust identifier. * [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing) which allows to sign pending certificate requests on the master. Both methods are described in detail below. > **Note** > > [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing) is available in Icinga 2 v2.8+. ### CSR Auto-Signing A client which sends a certificate signing request (CSR) must authenticate itself in a trusted way. The master generates a client ticket which is included in this request. That way the master can verify that the request matches the previously trusted ticket and sign the request. > **Note** > > Icinga 2 v2.8 adds the possibility to forward signing requests on a satellite > to the master node. This helps with the setup of [three level clusters](#06-distributed-monitoring.md#distributed-monitoring-scenarios-master-satellite-client) > and more. Advantages: * Nodes can be installed by different users who have received the client ticket. * No manual interaction necessary on the master node. * Automation tools like Puppet, Ansible, etc. can retrieve the pre-generated ticket in their client catalog and run the node setup directly. Disadvantages: * Tickets need to be generated on the master and copied to client setup wizards. * No central signing management. Setup wizards for satellite/client nodes will ask you for this specific client ticket. There are two possible ways to retrieve the ticket: * [CLI command](11-cli-commands.md#cli-command-pki) executed on the master node. * [REST API](12-icinga2-api.md#icinga2-api) request against the master node. Required information: Parameter | Description --------------------|-------------------- Common name (CN) | **Required.** The common name for the satellite/client. By convention this should be the FQDN. The following example shows how to generate a ticket on the master node `icinga2-master1.localdomain` for the client `icinga2-client1.localdomain`: [root@icinga2-master1.localdomain /]# icinga2 pki ticket --cn icinga2-client1.localdomain Querying the [Icinga 2 API](12-icinga2-api.md#icinga2-api) on the master requires an [ApiUser](12-icinga2-api.md#icinga2-api-authentication) object with at least the `actions/generate-ticket` permission. [root@icinga2-master1.localdomain /]# vim /etc/icinga2/conf.d/api-users.conf object ApiUser "client-pki-ticket" { password = "bea11beb7b810ea9ce6ea" //change this permissions = [ "actions/generate-ticket" ] } [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Retrieve the ticket on the master node `icinga2-master1.localdomain` with `curl`, for example: [root@icinga2-master1.localdomain /]# curl -k -s -u client-pki-ticket:bea11beb7b810ea9ce6ea -H 'Accept: application/json' \ -X POST 'https://icinga2-master1.localdomain:5665/v1/actions/generate-ticket' -d '{ "cn": "icinga2-client1.localdomain" }' Store that ticket number for the satellite/client setup below. **Note**: Never expose the ticket salt and/or ApiUser credentials to your client nodes. Example: Retrieve the ticket on the Puppet master node and send the compiled catalog to the authorized Puppet agent node which will invoke the [automated setup steps](06-distributed-monitoring.md#distributed-monitoring-automation-cli-node-setup). ### On-Demand CSR Signing Icinga 2 v2.8 adds the possibility to sign certificates from clients without requiring a client ticket for auto-signing. Instead, the client sends a certificate signing request to specified parent node. This could either be directly the master, or a satellite which forwards the request to the signing master. Advantages: * Central certificate request signing management. * No pre-generated ticket is required for client setups. Disadvantages: * Asynchronous step for automated deployments. * Needs client verification on the master. You can list certificate requests by using the `ca list` CLI command. This also shows which requests already have been signed. ``` [root@icinga2-master1.localdomain /]# icinga2 ca list Fingerprint | Timestamp | Signed | Subject -----------------------------------------------------------------|---------------------|--------|-------- 403da5b228df384f07f980f45ba50202529cded7c8182abf96740660caa09727 | 2017/09/06 17:02:40 | * | CN = icinga2-client1.localdomain 71700c28445109416dd7102038962ac3fd421fbb349a6e7303b6033ec1772850 | 2017/09/06 17:20:02 | | CN = icinga2-client2.localdomain ``` **Tip**: Add `--json` to the CLI command to retrieve the details in JSON format. If you want to sign a specific request, you need to use the `ca sign` CLI command and pass its fingerprint as argument. ``` [root@icinga2-master1.localdomain /]# icinga2 ca sign 71700c28445109416dd7102038962ac3fd421fbb349a6e7303b6033ec1772850 information/cli: Signed certificate for 'CN = icinga2-client2.localdomain'. ``` ## Client/Satellite Setup This section describes the setup of a satellite and/or client connected to an existing master node setup. If you haven't done so already, please [run the master setup](06-distributed-monitoring.md#distributed-monitoring-setup-master). Icinga 2 on the master node must be running and accepting connections on port `5665`. ### Client/Satellite Setup on Linux Please ensure that you've run all the steps mentioned in the [client/satellite section](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client). Install the [Icinga 2 package](02-getting-started.md#setting-up-icinga2) and setup the required [plugins](02-getting-started.md#setting-up-check-plugins) if you haven't done so already. The next step is to run the `node wizard` CLI command. In this example we're generating a ticket on the master node `icinga2-master1.localdomain` for the client `icinga2-client1.localdomain`: [root@icinga2-master1.localdomain /]# icinga2 pki ticket --cn icinga2-client1.localdomain 4f75d2ecd253575fe9180938ebff7cbca262f96e Note: You don't need this step if you have chosen to use [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing). Start the wizard on the client `icinga2-client1.localdomain`: ``` [root@icinga2-client1.localdomain /]# icinga2 node wizard Welcome to the Icinga 2 Setup Wizard! We will guide you through all required configuration details. ``` Press `Enter` or add `y` to start a satellite or client setup. ``` Please specify if this is a satellite/client setup ('n' installs a master setup) [Y/n]: ``` Press `Enter` to use the proposed name in brackets, or add a specific common name (CN). By convention this should be the FQDN. ``` Starting the Client/Satellite setup routine... Please specify the common name (CN) [icinga2-client1.localdomain]: icinga2-client1.localdomain ``` Specify the direct parent for this node. This could be your primary master `icinga2-master1.localdomain` or a satellite node in a multi level cluster scenario. ``` Please specify the parent endpoint(s) (master or satellite) where this node should connect to: Master/Satellite Common Name (CN from your master/satellite node): icinga2-master1.localdomain ``` Press `Enter` or choose `y` to establish a connection to the parent node. ``` Do you want to establish a connection to the parent node from this node? [Y/n]: ``` > **Note:** > > If this node cannot connect to the parent node, choose `n`. The setup > wizard will provide instructions for this scenario -- signing questions are disabled then. Add the connection details for `icinga2-master1.localdomain`. ``` Please specify the master/satellite connection information: Master/Satellite endpoint host (IP address or FQDN): 192.168.56.101 Master/Satellite endpoint port [5665]: 5665 ``` You can add more parent nodes if necessary. Press `Enter` or choose `n` if you don't want to add any. This comes in handy if you have more than one parent node, e.g. two masters or two satellites. ``` Add more master/satellite endpoints? [y/N]: ``` Verify the parent node's certificate: ``` Parent certificate information: Subject: CN = icinga2-master1.localdomain Issuer: CN = Icinga CA Valid From: Sep 7 13:41:24 2017 GMT Valid Until: Sep 3 13:41:24 2032 GMT Fingerprint: AC 99 8B 2B 3D B0 01 00 E5 21 FA 05 2E EC D5 A9 EF 9E AA E3 Is this information correct? [y/N]: y ``` The setup wizard fetches the parent node's certificate and ask you to verify this information. This is to prevent MITM attacks or any kind of untrusted parent relationship. Note: The certificate is not fetched if you have chosen not to connect to the parent node. Proceed with adding the optional client ticket for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing): ``` Please specify the request ticket generated on your Icinga 2 master (optional). (Hint: # icinga2 pki ticket --cn 'icinga2-client1.localdomain'): 4f75d2ecd253575fe9180938ebff7cbca262f96e ``` In case you've chosen to use [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing) you can leave the ticket question blank. Instead, Icinga 2 tells you to approve the request later on the master node. ``` No ticket was specified. Please approve the certificate signing request manually on the master (see 'icinga2 ca list' and 'icinga2 ca sign --help' for details). ``` You can optionally specify a different bind host and/or port. ``` Please specify the API bind host/port (optional): Bind Host []: Bind Port []: ``` The next step asks you to accept configuration (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)) and commands (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). ``` Accept config from parent node? [y/N]: y Accept commands from parent node? [y/N]: y ``` The wizard proceeds and you are good to go. ``` Reconfiguring Icinga... Done. Now restart your Icinga 2 daemon to finish the installation! ``` > **Note** > > If you have chosen not to connect to the parent node, you cannot start > Icinga 2 yet. The wizard asked you to manually copy the master's public > CA certificate file into `/var/lib/icinga2/certs/ca.crt`. > > You need to manually sign the CSR on the master node. Restart Icinga 2 as requested. ``` [root@icinga2-client1.localdomain /]# systemctl restart icinga2 ``` Here is an overview of all parameters in detail: Parameter | Description --------------------|-------------------- Common name (CN) | **Required.** By convention this should be the host's FQDN. Defaults to the FQDN. Master common name | **Required.** Use the common name you've specified for your master node before. Establish connection to the parent node | **Optional.** Whether the node should attempt to connect to the parent node or not. Defaults to `y`. Master/Satellite endpoint host | **Required if the the client needs to connect to the master/satellite.** The parent endpoint's IP address or FQDN. This information is included in the `Endpoint` object configuration in the `zones.conf` file. Master/Satellite endpoint port | **Optional if the the client needs to connect to the master/satellite.** The parent endpoints's listening port. This information is included in the `Endpoint` object configuration. Add more master/satellite endpoints | **Optional.** If you have multiple master/satellite nodes configured, add them here. Parent Certificate information | **Required.** Verify that the connecting host really is the requested master node. Request ticket | **Optional.** Add the [ticket](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing) generated on the master. API bind host | **Optional.** Allows to specify the address the ApiListener is bound to. For advanced usage only. API bind port | **Optional.** Allows to specify the port the ApiListener is bound to. For advanced usage only (requires changing the default port 5665 everywhere). Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this defaults to `n`. Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this defaults to `n`. The setup wizard will ensure that the following steps are taken: * Enable the `api` feature. * Create a certificate signing request (CSR) for the local node. * Request a signed certificate i(optional with the provided ticket number) on the master node. * Allow to verify the parent node's certificate. * Store the signed client certificate and ca.crt in `/var/lib/icinga2/certs`. * Update the `zones.conf` file with the new zone hierarchy. * Update `/etc/icinga2/features-enabled/api.conf` (`accept_config`, `accept_commands`) and `constants.conf`. You can verify that the certificate files are stored in the `/var/lib/icinga2/certs` directory. > **Note** > > The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) > for more details. > **Note** > > If the client is not directly connected to the certificate signing master, > signing requests and responses might need some minutes to fully update the client certificates. > > If you have chosen to use [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing) > certificates need to be signed on the master first. Ticket-less setups require at least Icinga 2 v2.8+ on all involved instances. Now that you've successfully installed a Linux/Unix satellite/client instance, please proceed to the [configuration modes](06-distributed-monitoring.md#distributed-monitoring-configuration-modes). ### Client Setup on Windows Download the MSI-Installer package from [https://packages.icinga.com/windows/](https://packages.icinga.com/windows/). Requirements: * Windows Vista/Server 2008 or higher * Versions older than Windows 10/Server 2016 require the [Universal C Runtime for Windows](https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows) * [Microsoft .NET Framework 2.0](https://www.microsoft.com/de-de/download/details.aspx?id=1639) for the setup wizard The installer package includes the [NSClient++](https://www.nsclient.org/) package so that Icinga 2 can use its built-in plugins. You can find more details in [this chapter](06-distributed-monitoring.md#distributed-monitoring-windows-nscp). The Windows package also installs native [monitoring plugin binaries](06-distributed-monitoring.md#distributed-monitoring-windows-plugins) to get you started more easily. > **Note** > > Please note that Icinga 2 was designed to run as light-weight client on Windows. > There is no support for satellite instances. #### Windows Client Setup Start Run the MSI-Installer package and follow the instructions shown in the screenshots. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_01.png) ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_02.png) ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_03.png) ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_04.png) ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_05.png) The graphical installer offers to run the Icinga 2 setup wizard after the installation. Select the check box to proceed. > **Tip** > > You can also run the Icinga 2 setup wizard from the Start menu later. On a fresh installation the setup wizard guides you through the initial configuration. It also provides a mechanism to send a certificate request to the [CSR signing master](distributed-monitoring-setup-sign-certificates-master). The following configuration details are required: Parameter | Description --------------------|-------------------- Instance name | **Required.** By convention this should be the host's FQDN. Defaults to the FQDN. Setup ticket | **Optional.** Paste the previously generated [ticket number](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). If left blank, the certificate request must be [signed on the master node](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing). Fill in the required information and click `Add` to add a new master connection. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_01.png) Add the following details: Parameter | Description -------------------------------|------------------------------- Instance name | **Required.** The master/satellite endpoint name where this client is a direct child of. Master/Satellite endpoint host | **Required.** The master or satellite's IP address or FQDN. This information is included in the `Endpoint` object configuration in the `zones.conf` file. Master/Satellite endpoint port | **Optional.** The master or satellite's listening port. This information is included in the `Endpoint` object configuration. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_02.png) Optionally enable the following settings: Parameter | Description ----------------------------------|---------------------------------- Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default. Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default. Run Icinga 2 service as this user | **Optional.** Specify a different Windows user. This defaults to `NT AUTHORITY\Network Service` and is required for more privileged service checks. Install NSClient++ | **Optional.** The Windows installer bundles the NSClient++ installer for additional [plugin checks](06-distributed-monitoring.md#distributed-monitoring-windows-nscp). ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_03.png) Verify the certificate from the master/satellite instance where this node should connect to. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_04.png) #### Bundled NSClient++ Setup If you have chosen to install/update the NSClient++ package, the Icinga 2 setup wizard asks you to do so. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_01.png) Choose the `Generic` setup. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_02.png) Choose the `Custom` setup type. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_03.png) NSClient++ does not install a sample configuration by default. Change this as shown in the screenshot. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_04.png) Generate a secure password and enable the web server module. **Note**: The webserver module is available starting with NSClient++ 0.5.0. Icinga 2 v2.6+ is required which includes this version. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_05.png) Finish the installation. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_06.png) Open a web browser and navigate to `https://localhost:8443`. Enter the password you've configured during the setup. In case you lost it, look into the `C:\Program Files\NSClient++\nsclient.ini` configuration file. ![Icinga 2 Windows Setup NSClient++](images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_07.png) The NSClient++ REST API can be used to query metrics. [check_nscp_api](06-distributed-monitoring.md#distributed-monitoring-windows-nscp-check-api) uses this transport method. #### Finish Windows Client Setup Finish the Windows setup wizard. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_06_finish_with_ticket.png) If you did not provide a setup ticket, you need to sign the certificate request on the master. The setup wizards tells you to do so. The Icinga 2 service is running at this point already and will automatically receive and update a signed client certificate. > **Note** > > Ticket-less setups require at least Icinga 2 v2.8+ on all involved instances. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_06_finish_no_ticket.png) Icinga 2 is automatically started as a Windows service. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_running_service.png) The Icinga 2 configuration is stored inside the `C:\ProgramData\icinga2` directory. Click `Examine Config` in the setup wizard to open a new Explorer window. ![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_examine_config.png) The configuration files can be modified with your favorite editor e.g. Notepad. In order to use the [top down](06-distributed-monitoring.md#distributed-monitoring-top-down) client configuration prepare the following steps. Add a [global zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) for syncing check commands later. Navigate to `C:\ProgramData\icinga2\etc\icinga2` and open the `zones.conf` file in your preferred editor. Add the following lines if not existing already: object Zone "global-templates" { global = true } Note: Packages >= 2.8 provide this configuration by default. You don't need any local configuration on the client except for CheckCommand definitions which can be synced using the global zone above. Therefore disable the inclusion of the `conf.d` directory in the `icinga2.conf` file. Navigate to `C:\ProgramData\icinga2\etc\icinga2` and open the `icinga2.conf` file in your preferred editor. Remove or comment (`//`) the following line: // Commented out, not required on a client with top down mode //include_recursive "conf.d" Validate the configuration on Windows open an administrator terminal and run the following command: C:\WINDOWS\system32>cd "C:\Program Files\ICINGA2\sbin" C:\Program Files\ICINGA2\sbin>icinga2.exe daemon -C **Note**: You have to run this command in a shell with `administrator` privileges. Now you need to restart the Icinga 2 service. Run `services.msc` from the start menu and restart the `icinga2` service. Alternatively, you can use the `net {start,stop}` CLI commands. ![Icinga 2 Windows Service Start/Stop](images/distributed-monitoring/icinga2_windows_cmd_admin_net_start_stop.png) Now that you've successfully installed a Windows client, please proceed to the [detailed configuration modes](06-distributed-monitoring.md#distributed-monitoring-configuration-modes). > **Note** > > The certificate location changed in v2.8 to `%ProgramData%\var\lib\icinga2\certs`. > Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) > for more details. ## Configuration Modes There are different ways to ensure that the Icinga 2 cluster nodes execute checks, send notifications, etc. The preferred method is to configure monitoring objects on the master and distribute the configuration to satellites and clients. The following chapters will explain this in detail with hands-on manual configuration examples. You should test and implement this once to fully understand how it works. Once you are familiar with Icinga 2 and distributed monitoring, you can start with additional integrations to manage and deploy your configuration: * [Icinga Director](https://github.com/icinga/icingaweb2-module-director) provides a web interface to manage configuration and also allows to sync imported resources (CMDB, PuppetDB, etc.) * [Ansible Roles](https://github.com/Icinga/icinga2-ansible) * [Puppet Module](https://github.com/Icinga/puppet-icinga2) * [Chef Cookbook](https://github.com/Icinga/chef-icinga2) More details can be found [here](13-addons.md#configuration-tools). ### Top Down There are two different behaviors with check execution: * Send a command execution event remotely: The scheduler still runs on the parent node. * Sync the host/service objects directly to the child node: Checks are executed locally. Again, technically it does not matter whether this is a `client` or a `satellite` which is receiving configuration or command execution events. ### Top Down Command Endpoint This mode will force the Icinga 2 node to execute commands remotely on a specified endpoint. The host/service object configuration is located on the master/satellite and the client only needs the CheckCommand object definitions being used there. ![Icinga 2 Distributed Top Down Command Endpoint](images/distributed-monitoring/icinga2_distributed_top_down_command_endpoint.png) Advantages: * No local checks need to be defined on the child node (client). * Light-weight remote check execution (asynchronous events). * No [replay log](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-command-endpoint-log-duration) is necessary for the child node. * Pin checks to specific endpoints (if the child zone consists of 2 endpoints). Disadvantages: * If the child node is not connected, no more checks are executed. * Requires additional configuration attribute specified in host/service objects. * Requires local `CheckCommand` object configuration. Best practice is to use a [global config zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync). To make sure that all nodes involved will accept configuration and/or commands, you need to configure the `Zone` and `Endpoint` hierarchy on all nodes. * `icinga2-master1.localdomain` is the configuration master in this scenario. * `icinga2-client1.localdomain` acts as client which receives command execution messages via command endpoint from the master. In addition, it receives the global check command configuration from the master. Include the endpoint and zone configuration on **both** nodes in the file `/etc/icinga2/zones.conf`. The endpoint configuration could look like this, for example: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { host = "192.168.56.101" } object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" } Next, you need to define two zones. There is no naming convention, best practice is to either use `master`, `satellite`/`client-fqdn` or to choose region names for example `Europe`, `USA` and `Asia`, though. **Note**: Each client requires its own zone and endpoint configuration. Best practice is to use the client's FQDN for all object names. The `master` zone is a parent of the `icinga2-client1.localdomain` zone: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] //array with endpoint names } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" //establish zone hierarchy } In addition, add a [global zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) for syncing check commands later: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Zone "global-templates" { global = true } Note: Packages >= 2.8 provide this configuration by default. You don't need any local configuration on the client except for CheckCommand definitions which can be synced using the global zone above. Therefore disable the inclusion of the `conf.d` directory in `/etc/icinga2/icinga2.conf`. [root@icinga2-client1.localdomain /]# vim /etc/icinga2/icinga2.conf // Commented out, not required on a client as command endpoint //include_recursive "conf.d" Edit the `api` feature on the client `icinga2-client1.localdomain` in the `/etc/icinga2/features-enabled/api.conf` file and make sure to set `accept_commands` and `accept_config` to `true`: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/features-enabled/api.conf object ApiListener "api" { //... accept_commands = true accept_config = true } Now it is time to validate the configuration and to restart the Icinga 2 daemon on both nodes. Example on CentOS 7: [root@icinga2-client1.localdomain /]# icinga2 daemon -C [root@icinga2-client1.localdomain /]# systemctl restart icinga2 [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Once the clients have successfully connected, you are ready for the next step: **execute a remote check on the client using the command endpoint**. Include the host and service object configuration in the `master` zone -- this will help adding a secondary master for high-availability later. [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/master Add the host and service objects you want to monitor. There is no limitation for files and directories -- best practice is to sort things by type. By convention a master/satellite/client host object should use the same name as the endpoint object. You can also add multiple hosts which execute checks against remote services/clients. [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" //check is executed on the master address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name } Given that you are monitoring a Linux client, we'll add a remote [disk](10-icinga-template-library.md#plugin-check-command-disk) check. [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "disk" { check_command = "disk" //specify where the check is executed command_endpoint = host.vars.client_endpoint assign where host.vars.client_endpoint } If you have your own custom `CheckCommand` definition, add it to the global zone: [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/global-templates [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/global-templates/commands.conf object CheckCommand "my-cmd" { //... } Save the changes and validate the configuration on the master node: [root@icinga2-master1.localdomain /]# icinga2 daemon -C Restart the Icinga 2 daemon (example for CentOS 7): [root@icinga2-master1.localdomain /]# systemctl restart icinga2 The following steps will happen: * Icinga 2 validates the configuration on `icinga2-master1.localdomain` and restarts. * The `icinga2-master1.localdomain` node schedules and executes the checks. * The `icinga2-client1.localdomain` node receives the execute command event with additional command parameters. * The `icinga2-client1.localdomain` node maps the command parameters to the local check command, executes the check locally, and sends back the check result message. As you can see, no interaction from your side is required on the client itself, and it's not necessary to reload the Icinga 2 service on the client. You have learned the basics about command endpoint checks. Proceed with the [scenarios](06-distributed-monitoring.md#distributed-monitoring-scenarios) section where you can find detailed information on extending the setup. ### Top Down Config Sync This mode syncs the object configuration files within specified zones. It comes in handy if you want to configure everything on the master node and sync the satellite checks (disk, memory, etc.). The satellites run their own local scheduler and will send the check result messages back to the master. ![Icinga 2 Distributed Top Down Config Sync](images/distributed-monitoring/icinga2_distributed_top_down_config_sync.png) Advantages: * Sync the configuration files from the parent zone to the child zones. * No manual restart is required on the child nodes, as syncing, validation, and restarts happen automatically. * Execute checks directly on the child node's scheduler. * Replay log if the connection drops (important for keeping the check history in sync, e.g. for SLA reports). * Use a global zone for syncing templates, groups, etc. Disadvantages: * Requires a config directory on the master node with the zone name underneath `/etc/icinga2/zones.d`. * Additional zone and endpoint configuration needed. * Replay log is replicated on reconnect after connection loss. This might increase the data transfer and create an overload on the connection. To make sure that all involved nodes accept configuration and/or commands, you need to configure the `Zone` and `Endpoint` hierarchy on all nodes. * `icinga2-master1.localdomain` is the configuration master in this scenario. * `icinga2-client2.localdomain` acts as client which receives configuration from the master. Checks are scheduled locally. Include the endpoint and zone configuration on **both** nodes in the file `/etc/icinga2/zones.conf`. The endpoint configuration could look like this: [root@icinga2-client2.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { host = "192.168.56.101" } object Endpoint "icinga2-client2.localdomain" { host = "192.168.56.112" } Next, you need to define two zones. There is no naming convention, best practice is to either use `master`, `satellite`/`client-fqdn` or to choose region names for example `Europe`, `USA` and `Asia`, though. **Note**: Each client requires its own zone and endpoint configuration. Best practice is to use the client's FQDN for all object names. The `master` zone is a parent of the `icinga2-client2.localdomain` zone: [root@icinga2-client2.localdomain /]# vim /etc/icinga2/zones.conf object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] //array with endpoint names } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "master" //establish zone hierarchy } Edit the `api` feature on the client `icinga2-client2.localdomain` in the `/etc/icinga2/features-enabled/api.conf` file and set `accept_config` to `true`. [root@icinga2-client2.localdomain /]# vim /etc/icinga2/features-enabled/api.conf object ApiListener "api" { //... accept_config = true } Now it is time to validate the configuration and to restart the Icinga 2 daemon on both nodes. Example on CentOS 7: [root@icinga2-client2.localdomain /]# icinga2 daemon -C [root@icinga2-client2.localdomain /]# systemctl restart icinga2 [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 **Tip**: Best practice is to use a [global zone](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) for common configuration items (check commands, templates, groups, etc.). Once the clients have connected successfully, it's time for the next step: **execute a local check on the client using the configuration sync**. Navigate to `/etc/icinga2/zones.d` on your master node `icinga2-master1.localdomain` and create a new directory with the same name as your satellite/client zone name: [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/icinga2-client2.localdomain Add the host and service objects you want to monitor. There is no limitation for files and directories -- best practice is to sort things by type. By convention a master/satellite/client host object should use the same name as the endpoint object. You can also add multiple hosts which execute checks against remote services/clients. [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/icinga2-client2.localdomain [root@icinga2-master1.localdomain /etc/icinga2/zones.d/icinga2-client2.localdomain]# vim hosts.conf object Host "icinga2-client2.localdomain" { check_command = "hostalive" address = "192.168.56.112" zone = "master" //optional trick: sync the required host object to the client, but enforce the "master" zone to execute the check } Given that you are monitoring a Linux client we'll just add a local [disk](10-icinga-template-library.md#plugin-check-command-disk) check. [root@icinga2-master1.localdomain /etc/icinga2/zones.d/icinga2-client2.localdomain]# vim services.conf object Service "disk" { host_name = "icinga2-client2.localdomain" check_command = "disk" } Save the changes and validate the configuration on the master node: [root@icinga2-master1.localdomain /]# icinga2 daemon -C Restart the Icinga 2 daemon (example for CentOS 7): [root@icinga2-master1.localdomain /]# systemctl restart icinga2 The following steps will happen: * Icinga 2 validates the configuration on `icinga2-master1.localdomain`. * Icinga 2 copies the configuration into its zone config store in `/var/lib/icinga2/api/zones`. * The `icinga2-master1.localdomain` node sends a config update event to all endpoints in the same or direct child zones. * The `icinga2-client2.localdomain` node accepts config and populates the local zone config store with the received config files. * The `icinga2-client2.localdomain` node validates the configuration and automatically restarts. Again, there is no interaction required on the client itself. You can also use the config sync inside a high-availability zone to ensure that all config objects are synced among zone members. **Note**: You can only have one so-called "config master" in a zone which stores the configuration in the `zones.d` directory. Multiple nodes with configuration files in the `zones.d` directory are **not supported**. Now that you've learned the basics about the configuration sync, proceed with the [scenarios](06-distributed-monitoring.md#distributed-monitoring-scenarios) section where you can find detailed information on extending the setup. If you are eager to start fresh instead you might take a look into the [Icinga Director](https://github.com/icinga/icingaweb2-module-director). ## Scenarios The following examples should give you an idea on how to build your own distributed monitoring environment. We've seen them all in production environments and received feedback from our [community](https://www.icinga.com/community/get-involved/) and [partner support](https://www.icinga.com/services/support/) channels: * Single master with clients. * HA master with clients as command endpoint. * Three level cluster with config HA masters, satellites receiving config sync, and clients checked using command endpoint. ### Master with Clients ![Icinga 2 Distributed Master with Clients](images/distributed-monitoring/icinga2_distributed_scenarios_master_clients.png) * `icinga2-master1.localdomain` is the primary master node. * `icinga2-client1.localdomain` and `icinga2-client2.localdomain` are two child nodes as clients. Setup requirements: * Set up `icinga2-master1.localdomain` as [master](06-distributed-monitoring.md#distributed-monitoring-setup-master). * Set up `icinga2-client1.localdomain` and `icinga2-client2.localdomain` as [client](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client). Edit the `zones.conf` configuration file on the master: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { } object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" //the master actively tries to connect to the client } object Endpoint "icinga2-client2.localdomain" { host = "192.168.56.112" //the master actively tries to connect to the client } object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } The two client nodes do not necessarily need to know about each other. The only important thing is that they know about the parent zone and their endpoint members (and optionally the global zone). If you specify the `host` attribute in the `icinga2-master1.localdomain` endpoint object, the client will actively try to connect to the master node. Since we've specified the client endpoint's attribute on the master node already, we don't want the clients to connect to the master. **Choose one [connection direction](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-connection-direction).** [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-client1.localdomain" { } object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } [root@icinga2-client2.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-client2.localdomain" { } object Zone "master" { endpoints = [ "icinga2-master1.localdomain" ] } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } Now it is time to define the two client hosts and apply service checks using the command endpoint execution method on them. Note: You can also use the config sync mode here. Create a new configuration directory on the master node: [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/master Add the two client nodes as host objects: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name } object Host "icinga2-client2.localdomain" { check_command = "hostalive" address = "192.168.56.112" vars.client_endpoint = name //follows the convention that host name == endpoint name } Add services using command endpoint checks: [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "ping4" { check_command = "ping4" //check is executed on the master node assign where host.address } apply Service "disk" { check_command = "disk" //specify where the check is executed command_endpoint = host.vars.client_endpoint assign where host.vars.client_endpoint } Validate the configuration and restart Icinga 2 on the master node `icinga2-master1.localdomain`. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Open Icinga Web 2 and check the two newly created client hosts with two new services -- one executed locally (`ping4`) and one using command endpoint (`disk`). ### High-Availability Master with Clients ![Icinga 2 Distributed High Availability Master with Clients](images/distributed-monitoring/icinga2_distributed_scenarios_ha_master_clients.png) This scenario is similar to the one in the [previous section](06-distributed-monitoring.md#distributed-monitoring-master-clients). The only difference is that we will now set up two master nodes in a high-availability setup. These nodes must be configured as zone and endpoints objects. The setup uses the capabilities of the Icinga 2 cluster. All zone members replicate cluster events amongst each other. In addition to that, several Icinga 2 features can enable HA functionality. **Note**: All nodes in the same zone require that you enable the same features for high-availability (HA). Overview: * `icinga2-master1.localdomain` is the config master master node. * `icinga2-master2.localdomain` is the secondary master master node without config in `zones.d`. * `icinga2-client1.localdomain` and `icinga2-client2.localdomain` are two child nodes as clients. Setup requirements: * Set up `icinga2-master1.localdomain` as [master](06-distributed-monitoring.md#distributed-monitoring-setup-master). * Set up `icinga2-master2.localdomain` as [client](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client) (we will modify the generated configuration). * Set up `icinga2-client1.localdomain` and `icinga2-client2.localdomain` as [clients](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client) (when asked for adding multiple masters, set to `y` and add the secondary master `icinga2-master2.localdomain`). In case you don't want to use the CLI commands, you can also manually create and sync the required SSL certificates. We will modify and discuss all the details of the automatically generated configuration here. Since there are now two nodes in the same zone, we must consider the [high-availability features](06-distributed-monitoring.md#distributed-monitoring-high-availability-features). * Checks and notifications are balanced between the two master nodes. That's fine, but it requires check plugins and notification scripts to exist on both nodes. * The IDO feature will only be active on one node by default. Since all events are replicated between both nodes, it is easier to just have one central database. One possibility is to use a dedicated MySQL cluster VIP (external application cluster) and leave the IDO feature with enabled HA capabilities. Alternatively, you can disable the HA feature and write to a local database on each node. Both methods require that you configure Icinga Web 2 accordingly (monitoring backend, IDO database, used transports, etc.). The zone hierarchy could look like this. It involves putting the two master nodes `icinga2-master1.localdomain` and `icinga2-master2.localdomain` into the `master` zone. [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { host = "192.168.56.101" } object Endpoint "icinga2-master2.localdomain" { host = "192.168.56.102" } object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" //the master actively tries to connect to the client } object Endpoint "icinga2-client2.localdomain" { host = "192.168.56.112" //the master actively tries to connect to the client } object Zone "master" { endpoints = [ "icinga2-master1.localdomain", "icinga2-master2.localdomain" ] } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } The two client nodes do not necessarily need to know about each other. The only important thing is that they know about the parent zone and their endpoint members (and optionally about the global zone). If you specify the `host` attribute in the `icinga2-master1.localdomain` and `icinga2-master2.localdomain` endpoint objects, the client will actively try to connect to the master node. Since we've specified the client endpoint's attribute on the master node already, we don't want the clients to connect to the master nodes. **Choose one [connection direction](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-connection-direction).** [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-master2.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-client1.localdomain" { } object Zone "master" { endpoints = [ "icinga2-master1.localdomain", "icinga2-master2.localdomain" ] } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } [root@icinga2-client2.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-master2.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute } object Endpoint "icinga2-client2.localdomain" { } object Zone "master" { endpoints = [ "icinga2-master1.localdomain", "icinga2-master2.localdomain" ] } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } Now it is time to define the two client hosts and apply service checks using the command endpoint execution method. Note: You can also use the config sync mode here. Create a new configuration directory on the master node `icinga2-master1.localdomain`. **Note**: The secondary master node `icinga2-master2.localdomain` receives the configuration using the [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync). [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/master Add the two client nodes as host objects: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name } object Host "icinga2-client2.localdomain" { check_command = "hostalive" address = "192.168.56.112" vars.client_endpoint = name //follows the convention that host name == endpoint name } Add services using command endpoint checks: [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "ping4" { check_command = "ping4" //check is executed on the master node assign where host.address } apply Service "disk" { check_command = "disk" //specify where the check is executed command_endpoint = host.vars.client_endpoint assign where host.vars.client_endpoint } Validate the configuration and restart Icinga 2 on the master node `icinga2-master1.localdomain`. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Open Icinga Web 2 and check the two newly created client hosts with two new services -- one executed locally (`ping4`) and one using command endpoint (`disk`). **Tip**: It's a good idea to add [health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks) to make sure that your cluster notifies you in case of failure. ### Three Levels with Master, Satellites, and Clients ![Icinga 2 Distributed Master and Satellites with Clients](images/distributed-monitoring/icinga2_distributed_scenarios_master_satellite_client.png) This scenario combines everything you've learned so far: High-availability masters, satellites receiving their configuration from the master zone, and clients checked via command endpoint from the satellite zones. **Tip**: It can get complicated, so grab a pen and paper and bring your thoughts to life. Play around with a test setup before using it in a production environment! Overview: * `icinga2-master1.localdomain` is the configuration master master node. * `icinga2-master2.localdomain` is the secondary master master node without configuration in `zones.d`. * `icinga2-satellite1.localdomain` and `icinga2-satellite2.localdomain` are satellite nodes in a `master` child zone. * `icinga2-client1.localdomain` and `icinga2-client2.localdomain` are two child nodes as clients. Setup requirements: * Set up `icinga2-master1.localdomain` as [master](06-distributed-monitoring.md#distributed-monitoring-setup-master). * Set up `icinga2-master2.localdomain`, `icinga2-satellite1.localdomain` and `icinga2-satellite2.localdomain` as [clients](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client) (we will modify the generated configuration). * Set up `icinga2-client1.localdomain` and `icinga2-client2.localdomain` as [clients](06-distributed-monitoring.md#distributed-monitoring-setup-satellite-client). When being asked for the master endpoint providing CSR auto-signing capabilities, please add the master node which holds the CA and has the `ApiListener` feature configured and enabled. The parent endpoint must still remain the satellite endpoint name. Example for `icinga2-client1.localdomain`: Please specify the master endpoint(s) this node should connect to: Master is the first satellite `icinga2-satellite1.localdomain`: Master Common Name (CN from your master setup): icinga2-satellite1.localdomain Do you want to establish a connection to the master from this node? [Y/n]: y Please fill out the master connection information: Master endpoint host (Your master's IP address or FQDN): 192.168.56.105 Master endpoint port [5665]: Add the second satellite `icinga2-satellite2.localdomain` as master: Add more master endpoints? [y/N]: y Master Common Name (CN from your master setup): icinga2-satellite2.localdomain Do you want to establish a connection to the master from this node? [Y/n]: y Please fill out the master connection information: Master endpoint host (Your master's IP address or FQDN): 192.168.56.106 Master endpoint port [5665]: Add more master endpoints? [y/N]: n Specify the master node `icinga2-master2.localdomain` with the CA private key and ticket salt: Please specify the master connection for CSR auto-signing (defaults to master endpoint host): Host [192.168.56.106]: icinga2-master1.localdomain Port [5665]: In case you cannot connect to the master node from your clients, you'll manually need to [generate the SSL certificates](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-certificates-manual) and modify the configuration accordingly. We'll discuss the details of the required configuration below. The zone hierarchy can look like this. We'll define only the directly connected zones here. You can safely deploy this configuration onto all master and satellite zone members. You should keep in mind to control the endpoint [connection direction](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-connection-direction) using the `host` attribute. [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-master1.localdomain" { host = "192.168.56.101" } object Endpoint "icinga2-master2.localdomain" { host = "192.168.56.102" } object Endpoint "icinga2-satellite1.localdomain" { host = "192.168.56.105" } object Endpoint "icinga2-satellite2.localdomain" { host = "192.168.56.106" } object Zone "master" { endpoints = [ "icinga2-master1.localdomain", "icinga2-master2.localdomain" ] } object Zone "satellite" { endpoints = [ "icinga2-satellite1.localdomain", "icinga2-satellite2.localdomain" ] parent = "master" } /* sync global commands */ object Zone "global-templates" { global = true } Repeat the configuration step for `icinga2-master2.localdomain`, `icinga2-satellite1.localdomain` and `icinga2-satellite2.localdomain`. Since we want to use [top down command endpoint](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) checks, we must configure the client endpoint and zone objects. In order to minimize the effort, we'll sync the client zone and endpoint configuration to the satellites where the connection information is needed as well. [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/{master,satellite,global-templates} [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/satellite [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim icinga2-client1.localdomain.conf object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" //the satellite actively tries to connect to the client } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "satellite" } [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim icinga2-client2.localdomain.conf object Endpoint "icinga2-client2.localdomain" { host = "192.168.56.112" //the satellite actively tries to connect to the client } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "satellite" } The two client nodes do not necessarily need to know about each other, either. The only important thing is that they know about the parent zone (the satellite) and their endpoint members (and optionally the global zone). If you specify the `host` attribute in the `icinga2-satellite1.localdomain` and `icinga2-satellite2.localdomain` endpoint objects, the client node will actively try to connect to the satellite node. Since we've specified the client endpoint's attribute on the satellite node already, we don't want the client node to connect to the satellite nodes. **Choose one [connection direction](06-distributed-monitoring.md#distributed-monitoring-advanced-hints-connection-direction).** Example for `icinga2-client1.localdomain`: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-satellite1.localdomain" { //do not actively connect to the satellite by leaving out the 'host' attribute } object Endpoint "icinga2-satellite2.localdomain" { //do not actively connect to the satellite by leaving out the 'host' attribute } object Endpoint "icinga2-client1.localdomain" { //that's us } object Zone "satellite" { endpoints = [ "icinga2-satellite1.localdomain", "icinga2-satellite2.localdomain" ] } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "satellite" } /* sync global commands */ object Zone "global-templates" { global = true } Example for `icinga2-client2.localdomain`: [root@icinga2-client2.localdomain /]# vim /etc/icinga2/zones.conf object Endpoint "icinga2-satellite1.localdomain" { //do not actively connect to the satellite by leaving out the 'host' attribute } object Endpoint "icinga2-satellite2.localdomain" { //do not actively connect to the satellite by leaving out the 'host' attribute } object Endpoint "icinga2-client2.localdomain" { //that's us } object Zone "satellite" { endpoints = [ "icinga2-satellite1.localdomain", "icinga2-satellite2.localdomain" ] } object Zone "icinga2-client2.localdomain" { endpoints = [ "icinga2-client2.localdomain" ] parent = "satellite" } /* sync global commands */ object Zone "global-templates" { global = true } Now it is time to define the two client hosts on the master, sync them to the satellites and apply service checks using the command endpoint execution method to them. Add the two client nodes as host objects to the `satellite` zone. We've already created the directories in `/etc/icinga2/zones.d` including the files for the zone and endpoint configuration for the clients. [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/satellite Add the host object configuration for the `icinga2-client1.localdomain` client. You should have created the configuration file in the previous steps and it should contain the endpoint and zone object configuration already. [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim icinga2-client1.localdomain.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name } Add the host object configuration for the `icinga2-client2.localdomain` client configuration file: [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim icinga2-client2.localdomain.conf object Host "icinga2-client2.localdomain" { check_command = "hostalive" address = "192.168.56.112" vars.client_endpoint = name //follows the convention that host name == endpoint name } Add a service object which is executed on the satellite nodes (e.g. `ping4`). Pin the apply rule to the `satellite` zone only. [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim services.conf apply Service "ping4" { check_command = "ping4" //check is executed on the satellite node assign where host.zone == "satellite" && host.address } Add services using command endpoint checks. Pin the apply rules to the `satellite` zone only. [root@icinga2-master1.localdomain /etc/icinga2/zones.d/satellite]# vim services.conf apply Service "disk" { check_command = "disk" //specify where the check is executed command_endpoint = host.vars.client_endpoint assign where host.zone == "satellite" && host.vars.client_endpoint } Validate the configuration and restart Icinga 2 on the master node `icinga2-master1.localdomain`. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Open Icinga Web 2 and check the two newly created client hosts with two new services -- one executed locally (`ping4`) and one using command endpoint (`disk`). **Tip**: It's a good idea to add [health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks) to make sure that your cluster notifies you in case of failure. ## Best Practice We've put together a collection of configuration examples from community feedback. If you like to share your tips and tricks with us, please join the [community channels](https://www.icinga.com/community/get-involved/)! ### Global Zone for Config Sync Global zones can be used to sync generic configuration objects to all nodes depending on them. Common examples are: * Templates which are imported into zone specific objects. * Command objects referenced by Host, Service, Notification objects. * Apply rules for services, notifications, dependencies and scheduled downtimes. * User objects referenced in notifications. * Group objects. * TimePeriod objects. Plugin scripts and binaries cannot be synced, this is for Icinga 2 configuration files only. Use your preferred package repository and/or configuration management tool (Puppet, Ansible, Chef, etc.) for that. **Note**: Checkable objects (hosts and services) cannot be put into a global zone. The configuration validation will terminate with an error. The zone object configuration must be deployed on all nodes which should receive the global configuration files: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf object Zone "global-templates" { global = true } Note: Packages >= 2.8 provide this configuration by default. Similar to the zone configuration sync you'll need to create a new directory in `/etc/icinga2/zones.d`: [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/global-templates Next, add a new check command, for example: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/global-templates/commands.conf object CheckCommand "my-cmd" { //... } Restart the client(s) which should receive the global zone before before restarting the parent master/satellite nodes. Then validate the configuration on the master node and restart Icinga 2. **Tip**: You can copy the example configuration files located in `/etc/icinga2/conf.d` into your global zone. Example: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/conf.d [root@icinga2-master1.localdomain /etc/icinga2/conf.d]# cp {commands,downtimes,groups,notifications,templates,timeperiods,users}.conf /etc/icinga2/zones.d/global-templates ### Health Checks In case of network failures or other problems, your monitoring might either have late check results or just send out mass alarms for unknown checks. In order to minimize the problems caused by this, you should configure additional health checks. The `cluster` check, for example, will check if all endpoints in the current zone and the directly connected zones are working properly: [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/icinga2-master1.localdomain.conf object Host "icinga2-master1.localdomain" { check_command = "hostalive" address = "192.168.56.101" } [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/cluster.conf object Service "cluster" { check_command = "cluster" check_interval = 5s retry_interval = 1s host_name = "icinga2-master1.localdomain" } The `cluster-zone` check will test whether the configured target zone is currently connected or not. This example adds a health check for the [ha master with clients scenario](06-distributed-monitoring.md#distributed-monitoring-scenarios-ha-master-clients). [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/services.conf apply Service "cluster-health" { check_command = "cluster-zone" display_name = "cluster-health-" + host.name /* This follows the convention that the client zone name is the FQDN which is the same as the host object name. */ vars.cluster_zone = host.name assign where host.vars.client_endpoint } In case you cannot assign the `cluster_zone` attribute, add specific checks to your cluster: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/cluster.conf object Service "cluster-zone-satellite" { check_command = "cluster-zone" check_interval = 5s retry_interval = 1s vars.cluster_zone = "satellite" host_name = "icinga2-master1.localdomain" } If you are using top down checks with command endpoint configuration, you can add a dependency which prevents notifications for all other failing services: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/dependencies.conf apply Dependency "health-check" to Service { parent_service_name = "child-health" states = [ OK ] disable_notifications = true assign where host.vars.client_endpoint ignore where service.name == "child-health" } ### Pin Checks in a Zone In case you want to pin specific checks to their endpoints in a given zone you'll need to use the `command_endpoint` attribute. This is reasonable if you want to execute a local disk check in the `master` Zone on a specific endpoint then. [root@icinga2-master1.localdomain /]# mkdir -p /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/icinga2-master1.localdomain.conf object Host "icinga2-master1.localdomain" { check_command = "hostalive" address = "192.168.56.101" } [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.d/master/services.conf apply Service "disk" { check_command = "disk" command_endpoint = host.name //requires a host object matching the endpoint object name e.g. icinga2-master1.localdomain assign where host.zone == "master" && match("icinga2-master*", host.name) } The `host.zone` attribute check inside the expression ensures that the service object is only created for host objects inside the `master` zone. In addition to that the [match](18-library-reference.md#global-functions-match) function ensures to only create services for the master nodes. ### Windows Firewall #### ICMP Requests By default ICMP requests are disabled in the Windows firewall. You can change that by [adding a new rule](https://support.microsoft.com/en-us/kb/947709). C:\WINDOWS\system32>netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow #### Icinga 2 If your master/satellite nodes should actively connect to the Windows client you'll also need to ensure that port `5665` is enabled. C:\WINDOWS\system32>netsh advfirewall firewall add rule name="Open port 5665 (Icinga 2)" dir=in action=allow protocol=TCP localport=5665 #### NSClient++ API If the [check_nscp_api](06-distributed-monitoring.md#distributed-monitoring-windows-nscp-check-api) plugin is used to query NSClient++ remotely, you need to ensure that its port is enabled. C:\WINDOWS\system32>netsh advfirewall firewall add rule name="Open port 8443 (NSClient++ API)" dir=in action=allow protocol=TCP localport=8443 ### Windows Client and Plugins The Icinga 2 package on Windows already provides several plugins. Detailed [documentation](10-icinga-template-library.md#windows-plugins) is available for all check command definitions. Add the following `include` statement on all your nodes (master, satellite, client): vim /etc/icinga2/icinga2.conf include Based on the [master with clients](06-distributed-monitoring.md#distributed-monitoring-master-clients) scenario we'll now add a local disk check. First, add the client node as host object: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client2.localdomain" { check_command = "hostalive" address = "192.168.56.112" vars.client_endpoint = name //follows the convention that host name == endpoint name vars.os_type = "windows" } Next, add the disk check using command endpoint checks (details in the [disk-windows](10-icinga-template-library.md#windows-plugins-disk-windows) documentation): [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "disk C:" { check_command = "disk-windows" vars.disk_win_path = "C:" //specify where the check is executed command_endpoint = host.vars.client_endpoint assign where host.vars.os_type == "windows" && host.vars.client_endpoint } Validate the configuration and restart Icinga 2. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Open Icinga Web 2 and check your newly added Windows disk check :) ![Icinga 2 Client Windows](images/distributed-monitoring/icinga2_distributed_windows_client_disk_icingaweb2.png) If you want to add your own plugins please check [this chapter](05-service-monitoring.md#service-monitoring-requirements) for the requirements. ### Windows Client and NSClient++ There are two methods available for querying NSClient++: * Query the [HTTP API](06-distributed-monitoring.md#distributed-monitoring-windows-nscp-check-api) locally or remotely (requires a running NSClient++ service) * Run a [local CLI check](06-distributed-monitoring.md#distributed-monitoring-windows-nscp-check-local) (does not require NSClient++ as a service) Both methods have their advantages and disadvantages. One thing to note: If you rely on performance counter delta calculations such as CPU utilization, please use the HTTP API instead of the CLI sample call. #### NSCLient++ with check_nscp_api The [Windows setup](06-distributed-monitoring.md#distributed-monitoring-setup-client-windows) already allows you to install the NSClient++ package. In addition to the Windows plugins you can use the [nscp_api command](10-icinga-template-library.md#nscp-check-api) provided by the Icinga Template Library (ITL). The initial setup for the NSClient++ API and the required arguments is the described in the ITL chapter for the [nscp_api](10-icinga-template-library.md#nscp-check-api) CheckCommand. Based on the [master with clients](06-distributed-monitoring.md#distributed-monitoring-master-clients) scenario we'll now add a local nscp check which queries the NSClient++ API to check the free disk space. Define a host object called `icinga2-client2.localdomain` on the master. Add the `nscp_api_password` custom attribute and specify the drives to check. [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name vars.os_type = "Windows" vars.nscp_api_password = "icinga" vars.drives = [ "C:", "D:" ] } The service checks are generated using an [apply for](03-monitoring-basics.md#using-apply-for) rule based on `host.vars.drives`: [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "nscp-api-" for (drive in host.vars.drives) { import "generic-service" check_command = "nscp_api" command_endpoint = host.vars.client_endpoint //display_name = "nscp-drive-" + drive vars.nscp_api_host = "localhost" vars.nscp_api_query = "check_drivesize" vars.nscp_api_password = host.vars.nscp_api_password vars.nscp_api_arguments = [ "drive=" + drive ] ignore where host.vars.os_type != "Windows" } Validate the configuration and restart Icinga 2. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Two new services ("nscp-drive-D:" and "nscp-drive-C:") will be visible in Icinga Web 2. ![Icinga 2 Distributed Monitoring Windows Client with NSClient++ nscp-api](images/distributed-monitoring/icinga2_distributed_windows_nscp_api_drivesize_icingaweb2.png) Note: You can also omit the `command_endpoint` configuration to execute the command on the master. This also requires a different value for `nscp_api_host` which defaults to `host.address`. //command_endpoint = host.vars.client_endpoint //vars.nscp_api_host = "localhost" You can verify the check execution by looking at the `Check Source` attribute in Icinga Web 2 or the REST API. If you want to monitor specific Windows services, you could use the following example: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name vars.os_type = "Windows" vars.nscp_api_password = "icinga" vars.services = [ "Windows Update", "wscsvc" ] } [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "nscp-api-" for (svc in host.vars.services) { import "generic-service" check_command = "nscp_api" command_endpoint = host.vars.client_endpoint //display_name = "nscp-service-" + svc vars.nscp_api_host = "localhost" vars.nscp_api_query = "check_service" vars.nscp_api_password = host.vars.nscp_api_password vars.nscp_api_arguments = [ "service=" + svc ] ignore where host.vars.os_type != "Windows" } #### NSCLient++ with nscp-local The [Windows setup](06-distributed-monitoring.md#distributed-monitoring-setup-client-windows) already allows you to install the NSClient++ package. In addition to the Windows plugins you can use the [nscp-local commands](10-icinga-template-library.md#nscp-plugin-check-commands) provided by the Icinga Template Library (ITL). ![Icinga 2 Distributed Monitoring Windows Client with NSClient++](images/distributed-monitoring/icinga2_distributed_windows_nscp.png) Add the following `include` statement on all your nodes (master, satellite, client): vim /etc/icinga2/icinga2.conf include The CheckCommand definitions will automatically determine the installed path to the `nscp.exe` binary. Based on the [master with clients](06-distributed-monitoring.md#distributed-monitoring-master-clients) scenario we'll now add a local nscp check querying a given performance counter. First, add the client node as host object: [root@icinga2-master1.localdomain /]# cd /etc/icinga2/zones.d/master [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim hosts.conf object Host "icinga2-client1.localdomain" { check_command = "hostalive" address = "192.168.56.111" vars.client_endpoint = name //follows the convention that host name == endpoint name vars.os_type = "windows" } Next, add a performance counter check using command endpoint checks (details in the [nscp-local-counter](10-icinga-template-library.md#nscp-check-local-counter) documentation): [root@icinga2-master1.localdomain /etc/icinga2/zones.d/master]# vim services.conf apply Service "nscp-local-counter-cpu" { check_command = "nscp-local-counter" command_endpoint = host.vars.client_endpoint vars.nscp_counter_name = "\\Processor(_total)\\% Processor Time" vars.nscp_counter_perfsyntax = "Total Processor Time" vars.nscp_counter_warning = 1 vars.nscp_counter_critical = 5 vars.nscp_counter_showall = true assign where host.vars.os_type == "windows" && host.vars.client_endpoint } Validate the configuration and restart Icinga 2. [root@icinga2-master1.localdomain /]# icinga2 daemon -C [root@icinga2-master1.localdomain /]# systemctl restart icinga2 Open Icinga Web 2 and check your newly added Windows NSClient++ check :) ![Icinga 2 Distributed Monitoring Windows Client with NSClient++ nscp-local](images/distributed-monitoring/icinga2_distributed_windows_nscp_counter_icingaweb2.png) ## Advanced Hints You can find additional hints in this section if you prefer to go your own route with automating setups (setup, certificates, configuration). ### Certificate Auto-Renewal Icinga 2 v2.8+ adds the possibility that nodes request certificate updates on their own. If their expiration date is soon enough, they automatically renew their already signed certificate by sending a signing request to the parent node. ### High-Availability for Icinga 2 Features All nodes in the same zone require that you enable the same features for high-availability (HA). By default, the following features provide advanced HA functionality: * [Checks](06-distributed-monitoring.md#distributed-monitoring-high-availability-checks) (load balanced, automated failover). * [Notifications](06-distributed-monitoring.md#distributed-monitoring-high-availability-notifications) (load balanced, automated failover). * [DB IDO](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido) (Run-Once, automated failover). #### High-Availability with Checks All instances within the same zone (e.g. the `master` zone as HA cluster) must have the `checker` feature enabled. Example: # icinga2 feature enable checker All nodes in the same zone load-balance the check execution. If one instance shuts down, the other nodes will automatically take over the remaining checks. #### High-Availability with Notifications All instances within the same zone (e.g. the `master` zone as HA cluster) must have the `notification` feature enabled. Example: # icinga2 feature enable notification Notifications are load-balanced amongst all nodes in a zone. By default this functionality is enabled. If your nodes should send out notifications independently from any other nodes (this will cause duplicated notifications if not properly handled!), you can set `enable_ha = false` in the [NotificationComponent](09-object-types.md#objecttype-notificationcomponent) feature. #### High-Availability with DB IDO All instances within the same zone (e.g. the `master` zone as HA cluster) must have the DB IDO feature enabled. Example DB IDO MySQL: # icinga2 feature enable ido-mysql By default the DB IDO feature only runs on one node. All other nodes in the same zone disable the active IDO database connection at runtime. The node with the active DB IDO connection is not necessarily the zone master. **Note**: The DB IDO HA feature can be disabled by setting the `enable_ha` attribute to `false` for the [IdoMysqlConnection](09-object-types.md#objecttype-idomysqlconnection) or [IdoPgsqlConnection](09-object-types.md#objecttype-idopgsqlconnection) object on **all** nodes in the **same** zone. All endpoints will enable the DB IDO feature and connect to the configured database and dump configuration, status and historical data on their own. If the instance with the active DB IDO connection dies, the HA functionality will automatically elect a new DB IDO master. The DB IDO feature will try to determine which cluster endpoint is currently writing to the database and bail out if another endpoint is active. You can manually verify that by running the following query command: icinga=> SELECT status_update_time, endpoint_name FROM icinga_programstatus; status_update_time | endpoint_name ------------------------+--------------- 2016-08-15 15:52:26+02 | icinga2-master1.localdomain (1 Zeile) This is useful when the cluster connection between endpoints breaks, and prevents data duplication in split-brain-scenarios. The failover timeout can be set for the `failover_timeout` attribute, but not lower than 60 seconds. ### Endpoint Connection Direction Nodes will attempt to connect to another node when its local [Endpoint](09-object-types.md#objecttype-endpoint) object configuration specifies a valid `host` attribute (FQDN or IP address). Example for the master node `icinga2-master1.localdomain` actively connecting to the client node `icinga2-client1.localdomain`: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf //... object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" //the master actively tries to connect to the client log_duration = 0 } Example for the client node `icinga2-client1.localdomain` not actively connecting to the master node `icinga2-master1.localdomain`: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf //... object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute log_duration = 0 } It is not necessary that both the master and the client node establish two connections to each other. Icinga 2 will only use one connection and close the second connection if established. **Tip**: Choose either to let master/satellite nodes connect to client nodes or vice versa. ### Disable Log Duration for Command Endpoints The replay log is a built-in mechanism to ensure that nodes in a distributed setup keep the same history (check results, notifications, etc.) when nodes are temporarily disconnected and then reconnect. This functionality is not needed when a master/satellite node is sending check execution events to a client which is purely configured for [command endpoint](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) checks only. The [Endpoint](09-object-types.md#objecttype-endpoint) object attribute `log_duration` can be lower or set to 0 to fully disable any log replay updates when the client is not connected. Configuration on the master node `icinga2-master1.localdomain`: [root@icinga2-master1.localdomain /]# vim /etc/icinga2/zones.conf //... object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" //the master actively tries to connect to the client log_duration = 0 } object Endpoint "icinga2-client2.localdomain" { host = "192.168.56.112" //the master actively tries to connect to the client log_duration = 0 } Configuration on the client `icinga2-client1.localdomain`: [root@icinga2-client1.localdomain /]# vim /etc/icinga2/zones.conf //... object Endpoint "icinga2-master1.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute log_duration = 0 } object Endpoint "icinga2-master2.localdomain" { //do not actively connect to the master by leaving out the 'host' attribute log_duration = 0 } ### CSR auto-signing with HA and multiple Level Cluster If you are using two masters in a High-Availability setup it can be necessary to allow both to sign requested certificates. Ensure to safely sync the following details in private: * `TicketSalt` constant in `constants.conf`. * `var/lib/icinga2/ca` directory. This also helps if you are using a [three level cluster](06-distributed-monitoring.md#distributed-monitoring-scenarios-master-satellite-client) and your client nodes are not able to reach the CSR auto-signing master node(s). Make sure that the directory permissions for `/var/lib/icinga2/ca` are secure (not world readable). **Do not expose these private keys to anywhere else. This is a matter of security.** ### Manual Certificate Creation #### Create CA on the Master Choose the host which should store the certificate authority (one of the master nodes). The first step is the creation of the certificate authority (CA) by running the following command as root user: [root@icinga2-master1.localdomain /root]# icinga2 pki new-ca #### Create CSR and Certificate Create a certificate signing request (CSR) for the local instance: ``` [root@icinga2-master1.localdomain /root]# icinga2 pki new-cert --cn icinga2-master1.localdomain \ --key icinga2-master1.localdomain.key \ --csr icinga2-master1.localdomain.csr ``` Sign the CSR with the previously created CA: ``` [root@icinga2-master1.localdomain /root]# icinga2 pki sign-csr --csr icinga2-master1.localdomain.csr --cert icinga2-master1.localdomain ``` Repeat the steps for all instances in your setup. > **Note** > > The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) > for more details. #### Copy Certificates Copy the host's certificate files and the public CA certificate to `/var/lib/icinga2/certs`: ``` [root@icinga2-master1.localdomain /root]# mkdir -p /var/lib/icinga2/certs [root@icinga2-master1.localdomain /root]# cp icinga2-master1.localdomain.{crt,key} /var/lib/icinga2/certs [root@icinga2-master1.localdomain /root]# cp /var/lib/icinga2/ca/ca.crt /var/lib/icinga2/certs ``` Ensure that proper permissions are set (replace `icinga` with the Icinga 2 daemon user): ``` [root@icinga2-master1.localdomain /root]# chown -R icinga:icinga /var/lib/icinga2/certs [root@icinga2-master1.localdomain /root]# chmod 600 /var/lib/icinga2/certs/*.key [root@icinga2-master1.localdomain /root]# chmod 644 /var/lib/icinga2/certs/*.crt ``` The CA public and private key are stored in the `/var/lib/icinga2/ca` directory. Keep this path secure and include it in your backups. #### Create Multiple Certificates Use your preferred method to automate the certificate generation process. ``` [root@icinga2-master1.localdomain /var/lib/icinga2/certs]# for node in icinga2-master1.localdomain icinga2-master2.localdomain icinga2-satellite1.localdomain; do icinga2 pki new-cert --cn $node --csr $node.csr --key $node.key; done information/base: Writing private key to 'icinga2-master1.localdomain.key'. information/base: Writing certificate signing request to 'icinga2-master1.localdomain.csr'. information/base: Writing private key to 'icinga2-master2.localdomain.key'. information/base: Writing certificate signing request to 'icinga2-master2.localdomain.csr'. information/base: Writing private key to 'icinga2-satellite1.localdomain.key'. information/base: Writing certificate signing request to 'icinga2-satellite1.localdomain.csr'. [root@icinga2-master1.localdomain /var/lib/icinga2/certs]# for node in icinga2-master1.localdomain icinga2-master2.localdomain icinga2-satellite1.localdomain; do sudo icinga2 pki sign-csr --csr $node.csr --cert $node.crt; done information/pki: Writing certificate to file 'icinga2-master1.localdomain.crt'. information/pki: Writing certificate to file 'icinga2-master2.localdomain.crt'. information/pki: Writing certificate to file 'icinga2-satellite1.localdomain.crt'. ``` Copy and move these certificates to the respective instances e.g. with SSH/SCP. ## Automation These hints should get you started with your own automation tools (Puppet, Ansible, Chef, Salt, etc.) or custom scripts for automated setup. These are collected best practices from various community channels. * [Silent Windows setup](06-distributed-monitoring.md#distributed-monitoring-automation-windows-silent) * [Node Setup CLI command](06-distributed-monitoring.md#distributed-monitoring-automation-cli-node-setup) with parameters If you prefer an alternate method, we still recommend leaving all the Icinga 2 features intact (e.g. `icinga2 feature enable api`). You should also use well known and documented default configuration file locations (e.g. `zones.conf`). This will tremendously help when someone is trying to help in the [community channels](https://www.icinga.com/community/get-involved/). ### Silent Windows Setup If you want to install the client silently/unattended, use the `/qn` modifier. The installation should not trigger a restart, but if you want to be completely sure, you can use the `/norestart` modifier. C:> msiexec /i C:\Icinga2-v2.5.0-x86.msi /qn /norestart Once the setup is completed you can use the `node setup` cli command too. ### Node Setup using CLI Parameters Instead of using the `node wizard` CLI command, there is an alternative `node setup` command available which has some prerequisites. **Note**: The CLI command can be used on Linux/Unix and Windows operating systems. The graphical Windows setup wizard actively uses these CLI commands. #### Node Setup on the Master Node In case you want to setup a master node you must add the `--master` parameter to the `node setup` CLI command. In addition to that the `--cn` can optionally be passed (defaults to the FQDN). Parameter | Description --------------------|-------------------- Common name (CN) | **Optional.** Specified with the `--cn` parameter. By convention this should be the host's FQDN. Defaults to the FQDN. Listen on | **Optional.** Specified with the `--listen` parameter. Syntax is `host,port`. Example: [root@icinga2-master1.localdomain /]# icinga2 node setup --master In case you want to bind the `ApiListener` object to a specific host/port you can specify it like this: --listen 192.68.56.101,5665 #### Node Setup with Satellites/Clients > **Note** > > The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) > for more details. Make sure that the `/var/lib/icinga2/certs` directory exists and is owned by the `icinga` user (or the user Icinga 2 is running as). [root@icinga2-client1.localdomain /]# mkdir -p /var/lib/icinga2/certs [root@icinga2-client1.localdomain /]# chown -R icinga:icinga /var/lib/icinga2/certs First you'll need to generate a new local self-signed certificate. Pass the following details to the `pki new-cert` CLI command: Parameter | Description --------------------|-------------------- Common name (CN) | **Required.** By convention this should be the host's FQDN. Defaults to the FQDN. Client certificate files | **Required.** These generated files will be put into the specified location (--key and --file). By convention this should be using `/var/lib/icinga2/certs` as directory. Example: [root@icinga2-client1.localdomain /]# icinga2 pki new-cert --cn icinga2-client1.localdomain \ --key /var/lib/icinga2/certs/icinga2-client1.localdomain.key \ --cert /var/lib/icinga2/certs/icinga2-client1.localdomain.crt Request the master certificate from the master host (`icinga2-master1.localdomain`) and store it as `trusted-master.crt`. Review it and continue. Pass the following details to the `pki save-cert` CLI command: Parameter | Description --------------------|-------------------- Client certificate files | **Required.** Pass the previously generated files using the `--key` and `--cert` parameters. Trusted master certificate | **Required.** Store the master's certificate file. Manually verify that you're trusting it. Master host | **Required.** FQDN or IP address of the master host. Example: [root@icinga2-client1.localdomain /]# icinga2 pki save-cert --key /var/lib/icinga2/certs/icinga2-client1.localdomain.key \ --cert /var/lib/icinga2/certs/icinga2-client1.localdomain.crt \ --trustedcert /var/lib/icinga2/certs/trusted-master.crt \ --host icinga2-master1.localdomain Continue with the additional node setup step. Specify a local endpoint and zone name (`icinga2-client1.localdomain`) and set the master host (`icinga2-master1.localdomain`) as parent zone configuration. Specify the path to the previously stored trusted master certificate. Pass the following details to the `node setup` CLI command: Parameter | Description --------------------|-------------------- Common name (CN) | **Optional.** Specified with the `--cn` parameter. By convention this should be the host's FQDN. Request ticket | **Required.** Add the previously generated [ticket number](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). Trusted master certificate | **Required.** Add the previously fetched trusted master certificate (this step means that you've verified its origin). Master endpoint | **Required.** Specify the master's endpoint name. Client zone name | **Required.** Specify the client's zone name. Master host | **Required.** FQDN or IP address of the master host. Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)). Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). Example for Icinga 2 v2.8: [root@icinga2-client1.localdomain /]# icinga2 node setup --ticket ead2d570e18c78abf285d6b85524970a0f69c22d \ --cn icinga2-client1.localdomain \ --endpoint icinga2-master1.localdomain \ --zone icinga2-client1.localdomain \ --master_host icinga2-master1.localdomain \ --trustedcert /var/lib/icinga2/certs/trusted-master.crt \ --accept-commands --accept-config In case the client should connect to the master node, you'll need to modify the `--endpoint` parameter using the format `cn,host,port`: --endpoint icinga2-master1.localdomain,192.168.56.101,5665 Restart Icinga 2 afterwards: # service icinga2 restart **You can find additional best practices below.** Add an additional global zone. Please note the `>>` append mode. [root@icinga2-client1.localdomain /]# cat <>/etc/icinga2/zones.conf object Zone "global-templates" { global = true } EOF Note: Packages >= 2.8 provide this configuration by default. If this client node is configured as [remote command endpoint execution](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) you can safely disable the `checker` feature. The `node setup` CLI command already disabled the `notification` feature. [root@icinga2-client1.localdomain /]# icinga2 feature disable checker Disable "conf.d" inclusion if this is a [top down](06-distributed-monitoring.md#distributed-monitoring-top-down) configured client. [root@icinga2-client1.localdomain /]# sed -i 's/include_recursive "conf.d"/\/\/include_recursive "conf.d"/g' /etc/icinga2/icinga2.conf **Optional**: Add an ApiUser object configuration for remote troubleshooting. [root@icinga2-client1.localdomain /]# cat </etc/icinga2/conf.d/api-users.conf object ApiUser "root" { password = "clientsupersecretpassword" permissions = ["*"] } EOF In case you've previously disabled the "conf.d" directory only add the file file `conf.d/api-users.conf`: [root@icinga2-client1.localdomain /]# echo 'include "conf.d/api-users.conf"' >> /etc/icinga2/icinga2.conf Finally restart Icinga 2. [root@icinga2-client1.localdomain /]# systemctl restart icinga2 Your automation tool must then configure master node in the meantime. Add the global zone `global-templates` in case it did not exist. # cat <>/etc/icinga2/zones.conf object Endpoint "icinga2-client1.localdomain" { //client connects itself } object Zone "icinga2-client1.localdomain" { endpoints = [ "icinga2-client1.localdomain" ] parent = "master" } object Zone "global-templates" { global = true } EOF icinga2-2.8.1/doc/07-agent-based-monitoring.md000066400000000000000000000303711322762156600207240ustar00rootroot00000000000000# Additional Agent-based Checks If the remote services are not directly accessible through the network, a local agent installation exposing the results to check queries can become handy. ## SNMP The SNMP daemon runs on the remote system and answers SNMP queries by plugin binaries. The [Monitoring Plugins package](02-getting-started.md#setting-up-check-plugins) ships the `check_snmp` plugin binary, but there are plenty of [existing plugins](05-service-monitoring.md#service-monitoring-plugins) for specific use cases already around, for example monitoring Cisco routers. The following example uses the [SNMP ITL](10-icinga-template-library.md#plugin-check-command-snmp) `CheckCommand` and just overrides the `snmp_oid` custom attribute. A service is created for all hosts which have the `snmp-community` custom attribute. apply Service "uptime" { import "generic-service" check_command = "snmp" vars.snmp_oid = "1.3.6.1.2.1.1.3.0" vars.snmp_miblist = "DISMAN-EVENT-MIB" assign where host.vars.snmp_community != "" } Additional SNMP plugins are available using the [Manubulon SNMP Plugins](10-icinga-template-library.md#snmp-manubulon-plugin-check-commands). If no `snmp_miblist` is specified, the plugin will default to `ALL`. As the number of available MIB files on the system increases so will the load generated by this plugin if no `MIB` is specified. As such, it is recommended to always specify at least one `MIB`. ## SSH Calling a plugin using the SSH protocol to execute a plugin on the remote server fetching its return code and output. The `by_ssh` command object is part of the built-in templates and requires the `check_by_ssh` check plugin which is available in the [Monitoring Plugins package](02-getting-started.md#setting-up-check-plugins). object CheckCommand "by_ssh_swap" { import "by_ssh" vars.by_ssh_command = "/usr/lib/nagios/plugins/check_swap -w $by_ssh_swap_warn$ -c $by_ssh_swap_crit$" vars.by_ssh_swap_warn = "75%" vars.by_ssh_swap_crit = "50%" } object Service "swap" { import "generic-service" host_name = "remote-ssh-host" check_command = "by_ssh_swap" vars.by_ssh_logname = "icinga" } ## NSClient++ [NSClient++](https://nsclient.org/) works on both Windows and Linux platforms and is well known for its magnificent Windows support. There are alternatives like the WMI interface, but using `NSClient++` will allow you to run local scripts similar to check plugins fetching the required output and performance counters. You can use the `check_nt` plugin from the Monitoring Plugins project to query NSClient++. Icinga 2 provides the [nscp check command](10-icinga-template-library.md#plugin-check-command-nscp) for this: Example: object Service "disk" { import "generic-service" host_name = "remote-windows-host" check_command = "nscp" vars.nscp_variable = "USEDDISKSPACE" vars.nscp_params = "c" vars.nscp_warn = 70 vars.nscp_crit = 80 } For details on the `NSClient++` configuration please refer to the [official documentation](https://docs.nsclient.org/). ## NSCA-NG [NSCA-ng](http://www.nsca-ng.org) provides a client-server pair that allows the remote sender to push check results into the Icinga 2 `ExternalCommandListener` feature. > **Note** > > This addon works in a similar fashion like the Icinga 1.x distributed model. If you > are looking for a real distributed architecture with Icinga 2, scroll down. ## NRPE [NRPE](https://docs.icinga.com/latest/en/nrpe.html) runs as daemon on the remote client including the required plugins and command definitions. Icinga 2 calls the `check_nrpe` plugin binary in order to query the configured command on the remote client. > **Note** > > The NRPE protocol is considered insecure and has multiple flaws in its > design. Upstream is not willing to fix these issues. > > In order to stay safe, please use the native [Icinga 2 client](06-distributed-monitoring.md#distributed-monitoring) > instead. The NRPE daemon uses its own configuration format in nrpe.cfg while `check_nrpe` can be embedded into the Icinga 2 `CheckCommand` configuration syntax. You can use the `check_nrpe` plugin from the NRPE project to query the NRPE daemon. Icinga 2 provides the [nrpe check command](10-icinga-template-library.md#plugin-check-command-nrpe) for this: Example: object Service "users" { import "generic-service" host_name = "remote-nrpe-host" check_command = "nrpe" vars.nrpe_command = "check_users" } nrpe.cfg: command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10 If you are planning to pass arguments to NRPE using the `-a` command line parameter, make sure that your NRPE daemon has them supported and enabled. > **Note** > > Enabling command arguments in NRPE is considered harmful > and exposes a security risk allowing attackers to execute > commands remotely. Details at [seclists.org](http://seclists.org/fulldisclosure/2014/Apr/240). The plugin check command `nrpe` provides the `nrpe_arguments` custom attribute which expects either a single value or an array of values. Example: object Service "nrpe-disk-/" { import "generic-service" host_name = "remote-nrpe-host" check_command = "nrpe" vars.nrpe_command = "check_disk" vars.nrpe_arguments = [ "20%", "10%", "/" ] } Icinga 2 will execute the nrpe plugin like this: /usr/lib/nagios/plugins/check_nrpe -H -c 'check_disk' -a '20%' '10%' '/' NRPE expects all additional arguments in an ordered fashion and interprets the first value as `$ARG1$` macro, the second value as `$ARG2$`, and so on. nrpe.cfg: command[check_disk]=/usr/local/icinga/libexec/check_disk -w $ARG1$ -c $ARG2$ -p $ARG3$ Using the above example with `nrpe_arguments` the command executed by the NRPE daemon looks similar to that: /usr/local/icinga/libexec/check_disk -w 20% -c 10% -p / You can pass arguments in a similar manner to [NSClient++](07-agent-based-monitoring.md#agent-based-checks-nsclient) when using its NRPE supported check method. ## Passive Check Results and SNMP Traps SNMP Traps can be received and filtered by using [SNMPTT](http://snmptt.sourceforge.net/) and specific trap handlers passing the check results to Icinga 2. Following the SNMPTT [Format](http://snmptt.sourceforge.net/docs/snmptt.shtml#SNMPTT.CONF-FORMAT) documentation and the Icinga external command syntax found [here](24-appendix.md#external-commands-list-detail) we can create generic services that can accommodate any number of hosts for a given scenario. ### Simple SNMP Traps A simple example might be monitoring host reboots indicated by an SNMP agent reset. Building the event to auto reset after dispatching a notification is important. Setup the manual check parameters to reset the event from an initial unhandled state or from a missed reset event. Add a directive in `snmptt.conf` EVENT coldStart .1.3.6.1.6.3.1.1.5.1 "Status Events" Normal FORMAT Device reinitialized (coldStart) EXEC echo "[$@] PROCESS_SERVICE_CHECK_RESULT;$A;Coldstart;2;The snmp agent has reinitialized." >> /var/run/icinga2/cmd/icinga2.cmd SDESC A coldStart trap signifies that the SNMPv2 entity, acting in an agent role, is reinitializing itself and that its configuration may have been altered. EDESC 1. Define the `EVENT` as per your need. 2. Construct the `EXEC` statement with the service name matching your template applied to your _n_ hosts. The host address inferred by SNMPTT will be the correlating factor. You can have snmptt provide host names or ip addresses to match your Icinga convention. Add an `EventCommand` configuration object for the passive service auto reset event. object EventCommand "coldstart-reset-event" { command = [ SysconfDir + "/icinga2/conf.d/custom/scripts/coldstart_reset_event.sh" ] arguments = { "-i" = "$service.state_id$" "-n" = "$host.name$" "-s" = "$service.name$" } } Create the `coldstart_reset_event.sh` shell script to pass the expanded variable data in. The `$service.state_id$` is important in order to prevent an endless loop of event firing after the service has been reset. #!/bin/bash SERVICE_STATE_ID="" HOST_NAME="" SERVICE_NAME="" show_help() { cat <<-EOF Usage: ${0##*/} [-h] -n HOST_NAME -s SERVICE_NAME Writes a coldstart reset event to the Icinga command pipe. -h Display this help and exit. -i SERVICE_STATE_ID The associated service state id. -n HOST_NAME The associated host name. -s SERVICE_NAME The associated service name. EOF } while getopts "hi:n:s:" opt; do case "$opt" in h) show_help exit 0 ;; i) SERVICE_STATE_ID=$OPTARG ;; n) HOST_NAME=$OPTARG ;; s) SERVICE_NAME=$OPTARG ;; '?') show_help exit 0 ;; esac done if [ -z "$SERVICE_STATE_ID" ]; then show_help printf "\n Error: -i required.\n" exit 1 fi if [ -z "$HOST_NAME" ]; then show_help printf "\n Error: -n required.\n" exit 1 fi if [ -z "$SERVICE_NAME" ]; then show_help printf "\n Error: -s required.\n" exit 1 fi if [ "$SERVICE_STATE_ID" -gt 0 ]; then echo "[`date +%s`] PROCESS_SERVICE_CHECK_RESULT;$HOST_NAME;$SERVICE_NAME;0;Auto-reset (`date +"%m-%d-%Y %T"`)." >> /var/run/icinga2/cmd/icinga2.cmd fi Finally create the `Service` and assign it: apply Service "Coldstart" { import "generic-service-custom" check_command = "dummy" event_command = "coldstart-reset-event" enable_notifications = 1 enable_active_checks = 0 enable_passive_checks = 1 enable_flapping = 0 volatile = 1 enable_perfdata = 0 vars.dummy_state = 0 vars.dummy_text = "Manual reset." vars.sla = "24x7" assign where (host.vars.os == "Linux" || host.vars.os == "Windows") } ### Complex SNMP Traps A more complex example might be passing dynamic data from a traps varbind list for a backup scenario where the backup software dispatches status updates. By utilizing active and passive checks, the older freshness concept can be leveraged. By defining the active check as a hard failed state, a missed backup can be reported. As long as the most recent passive update has occurred, the active check is bypassed. Add a directive in `snmptt.conf` EVENT enterpriseSpecific "Status Events" Normal FORMAT Enterprise specific trap EXEC echo "[$@] PROCESS_SERVICE_CHECK_RESULT;$A;$1;$2;$3" >> /var/run/icinga2/cmd/icinga2.cmd SDESC An enterprise specific trap. The varbinds in order denote the Icinga service name, state and text. EDESC 1. Define the `EVENT` as per your need using your actual oid. 2. The service name, state and text are extracted from the first three varbinds. This has the advantage of accommodating an unlimited set of use cases. Create a `Service` for the specific use case associated to the host. If the host matches and the first varbind value is `Backup`, SNMPTT will submit the corresponding passive update with the state and text from the second and third varbind: object Service "Backup" { import "generic-service-custom" host_name = "host.domain.com" check_command = "dummy" enable_notifications = 1 enable_active_checks = 1 enable_passive_checks = 1 enable_flapping = 0 volatile = 1 max_check_attempts = 1 check_interval = 87000 enable_perfdata = 0 vars.sla = "24x7" vars.dummy_state = 2 vars.dummy_text = "No passive check result received." } icinga2-2.8.1/doc/08-advanced-topics.md000066400000000000000000001242111322762156600174310ustar00rootroot00000000000000# Advanced Topics This chapter covers a number of advanced topics. If you're new to Icinga, you can safely skip over things you're not interested in. ## Downtimes Downtimes can be scheduled for planned server maintenance or any other targeted service outage you are aware of in advance. Downtimes will suppress any notifications, and may trigger other downtimes too. If the downtime was set by accident, or the duration exceeds the maintenance, you can manually cancel the downtime. Planned downtimes will also be taken into account for SLA reporting tools calculating the SLAs based on the state and downtime history. Multiple downtimes for a single object may overlap. This is useful when you want to extend your maintenance window taking longer than expected. If there are multiple downtimes triggered for one object, the overall downtime depth will be greater than `1`. If the downtime was scheduled after the problem changed to a critical hard state triggering a problem notification, and the service recovers during the downtime window, the recovery notification won't be suppressed. ### Fixed and Flexible Downtimes A `fixed` downtime will be activated at the defined start time, and removed at the end time. During this time window the service state will change to `NOT-OK` and then actually trigger the downtime. Notifications are suppressed and the downtime depth is incremented. Common scenarios are a planned distribution upgrade on your linux servers, or database updates in your warehouse. The customer knows about a fixed downtime window between 23:00 and 24:00. After 24:00 all problems should be alerted again. Solution is simple - schedule a `fixed` downtime starting at 23:00 and ending at 24:00. Unlike a `fixed` downtime, a `flexible` downtime will be triggered by the state change in the time span defined by start and end time, and then last for the specified duration in minutes. Imagine the following scenario: Your service is frequently polled by users trying to grab free deleted domains for immediate registration. Between 07:30 and 08:00 the impact will hit for 15 minutes and generate a network outage visible to the monitoring. The service is still alive, but answering too slow to Icinga 2 service checks. For that reason, you may want to schedule a downtime between 07:30 and 08:00 with a duration of 15 minutes. The downtime will then last from its trigger time until the duration is over. After that, the downtime is removed (may happen before or after the actual end time!). ### Scheduling a downtime You can schedule a downtime either by using the Icinga 2 API action [schedule-downtime](12-icinga2-api.md#icinga2-api-actions-schedule-downtime) or by sending an [external command](14-features.md#external-commands). #### Fixed Downtime If the host/service changes into a NOT-OK state between the start and end time window, the downtime will be marked as `in effect` and increases the downtime depth counter. ``` | | | start | end trigger time ``` #### Flexible Downtime A flexible downtime defines a time window where the downtime may be triggered from a host/service NOT-OK state change. It will then last until the specified time duration is reached. That way it can happen that the downtime end time is already gone, but the downtime ends at `trigger time + duration`. ``` | | | start | end actual end time |--------------duration--------| trigger time ``` ### Triggered Downtimes This is optional when scheduling a downtime. If there is already a downtime scheduled for a future maintenance, the current downtime can be triggered by that downtime. This renders useful if you have scheduled a host downtime and are now scheduling a child host's downtime getting triggered by the parent downtime on `NOT-OK` state change. ### Recurring Downtimes [ScheduledDowntime objects](09-object-types.md#objecttype-scheduleddowntime) can be used to set up recurring downtimes for services. Example: apply ScheduledDowntime "backup-downtime" to Service { author = "icingaadmin" comment = "Scheduled downtime for backup" ranges = { monday = "02:00-03:00" tuesday = "02:00-03:00" wednesday = "02:00-03:00" thursday = "02:00-03:00" friday = "02:00-03:00" saturday = "02:00-03:00" sunday = "02:00-03:00" } assign where "backup" in service.groups } ## Comments Comments can be added at runtime and are persistent over restarts. You can add useful information for others on repeating incidents (for example "last time syslog at 100% cpu on 17.10.2013 due to stale nfs mount") which is primarily accessible using web interfaces. You can add a comment either by using the Icinga 2 API action [add-comment](12-icinga2-api.md#icinga2-api-actions-add-comment) or by sending an [external command](14-features.md#external-commands). ## Acknowledgements If a problem persists and notifications have been sent, you can acknowledge the problem. That way other users will get a notification that you're aware of the issue and probably are already working on a fix. Note: Acknowledgements also add a new [comment](08-advanced-topics.md#comments-intro) which contains the author and text fields. You can send an acknowledgement either by using the Icinga 2 API action [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) or by sending an [external command](14-features.md#external-commands). ### Sticky Acknowledgements The acknowledgement is removed if a state change occurs or if the host/service recovers (OK/Up state). If you acknowledge a problem once you've received a `Critical` notification, the acknowledgement will be removed if there is a state transition to `Warning`. ``` OK -> WARNING -> CRITICAL -> WARNING -> OK ``` If you prefer to keep the acknowledgement until the problem is resolved (`OK` recovery) you need to enable the `sticky` parameter. ### Expiring Acknowledgements Once a problem is acknowledged it may disappear from your `handled problems` dashboard and no-one ever looks at it again since it will suppress notifications too. This `fire-and-forget` action is quite common. If you're sure that a current problem should be resolved in the future at a defined time, you can define an expiration time when acknowledging the problem. Icinga 2 will clear the acknowledgement when expired and start to re-notify, if the problem persists. ## Time Periods [Time Periods](09-object-types.md#objecttype-timeperiod) define time ranges in Icinga where event actions are triggered, for example whether a service check is executed or not within the `check_period` attribute. Or a notification should be sent to users or not, filtered by the `period` and `notification_period` configuration attributes for `Notification` and `User` objects. > **Note** > > If you are familiar with Icinga 1.x, these time period definitions > are called `legacy timeperiods` in Icinga 2. > > An Icinga 2 legacy timeperiod requires the `ITL` provided template >`legacy-timeperiod`. The `TimePeriod` attribute `ranges` may contain multiple directives, including weekdays, days of the month, and calendar dates. These types may overlap/override other types in your ranges dictionary. The descending order of precedence is as follows: * Calendar date (2008-01-01) * Specific month date (January 1st) * Generic month date (Day 15) * Offset weekday of specific month (2nd Tuesday in December) * Offset weekday (3rd Monday) * Normal weekday (Tuesday) If you don't set any `check_period` or `notification_period` attribute on your configuration objects, Icinga 2 assumes `24x7` as time period as shown below. object TimePeriod "24x7" { import "legacy-timeperiod" display_name = "Icinga 2 24x7 TimePeriod" ranges = { "monday" = "00:00-24:00" "tuesday" = "00:00-24:00" "wednesday" = "00:00-24:00" "thursday" = "00:00-24:00" "friday" = "00:00-24:00" "saturday" = "00:00-24:00" "sunday" = "00:00-24:00" } } If your operation staff should only be notified during workhours, create a new timeperiod named `workhours` defining a work day from 09:00 to 17:00. object TimePeriod "workhours" { import "legacy-timeperiod" display_name = "Icinga 2 8x5 TimePeriod" ranges = { "monday" = "09:00-17:00" "tuesday" = "09:00-17:00" "wednesday" = "09:00-17:00" "thursday" = "09:00-17:00" "friday" = "09:00-17:00" } } Furthermore if you wish to specify a notification period across midnight, you can define it the following way: object Timeperiod "across-midnight" { import "legacy-timeperiod" display_name = "Nightly Notification" ranges = { "saturday" = "22:00-24:00" "sunday" = "00:00-03:00" } } Below you can see another example for configuring timeperiods across several days, weeks or months. This can be useful when taking components offline for a distinct period of time. object Timeperiod "standby" { import "legacy-timeperiod" display_name = "Standby" ranges = { "2016-09-30 - 2016-10-30" = "00:00-24:00" } } Please note that the spaces before and after the dash are mandatory. Once your time period is configured you can Use the `period` attribute to assign time periods to `Notification` and `Dependency` objects: object Notification "mail" { import "generic-notification" host_name = "localhost" command = "mail-notification" users = [ "icingaadmin" ] period = "workhours" } ### Time Periods Inclusion and Exclusion Sometimes it is necessary to exclude certain time ranges from your default time period definitions, for example, if you don't want to send out any notification during the holiday season, or if you only want to allow small time windows for executed checks. The [TimePeriod object](09-object-types.md#objecttype-timeperiod) provides the `includes` and `excludes` attributes to solve this issue. `prefer_includes` defines whether included or excluded time periods are preferred. The following example defines a time period called `holidays` where notifications should be suppressed: object TimePeriod "holidays" { import "legacy-timeperiod" ranges = { "january 1" = "00:00-24:00" //new year's day "july 4" = "00:00-24:00" //independence day "december 25" = "00:00-24:00" //christmas "december 31" = "18:00-24:00" //new year's eve (6pm+) "2017-04-16" = "00:00-24:00" //easter 2017 "monday -1 may" = "00:00-24:00" //memorial day (last monday in may) "monday 1 september" = "00:00-24:00" //labor day (1st monday in september) "thursday 4 november" = "00:00-24:00" //thanksgiving (4th thursday in november) } } In addition to that the time period `weekends` defines an additional time window which should be excluded from notifications: object TimePeriod "weekends-excluded" { import "legacy-timeperiod" ranges = { "saturday" = "00:00-09:00,18:00-24:00" "sunday" = "00:00-09:00,18:00-24:00" } } The time period `prod-notification` defines the default time ranges and adds the excluded time period names as an array. object TimePeriod "prod-notification" { import "legacy-timeperiod" excludes = [ "holidays", "weekends-excluded" ] ranges = { "monday" = "00:00-24:00" "tuesday" = "00:00-24:00" "wednesday" = "00:00-24:00" "thursday" = "00:00-24:00" "friday" = "00:00-24:00" "saturday" = "00:00-24:00" "sunday" = "00:00-24:00" } } ## External Check Results Hosts or services which do not actively execute a check plugin to receive the state and output are called "passive checks" or "external check results". In this scenario an external client or script is sending in check results. You can feed check results into Icinga 2 with the following transport methods: * [process-check-result action](12-icinga2-api.md#icinga2-api-actions-process-check-result) available with the [REST API](12-icinga2-api.md#icinga2-api) (remote and local) * External command sent via command pipe (local only) Each time a new check result is received, the next expected check time is updated. This means that if there are no check result received from the external source, Icinga 2 will execute [freshness checks](08-advanced-topics.md#check-result-freshness). > **Note** > > The REST API action allows to specify the `check_source` attribute > which helps identifying the external sender. This is also visible > in Icinga Web 2 and the REST API queries. ## Check Result Freshness In Icinga 2 active check freshness is enabled by default. It is determined by the `check_interval` attribute and no incoming check results in that period of time. The threshold is calculated based on the last check execution time for actively executed checks: (last check execution time + check interval) > current time If this host/service receives check results from an [external source](08-advanced-topics.md#external-check-results), the threshold is based on the last time a check result was received: (last check result time + check interval) > current time If the freshness checks fail, Icinga 2 will execute the defined check command. Best practice is to define a [dummy](10-icinga-template-library.md#plugin-check-command-dummy) `check_command` which gets executed when freshness checks fail. ``` apply Service "external-check" { check_command = "dummy" check_interval = 1m /* Set the state to UNKNOWN (3) if freshness checks fail. */ vars.dummy_state = 3 /* Use a runtime function to retrieve the last check time and more details. */ vars.dummy_text = {{ var service = get_service(macro("$host.name$"), macro("$service.name$")) var lastCheck = DateTime(service.last_check).to_string() return "No check results received. Last result time: " + lastCheck }} assign where "external" in host.vars.services } ``` References: [get_service](18-library-reference.md#objref-get_service), [macro](18-library-reference.md#scoped-functions-macro), [DateTime](18-library-reference.md#datetime-type). Example output in Icinga Web 2: ![Icinga 2 Freshness Checks](images/advanced-topics/icinga2_external_checks_freshness_icingaweb2.png) ## Check Flapping Icinga 2 supports optional detection of hosts and services that are "flapping". Flapping occurs when a service or host changes state too frequently, which would result in a storm of problem and recovery notifications. With flapping detection enabled a flapping notification will be sent while other notifications are suppresed until it calms down after receiving the same status from checks a few times. Flapping detection can help detect configuration problems (wrong thresholds), troublesome services, or network problems. Flapping detection can be enabled or disabled using the `enable_flapping` attribute. The `flapping_threshold_high` and `flapping_threshold_low` attributes allows to specify the thresholds that control when a [host](09-object-types.md#objecttype-host) or [service](objecttype-service) is considered to be flapping. The default thresholds are 30% for high and 25% for low. If the computed flapping value exceeds the high threshold a host or service is considered flapping until it drops below the low flapping threshold. `FlappingStart` and `FlappingEnd` notifications will be sent out accordingly, if configured. See the chapter on [notifications](alert-notifications) for details > Note: There is no distinctions between hard and soft states with flapping. All state changes count and notifications > will be sent out regardless of the objects state. ### How it works Icinga 2 saves the last 20 state changes for every host and service. See the graphic below: ![Icinga 2 Flapping State Timeline](images/advanced-topics/flapping-state-graph.png) All the states ware weighted, with the most recent one being worth the most (1.15) and the 20th the least (0.8). The states in between are fairly distributed. The final flapping value are the weighted state changes divided by the total count of 20. In the example above, the added states would have a total value of 7.82 (`0.84 + 0.86 + 0.88 + 0.9 + 0.98 + 1.06 + 1.12 + 1.18`). This yields a flapping percentage of 39.1% (`7.82 / 20 * 100`). As the default upper flapping threshold is 30%, it would be considered flapping. If the next seven check results then would not be state changes, the flapping percentage would fall below the lower threshold of 25% and therefore the host or service would recover from flapping. ## Volatile Services By default all services remain in a non-volatile state. When a problem occurs, the `SOFT` state applies and once `max_check_attempts` attribute is reached with the check counter, a `HARD` state transition happens. Notifications are only triggered by `HARD` state changes and are then re-sent defined by the `interval` attribute. It may be reasonable to have a volatile service which stays in a `HARD` state type if the service stays in a `NOT-OK` state. That way each service recheck will automatically trigger a notification unless the service is acknowledged or in a scheduled downtime. ## Monitoring Icinga 2 Why should you do that? Icinga and its components run like any other service application on your server. There are predictable issues such as "disk space is running low" and your monitoring suffers from just that. You would also like to ensure that features and backends are running and storing required data. Be it the database backend where Icinga Web 2 presents fancy dashboards, forwarded metrics to Graphite or InfluxDB or the entire distributed setup. This list isn't complete but should help with your own setup. Windows client specific checks are highlighted. Type | Description | Plugins and CheckCommands ----------------|-------------------------------|----------------------------------------------------- System | Filesystem | [disk](10-icinga-template-library.md#plugin-check-command-disk), [disk-windows](10-icinga-template-library.md#windows-plugins) (Windows Client) System | Memory, Swap | [mem](10-icinga-template-library.md#plugin-contrib-command-mem), [swap](10-icinga-template-library.md#plugin-check-command-swap), [memory](10-icinga-template-library.md#windows-plugins) (Windows Client) System | Hardware | [hpasm](10-icinga-template-library.md#plugin-contrib-command-hpasm), [ipmi-sensor](10-icinga-template-library.md#plugin-contrib-command-ipmi-sensor) System | Virtualization | [VMware](10-icinga-template-library.md#plugin-contrib-vmware), [esxi_hardware](10-icinga-template-library.md#plugin-contrib-command-esxi-hardware) System | Processes | [procs](10-icinga-template-library.md#plugin-check-command-processes), [service-windows](10-icinga-template-library.md#windows-plugins) (Windows Client) System | System Activity Reports | [check_sar_perf](https://github.com/dnsmichi/icinga-plugins/blob/master/scripts/check_sar_perf.py) System | I/O | [iostat](10-icinga-template-library.md#plugin-contrib-command-iostat) System | Network interfaces | [nwc_health](10-icinga-template-library.md#plugin-contrib-command-nwc_health), [interfaces](10-icinga-template-library.md#plugin-contrib-command-interfaces) System | Users | [users](10-icinga-template-library.md#plugin-check-command-users), [users-windows](10-icinga-template-library.md#windows-plugins) (Windows Client) System | Logs | Forward them to [Elastic Stack](14-features.md#elastic-stack-integration) or [Graylog](14-features.md#graylog-integration) and add your own alerts. System | NTP | [ntp_time](10-icinga-template-library.md#plugin-check-command-ntp-time) System | Updates | [apt](10-icinga-template-library.md#plugin-check-command-apt), [yum](10-icinga-template-library.md#plugin-contrib-command-yum) Icinga | Status & Stats | [icinga](10-icinga-template-library.md#itl-icinga) (more below) Icinga | Cluster & Clients | [health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks) Database | MySQL | [mysql_health](10-icinga-template-library.md#plugin-contrib-command-mysql_health) Database | PostgreSQL | [postgres](10-icinga-template-library.md#plugin-contrib-command-postgres) Database | Housekeeping | Check the database size and growth and analyse metrics to examine trends. Database | DB IDO | [ido](10-icinga-template-library.md#itl-icinga-ido) (more below) Webserver | Apache2, Nginx, etc. | [http](10-icinga-template-library.md#plugin-check-command-http), [apache_status](10-icinga-template-library.md#plugin-contrib-command-apache_status), [nginx_status](10-icinga-template-library.md#plugin-contrib-command-nginx_status) Webserver | Certificates | [http](10-icinga-template-library.md#plugin-check-command-http) Webserver | Authorization | [http](10-icinga-template-library.md#plugin-check-command-http) Notifications | Mail (queue) | [smtp](10-icinga-template-library.md#plugin-check-command-smtp), [mailq](10-icinga-template-library.md#plugin-check-command-mailq) Notifications | SMS (GSM modem) | [check_sms3_status](https://exchange.icinga.com/netways/check_sms3status) Notifications | Messengers, Cloud services | XMPP, Twitter, IRC, Telegram, PagerDuty, VictorOps, etc. Metrics | PNP, RRDTool | [check_pnp_rrds](https://github.com/lingej/pnp4nagios/tree/master/scripts) checks for stale RRD files. Metrics | Graphite | [graphite](10-icinga-template-library.md#plugin-contrib-command-graphite) Metrics | InfluxDB | [check_influxdb](https://exchange.icinga.com/Mikanoshi/InfluxDB+data+monitoring+plugin) Metrics | Elastic Stack | [elasticsearch](10-icinga-template-library.md#plugin-contrib-command-elasticsearch), [Elastic Stack integration](14-features.md#elastic-stack-integration) Metrics | Graylog | [Graylog integration](14-features.md#graylog-integration) The [icinga](10-icinga-template-library.md#itl-icinga) CheckCommand provides metrics for the runtime stats of Icinga 2. You can forward them to your preferred graphing solution. If you require more metrics you can also query the [REST API](12-icinga2-api.md#icinga2-api) and write your own custom check plugin. Or you keep using the built-in [object accessor functions](08-advanced-topics.md#access-object-attributes-at-runtime) to calculate stats in-memory. There is a built-in [ido](10-icinga-template-library.md#itl-icinga-ido) check available for DB IDO MySQL/PostgreSQL which provides additional metrics for the IDO database. ``` apply Service "ido-mysql" { check_command = "ido" vars.ido_type = "IdoMysqlConnection" vars.ido_name = "ido-mysql" //the name defined in /etc/icinga2/features-enabled/ido-mysql.conf assign where match("master*.localdomain", host.name) } ``` More specific database queries can be found in the [DB IDO](14-features.md#db-ido) chapter. Distributed setups should include specific [health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks). You might also want to add additional checks for SSL certificate expiration. ## Advanced Configuration Hints ### Advanced Use of Apply Rules [Apply rules](03-monitoring-basics.md#using-apply) can be used to create a rule set which is entirely based on host objects and their attributes. In addition to that [apply for and custom attribute override](03-monitoring-basics.md#using-apply-for) extend the possibilities. The following example defines a dictionary on the host object which contains configuration attributes for multiple web servers. This then used to add three checks: * A `ping4` check using the local IP `address` of the web server. * A `tcp` check querying the TCP port where the HTTP service is running on. * If the `url` key is defined, the third apply for rule will create service objects using the `http` CheckCommand. In addition to that you can optionally define the `ssl` attribute which enables HTTPS checks. Host definition: object Host "webserver01" { import "generic-host" address = "192.168.56.200" vars.os = "Linux" vars.webserver = { instance["status"] = { address = "192.168.56.201" port = "80" url = "/status" } instance["tomcat"] = { address = "192.168.56.202" port = "8080" } instance["icingaweb2"] = { address = "192.168.56.210" port = "443" url = "/icingaweb2" ssl = true } } } Service apply for definitions: apply Service "webserver_ping" for (instance => config in host.vars.webserver.instance) { display_name = "webserver_" + instance check_command = "ping4" vars.ping_address = config.address assign where host.vars.webserver.instance } apply Service "webserver_port" for (instance => config in host.vars.webserver.instance) { display_name = "webserver_" + instance + "_" + config.port check_command = "tcp" vars.tcp_address = config.address vars.tcp_port = config.port assign where host.vars.webserver.instance } apply Service "webserver_url" for (instance => config in host.vars.webserver.instance) { display_name = "webserver_" + instance + "_" + config.url check_command = "http" vars.http_address = config.address vars.http_port = config.port vars.http_uri = config.url if (config.ssl) { vars.http_ssl = config.ssl } assign where config.url != "" } The variables defined in the host dictionary are not using the typical custom attribute prefix recommended for CheckCommand parameters. Instead they are re-used for multiple service checks in this example. In addition to defining check parameters this way, you can also enrich the `display_name` attribute with more details. This will be shown in in Icinga Web 2 for example. ### Use Functions in Object Configuration There is a limited scope where functions can be used as object attributes such as: * As value for [Custom Attributes](03-monitoring-basics.md#custom-attributes-functions) * Returning boolean expressions for [set_if](08-advanced-topics.md#use-functions-command-arguments-setif) inside command arguments * Returning a [command](08-advanced-topics.md#use-functions-command-attribute) array inside command objects The other way around you can create objects dynamically using your own global functions. > **Note** > > Functions called inside command objects share the same global scope as runtime macros. > Therefore you can access host custom attributes like `host.vars.os`, or any other > object attribute from inside the function definition used for [set_if](08-advanced-topics.md#use-functions-command-arguments-setif) or [command](08-advanced-topics.md#use-functions-command-attribute). Tips when implementing functions: * Use [log()](18-library-reference.md#global-functions-log) to dump variables. You can see the output inside the `icinga2.log` file depending in your log severity * Use the `icinga2 console` to test basic functionality (e.g. iterating over a dictionary) * Build them step-by-step. You can always refactor your code later on. #### Use Functions in Command Arguments set_if The `set_if` attribute inside the command arguments definition in the [CheckCommand object definition](09-object-types.md#objecttype-checkcommand) is primarily used to evaluate whether the command parameter should be set or not. By default you can evaluate runtime macros for their existence. If the result is not an empty string, the command parameter is passed. This becomes fairly complicated when want to evaluate multiple conditions and attributes. The following example was found on the community support channels. The user had defined a host dictionary named `compellent` with the key `disks`. This was then used inside service apply for rules. object Host "dict-host" { check_command = "check_compellent" vars.compellent["disks"] = { file = "/var/lib/check_compellent/san_disks.0.json", checks = ["disks"] } } The more significant problem was to only add the command parameter `--disk` to the plugin call when the dictionary `compellent` contains the key `disks`, and omit it if not found. By defining `set_if` as [abbreviated lambda function](17-language-reference.md#nullary-lambdas) and evaluating the host custom attribute `compellent` containing the `disks` this problem was solved like this: object CheckCommand "check_compellent" { command = [ "/usr/bin/check_compellent" ] arguments = { "--disks" = { set_if = {{ var host_vars = host.vars log(host_vars) var compel = host_vars.compellent log(compel) compel.contains("disks") }} } } } This implementation uses the dictionary type method [contains](18-library-reference.md#dictionary-contains) and will fail if `host.vars.compellent` is not of the type `Dictionary`. Therefore you can extend the checks using the [typeof](17-language-reference.md#types) function. You can test the types using the `icinga2 console`: # icinga2 console Icinga (version: v2.3.0-193-g3eb55ad) <1> => srv_vars.compellent["check_a"] = { file="outfile_a.json", checks = [ "disks", "fans" ] } null <2> => srv_vars.compellent["check_b"] = { file="outfile_b.json", checks = [ "power", "voltages" ] } null <3> => typeof(srv_vars.compellent) type 'Dictionary' <4> => The more programmatic approach for `set_if` could look like this: "--disks" = { set_if = {{ var srv_vars = service.vars if(len(srv_vars) > 0) { if (typeof(srv_vars.compellent) == Dictionary) { return srv_vars.compellent.contains("disks") } else { log(LogInformationen, "checkcommand set_if", "custom attribute compellent_checks is not a dictionary, ignoring it.") return false } } else { log(LogWarning, "checkcommand set_if", "empty custom attributes") return false } }} } #### Use Functions as Command Attribute This comes in handy for [NotificationCommands](09-object-types.md#objecttype-notificationcommand) or [EventCommands](09-object-types.md#objecttype-eventcommand) which does not require a returned checkresult including state/output. The following example was taken from the community support channels. The requirement was to specify a custom attribute inside the notification apply rule and decide which notification script to call based on that. object User "short-dummy" { } object UserGroup "short-dummy-group" { assign where user.name == "short-dummy" } apply Notification "mail-admins-short" to Host { import "mail-host-notification" command = "mail-host-notification-test" user_groups = [ "short-dummy-group" ] vars.short = true assign where host.vars.notification.mail } The solution is fairly simple: The `command` attribute is implemented as function returning an array required by the caller Icinga 2. The local variable `mailscript` sets the default value for the notification scrip location. If the notification custom attribute `short` is set, it will override the local variable `mailscript` with a new value. The `mailscript` variable is then used to compute the final notification command array being returned. You can omit the `log()` calls, they only help debugging. object NotificationCommand "mail-host-notification-test" { command = {{ log("command as function") var mailscript = "mail-host-notification-long.sh" if (notification.vars.short) { mailscript = "mail-host-notification-short.sh" } log("Running command") log(mailscript) var cmd = [ SysconfDir + "/icinga2/scripts/" + mailscript ] log(LogCritical, "me", cmd) return cmd }} env = { } } #### Use Custom Functions as Attribute To use custom functions as attributes, the function must be defined in a slightly unexpected way. The following example shows how to assign values depending on group membership. All hosts in the `slow-lan` host group use 300 as value for `ping_wrta`, all other hosts use 100. globals.group_specific_value = function(group, group_value, non_group_value) { return function() use (group, group_value, non_group_value) { if (group in host.groups) { return group_value } else { return non_group_value } } } apply Service "ping4" { import "generic-service" check_command = "ping4" vars.ping_wrta = group_specific_value("slow-lan", 300, 100) vars.ping_crta = group_specific_value("slow-lan", 500, 200) assign where true } #### Use Functions in Assign Where Expressions If a simple expression for matching a name or checking if an item exists in an array or dictionary does not fit, you should consider writing your own global [functions](17-language-reference.md#functions). You can call them inside `assign where` and `ignore where` expressions for [apply rules](03-monitoring-basics.md#using-apply-expressions) or [group assignments](03-monitoring-basics.md#group-assign-intro) just like any other global functions for example [match](18-library-reference.md#global-functions-match). The following example requires the host `myprinter` being added to the host group `printers-lexmark` but only if the host uses a template matching the name `lexmark*`. template Host "lexmark-printer-host" { vars.printer_type = "Lexmark" } object Host "myprinter" { import "generic-host" import "lexmark-printer-host" address = "192.168.1.1" } /* register a global function for the assign where call */ globals.check_host_templates = function(host, search) { /* iterate over all host templates and check if the search matches */ for (tmpl in host.templates) { if (match(search, tmpl)) { return true } } /* nothing matched */ return false } object HostGroup "printers-lexmark" { display_name = "Lexmark Printers" /* call the global function and pass the arguments */ assign where check_host_templates(host, "lexmark*") } Take a different more complex example: All hosts with the custom attribute `vars_app` as nested dictionary should be added to the host group `ABAP-app-server`. But only if the `app_type` for all entries is set to `ABAP`. It could read as wildcard match for nested dictionaries: where host.vars.vars_app["*"].app_type == "ABAP" The solution for this problem is to register a global function which checks the `app_type` for all hosts with the `vars_app` dictionary. object Host "appserver01" { check_command = "dummy" vars.vars_app["ABC"] = { app_type = "ABAP" } } object Host "appserver02" { check_command = "dummy" vars.vars_app["DEF"] = { app_type = "ABAP" } } globals.check_app_type = function(host, type) { /* ensure that other hosts without the custom attribute do not match */ if (typeof(host.vars.vars_app) != Dictionary) { return false } /* iterate over the vars_app dictionary */ for (key => val in host.vars.vars_app) { /* if the value is a dictionary and if contains the app_type being the requested type */ if (typeof(val) == Dictionary && val.app_type == type) { return true } } /* nothing matched */ return false } object HostGroup "ABAP-app-server" { assign where check_app_type(host, "ABAP") } ### Access Object Attributes at Runtime The [Object Accessor Functions](18-library-reference.md#object-accessor-functions) can be used to retrieve references to other objects by name. This allows you to access configuration and runtime object attributes. A detailed list can be found [here](09-object-types.md#object-types). #### Access Object Attributes at Runtime: Cluster Check This is a simple cluster example for accessing two host object states and calculating a virtual cluster state and output: ``` object Host "cluster-host-01" { check_command = "dummy" vars.dummy_state = 2 vars.dummy_text = "This host is down." } object Host "cluster-host-02" { check_command = "dummy" vars.dummy_state = 0 vars.dummy_text = "This host is up." } object Host "cluster" { check_command = "dummy" vars.cluster_nodes = [ "cluster-host-01", "cluster-host-02" ] vars.dummy_state = {{ var up_count = 0 var down_count = 0 var cluster_nodes = macro("$cluster_nodes$") for (node in cluster_nodes) { if (get_host(node).state > 0) { down_count += 1 } else { up_count += 1 } } if (up_count >= down_count) { return 0 //same up as down -> UP } else { return 2 //something is broken } }} vars.dummy_text = {{ var output = "Cluster hosts:\n" var cluster_nodes = macro("$cluster_nodes$") for (node in cluster_nodes) { output += node + ": " + get_host(node).last_check_result.output + "\n" } return output }} } ``` #### Time Dependent Thresholds The following example sets time dependent thresholds for the load check based on the current time of the day compared to the defined time period. ``` object TimePeriod "backup" { import "legacy-timeperiod" ranges = { monday = "02:00-03:00" tuesday = "02:00-03:00" wednesday = "02:00-03:00" thursday = "02:00-03:00" friday = "02:00-03:00" saturday = "02:00-03:00" sunday = "02:00-03:00" } } object Host "webserver-with-backup" { check_command = "hostalive" address = "127.0.0.1" } object Service "webserver-backup-load" { check_command = "load" host_name = "webserver-with-backup" vars.load_wload1 = {{ if (get_time_period("backup").is_inside) { return 20 } else { return 5 } }} vars.load_cload1 = {{ if (get_time_period("backup").is_inside) { return 40 } else { return 10 } }} } ``` ## Advanced Value Types In addition to the default value types Icinga 2 also uses a few other types to represent its internal state. The following types are exposed via the [API](12-icinga2-api.md#icinga2-api). ### CheckResult Name | Type | Description --------------------------|-----------------------|---------------------------------- exit\_status | Number | The exit status returned by the check execution. output | String | The check output. performance\_data | Array | Array of [performance data values](08-advanced-topics.md#advanced-value-types-perfdatavalue). check\_source | String | Name of the node executing the check. state | Number | The current state (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN). command | Value | Array of command with shell-escaped arguments or command line string. execution\_start | Timestamp | Check execution start time (as a UNIX timestamp). execution\_end | Timestamp | Check execution end time (as a UNIX timestamp). schedule\_start | Timestamp | Scheduled check execution start time (as a UNIX timestamp). schedule\_end | Timestamp | Scheduled check execution end time (as a UNIX timestamp). active | Boolean | Whether the result is from an active or passive check. vars\_before | Dictionary | Internal attribute used for calculations. vars\_after | Dictionary | Internal attribute used for calculations. ### PerfdataValue Icinga 2 parses performance data strings returned by check plugins and makes the information available to external interfaces (e.g. [GraphiteWriter](09-object-types.md#objecttype-graphitewriter) or the [Icinga 2 API](12-icinga2-api.md#icinga2-api)). Name | Type | Description --------------------------|-----------------------|---------------------------------- label | String | Performance data label. value | Number | Normalized performance data value without unit. counter | Boolean | Enabled if the original value contains `c` as unit. Defaults to `false`. unit | String | Unit of measurement (`seconds`, `bytes`. `percent`) according to the [plugin API](05-service-monitoring.md#service-monitoring-plugin-api). crit | Value | Critical threshold value. warn | Value | Warning threshold value. min | Value | Minimum value returned by the check. max | Value | Maximum value returned by the check. icinga2-2.8.1/doc/09-object-types.md000066400000000000000000002702601322762156600170040ustar00rootroot00000000000000# Config Object Types This chapter provides an overview of all available config object types which can be instantiated using the `object` keyword. Additional details on configuration and runtime attributes and their description are explained here too. The attributes need to have a specific type value. Many of them are explained in [this chapter](03-monitoring-basics.md#attribute-value-types) already. You should note that the `Timestamp` type is a `Number`. In addition to that `Object name` is an object reference to an existing object name as `String` type. Configuration objects share these runtime attributes which cannot be modified by the user. You can access these attributes using the [Icinga 2 API](12-icinga2-api.md#icinga2-api-config-objects). Name | Type | Description --------------------------|-----------------------|---------------------------------- version | Number | Timestamp when the object was created or modified. Synced throughout cluster nodes. type | String | Object type. original\_attributes | Dictionary | Original values of object attributes modified at runtime. active | Boolean | Object is active (e.g. a service being checked). paused | Boolean | Object has been paused at runtime (e.g. [IdoMysqlConnection](09-object-types.md#objecttype-idomysqlconnection). Defaults to `false`. templates | Array | Templates imported on object compilation. package | String | [Configuration package name](12-icinga2-api.md#icinga2-api-config-management) this object belongs to. Local configuration is set to `_etc`, runtime created objects use `_api`. source\_location | Dictionary | Location information where the configuration files are stored. ## ApiListener ApiListener objects are used for distributed monitoring setups and API usage specifying the certificate files used for ssl authorization and additional restrictions. This configuration object is available as [api feature](11-cli-commands.md#cli-command-feature). The `TicketSalt` constant must be defined in [constants.conf](04-configuring-icinga-2.md#constants-conf). Example: ``` object ApiListener "api" { accept_commands = true accept_config = true ticket_salt = TicketSalt } ``` Configuration Attributes: Name | Type | Description --------------------------------------|-----------------------|---------------------------------- cert\_path | String | **Deprecated.** Path to the public key. key\_path | String | **Deprecated.** Path to the private key. ca\_path | String | **Deprecated.** Path to the CA certificate file. ticket\_salt | String | **Optional.** Private key for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). **Required** for a signing master instance. crl\_path | String | **Optional.** Path to the CRL file. bind\_host | String | **Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`. bind\_port | Number | **Optional.** The port the api listener should be bound to. Defaults to `5665`. accept\_config | Boolean | **Optional.** Accept zone configuration. Defaults to `false`. accept\_commands | Boolean | **Optional.** Accept remote commands. Defaults to `false`. cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL`. tls\_protocolmin | String | **Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`. access\_control\_allow\_origin | Array | **Optional.** Specifies an array of origin URLs that may access the API. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin) access\_control\_allow\_credentials | Boolean | **Optional.** Indicates whether or not the actual request can be made using credentials. Defaults to `true`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Credentials) access\_control\_allow\_headers | String | **Optional.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers) access\_control\_allow\_methods | String | **Optional.** Used in response to a preflight request to indicate which HTTP methods can be used when making the actual request. Defaults to `GET, POST, PUT, DELETE`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Methods) The ApiListener type expects its certificate files to be in the following locations: Type | Location ---------------------|------------------------------------- Private key | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"` Certificate file | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"` CA certificate file | `LocalStateDir + "/lib/icinga2/certs/ca.crt"` If the deprecated attributes `cert_path`, `key_path` and/or `ca_path` are specified Icinga 2 copies those files to the new location in `LocalStateDir + "/lib/icinga2/certs"` unless the file(s) there are newer. Please check the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) for more details. While Icinga 2 and the underlying OpenSSL library use sane and secure defaults, the attributes `cipher_list` and `tls_protocolmin` can be used to increase communication security. A good source for a more secure configuration is provided by the [Mozilla Wiki](https://wiki.mozilla.org/Security/Server_Side_TLS). Ensure to use the same configuration for both attributes on **all** endpoints to avoid communication problems which requires to use `cipher_list` compatible with the endpoint using the oldest version of the OpenSSL library. If using other tools to connect to the API ensure also compatibility with them as this setting affects not only inter-cluster communcation but also the REST API. ## ApiUser ApiUser objects are used for authentication against the [Icinga 2 API](12-icinga2-api.md#icinga2-api-authentication). Example: ``` object ApiUser "root" { password = "mysecretapipassword" permissions = [ "*" ] } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- password | String | **Optional.** Password string. Note: This attribute is hidden in API responses. client\_cn | String | **Optional.** Client Common Name (CN). permissions | Array | **Required.** Array of permissions. Either as string or dictionary with the keys `permission` and `filter`. The latter must be specified as function. Available permissions are explained in the [API permissions](12-icinga2-api.md#icinga2-api-permissions) chapter. ## CheckCommand A check command definition. Additional default command custom attributes can be defined here. > **Note** > > Icinga 2 versions < 2.6.0 require the import of the [plugin-check-command](10-icinga-template-library.md#itl-plugin-check-command) template. Example: ``` object CheckCommand "http" { command = [ PluginDir + "/check_http" ] arguments = { "-H" = "$http_vhost$" "-I" = "$http_address$" "-u" = "$http_uri$" "-p" = "$http_port$" "-S" = { set_if = "$http_ssl$" } "--sni" = { set_if = "$http_sni$" } "-a" = { value = "$http_auth_pair$" description = "Username:password on sites with basic authentication" } "--no-body" = { set_if = "$http_ignore_body$" } "-r" = "$http_expect_body_regex$" "-w" = "$http_warn_time$" "-c" = "$http_critical_time$" "-e" = "$http_expect$" } vars.http_address = "$address$" vars.http_ssl = false vars.http_sni = false } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- command | Array | **Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. When using the "arguments" attribute this must be an array. Can be specified as function for advanced implementations. env | Dictionary | **Optional.** A dictionary of macros which should be exported as environment variables prior to executing the command. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this command. timeout | Duration | **Optional.** The command timeout in seconds. Defaults to `1m`. arguments | Dictionary | **Optional.** A dictionary of command arguments. ### CheckCommand Arguments Command arguments can be defined as key-value-pairs in the `arguments` dictionary. If the argument requires additional configuration, for example a `description` attribute or an optional condition, the value can be defined as dictionary specifying additional options. Service: ``` vars.x_val = "My command argument value." vars.have_x = "true" ``` CheckCommand: ``` arguments = { "-X" = { value = "$x_val$" key = "-Xnew" /* optional, set a new key identifier */ description = "My plugin requires this argument for doing X." required = false /* optional, no error if not set */ skip_key = false /* always use "-X " */ set_if = "$have_x$" /* only set if variable defined and resolves to a numeric value. String values are not supported */ order = -1 /* first position */ repeat_key = true /* if `value` is an array, repeat the key as parameter: ... 'key' 'value[0]' 'key' 'value[1]' 'key' 'value[2]' ... */ } "-Y" = { value = "$y_val$" description = "My plugin requires this argument for doing Y." required = false /* optional, no error if not set */ skip_key = true /* don't prefix "-Y" only use "" */ set_if = "$have_y$" /* only set if variable defined and resolves to a numeric value. String values are not supported */ order = 0 /* second position */ repeat_key = false /* if `value` is an array, do not repeat the key as parameter: ... 'key' 'value[0]' 'value[1]' 'value[2]' ... */ } } ``` Name | Type | Description --------------------------|-----------------------|---------------------------------- value | String/Function | Optional argument value set by a [runtime macro string](03-monitoring-basics.md#runtime-macros) or a [function call](17-language-reference.md#functions). key | String | Optional argument key overriding the key identifier. description | String | Optional argument description. required | Boolean | Required argument. Execution error if not set. Defaults to false (optional). skip\_key | Boolean | Use the value as argument and skip the key. set\_if | String/Function | Argument is added if the [runtime macro string](03-monitoring-basics.md#runtime-macros) resolves to a defined numeric or boolean value. String values are not supported. [Function calls](17-language-reference.md#functions) returning a value are supported too. order | Number | Set if multiple arguments require a defined argument order. repeat\_key | Boolean | If the argument value is an array, repeat the argument key, or not. Defaults to true (repeat). Argument order: ``` ..., -3, -2, -1, , 1, 2, 3, ... ``` Argument array with `repeat_key = true`: ``` 'key' 'value[0]' 'key' 'value[1]' 'key' 'value[2]' ``` Argument array with `repeat_key = false`: ``` 'key' 'value[0]' 'value[1]' 'value[2]' ``` ## CheckerComponent The checker component is responsible for scheduling active checks. This configuration object is available as [checker feature](11-cli-commands.md#cli-command-feature). Example: ``` library "checker" object CheckerComponent "checker" { concurrent_checks = 512 } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- concurrent\_checks | Number | **Optional.** The maximum number of concurrent checks. Defaults to 512. ## CheckResultReader Reads Icinga 1.x check result files from a directory. This functionality is provided to help existing Icinga 1.x users and might be useful for migration scenarios. Example: ``` library "compat" object CheckResultReader "reader" { spool_dir = "/data/check-results" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- spool\_dir | String | **Optional.** The directory which contains the check result files. Defaults to LocalStateDir + "/lib/icinga2/spool/checkresults/". ## Comment Comments created at runtime are represented as objects. Note: This is for reference only. You can create comments with the [add-comment](12-icinga2-api.md#icinga2-api-actions-add-comment) API action. Example: ``` object Comment "localhost!my-comment" { host_name = "localhost" author = "icingaadmin" text = "This is a comment." } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host\_name | Object name | **Required.** The name of the host this comment belongs to. service\_name | Object name | **Optional.** The short name of the service this comment belongs to. If omitted, this comment object is treated as host comment. author | String | **Required.** The author's name. text | String | **Required.** The comment text. entry\_time | Timestamp | **Optional.** The UNIX timestamp when this comment was added. entry\_type | Number | **Optional.** The comment type (`User` = 1, `Downtime` = 2, `Flapping` = 3, `Acknowledgement` = 4). expire\_time | Timestamp | **Optional.** The comment's expire time as UNIX timestamp. persistent | Boolean | **Optional.** Only evaluated for `entry_type` Acknowledgement. `true` does not remove the comment when the acknowledgement is removed. ## CompatLogger Writes log files in a format that's compatible with Icinga 1.x. This configuration object is available as [compatlog feature](14-features.md#compat-logging). Example: ``` library "compat" object CompatLogger "compatlog" { log_dir = "/var/log/icinga2/compat" rotation_method = "DAILY" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- log\_dir | String | **Optional.** Path to the compat log directory. Defaults to LocalStateDir + "/log/icinga2/compat". rotation\_method | String | **Optional.** Specifies when to rotate log files. Can be one of "HOURLY", "DAILY", "WEEKLY" or "MONTHLY". Defaults to "HOURLY". ## Dependency Dependency objects are used to specify dependencies between hosts and services. Dependencies can be defined as Host-to-Host, Service-to-Service, Service-to-Host, or Host-to-Service relations. > **Best Practice** > > Rather than creating a `Dependency` object for a specific host or service it is usually easier > to just create a `Dependency` template and use the `apply` keyword to assign the > dependency to a number of hosts or services. Use the `to` keyword to set the specific target > type for `Host` or `Service`. > Check the [dependencies](03-monitoring-basics.md#dependencies) chapter for detailed examples. Service-to-Service Example: ``` object Dependency "webserver-internet" { parent_host_name = "internet" parent_service_name = "ping4" child_host_name = "webserver" child_service_name = "ping4" states = [ OK, Warning ] disable_checks = true } ``` Host-to-Host Example: ``` object Dependency "webserver-internet" { parent_host_name = "internet" child_host_name = "webserver" states = [ Up ] disable_checks = true } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- parent\_host\_name | Object name | **Required.** The parent host. parent\_service\_name | Object name | **Optional.** The parent service. If omitted, this dependency object is treated as host dependency. child\_host\_name | Object name | **Required.** The child host. child\_service\_name | Object name | **Optional.** The child service. If omitted, this dependency object is treated as host dependency. disable\_checks | Boolean | **Optional.** Whether to disable checks when this dependency fails. Defaults to false. disable\_notifications | Boolean | **Optional.** Whether to disable notifications when this dependency fails. Defaults to true. ignore\_soft\_states | Boolean | **Optional.** Whether to ignore soft states for the reachability calculation. Defaults to true. period | Object name | **Optional.** Time period object during which this dependency is enabled. states | Array | **Optional.** A list of state filters when this dependency should be OK. Defaults to [ OK, Warning ] for services and [ Up ] for hosts. Available state filters: OK Warning Critical Unknown Up Down When using [apply rules](03-monitoring-basics.md#using-apply) for dependencies, you can leave out certain attributes which will be automatically determined by Icinga 2. Service-to-Host Dependency Example: ``` apply Dependency "internet" to Service { parent_host_name = "dsl-router" disable_checks = true assign where host.name != "dsl-router" } ``` This example sets all service objects matching the assign condition into a dependency relation to the parent host object `dsl-router` as implicit child services. Service-to-Service-on-the-same-Host Dependency Example: ``` apply Dependency "disable-agent-checks" to Service { parent_service_name = "agent-health" assign where service.check_command == "ssh" ignore where service.name == "agent-health" } ``` This example omits the `parent_host_name` attribute and Icinga 2 automatically sets its value to the name of the host object matched by the apply rule condition. All services where apply matches are made implicit child services in this dependency relation. Dependency objects have composite names, i.e. their names are based on the `child_host_name` and `child_service_name` attributes and the name you specified. This means you can define more than one object with the same (short) name as long as one of the `child_host_name` and `child_service_name` attributes has a different value. ## Downtime Downtimes created at runtime are represented as objects. You can create downtimes with the [schedule-downtime](12-icinga2-api.md#icinga2-api-actions-schedule-downtime) API action. Example: ``` object Downtime "my-downtime" { host_name = "localhost" author = "icingaadmin" comment = "This is a downtime." start_time = 1505312869 end_time = 1505312924 } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host\_name | Object name | **Required.** The name of the host this comment belongs to. service\_name | Object name | **Optional.** The short name of the service this comment belongs to. If omitted, this comment object is treated as host comment. author | String | **Required.** The author's name. comment | String | **Required.** The comment text. start\_time | Timestamp | **Required.** The start time as UNIX timestamp. end\_time | Timestamp | **Required.** The end time as UNIX timestamp. duration | Number | **Optional.** The duration as number. entry\_time | Timestamp | **Optional.** The UNIX timestamp when this downtime was added. fixed | Boolean | **Optional.** Whether the downtime is fixed (true) or flexible (false). Defaults to flexible. Details in the [advanced topics chapter](08-advanced-topics.md#fixed-flexible-downtimes). triggers | Array of object names | **Optional.** List of downtimes which should be triggered by this downtime. Runtime Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- trigger\_time | Timestamp | The UNIX timestamp when this downtime was triggered. triggered\_by | Object name | The name of the downtime this downtime was triggered by. ## ElasticsearchWriter Writes check result metrics and performance data to an Elasticsearch instance. This configuration object is available as [elasticsearch feature](14-features.md#elasticsearch-writer). Example: ``` library "perfdata" object ElasticsearchWriter "elasticsearch" { host = "127.0.0.1" port = 9200 index = "icinga2" enable_send_perfdata = true flush_threshold = 1024 flush_interval = 10 } ``` The index is rotated daily, as is recommended by Elastic, meaning the index will be renamed to `$index-$d.$M.$y`. Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Required.** Elasticsearch host address. Defaults to `127.0.0.1`. port | Number | **Required.** Elasticsearch port. Defaults to `9200`. index | String | **Required.** Elasticsearch index name. Defaults to `icinga2`. enable\_send\_perfdata | Boolean | **Optional.** Send parsed performance data metrics for check results. Defaults to `false`. flush\_interval | Duration | **Optional.** How long to buffer data points before transferring to Elasticsearch. Defaults to `10s`. flush\_threshold | Number | **Optional.** How many data points to buffer before forcing a transfer to Elasticsearch. Defaults to `1024`. username | String | **Optional.** Basic auth username if Elasticsearch is hidden behind an HTTP proxy. password | String | **Optional.** Basic auth password if Elasticsearch is hidden behind an HTTP proxy. enable\_tls | Boolean | **Optional.** Whether to use a TLS stream. Defaults to `false`. Requires an HTTP proxy. ca\_path | String | **Optional.** Path to CA certificate to validate the remote host. Requires `enable_tls` set to `true`. cert\_path | String | **Optional.** Path to host certificate to present to the remote host for mutual verification. Requires `enable_tls` set to `true`. key\_path | String | **Optional.** Path to host key to accompany the cert\_path. Requires `enable_tls` set to `true`. Note: If `flush_threshold` is set too low, this will force the feature to flush all data to Elasticsearch too often. Experiment with the setting, if you are processing more than 1024 metrics per second or similar. Basic auth is supported with the `username` and `password` attributes. This requires an HTTP proxy (Nginx, etc.) in front of the Elasticsearch instance. Check [this blogpost](https://blog.netways.de/2017/09/14/secure-elasticsearch-and-kibana-with-an-nginx-http-proxy/) for an example. TLS for the HTTP proxy can be enabled with `enable_tls`. In addition to that you can specify the certificates with the `ca_path`, `cert_path` and `cert_key` attributes. ## Endpoint Endpoint objects are used to specify connection information for remote Icinga 2 instances. More details can be found in the [distributed monitoring chapter](06-distributed-monitoring.md#distributed-monitoring). Example: ``` object Endpoint "icinga2-client1.localdomain" { host = "192.168.56.111" port = 5665 log_duration = 1d } ``` Example (disable replay log): ``` object Endpoint "icinga2-client1.localdomain" { host = "192.168.5.111" port = 5665 log_duration = 0 } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** The hostname/IP address of the remote Icinga 2 instance. port | Number | **Optional.** The service name/port of the remote Icinga 2 instance. Defaults to `5665`. log\_duration | Duration | **Optional.** Duration for keeping replay logs on connection loss. Defaults to `1d` (86400 seconds). Attribute is specified in seconds. If log_duration is set to 0, replaying logs is disabled. You could also specify the value in human readable format like `10m` for 10 minutes or `1h` for one hour. Endpoint objects cannot currently be created with the API. ## EventCommand An event command definition. > **Note** > > Icinga 2 versions < 2.6.0 require the import of the [plugin-event-command](10-icinga-template-library.md#itl-plugin-event-command) template. Example: ``` object EventCommand "restart-httpd-event" { command = "/opt/bin/restart-httpd.sh" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- command | Array | **Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. When using the "arguments" attribute this must be an array. Can be specified as function for advanced implementations. env | Dictionary | **Optional.** A dictionary of macros which should be exported as environment variables prior to executing the command. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this command. timeout | Duration | **Optional.** The command timeout in seconds. Defaults to `1m`. arguments | Dictionary | **Optional.** A dictionary of command arguments. Command arguments can be used the same way as for [CheckCommand objects](09-object-types.md#objecttype-checkcommand-arguments). More advanced examples for event command usage can be found [here](03-monitoring-basics.md#event-commands). ## ExternalCommandListener Implements the Icinga 1.x command pipe which can be used to send commands to Icinga. This configuration object is available as [command feature](14-features.md#external-commands). Example: ``` library "compat" object ExternalCommandListener "command" { command_path = "/var/run/icinga2/cmd/icinga2.cmd" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- command\_path | String | **Optional.** Path to the command pipe. Defaults to RunDir + "/icinga2/cmd/icinga2.cmd". ## FileLogger Specifies Icinga 2 logging to a file. This configuration object is available as `mainlog` and `debuglog` [logging feature](14-features.md#logging). Example: ``` object FileLogger "debug-file" { severity = "debug" path = "/var/log/icinga2/debug.log" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- path | String | **Required.** The log path. severity | String | **Optional.** The minimum severity for this log. Can be "debug", "notice", "information", "warning" or "critical". Defaults to "information". ## GelfWriter Writes event log entries to a defined GELF receiver host (Graylog, Logstash). This configuration object is available as [gelf feature](14-features.md#gelfwriter). Example: ``` library "perfdata" object GelfWriter "gelf" { host = "127.0.0.1" port = 12201 } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** GELF receiver host address. Defaults to `127.0.0.1`. port | Number | **Optional.** GELF receiver port. Defaults to `12201`. source | String | **Optional.** Source name for this instance. Defaults to `icinga2`. enable\_send\_perfdata | Boolean | **Optional.** Enable performance data for 'CHECK RESULT' events. ## GraphiteWriter Writes check result metrics and performance data to a defined Graphite Carbon host. This configuration object is available as [graphite feature](14-features.md#graphite-carbon-cache-writer). Example: ``` library "perfdata" object GraphiteWriter "graphite" { host = "127.0.0.1" port = 2003 } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** Graphite Carbon host address. Defaults to `127.0.0.1`. port | Number | **Optional.** Graphite Carbon port. Defaults to `2003`. host\_name\_template | String | **Optional.** Metric prefix for host name. Defaults to `icinga2.$host.name$.host.$host.check_command$`. service\_name\_template | String | **Optional.** Metric prefix for service name. Defaults to `icinga2.$host.name$.services.$service.name$.$service.check_command$`. enable\_send\_thresholds | Boolean | **Optional.** Send additional threshold metrics. Defaults to `false`. enable\_send\_metadata | Boolean | **Optional.** Send additional metadata metrics. Defaults to `false`. Additional usage examples can be found [here](14-features.md#graphite-carbon-cache-writer). ## Host A host. Example: ``` object Host "icinga2-client1.localdomain" { display_name = "Linux Client 1" address = "192.168.56.111" address6 = "2a00:1450:4001:815::2003" groups = [ "linux-servers" ] check_command = "hostalive" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the host (e.g. displayed by external interfaces instead of the name if set). address | String | **Optional.** The host's IPv4 address. Available as command runtime macro `$address$` if set. address6 | String | **Optional.** The host's IPv6 address. Available as command runtime macro `$address6$` if set. groups | Array of object names | **Optional.** A list of host groups this host belongs to. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this host. check\_command | Object name | **Required.** The name of the check command. max\_check\_attempts | Number | **Optional.** The number of times a host is re-checked before changing into a hard state. Defaults to 3. check\_period | Object name | **Optional.** The name of a time period which determines when this host should be checked. Not set by default. check\_timeout | Duration | **Optional.** Check command timeout in seconds. Overrides the CheckCommand's `timeout` attribute. check\_interval | Duration | **Optional.** The check interval (in seconds). This interval is used for checks when the host is in a `HARD` state. Defaults to `5m`. retry\_interval | Duration | **Optional.** The retry interval (in seconds). This interval is used for checks when the host is in a `SOFT` state. Defaults to `1m`. enable\_notifications | Boolean | **Optional.** Whether notifications are enabled. Defaults to true. enable\_active\_checks | Boolean | **Optional.** Whether active checks are enabled. Defaults to true. enable\_passive\_checks | Boolean | **Optional.** Whether passive checks are enabled. Defaults to true. enable\_event\_handler | Boolean | **Optional.** Enables event handlers for this host. Defaults to true. enable\_flapping | Boolean | **Optional.** Whether flap detection is enabled. Defaults to false. enable\_perfdata | Boolean | **Optional.** Whether performance data processing is enabled. Defaults to true. event\_command | Object name | **Optional.** The name of an event command that should be executed every time the host's state changes or the host is in a `SOFT` state. flapping\_threshold\_high | Number | **Optional.** Flapping upper bound in percent for a host to be considered flapping. Default `30.0` flapping\_threshold\_low | Number | **Optional.** Flapping lower bound in percent for a host to be considered not flapping. Default `25.0` volatile | Boolean | **Optional.** The volatile setting enables always `HARD` state types if `NOT-OK` state changes occur. Defaults to false. zone | Object name | **Optional.** The zone this object is a member of. Please read the [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) chapter for details. command\_endpoint | Object name | **Optional.** The endpoint where commands are executed on. notes | String | **Optional.** Notes for the host. notes\_url | String | **Optional.** URL for notes for the host (for example, in notification commands). action\_url | String | **Optional.** URL for actions for the host (for example, an external graphing tool). icon\_image | String | **Optional.** Icon image for the host. Used by external interfaces only. icon\_image\_alt | String | **Optional.** Icon image description for the host. Used by external interface only. The actual check interval might deviate slightly from the configured values due to the fact that Icinga tries to evenly distribute all checks over a certain period of time, i.e. to avoid load spikes. > **Best Practice** > > The `address` and `address6` attributes are required for running commands using > the `$address$` and `$address6$` runtime macros. Runtime Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- next\_check | Timestamp | When the next check occurs (as a UNIX timestamp). last\_check | Timestamp | When the last check occurred (as a UNIX timestamp). check\_attempt | Number | The current check attempt number. state\_type | Number | The current state type (0 = SOFT, 1 = HARD). last\_state\_type | Number | The previous state type (0 = SOFT, 1 = HARD). last\_reachable | Boolean | Whether the host was reachable when the last check occurred. last\_check\_result | CheckResult | The current [check result](08-advanced-topics.md#advanced-value-types-checkresult). last\_state\_change | Timestamp | When the last state change occurred (as a UNIX timestamp). last\_hard\_state\_change | Timestamp | When the last hard state change occurred (as a UNIX timestamp). last\_in\_downtime | Boolean | Whether the host was in a downtime when the last check occurred. acknowledgement | Number | The acknowledgement type (0 = NONE, 1 = NORMAL, 2 = STICKY). acknowledgement\_expiry | Timestamp | When the acknowledgement expires (as a UNIX timestamp; 0 = no expiry). downtime\_depth | Number | Whether the host has one or more active downtimes. flapping\_last\_change | Timestamp | When the last flapping change occurred (as a UNIX timestamp). flapping | Boolean | Whether the host is flapping between states. flapping\_current | Number | Current flapping value in percent (see flapping\_thresholds) state | Number | The current state (0 = UP, 1 = DOWN). last\_state | Number | The previous state (0 = UP, 1 = DOWN). last\_hard\_state | Number | The last hard state (0 = UP, 1 = DOWN). last\_state\_up | Timestamp | When the last UP state occurred (as a UNIX timestamp). last\_state\_down | Timestamp | When the last DOWN state occurred (as a UNIX timestamp). ## HostGroup A group of hosts. > **Best Practice** > > Assign host group members using the [group assign](17-language-reference.md#group-assign) rules. Example: ``` object HostGroup "linux-servers" { display_name = "Linux Servers" assign where host.vars.os == "Linux" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the host group. groups | Array of object names | **Optional.** An array of nested group names. ## IcingaApplication The IcingaApplication object is required to start Icinga 2. The object name must be `app`. If the object configuration is missing, Icinga 2 will automatically create an IcingaApplication object. Example: ``` object IcingaApplication "app" { enable_perfdata = false } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- enable\_notifications | Boolean | **Optional.** Whether notifications are globally enabled. Defaults to true. enable\_event\_handlers | Boolean | **Optional.** Whether event handlers are globally enabled. Defaults to true. enable\_flapping | Boolean | **Optional.** Whether flap detection is globally enabled. Defaults to true. enable\_host\_checks | Boolean | **Optional.** Whether active host checks are globally enabled. Defaults to true. enable\_service\_checks | Boolean | **Optional.** Whether active service checks are globally enabled. Defaults to true. enable\_perfdata | Boolean | **Optional.** Whether performance data processing is globally enabled. Defaults to true. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are available globally. ## IdoMySqlConnection IDO database adapter for MySQL. This configuration object is available as [ido-mysql feature](14-features.md#db-ido). Example: ``` library "db_ido_mysql" object IdoMysqlConnection "mysql-ido" { host = "127.0.0.1" port = 3306 user = "icinga" password = "icinga" database = "icinga" cleanup = { downtimehistory_age = 48h contactnotifications_age = 31d } } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** MySQL database host address. Defaults to `localhost`. port | Number | **Optional.** MySQL database port. Defaults to `3306`. socket\_path | String | **Optional.** MySQL socket path. user | String | **Optional.** MySQL database user with read/write permission to the icinga database. Defaults to `icinga`. password | String | **Optional.** MySQL database user's password. Defaults to `icinga`. database | String | **Optional.** MySQL database name. Defaults to `icinga`. enable\_ssl | Boolean | **Optional.** Use SSL. Defaults to false. Change to `true` in case you want to use any of the SSL options. ssl\_key | String | **Optional.** MySQL SSL client key file path. ssl\_cert | String | **Optional.** MySQL SSL certificate file path. ssl\_ca | String | **Optional.** MySQL SSL certificate authority certificate file path. ssl\_capath | String | **Optional.** MySQL SSL trusted SSL CA certificates in PEM format directory path. ssl\_cipher | String | **Optional.** MySQL SSL list of allowed ciphers. table\_prefix | String | **Optional.** MySQL database table prefix. Defaults to `icinga_`. instance\_name | String | **Optional.** Unique identifier for the local Icinga 2 instance. Defaults to `default`. instance\_description | String | **Optional.** Description for the Icinga 2 instance. enable\_ha | Boolean | **Optional.** Enable the high availability functionality. Only valid in a [cluster setup](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido). Defaults to "true". failover\_timeout | Duration | **Optional.** Set the failover timeout in a [HA cluster](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido). Must not be lower than 60s. Defaults to `60s`. cleanup | Dictionary | **Optional.** Dictionary with items for historical table cleanup. categories | Array | **Optional.** Array of information types that should be written to the database. Cleanup Items: Name | Type | Description --------------------------------|-----------------------|---------------------------------- acknowledgements\_age | Duration | **Optional.** Max age for acknowledgements table rows (entry\_time). Defaults to 0 (never). commenthistory\_age | Duration | **Optional.** Max age for commenthistory table rows (entry\_time). Defaults to 0 (never). contactnotifications\_age | Duration | **Optional.** Max age for contactnotifications table rows (start\_time). Defaults to 0 (never). contactnotificationmethods\_age | Duration | **Optional.** Max age for contactnotificationmethods table rows (start\_time). Defaults to 0 (never). downtimehistory\_age | Duration | **Optional.** Max age for downtimehistory table rows (entry\_time). Defaults to 0 (never). eventhandlers\_age | Duration | **Optional.** Max age for eventhandlers table rows (start\_time). Defaults to 0 (never). externalcommands\_age | Duration | **Optional.** Max age for externalcommands table rows (entry\_time). Defaults to 0 (never). flappinghistory\_age | Duration | **Optional.** Max age for flappinghistory table rows (event\_time). Defaults to 0 (never). hostchecks\_age | Duration | **Optional.** Max age for hostalives table rows (start\_time). Defaults to 0 (never). logentries\_age | Duration | **Optional.** Max age for logentries table rows (logentry\_time). Defaults to 0 (never). notifications\_age | Duration | **Optional.** Max age for notifications table rows (start\_time). Defaults to 0 (never). processevents\_age | Duration | **Optional.** Max age for processevents table rows (event\_time). Defaults to 0 (never). statehistory\_age | Duration | **Optional.** Max age for statehistory table rows (state\_time). Defaults to 0 (never). servicechecks\_age | Duration | **Optional.** Max age for servicechecks table rows (start\_time). Defaults to 0 (never). systemcommands\_age | Duration | **Optional.** Max age for systemcommands table rows (start\_time). Defaults to 0 (never). Data Categories: Name | Description | Required by ---------------------|------------------------|-------------------- DbCatConfig | Configuration data | Icinga Web 2 DbCatState | Current state data | Icinga Web 2 DbCatAcknowledgement | Acknowledgements | Icinga Web 2 DbCatComment | Comments | Icinga Web 2 DbCatDowntime | Downtimes | Icinga Web 2 DbCatEventHandler | Event handler data | Icinga Web 2 DbCatExternalCommand | External commands | -- DbCatFlapping | Flap detection data | Icinga Web 2 DbCatCheck | Check results | -- DbCatLog | Log messages | -- DbCatNotification | Notifications | Icinga Web 2 DbCatProgramStatus | Program status data | Icinga Web 2 DbCatRetention | Retention data | Icinga Web 2 DbCatStateHistory | Historical state data | Icinga Web 2 The default value for `categories` includes everything required by Icinga Web 2 in the table above. In addition to the category flags listed above the `DbCatEverything` flag may be used as a shortcut for listing all flags. ## IdoPgsqlConnection IDO database adapter for PostgreSQL. This configuration object is available as [ido-pgsql feature](14-features.md#db-ido). Example: ``` library "db_ido_pgsql" object IdoPgsqlConnection "pgsql-ido" { host = "127.0.0.1" port = 5432 user = "icinga" password = "icinga" database = "icinga" cleanup = { downtimehistory_age = 48h contactnotifications_age = 31d } } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** PostgreSQL database host address. Defaults to `localhost`. port | Number | **Optional.** PostgreSQL database port. Defaults to `5432`. user | String | **Optional.** PostgreSQL database user with read/write permission to the icinga database. Defaults to `icinga`. password | String | **Optional.** PostgreSQL database user's password. Defaults to `icinga`. database | String | **Optional.** PostgreSQL database name. Defaults to `icinga`. table\_prefix | String | **Optional.** PostgreSQL database table prefix. Defaults to `icinga_`. instance\_name | String | **Optional.** Unique identifier for the local Icinga 2 instance. Defaults to `default`. instance\_description | String | **Optional.** Description for the Icinga 2 instance. enable\_ha | Boolean | **Optional.** Enable the high availability functionality. Only valid in a [cluster setup](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido). Defaults to "true". failover\_timeout | Duration | **Optional.** Set the failover timeout in a [HA cluster](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido). Must not be lower than 60s. Defaults to `60s`. cleanup | Dictionary | **Optional.** Dictionary with items for historical table cleanup. categories | Array | **Optional.** Array of information types that should be written to the database. Cleanup Items: Name | Type | Description --------------------------------|-----------------------|---------------------------------- acknowledgements\_age | Duration | **Optional.** Max age for acknowledgements table rows (entry\_time). Defaults to 0 (never). commenthistory\_age | Duration | **Optional.** Max age for commenthistory table rows (entry\_time). Defaults to 0 (never). contactnotifications\_age | Duration | **Optional.** Max age for contactnotifications table rows (start\_time). Defaults to 0 (never). contactnotificationmethods\_age | Duration | **Optional.** Max age for contactnotificationmethods table rows (start\_time). Defaults to 0 (never). downtimehistory\_age | Duration | **Optional.** Max age for downtimehistory table rows (entry\_time). Defaults to 0 (never). eventhandlers\_age | Duration | **Optional.** Max age for eventhandlers table rows (start\_time). Defaults to 0 (never). externalcommands\_age | Duration | **Optional.** Max age for externalcommands table rows (entry\_time). Defaults to 0 (never). flappinghistory\_age | Duration | **Optional.** Max age for flappinghistory table rows (event\_time). Defaults to 0 (never). hostchecks\_age | Duration | **Optional.** Max age for hostalives table rows (start\_time). Defaults to 0 (never). logentries\_age | Duration | **Optional.** Max age for logentries table rows (logentry\_time). Defaults to 0 (never). notifications\_age | Duration | **Optional.** Max age for notifications table rows (start\_time). Defaults to 0 (never). processevents\_age | Duration | **Optional.** Max age for processevents table rows (event\_time). Defaults to 0 (never). statehistory\_age | Duration | **Optional.** Max age for statehistory table rows (state\_time). Defaults to 0 (never). servicechecks\_age | Duration | **Optional.** Max age for servicechecks table rows (start\_time). Defaults to 0 (never). systemcommands\_age | Duration | **Optional.** Max age for systemcommands table rows (start\_time). Defaults to 0 (never). Data Categories: Name | Description | Required by ---------------------|------------------------|-------------------- DbCatConfig | Configuration data | Icinga Web 2 DbCatState | Current state data | Icinga Web 2 DbCatAcknowledgement | Acknowledgements | Icinga Web 2 DbCatComment | Comments | Icinga Web 2 DbCatDowntime | Downtimes | Icinga Web 2 DbCatEventHandler | Event handler data | Icinga Web 2 DbCatExternalCommand | External commands | -- DbCatFlapping | Flap detection data | Icinga Web 2 DbCatCheck | Check results | -- DbCatLog | Log messages | -- DbCatNotification | Notifications | Icinga Web 2 DbCatProgramStatus | Program status data | Icinga Web 2 DbCatRetention | Retention data | Icinga Web 2 DbCatStateHistory | Historical state data | Icinga Web 2 The default value for `categories` includes everything required by Icinga Web 2 in the table above. In addition to the category flags listed above the `DbCatEverything` flag may be used as a shortcut for listing all flags. ## InfluxdbWriter Writes check result metrics and performance data to a defined InfluxDB host. This configuration object is available as [influxdb feature](14-features.md#influxdb-writer). Example: ``` library "perfdata" object InfluxdbWriter "influxdb" { host = "127.0.0.1" port = 8086 database = "icinga2" flush_threshold = 1024 flush_interval = 10s host_template = { measurement = "$host.check_command$" tags = { hostname = "$host.name$" } } service_template = { measurement = "$service.check_command$" tags = { hostname = "$host.name$" service = "$service.name$" } } } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Required.** InfluxDB host address. Defaults to `127.0.0.1`. port | Number | **Required.** InfluxDB HTTP port. Defaults to `8086`. database | String | **Required.** InfluxDB database name. Defaults to `icinga2`. username | String | **Optional.** InfluxDB user name. Defaults to `none`. password | String | **Optional.** InfluxDB user password. Defaults to `none`. ssl\_enable | Boolean | **Optional.** Whether to use a TLS stream. Defaults to `false`. ssl\_ca\_cert | String | **Optional.** Path to CA certificate to validate the remote host. ssl\_cert | String | **Optional.** Path to host certificate to present to the remote host for mutual verification. ssl\_key | String | **Optional.** Path to host key to accompany the ssl\_cert. host\_template | String | **Required.** Host template to define the InfluxDB line protocol. service\_template | String | **Required.** Service template to define the influxDB line protocol. enable\_send\_thresholds | Boolean | **Optional.** Whether to send warn, crit, min & max tagged data. enable\_send\_metadata | Boolean | **Optional.** Whether to send check metadata e.g. states, execution time, latency etc. flush\_interval | Duration | **Optional.** How long to buffer data points before transferring to InfluxDB. Defaults to `10s`. flush\_threshold | Number | **Optional.** How many data points to buffer before forcing a transfer to InfluxDB. Defaults to `1024`. Note: If `flush_threshold` is set too low, this will always force the feature to flush all data to InfluxDB. Experiment with the setting, if you are processing more than 1024 metrics per second or similar. ## LiveStatusListener Livestatus API interface available as TCP or UNIX socket. Historical table queries require the [CompatLogger](09-object-types.md#objecttype-compatlogger) feature enabled pointing to the log files using the `compat_log_path` configuration attribute. This configuration object is available as [livestatus feature](14-features.md#setting-up-livestatus). Examples: ``` library "livestatus" object LivestatusListener "livestatus-tcp" { socket_type = "tcp" bind_host = "127.0.0.1" bind_port = "6558" } object LivestatusListener "livestatus-unix" { socket_type = "unix" socket_path = "/var/run/icinga2/cmd/livestatus" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- socket\_type | String | **Optional.** Specifies the socket type. Can be either `tcp` or `unix`. Defaults to `unix`. bind\_host | String | **Optional.** Only valid when `socket_type` is set to `tcp`. Host address to listen on for connections. Defaults to `127.0.0.1`. bind\_port | Number | **Optional.** Only valid when `socket_type` is set to `tcp`. Port to listen on for connections. Defaults to `6558`. socket\_path | String | **Optional.** Only valid when `socket_type` is set to `unix`. Specifies the path to the UNIX socket file. Defaults to RunDir + "/icinga2/cmd/livestatus". compat\_log\_path | String | **Optional.** Path to Icinga 1.x log files. Required for historical table queries. Requires `CompatLogger` feature enabled. Defaults to LocalStateDir + "/log/icinga2/compat" > **Note** > > UNIX sockets are not supported on Windows. ## Notification Notification objects are used to specify how users should be notified in case of host and service state changes and other events. > **Best Practice** > > Rather than creating a `Notification` object for a specific host or service it is > usually easier to just create a `Notification` template and use the `apply` keyword > to assign the notification to a number of hosts or services. Use the `to` keyword > to set the specific target type for `Host` or `Service`. > Check the [notifications](03-monitoring-basics.md#alert-notifications) chapter for detailed examples. Example: ``` object Notification "localhost-ping-notification" { host_name = "localhost" service_name = "ping4" command = "mail-notification" users = [ "user1", "user2" ] types = [ Problem, Recovery ] } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host\_name | Object name | **Required.** The name of the host this notification belongs to. service\_name | Object name | **Optional.** The short name of the service this notification belongs to. If omitted, this notification object is treated as host notification. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this notification object. users | Array of object names | **Optional.** A list of user names who should be notified. user\_groups | Array of object names | **Optional.** A list of user group names who should be notified. times | Dictionary | **Optional.** A dictionary containing `begin` and `end` attributes for the notification. command | Object name | **Required.** The name of the notification command which should be executed when the notification is triggered. interval | Duration | **Optional.** The notification interval (in seconds). This interval is used for active notifications. Defaults to 30 minutes. If set to 0, [re-notifications](03-monitoring-basics.md#disable-renotification) are disabled. period | Object name | **Optional.** The name of a time period which determines when this notification should be triggered. Not set by default. zone | Object name | **Optional.** The zone this object is a member of. Please read the [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) chapter for details. types | Array | **Optional.** A list of type filters when this notification should be triggered. By default everything is matched. states | Array | **Optional.** A list of state filters when this notification should be triggered. By default everything is matched. Available notification state filters for Service: OK Warning Critical Unknown Available notification state filters for Host: Up Down Available notification type filters: DowntimeStart DowntimeEnd DowntimeRemoved Custom Acknowledgement Problem Recovery FlappingStart FlappingEnd Runtime Attributes: Name | Type | Description ----------------------------|-----------------------|----------------- last\_notification | Timestamp | When the last notification was sent for this Notification object (as a UNIX timestamp). next\_notification | Timestamp | When the next notification is going to be sent for this assuming the associated host/service is still in a non-OK state (as a UNIX timestamp). notification\_number | Number | The notification number. last\_problem\_notification | Timestamp | When the last notification was sent for a problem (as a UNIX timestamp). ## NotificationCommand A notification command definition. > **Note** > > Icinga 2 versions < 2.6.0 require the import of the [plugin-notification-command](10-icinga-template-library.md#itl-plugin-notification-command) template. Example: ``` object NotificationCommand "mail-service-notification" { command = [ SysconfDir + "/icinga2/scripts/mail-service-notification.sh" ] arguments += { "-4" = { required = true value = "$notification_address$" } "-6" = "$notification_address6$" "-b" = "$notification_author$" "-c" = "$notification_comment$" "-d" = { required = true value = "$notification_date$" } "-e" = { required = true value = "$notification_servicename$" } "-f" = { value = "$notification_from$" description = "Set from address. Requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)" } "-i" = "$notification_icingaweb2url$" "-l" = { required = true value = "$notification_hostname$" } "-n" = { required = true value = "$notification_hostdisplayname$" } "-o" = { required = true value = "$notification_serviceoutput$" } "-r" = { required = true value = "$notification_useremail$" } "-s" = { required = true value = "$notification_servicestate$" } "-t" = { required = true value = "$notification_type$" } "-u" = { required = true value = "$notification_servicedisplayname$" } "-v" = "$notification_logtosyslog$" } vars += { notification_address = "$address$" notification_address6 = "$address6$" notification_author = "$notification.author$" notification_comment = "$notification.comment$" notification_type = "$notification.type$" notification_date = "$icinga.long_date_time$" notification_hostname = "$host.name$" notification_hostdisplayname = "$host.display_name$" notification_servicename = "$service.name$" notification_serviceoutput = "$service.output$" notification_servicestate = "$service.state$" notification_useremail = "$user.email$" notification_servicedisplayname = "$service.display_name$" } } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- command | Array | **Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. When using the "arguments" attribute this must be an array. Can be specified as function for advanced implementations. env | Dictionary | **Optional.** A dictionary of macros which should be exported as environment variables prior to executing the command. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this command. timeout | Duration | **Optional.** The command timeout in seconds. Defaults to `1m`. arguments | Dictionary | **Optional.** A dictionary of command arguments. Command arguments can be used the same way as for [CheckCommand objects](09-object-types.md#objecttype-checkcommand-arguments). More details on specific attributes can be found in [this chapter](03-monitoring-basics.md#notification-commands). ## NotificationComponent The notification component is responsible for sending notifications. This configuration object is available as [notification feature](11-cli-commands.md#cli-command-feature). Example: ``` library "notification" object NotificationComponent "notification" { } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- enable\_ha | Boolean | **Optional.** Enable the high availability functionality. Only valid in a [cluster setup](06-distributed-monitoring.md#distributed-monitoring-high-availability-notifications). Disabling this currently only affects reminder notifications. Defaults to "true". ## OpenTsdbWriter Writes check result metrics and performance data to [OpenTSDB](http://opentsdb.net). This configuration object is available as [opentsdb feature](14-features.md#opentsdb-writer). Example: ``` library "perfdata" object OpenTsdbWriter "opentsdb" { host = "127.0.0.1" port = 4242 ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host | String | **Optional.** OpenTSDB host address. Defaults to `127.0.0.1`. port | Number | **Optional.** OpenTSDB port. Defaults to `4242`. ## PerfdataWriter Writes check result performance data to a defined path using macro pattern consisting of custom attributes and runtime macros. This configuration object is available as [perfdata feature](14-features.md#writing-performance-data-files). Example: ``` library "perfdata" object PerfdataWriter "perfdata" { host_perfdata_path = "/var/spool/icinga2/perfdata/host-perfdata" service_perfdata_path = "/var/spool/icinga2/perfdata/service-perfdata" host_format_template = "DATATYPE::HOSTPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tHOSTPERFDATA::$host.perfdata$\tHOSTCHECKCOMMAND::$host.check_command$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$" service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tSERVICEDESC::$service.name$\tSERVICEPERFDATA::$service.perfdata$\tSERVICECHECKCOMMAND::$service.check_command$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$\tSERVICESTATE::$service.state$\tSERVICESTATETYPE::$service.state_type$" rotation_interval = 15s } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host\_perfdata\_path | String | **Optional.** Path to the host performance data file. Defaults to LocalStateDir + "/spool/icinga2/perfdata/host-perfdata". service\_perfdata\_path | String | **Optional.** Path to the service performance data file. Defaults to LocalStateDir + "/spool/icinga2/perfdata/service-perfdata". host\_temp\_path | String | **Optional.** Path to the temporary host file. Defaults to LocalStateDir + "/spool/icinga2/tmp/host-perfdata". service\_temp\_path | String | **Optional.** Path to the temporary service file. Defaults to LocalStateDir + "/spool/icinga2/tmp/service-perfdata". host\_format\_template | String | **Optional.** Host Format template for the performance data file. Defaults to a template that's suitable for use with PNP4Nagios. service\_format\_template | String | **Optional.** Service Format template for the performance data file. Defaults to a template that's suitable for use with PNP4Nagios. rotation\_interval | Duration | **Optional.** Rotation interval for the files specified in `{host,service}_perfdata_path`. Defaults to `30s`. When rotating the performance data file the current UNIX timestamp is appended to the path specified in `host_perfdata_path` and `service_perfdata_path` to generate a unique filename. ## ScheduledDowntime ScheduledDowntime objects can be used to set up recurring downtimes for hosts/services. > **Best Practice** > > Rather than creating a `ScheduledDowntime` object for a specific host or service it is usually easier > to just create a `ScheduledDowntime` template and use the `apply` keyword to assign the > scheduled downtime to a number of hosts or services. Use the `to` keyword to set the specific target > type for `Host` or `Service`. > Check the [recurring downtimes](08-advanced-topics.md#recurring-downtimes) example for details. Example: ``` object ScheduledDowntime "some-downtime" { host_name = "localhost" service_name = "ping4" author = "icingaadmin" comment = "Some comment" fixed = false duration = 30m ranges = { "sunday" = "02:00-03:00" } } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- host\_name | Object name | **Required.** The name of the host this scheduled downtime belongs to. service\_name | Object name | **Optional.** The short name of the service this scheduled downtime belongs to. If omitted, this downtime object is treated as host downtime. author | String | **Required.** The author of the downtime. comment | String | **Required.** A comment for the downtime. fixed | Boolean | **Optional.** Whether this is a fixed downtime. Defaults to `true`. duration | Duration | **Optional.** How long the downtime lasts. Only has an effect for flexible (non-fixed) downtimes. ranges | Dictionary | **Required.** A dictionary containing information which days and durations apply to this timeperiod. ScheduledDowntime objects have composite names, i.e. their names are based on the `host_name` and `service_name` attributes and the name you specified. This means you can define more than one object with the same (short) name as long as one of the `host_name` and `service_name` attributes has a different value. ## Service Service objects describe network services and how they should be checked by Icinga 2. > **Best Practice** > > Rather than creating a `Service` object for a specific host it is usually easier > to just create a `Service` template and use the `apply` keyword to assign the > service to a number of hosts. > Check the [apply](03-monitoring-basics.md#using-apply) chapter for details. Example: ``` object Service "uptime" { host_name = "localhost" display_name = "localhost Uptime" check_command = "snmp" vars.snmp_community = "public" vars.snmp_oid = "DISMAN-EVENT-MIB::sysUpTimeInstance" check_interval = 60s retry_interval = 15s groups = [ "all-services", "snmp" ] } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the service. host\_name | Object name | **Required.** The host this service belongs to. There must be a `Host` object with that name. groups | Array of object names | **Optional.** The service groups this service belongs to. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this service. check\_command | Object name | **Required.** The name of the check command. max\_check\_attempts | Number | **Optional.** The number of times a service is re-checked before changing into a hard state. Defaults to 3. check\_period | Object name | **Optional.** The name of a time period which determines when this service should be checked. Not set by default. check\_timeout | Duration | **Optional.** Check command timeout in seconds. Overrides the CheckCommand's `timeout` attribute. check\_interval | Duration | **Optional.** The check interval (in seconds). This interval is used for checks when the service is in a `HARD` state. Defaults to `5m`. retry\_interval | Duration | **Optional.** The retry interval (in seconds). This interval is used for checks when the service is in a `SOFT` state. Defaults to `1m`. enable\_notifications | Boolean | **Optional.** Whether notifications are enabled. Defaults to `true`. enable\_active\_checks | Boolean | **Optional.** Whether active checks are enabled. Defaults to `true`. enable\_passive\_checks | Boolean | **Optional.** Whether passive checks are enabled. Defaults to `true`. enable\_event\_handler | Boolean | **Optional.** Enables event handlers for this host. Defaults to `true`. enable\_flapping | Boolean | **Optional.** Whether flap detection is enabled. Defaults to `false`. flapping\_threshold\_high | Number | **Optional.** Flapping upper bound in percent for a service to be considered flapping. `30.0` flapping\_threshold\_low | Number | **Optional.** Flapping lower bound in percent for a service to be considered not flapping. `25.0` enable\_perfdata | Boolean | **Optional.** Whether performance data processing is enabled. Defaults to `true`. event\_command | Object name | **Optional.** The name of an event command that should be executed every time the service's state changes or the service is in a `SOFT` state. volatile | Boolean | **Optional.** The volatile setting enables always `HARD` state types if `NOT-OK` state changes occur. Defaults to `false`. zone | Object name | **Optional.** The zone this object is a member of. Please read the [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) chapter for details. name | String | **Required.** The service name. Must be unique on a per-host basis. For advanced usage in [apply rules](03-monitoring-basics.md#using-apply) only. command\_endpoint | Object name | **Optional.** The endpoint where commands are executed on. notes | String | **Optional.** Notes for the service. notes\_url | String | **Optional.** URL for notes for the service (for example, in notification commands). action\_url | String | **Optional.** URL for actions for the service (for example, an external graphing tool). icon\_image | String | **Optional.** Icon image for the service. Used by external interfaces only. icon\_image\_alt | String | **Optional.** Icon image description for the service. Used by external interface only. Service objects have composite names, i.e. their names are based on the host\_name attribute and the name you specified. This means you can define more than one object with the same (short) name as long as the `host_name` attribute has a different value. The actual check interval might deviate slightly from the configured values due to the fact that Icinga tries to evenly distribute all checks over a certain period of time, i.e. to avoid load spikes. Runtime Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- next\_check | Timestamp | When the next check occurs (as a UNIX timestamp). last\_check | Timestamp | When the last check occurred (as a UNIX timestamp). check\_attempt | Number | The current check attempt number. state\_type | Number | The current state type (0 = SOFT, 1 = HARD). last\_state\_type | Number | The previous state type (0 = SOFT, 1 = HARD). last\_reachable | Boolean | Whether the service was reachable when the last check occurred. last\_check\_result | CheckResult | The current [check result](08-advanced-topics.md#advanced-value-types-checkresult). last\_state\_change | Timestamp | When the last state change occurred (as a UNIX timestamp). last\_hard\_state\_change | Timestamp | When the last hard state change occurred (as a UNIX timestamp). last\_in\_downtime | Boolean | Whether the service was in a downtime when the last check occurred. acknowledgement | Number | The acknowledgement type (0 = NONE, 1 = NORMAL, 2 = STICKY). acknowledgement\_expiry | Timestamp | When the acknowledgement expires (as a UNIX timestamp; 0 = no expiry). downtime\_depth | Number | Whether the service has one or more active downtimes. flapping\_last\_change | Timestamp | When the last flapping change occurred (as a UNIX timestamp). flapping\_current | Number | Current flapping value in percent (see flapping\_thresholds) flapping | Boolean | Whether the host is flapping between states. state | Number | The current state (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN). last\_state | Number | The previous state (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN). last\_hard\_state | Number | The last hard state (0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN). last\_state\_ok | Timestamp | When the last OK state occurred (as a UNIX timestamp). last\_state\_warning | Timestamp | When the last WARNING state occurred (as a UNIX timestamp). last\_state\_critical | Timestamp | When the last CRITICAL state occurred (as a UNIX timestamp). last\_state\_unknown | Timestamp | When the last UNKNOWN state occurred (as a UNIX timestamp). ## ServiceGroup A group of services. > **Best Practice** > > Assign service group members using the [group assign](17-language-reference.md#group-assign) rules. Example: ``` object ServiceGroup "snmp" { display_name = "SNMP services" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the service group. groups | Array of object names | **Optional.** An array of nested group names. ## StatusDataWriter Periodically writes status and configuration data files which are used by third-party tools. This configuration object is available as [statusdata feature](14-features.md#status-data). Example: ``` library "compat" object StatusDataWriter "status" { status_path = "/var/cache/icinga2/status.dat" objects_path = "/var/cache/icinga2/objects.cache" update_interval = 30s } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- status\_path | String | **Optional.** Path to the `status.dat` file. Defaults to LocalStateDir + "/cache/icinga2/status.dat". objects\_path | String | **Optional.** Path to the `objects.cache` file. Defaults to LocalStateDir + "/cache/icinga2/objects.cache". update\_interval | Duration | **Optional.** The interval in which the status files are updated. Defaults to `15s`. ## SyslogLogger Specifies Icinga 2 logging to syslog. This configuration object is available as `syslog` [logging feature](14-features.md#logging). Example: ``` object SyslogLogger "syslog" { severity = "warning" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- severity | String | **Optional.** The minimum severity for this log. Can be "debug", "notice", "information", "warning" or "critical". Defaults to "warning". facility | String | **Optional.** Defines the facility to use for syslog entries. This can be a facility constant like `FacilityDaemon`. Defaults to `FacilityUser`. Facility Constants: Name | Facility | Description ---------------------|---------------|---------------- FacilityAuth | LOG\_AUTH | The authorization system. FacilityAuthPriv | LOG\_AUTHPRIV | The same as `FacilityAuth`, but logged to a file readable only by selected individuals. FacilityCron | LOG\_CRON | The cron daemon. FacilityDaemon | LOG\_DAEMON | System daemons that are not provided for explicitly by other facilities. FacilityFtp | LOG\_FTP | The file transfer protocol daemons. FacilityKern | LOG\_KERN | Messages generated by the kernel. These cannot be generated by any user processes. FacilityLocal0 | LOG\_LOCAL0 | Reserved for local use. FacilityLocal1 | LOG\_LOCAL1 | Reserved for local use. FacilityLocal2 | LOG\_LOCAL2 | Reserved for local use. FacilityLocal3 | LOG\_LOCAL3 | Reserved for local use. FacilityLocal4 | LOG\_LOCAL4 | Reserved for local use. FacilityLocal5 | LOG\_LOCAL5 | Reserved for local use. FacilityLocal6 | LOG\_LOCAL6 | Reserved for local use. FacilityLocal7 | LOG\_LOCAL7 | Reserved for local use. FacilityLpr | LOG\_LPR | The line printer spooling system. FacilityMail | LOG\_MAIL | The mail system. FacilityNews | LOG\_NEWS | The network news system. FacilitySyslog | LOG\_SYSLOG | Messages generated internally by syslogd. FacilityUser | LOG\_USER | Messages generated by user processes. This is the default facility identifier if none is specified. FacilityUucp | LOG\_UUCP | The UUCP system. ## TimePeriod Time periods can be used to specify when hosts/services should be checked or to limit when notifications should be sent out. > **Note** > > Icinga 2 versions < 2.6.0 require the import of the [legacy-timeperiod](10-icinga-template-library.md#itl-legacy-timeperiod) template. Examples: ``` object TimePeriod "nonworkhours" { display_name = "Icinga 2 TimePeriod for non working hours" ranges = { monday = "00:00-8:00,17:00-24:00" tuesday = "00:00-8:00,17:00-24:00" wednesday = "00:00-8:00,17:00-24:00" thursday = "00:00-8:00,17:00-24:00" friday = "00:00-8:00,16:00-24:00" saturday = "00:00-24:00" sunday = "00:00-24:00" } } object TimePeriod "exampledays" { display_name = "Icinga 2 TimePeriod for random example days" ranges = { //We still believe in Santa, no peeking! //Applies every 25th of December every year "december 25" = "00:00-24:00" //Any point in time can be specified, //but you still have to use a range "2038-01-19" = "03:13-03:15" //Evey 3rd day from the second monday of February //to 8th of November "monday 2 february - november 8 / 3" = "00:00-24:00" } } ``` Additional examples can be found [here](08-advanced-topics.md#timeperiods). Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the time period. ranges | Dictionary | **Required.** A dictionary containing information which days and durations apply to this timeperiod. prefer\_includes | Boolean | **Optional.** Whether to prefer timeperiods `includes` or `excludes`. Default to true. excludes | Array of object names | **Optional.** An array of timeperiods, which should exclude from your timerange. includes | Array of object names | **Optional.** An array of timeperiods, which should include into your timerange Runtime Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- is\_inside | Boolean | Whether we're currently inside this timeperiod. ## User A user. Example: ``` object User "icingaadmin" { display_name = "Icinga 2 Admin" groups = [ "icingaadmins" ] email = "icinga@localhost" pager = "icingaadmin@localhost.localdomain" period = "24x7" states = [ OK, Warning, Critical, Unknown ] types = [ Problem, Recovery ] vars.additional_notes = "This is the Icinga 2 Admin account." } ``` Available notification state filters: OK Warning Critical Unknown Up Down Available notification type filters: DowntimeStart DowntimeEnd DowntimeRemoved Custom Acknowledgement Problem Recovery FlappingStart FlappingEnd Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the user. email | String | **Optional.** An email string for this user. Useful for notification commands. pager | String | **Optional.** A pager string for this user. Useful for notification commands. vars | Dictionary | **Optional.** A dictionary containing custom attributes that are specific to this user. groups | Array of object names | **Optional.** An array of group names. enable\_notifications | Boolean | **Optional.** Whether notifications are enabled for this user. period | Object name | **Optional.** The name of a time period which determines when a notification for this user should be triggered. Not set by default. types | Array | **Optional.** A set of type filters when this notification should be triggered. By default everything is matched. states | Array | **Optional.** A set of state filters when this notification should be triggered. By default everything is matched. Runtime Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- last\_notification | Timestamp | When the last notification was sent for this user (as a UNIX timestamp). ## UserGroup A user group. > **Best Practice** > > Assign user group members using the [group assign](17-language-reference.md#group-assign) rules. Example: ``` object UserGroup "icingaadmins" { display_name = "Icinga 2 Admin Group" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- display\_name | String | **Optional.** A short description of the user group. groups | Array of object names | **Optional.** An array of nested group names. ## Zone Zone objects are used to specify which Icinga 2 instances are located in a zone. Please read the [distributed monitoring chapter](06-distributed-monitoring.md#distributed-monitoring) for additional details. Example: ``` object Zone "master" { endpoints = [ "icinga2-master1.localdomain", "icinga2-master2.localdomain" ] } object Zone "satellite" { endpoints = [ "icinga2-satellite1.localdomain" ] parent = "master" } ``` Configuration Attributes: Name | Type | Description --------------------------|-----------------------|---------------------------------- endpoints | Array of object names | **Optional.** Array of endpoint names located in this zone. parent | Object name | **Optional.** The name of the parent zone. global | Boolean | **Optional.** Whether configuration files for this zone should be [synced](06-distributed-monitoring.md#distributed-monitoring-global-zone-config-sync) to all endpoints. Defaults to `false`. Zone objects cannot currently be created with the API. icinga2-2.8.1/doc/10-icinga-template-library.md000066400000000000000000014222001322762156600210630ustar00rootroot00000000000000# Icinga Template Library The Icinga Template Library (ITL) implements standard templates and object definitions. There is a subset of templates and object definitions available: * [Generic ITL templates](10-icinga-template-library.md#itl-generic-templates) * [CheckCommand definitions for Icinga 2](10-icinga-template-library.md#itl-check-commands) (this includes [icinga](10-icinga-template-library.md#itl-icinga), [cluster](10-icinga-template-library.md#itl-icinga-cluster), [cluster-zone](10-icinga-template-library.md#itl-icinga-cluster-zone), [ido](10-icinga-template-library.md#itl-icinga-ido), etc.) * [CheckCommand definitions for Monitoring Plugins](10-icinga-template-library.md#plugin-check-commands-monitoring-plugins) * [CheckCommand definitions for Icinga 2 Windows Plugins](10-icinga-template-library.md#windows-plugins) * [CheckCommand definitions for NSClient++](10-icinga-template-library.md#nscp-plugin-check-commands) * [CheckCommand definitions for Manubulon SNMP](10-icinga-template-library.md#snmp-manubulon-plugin-check-commands) * [Contributed CheckCommand definitions](10-icinga-template-library.md#plugin-contrib) The ITL content is updated with new releases. Please do not modify templates and/or objects as changes will be overridden without further notice. You are advised to create your own CheckCommand definitions in `/etc/icinga2`. ## Generic Templates By default the generic templates are included in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file: include These templates are imported by the provided example configuration. > **Note**: > > These templates are built into the binaries. By convention > all command and timeperiod objects should import these templates. ### plugin-check-command Command template for check plugins executed by Icinga 2. The `plugin-check-command` command does not support any vars. By default this template is automatically imported into all [CheckCommand](09-object-types.md#objecttype-checkcommand) definitions. ### plugin-notification-command Command template for notification scripts executed by Icinga 2. The `plugin-notification-command` command does not support any vars. By default this template is automatically imported into all [NotificationCommand](09-object-types.md#objecttype-notificationcommand) definitions. ### plugin-event-command Command template for event handler scripts executed by Icinga 2. The `plugin-event-command` command does not support any vars. By default this template is automatically imported into all [EventCommand](09-object-types.md#objecttype-eventcommand) definitions. ### legacy-timeperiod Timeperiod template for [Timeperiod objects](09-object-types.md#objecttype-timeperiod). The `legacy-timeperiod` timeperiod does not support any vars. By default this template is automatically imported into all [TimePeriod](09-object-types.md#objecttype-timeperiod) definitions. ## Check Commands These check commands are embedded into Icinga 2 and do not require any external plugin scripts. ### icinga Check command for the built-in `icinga` check. This check returns performance data for the current Icinga instance. The `icinga` check command does not support any vars. ### cluster Check command for the built-in `cluster` check. This check returns performance data for the current Icinga instance and connected endpoints. The `cluster` check command does not support any vars. ### cluster-zone Check command for the built-in `cluster-zone` check. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------|--------------- cluster\_zone | **Required.** The zone name. Defaults to `$host.name$`. cluster\_lag\_warning | **Optional.** Warning threshold for log lag in seconds. Applies if the log lag is greater than the threshold. cluster\_lag\_critical | **Optional.** Critical threshold for log lag in seconds. Applies if the log lag is greater than the threshold. ### ido Check command for the built-in `ido` check. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------|--------------- ido\_type | **Required.** The type of the IDO connection object. Can be either "IdoMysqlConnection" or "IdoPgsqlConnection". ido\_name | **Required.** The name of the IDO connection object. ### random Check command for the built-in `random` check. This check returns random states and adds the check source to the check output. For test and demo purposes only. The `random` check command does not support any vars. ### exception Check command for the built-in `exception` check. This check throws an exception. For test and demo purposes only. The `exception` check command does not support any vars. ## Plugin Check Commands for Monitoring Plugins The Plugin Check Commands provides example configuration for plugin check commands provided by the [Monitoring Plugins](https://www.monitoring-plugins.org) project. By default the Plugin Check Commands are included in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file: include The plugin check commands assume that there's a global constant named `PluginDir` which contains the path of the plugins from the Monitoring Plugins project. **Note**: If there are command parameters missing for the provided CheckCommand definitions please kindly send a patch upstream. This should include an update for the ITL CheckCommand itself and this documentation section. ### apt The plugin [apt](https://www.monitoring-plugins.org/doc/index.html) checks for software updates on systems that use package management systems based on the apt-get(8) command found in Debian based systems. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- apt_extra_opts | **Optional.** Read options from an ini file. apt_upgrade | **Optional.** [Default] Perform an upgrade. If an optional OPTS argument is provided, apt-get will be run with these command line options instead of the default. apt_dist_upgrade | **Optional.** Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS can be provided to override the default options. apt_include | **Optional.** Include only packages matching REGEXP. Can be specified multiple times the values will be combined together. apt_exclude | **Optional.** Exclude packages matching REGEXP from the list of packages that would otherwise be included. Can be specified multiple times. apt_critical | **Optional.** If the full package information of any of the upgradable packages match this REGEXP, the plugin will return CRITICAL status. Can be specified multiple times. apt_timeout | **Optional.** Seconds before plugin times out (default: 10). apt_only_critical | **Optional.** Only warn about critical upgrades. ### breeze The [check_breeze](https://www.monitoring-plugins.org/doc/man/check_breeze.html) plugin reports the signal strength of a Breezecom wireless equipment. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------|--------------------------------- breeze_hostname | **Required.** Name or IP address of host to check. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. breeze_community | **Optional.** SNMPv1 community. Defaults to "public". breeze_warning | **Required.** Percentage strength below which a WARNING status will result. Defaults to 50. breeze_critical | **Required.** Percentage strength below which a WARNING status will result. Defaults to 20. ### by_ssh The [check_by_ssh](https://www.monitoring-plugins.org/doc/man/check_by_ssh.html) plugin uses SSH to execute commands on a remote host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- by_ssh_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. by_ssh_port | **Optional.** The SSH port. Defaults to 22. by_ssh_command | **Required.** The command that should be executed. Can be an array if multiple arguments should be passed to `check_by_ssh`. by_ssh_arguments| **Optional.** A dictionary with arguments for the command. This works exactly like the 'arguments' dictionary for ordinary CheckCommands. by_ssh_logname | **Optional.** The SSH username. by_ssh_identity | **Optional.** The SSH identity. by_ssh_quiet | **Optional.** Whether to suppress SSH warnings. Defaults to false. by_ssh_warn | **Optional.** The warning threshold. by_ssh_crit | **Optional.** The critical threshold. by_ssh_timeout | **Optional.** The timeout in seconds. by_ssh_options | **Optional.** Call ssh with '-o OPTION' (multiple options may be specified as an array). by_ssh_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. by_ssh_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### clamd The [check_clamd](https://www.monitoring-plugins.org/doc/man/check_clamd.html) plugin tests CLAMD connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------|-------------- clamd_address | **Required.** The host's address or unix socket (must be an absolute path). clamd_port | **Optional.** Port number (default: none). clamd_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. clamd_all | **Optional.** All expect strings need to occur in server response. Defaults to false. clamd_escape_send | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in send string. clamd_send | **Optional.** String to send to the server. clamd_escape_quit | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in quit string. clamd_quit | **Optional.** String to send server to initiate a clean close of the connection. clamd_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit. Defaults to crit. clamd_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit. Defaults to warn. clamd_jail | **Optional.** Hide output from TCP socket. clamd_maxbytes | **Optional.** Close connection once more than this number of bytes are received. clamd_delay | **Optional.** Seconds to wait between sending string and polling for response. clamd_certificate | **Optional.** Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma. clamd_ssl | **Optional.** Use SSL for the connection. Defaults to false. clamd_wtime | **Optional.** Response time to result in warning status (seconds). clamd_ctime | **Optional.** Response time to result in critical status (seconds). clamd_timeout | **Optional.** Seconds before connection times out. Defaults to 10. clamd_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. clamd_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### dhcp The [check_dhcp](https://www.monitoring-plugins.org/doc/man/check_dhcp.html) plugin tests the availability of DHCP servers on a network. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- dhcp_serverip | **Optional.** The IP address of the DHCP server which we should get a response from. dhcp_requestedip| **Optional.** The IP address which we should be offered by a DHCP server. dhcp_timeout | **Optional.** The timeout in seconds. dhcp_interface | **Optional.** The interface to use. dhcp_mac | **Optional.** The MAC address to use in the DHCP request. dhcp_unicast | **Optional.** Whether to use unicast requests. Defaults to false. ### dig The [check_dig](https://www.monitoring-plugins.org/doc/man/check_dig.html) plugin test the DNS service on the specified host using dig. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------|-------------- dig_server | **Optional.** The DNS server to query. Defaults to "127.0.0.1". dig_port | **Optional.** Port number (default: 53). dig_lookup | **Required.** The address that should be looked up. dig_record_type | **Optional.** Record type to lookup (default: A). dig_expected_address | **Optional.** An address expected to be in the answer section. If not set, uses whatever was in -l. dig_arguments | **Optional.** Pass STRING as argument(s) to dig. dig_retries | **Optional.** Number of retries passed to dig, timeout is divided by this value (Default: 3). dig_warning | **Optional.** Response time to result in warning status (seconds). dig_critical | **Optional.** Response time to result in critical status (seconds). dig_timeout | **Optional.** Seconds before connection times out (default: 10). dig_ipv4 | **Optional.** Force dig to only use IPv4 query transport. Defaults to false. dig_ipv6 | **Optional.** Force dig to only use IPv6 query transport. Defaults to false. ### disk The [check_disk](https://www.monitoring-plugins.org/doc/man/check_disk.html) plugin checks the amount of used disk space on a mounted file system and generates an alert if free space is less than one of the threshold values. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------|------------------------ disk\_wfree | **Optional.** The free space warning threshold. Defaults to "20%". If the percent sign is omitted, units from `disk_units` are used. disk\_cfree | **Optional.** The free space critical threshold. Defaults to "10%". If the percent sign is omitted, units from `disk_units` are used. disk\_inode\_wfree | **Optional.** The free inode warning threshold. disk\_inode\_cfree | **Optional.** The free inode critical threshold. disk\_partition | **Optional.** The partition. **Deprecated in 2.3.** disk\_partition\_excluded | **Optional.** The excluded partition. **Deprecated in 2.3.** disk\_partitions | **Optional.** The partition(s). Multiple partitions must be defined as array. disk\_partitions\_excluded | **Optional.** The excluded partition(s). Multiple partitions must be defined as array. disk\_clear | **Optional.** Clear thresholds. May be true or false. disk\_exact\_match | **Optional.** For paths or partitions specified with -p, only check for exact paths. May be true or false. disk\_errors\_only | **Optional.** Display only devices/mountpoints with errors. May be true or false. disk\_ignore\_reserved | **Optional.** If set, account root-reserved blocks are not accounted for freespace in perfdata. May be true or false. disk\_group | **Optional.** Group paths. Thresholds apply to (free-)space of all partitions together. disk\_kilobytes | **Optional.** Same as --units kB. May be true or false. disk\_local | **Optional.** Only check local filesystems. May be true or false. disk\_stat\_remote\_fs | **Optional.** Only check local filesystems against thresholds. Yet call stat on remote filesystems to test if they are accessible (e.g. to detect Stale NFS Handles). May be true or false. disk\_mountpoint | **Optional.** Display the mountpoint instead of the partition. May be true or false. disk\_megabytes | **Optional.** Same as --units MB. May be true or false. disk\_all | **Optional.** Explicitly select all paths. This is equivalent to -R '.\*'. May be true or false. disk\_eregi\_path | **Optional.** Case insensitive regular expression for path/partition. Multiple regular expression strings must be defined as array. disk\_ereg\_path | **Optional.** Regular expression for path or partition. Multiple regular expression strings must be defined as array. disk\_ignore\_eregi\_path | **Optional.** Regular expression to ignore selected path/partition (case insensitive). Multiple regular expression strings must be defined as array. disk\_ignore\_ereg\_path | **Optional.** Regular expression to ignore selected path or partition. Multiple regular expression strings must be defined as array. disk\_timeout | **Optional.** Seconds before connection times out (default: 10). disk\_units | **Optional.** Choose bytes, kB, MB, GB, TB (default: MB). disk\_exclude\_type | **Optional.** Ignore all filesystems of indicated type. Multiple regular expression strings must be defined as array. Defaults to "none", "tmpfs", "sysfs", "proc", "configfs", "devtmpfs", "devfs", "mtmfs", "tracefs", "cgroup", "fuse.gvfsd-fuse", "fuse.gvfs-fuse-daemon", "fdescfs". ### disk_smb The [check_disk_smb](https://www.monitoring-plugins.org/doc/man/check_disk_smb.html) plugin uses the `smbclient` binary to check SMB shares. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|------------------------ disk_smb_hostname | **Required.** NetBIOS name of the server. disk_smb_share | **Required.** Share name being queried. disk_smb_workgroup | **Optional.** Workgroup or Domain used (defaults to 'WORKGROUP' if omitted). disk_smb_address | **Optional.** IP address of the host (only necessary if host belongs to another network). disk_smb_username | **Optional.** Username for server log-in (defaults to 'guest' if omitted). disk_smb_password | **Optional.** Password for server log-in (defaults to an empty password if omitted). disk_smb_wused | **Optional.** The used space warning threshold. Defaults to "85%". If the percent sign is omitted, use optional disk units. disk_smb_cused | **Optional.** The used space critical threshold. Defaults to "95%". If the percent sign is omitted, use optional disk units. disk_smb_port | **Optional.** Connection port, e.g. `139` or `445`. Defaults to `smbclient` default if omitted. ### dns The [check_dns](https://www.monitoring-plugins.org/doc/man/check_dns.html) plugin uses the nslookup program to obtain the IP address for the given host/domain query. An optional DNS server to use may be specified. If no DNS server is specified, the default server(s) specified in `/etc/resolv.conf` will be used. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------|-------------- dns_lookup | **Optional.** The hostname or IP to query the DNS for. Defaults to "$host_name$". dns_server | **Optional.** The DNS server to query. Defaults to the server configured in the OS. dns_query_type | **Optional.** The DNS record query type where TYPE =(A, AAAA, SRV, TXT, MX, ANY). The default query type is 'A' (IPv4 host entry) dns_expected_answers | **Optional.** The answer(s) to look for. A hostname must end with a dot. Multiple answers must be defined as array. dns_authoritative | **Optional.** Expect the server to send an authoritative answer. dns_accept_cname | **Optional.** Accept cname responses as a valid result to a query. dns_wtime | **Optional.** Return warning if elapsed time exceeds value. dns_ctime | **Optional.** Return critical if elapsed time exceeds value. dns_timeout | **Optional.** Seconds before connection times out. Defaults to 10. ### dummy The [check_dummy](https://www.monitoring-plugins.org/doc/man/check_dummy.html) plugin will simply return the state corresponding to the numeric value of the `dummy_state` argument with optional text. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- dummy_state | **Optional.** The state. Can be one of 0 (ok), 1 (warning), 2 (critical) and 3 (unknown). Defaults to 0. dummy_text | **Optional.** Plugin output. Defaults to "Check was successful.". ### file_age The [check_file_age](https://www.monitoring-plugins.org/doc/man/check_file_age.html) plugin checks a file's size and modification time to make sure it's not empty and that it's sufficiently recent. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------|-------------------------------------------------------------------------------------------------------- file_age_file | **Required.** File to monitor. file_age_warning_time | **Optional.** File must be no more than this many seconds old as warning threshold. Defaults to "240s". file_age_critical_time | **Optional.** File must be no more than this many seconds old as critical threshold. Defaults to "600s". file_age_warning_size | **Optional.** File must be at least this many bytes long as warning threshold. No default given. file_age_critical_size | **Optional.** File must be at least this many bytes long as critical threshold. Defaults to "0B". file_age_ignoremissing | **Optional.** Return OK if the file does not exist. Defaults to false. ### flexlm The [check_flexlm](https://www.monitoring-plugins.org/doc/man/check_flexlm.html) plugin checks available flexlm license managers. Requires the `lmstat` command. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------|---------------------------------------------------------- flexlm_licensefile | **Required.** Name of license file (usually license.dat). flexlm_timeout | **Optional.** Plugin time out in seconds. Defaults to 15. ### fping4 The [check_fping](https://www.monitoring-plugins.org/doc/man/check_fping.html) plugin uses the `fping` command to ping the specified host for a fast check. Note that it is necessary to set the `suid` flag on `fping`. This CheckCommand expects an IPv4 address. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- fping_address | **Optional.** The host's IPv4 address. Defaults to "$address$". fping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. fping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. fping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. fping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. fping_number | **Optional.** The number of packets to send. Defaults to 5. fping_interval | **Optional.** The interval between packets in milli-seconds. Defaults to 500. fping_bytes | **Optional.** The size of ICMP packet. fping_target_timeout | **Optional.** The target timeout in milli-seconds. fping_source_ip | **Optional.** The name or ip address of the source ip. fping_source_interface | **Optional.** The source interface name. ### fping6 The [check_fping](https://www.monitoring-plugins.org/doc/man/check_fping.html) plugin will use the `fping` command to ping the specified host for a fast check. Note that it is necessary to set the `suid` flag on `fping`. This CheckCommand expects an IPv6 address. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- fping_address | **Optional.** The host's IPv6 address. Defaults to "$address6$". fping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. fping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. fping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. fping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. fping_number | **Optional.** The number of packets to send. Defaults to 5. fping_interval | **Optional.** The interval between packets in milli-seconds. Defaults to 500. fping_bytes | **Optional.** The size of ICMP packet. fping_target_timeout | **Optional.** The target timeout in milli-seconds. fping_source_ip | **Optional.** The name or ip address of the source ip. fping_source_interface | **Optional.** The source interface name. ### ftp The [check_ftp](https://www.monitoring-plugins.org/doc/man/check_ftp.html) plugin tests FTP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------|-------------- ftp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ftp_port | **Optional.** The FTP port number. ftp_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. ftp_all | **Optional.** All expect strings need to occur in server response. Defaults to false. ftp_escape_send | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in send string. ftp_send | **Optional.** String to send to the server. ftp_escape_quit | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in quit string. ftp_quit | **Optional.** String to send server to initiate a clean close of the connection. ftp_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit. Defaults to crit. ftp_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit. Defaults to warn. ftp_jail | **Optional.** Hide output from TCP socket. ftp_maxbytes | **Optional.** Close connection once more than this number of bytes are received. ftp_delay | **Optional.** Seconds to wait between sending string and polling for response. ftp_certificate | **Optional.** Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma. ftp_ssl | **Optional.** Use SSL for the connection. Defaults to false. ftp_wtime | **Optional.** Response time to result in warning status (seconds). ftp_ctime | **Optional.** Response time to result in critical status (seconds). ftp_timeout | **Optional.** Seconds before connection times out. Defaults to 10. ftp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. ftp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### game The [check_game](https://www.monitoring-plugins.org/doc/man/check_game.html) plugin tests game server connections with the specified host. This plugin uses the 'qstat' command, the popular game server status query tool. If you don't have the package installed, you will need to [download](http://www.activesw.com/people/steve/qstat.html) or install the package `quakestat` before you can use this plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------|------------------- game_game | **Required.** Name of the game. game_ipaddress | **Required.** Ipaddress of the game server to query. game_timeout | **Optional.** Seconds before connection times out. Defaults to 10. game_port | **Optional.** Port to connect to. game_gamefield | **Optional.** Field number in raw qstat output that contains game name. game_mapfield | **Optional.** Field number in raw qstat output that contains map name. game_pingfield | **Optional.** Field number in raw qstat output that contains ping time. game_gametime | **Optional.** Field number in raw qstat output that contains game time. game_hostname | **Optional.** Name of the host running the game. ### hostalive Check command object for the [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin with host check default values. This variant uses the host's `address` attribute if available and falls back to using the `address6` attribute if the `address` attribute is not set. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 3000. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 80. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 5000. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 100. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### hostalive4 Check command object for the [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin with host check default values. This variant uses the host's `address` attribute. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's IPv4 address. Defaults to "$address$". ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 3000. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 80. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 5000. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 100. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### hostalive6 Check command object for the [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin with host check default values. This variant uses the host's `address6` attribute. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's IPv6 address. Defaults to "$address6$". ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 3000. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 80. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 5000. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 100. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### hpjd The [check_hpjd](https://www.monitoring-plugins.org/doc/man/check_hpjd.html) plugin tests the state of an HP printer with a JetDirect card. Net-snmp must be installed on the computer running the plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- hpjd_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. hpjd_port | **Optional.** The host's SNMP port. Defaults to 161. hpjd_community | **Optional.** The SNMP community. Defaults to "public". ### http The [check_http](https://www.monitoring-plugins.org/doc/man/check_http.html) plugin tests the HTTP service on the specified host. It can test normal (http) and secure (https) servers, follow redirects, search for strings and regular expressions, check connection times, and report on certificate expiration times. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|--------------------------------- http_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. http_vhost | **Optional.** The virtual host that should be sent in the "Host" header. http_uri | **Optional.** The request URI for GET or POST. Defaults to `/`. http_port | **Optional.** The TCP port. Defaults to 80 when not using SSL, 443 otherwise. http_ssl | **Optional.** Whether to use SSL. Defaults to false. http_ssl_force_tlsv1 | **Optional.** Whether to force TLSv1. http_ssl_force_tlsv1_1 | **Optional.** Whether to force TLSv1.1. http_ssl_force_tlsv1_2 | **Optional.** Whether to force TLSv1.2. http_ssl_force_sslv2 | **Optional.** Whether to force SSLv2. http_ssl_force_sslv3 | **Optional.** Whether to force SSLv3. http_ssl_force_tlsv1_or_higher | **Optional.** Whether to force TLSv1 or higher. http_ssl_force_tlsv1_1_or_higher | **Optional.** Whether to force TLSv1.1 or higher. http_ssl_force_tlsv1_2_or_higher | **Optional.** Whether to force TLSv1.2 or higher. http_ssl_force_sslv2_or_higher | **Optional.** Whether to force SSLv2 or higher. http_ssl_force_sslv3_or_higher | **Optional.** Whether to force SSLv3 or higher. http_sni | **Optional.** Whether to use SNI. Defaults to false. http_auth_pair | **Optional.** Add 'username:password' authorization pair. http_proxy_auth_pair | **Optional.** Add 'username:password' authorization pair for proxy. http_ignore_body | **Optional.** Don't download the body, just the headers. http_linespan | **Optional.** Allow regex to span newline. http_expect_body_regex | **Optional.** A regular expression which the body must match against. Incompatible with http_ignore_body. http_expect_body_eregi | **Optional.** A case-insensitive expression which the body must match against. Incompatible with http_ignore_body. http_invertregex | **Optional.** Changes behavior of http_expect_body_regex and http_expect_body_eregi to return CRITICAL if found, OK if not. http_warn_time | **Optional.** The warning threshold. http_critical_time | **Optional.** The critical threshold. http_expect | **Optional.** Comma-delimited list of strings, at least one of them is expected in the first (status) line of the server response. Default: HTTP/1. http_certificate | **Optional.** Minimum number of days a certificate has to be valid. This parameter explicitly sets the port to 443 and ignores the URL if passed. http_clientcert | **Optional.** Name of file contains the client certificate (PEM format). http_privatekey | **Optional.** Name of file contains the private key (PEM format). http_headerstring | **Optional.** String to expect in the response headers. http_string | **Optional.** String to expect in the content. http_post | **Optional.** URL encoded http POST data. http_method | **Optional.** Set http method (for example: HEAD, OPTIONS, TRACE, PUT, DELETE). http_maxage | **Optional.** Warn if document is more than seconds old. http_contenttype | **Optional.** Specify Content-Type header when POSTing. http_useragent | **Optional.** String to be sent in http header as User Agent. http_header | **Optional.** Any other tags to be sent in http header. http_extendedperfdata | **Optional.** Print additional perfdata. Defaults to false. http_onredirect | **Optional.** How to handle redirect pages. Possible values: "ok" (default), "warning", "critical", "follow", "sticky" (like follow but stick to address), "stickyport" (like sticky but also to port) http_pagesize | **Optional.** Minimum page size required:Maximum page size required. http_timeout | **Optional.** Seconds before connection times out. http_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. http_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. http_link | **Optional.** Wrap output in HTML link. Defaults to false. http_verbose | **Optional.** Show details for command-line debugging. Defaults to false. ### icmp The [check_icmp](https://www.monitoring-plugins.org/doc/man/check_icmp.html) plugin check_icmp allows for checking multiple hosts at once compared to `check_ping`. The main difference is that check_ping executes the system's ping(1) command and parses its output while `check_icmp` talks ICMP itself. `check_icmp` must be installed with `setuid` root. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- icmp_address | **Optional.** The host's address. This can either be a single address or an array of addresses. Defaults to "$address$". icmp_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. icmp_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. icmp_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. icmp_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. icmp_source | **Optional.** The source IP address to send packets from. icmp_packets | **Optional.** The number of packets to send. Defaults to 5. icmp_packet_interval | **Optional** The maximum packet interval. Defaults to 80 (milliseconds). icmp_target_interval | **Optional.** The maximum target interval. icmp_hosts_alive | **Optional.** The number of hosts which have to be alive for the check to succeed. icmp_data_bytes | **Optional.** Payload size for each ICMP request. Defaults to 8. icmp_timeout | **Optional.** The plugin timeout in seconds. Defaults to 10 (seconds). icmp_ttl | **Optional.** The TTL on outgoing packets. ### imap The [check_imap](https://www.monitoring-plugins.org/doc/man/check_imap.html) plugin tests IMAP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------------|-------------- imap_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. imap_port | **Optional.** The port that should be checked. Defaults to 143. imap_escape | **Optional.** Can use \\n, \\r, \\t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\r\\n added to end of quit. imap_send | **Optional.** String to send to the server. imap_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. imap_all | **Optional.** All expect strings need to occur in server response. Default is any. imap_quit | **Optional.** String to send server to initiate a clean close of the connection. imap_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit (default: crit). imap_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit (default: warn). imap_jail | **Optional.** Hide output from TCP socket. imap_maxbytes | **Optional.** Close connection once more than this number of bytes are received. imap_delay | **Optional.** Seconds to wait between sending string and polling for response. imap_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. imap_ssl | **Optional.** Use SSL for the connection. imap_warning | **Optional.** Response time to result in warning status (seconds). imap_critical | **Optional.** Response time to result in critical status (seconds). imap_timeout | **Optional.** Seconds before connection times out (default: 10). imap_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. imap_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### ldap The [check_ldap](https://www.monitoring-plugins.org/doc/man/check_ldap.html) plugin can be used to check LDAP servers. The plugin can also be used for monitoring ldaps connections instead of the deprecated `check_ldaps`. This can be ensured by enabling `ldap_starttls` or `ldap_ssl`. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- ldap_address | **Optional.** Host name, IP Address, or unix socket (must be an absolute path). Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ldap_port | **Optional.** Port number. Defaults to 389. ldap_attr | **Optional.** LDAP attribute to search for (default: "(objectclass=*)") ldap_base | **Required.** LDAP base (eg. ou=myunit,o=myorg,c=at). ldap_bind | **Optional.** LDAP bind DN (if required). ldap_pass | **Optional.** LDAP password (if required). ldap_starttls | **Optional.** Use STARTSSL mechanism introduced in protocol version 3. ldap_ssl | **Optional.** Use LDAPS (LDAP v2 SSL method). This also sets the default port to 636. ldap_v2 | **Optional.** Use LDAP protocol version 2 (enabled by default). ldap_v3 | **Optional.** Use LDAP protocol version 3 (disabled by default) ldap_warning | **Optional.** Response time to result in warning status (seconds). ldap_critical | **Optional.** Response time to result in critical status (seconds). ldap_warning_entries | **Optional.** Number of found entries to result in warning status. ldap_critical_entries | **Optional.** Number of found entries to result in critical status. ldap_timeout | **Optional.** Seconds before connection times out (default: 10). ldap_verbose | **Optional.** Show details for command-line debugging (disabled by default) ### load The [check_load](https://www.monitoring-plugins.org/doc/man/check_load.html) plugin tests the current system load average. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- load_wload1 | **Optional.** The 1-minute warning threshold. Defaults to 5. load_wload5 | **Optional.** The 5-minute warning threshold. Defaults to 4. load_wload15 | **Optional.** The 15-minute warning threshold. Defaults to 3. load_cload1 | **Optional.** The 1-minute critical threshold. Defaults to 10. load_cload5 | **Optional.** The 5-minute critical threshold. Defaults to 6. load_cload15 | **Optional.** The 15-minute critical threshold. Defaults to 4. load_percpu | **Optional.** Divide the load averages by the number of CPUs (when possible). Defaults to false. ### mailq The [check_mailq](https://www.monitoring-plugins.org/doc/man/check_mailq.html) plugin checks the number of messages in the mail queue (supports multiple sendmail queues, qmail). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- mailq_warning | **Required.** Min. number of messages in queue to generate warning. mailq_critical | **Required.** Min. number of messages in queue to generate critical alert ( w < c ). mailq_domain_warning | **Optional.** Min. number of messages for same domain in queue to generate warning mailq_domain_critical | **Optional.** Min. number of messages for same domain in queue to generate critical alert ( W < C ). mailq_timeout | **Optional.** Plugin timeout in seconds (default = 15). mailq_servertype | **Optional.** [ sendmail \| qmail \| postfix \| exim \| nullmailer ] (default = autodetect). mailq_sudo | **Optional.** Use sudo to execute the mailq command. ### mysql The [check_mysql](https://www.monitoring-plugins.org/doc/man/check_mysql.html) plugin tests connections to a MySQL server. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|--------------------------------------------------------------- mysql_hostname | **Optional.** Host name, IP Address, or unix socket (must be an absolute path). mysql_port | **Optional.** Port number (default: 3306). mysql_socket | **Optional.** Use the specified socket (has no effect if `mysql_hostname` is used). mysql_ignore_auth | **Optional.** Ignore authentication failure and check for mysql connectivity only. mysql_database | **Optional.** Check database with indicated name. mysql_file | **Optional.** Read from the specified client options file. mysql_group | **Optional.** Use a client options group. mysql_username | **Optional.** Connect using the indicated username. mysql_password | **Optional.** Use the indicated password to authenticate the connection. mysql_check_slave | **Optional.** Check if the slave thread is running properly. mysql_warning | **Optional.** Exit with WARNING status if slave server is more than INTEGER seconds behind master. mysql_critical | **Optional.** Exit with CRITICAL status if slave server is more then INTEGER seconds behind master. mysql_ssl | **Optional.** Use ssl encryption. mysql_cacert | **Optional.** Path to CA signing the cert. mysql_cert | **Optional.** Path to SSL certificate. mysql_key | **Optional.** Path to private SSL key. mysql_cadir | **Optional.** Path to CA directory. mysql_ciphers | **Optional.** List of valid SSL ciphers. ### mysql_query The [check_mysql_query](https://www.monitoring-plugins.org/doc/man/check_mysql_query.html) plugin checks a query result against threshold levels. The result from the query should be numeric. For extra security, create a user with minimal access. **Note**: You must specify `mysql_query_password` with an empty string to force an empty password, overriding any my.cnf settings. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|--------------------------------------------------------------- mysql_query_hostname | **Optional.** Host name, IP Address, or unix socket (must be an absolute path). mysql_query_port | **Optional.** Port number (default: 3306). mysql_query_database | **Optional.** Check database with indicated name. mysql_query_file | **Optional.** Read from the specified client options file. mysql_query_group | **Optional.** Use a client options group. mysql_query_username | **Optional.** Connect using the indicated username. mysql_query_password | **Optional.** Use the indicated password to authenticate the connection. mysql_query_execute | **Required.** SQL Query to run on the MySQL Server. mysql_query_warning | **Optional.** Exit with WARNING status if query is outside of the range (format: start:end). mysql_query_critical | **Optional.** Exit with CRITICAL status if query is outside of the range. ### negate The [negate](https://www.monitoring-plugins.org/doc/man/negate.html) plugin negates the status of a plugin (returns OK for CRITICAL and vice-versa). Additional switches can be used to control which state becomes what. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------------|--------------------------------------------------------------- negate_timeout | **Optional.** Seconds before plugin times out (default: 11). negate_timeout_result | **Optional.** Custom result on Negate timeouts, default to UNKNOWN. negate_ok | **Optional.** OK, WARNING, CRITICAL or UNKNOWN. negate_warning | Numeric values are accepted. negate_critical | If nothing is specified, negate_unknown | permutes OK and CRITICAL. negate_substitute | **Optional.** Substitute output text as well. Will only substitute text in CAPITALS. negate_command | **Required.** Command to be negated. negate_arguments | **Optional.** Arguments for the negated command. ### nrpe The `check_nrpe` plugin can be used to query an [NRPE](https://docs.icinga.com/latest/en/nrpe.html) server or [NSClient++](https://www.nsclient.org). **Note**: This plugin is considered insecure/deprecated. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- nrpe_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. nrpe_port | **Optional.** The NRPE port. Defaults to 5666. nrpe_command | **Optional.** The command that should be executed. nrpe_no_ssl | **Optional.** Whether to disable SSL or not. Defaults to `false`. nrpe_timeout_unknown | **Optional.** Whether to set timeouts to unknown instead of critical state. Defaults to `false`. nrpe_timeout | **Optional.** The timeout in seconds. nrpe_arguments | **Optional.** Arguments that should be passed to the command. Multiple arguments must be defined as array. nrpe_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. nrpe_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. nrpe_version_2 | **Optional.** Use this if you want to connect using NRPE v2 protocol. Defaults to false. ### nscp The [check_nt](https://www.monitoring-plugins.org/doc/man/check_nt.html) plugin collects data from the [NSClient++](https://www.nsclient.org) service. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- nscp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. nscp_port | **Optional.** The NSClient++ port. Defaults to 12489. nscp_password | **Optional.** The NSClient++ password. nscp_variable | **Required.** The variable that should be checked. nscp_params | **Optional.** Parameters for the query. Multiple parameters must be defined as array. nscp_warn | **Optional.** The warning threshold. nscp_crit | **Optional.** The critical threshold. nscp_timeout | **Optional.** The query timeout in seconds. nscp_showall | **Optional.** Use with SERVICESTATE to see working services or PROCSTATE for running processes. Defaults to false. ### ntp_time The [check_ntp_time](https://www.monitoring-plugins.org/doc/man/check_ntp_time.html) plugin checks the clock offset between the local host and a remote NTP server. **Note**: If you want to monitor an NTP server, please use `ntp_peer`. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ntp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ntp_port | **Optional.** Port number (default: 123). ntp_quiet | **Optional.** Returns UNKNOWN instead of CRITICAL if offset cannot be found. ntp_warning | **Optional.** Offset to result in warning status (seconds). ntp_critical | **Optional.** Offset to result in critical status (seconds). ntp_timeoffset | **Optional.** Expected offset of the ntp server relative to local server (seconds). ntp_timeout | **Optional.** Seconds before connection times out (default: 10). ntp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. ntp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### ntp_peer The [check_ntp_peer](https://www.monitoring-plugins.org/doc/man/check_ntp_peer.html) plugin checks the health of an NTP server. It supports checking the offset with the sync peer, the jitter and stratum. This plugin will not check the clock offset between the local host and NTP server; please use `ntp_time` for that purpose. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ntp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ntp_port | **Optional.** The port to use. Default to 123. ntp_quiet | **Optional.** Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized. ntp_warning | **Optional.** Offset to result in warning status (seconds). ntp_critical | **Optional.** Offset to result in critical status (seconds). ntp_wstratum | **Optional.** Warning threshold for stratum of server's synchronization peer. ntp_cstratum | **Optional.** Critical threshold for stratum of server's synchronization peer. ntp_wjitter | **Optional.** Warning threshold for jitter. ntp_cjitter | **Optional.** Critical threshold for jitter. ntp_wsource | **Optional.** Warning threshold for number of usable time sources. ntp_csource | **Optional.** Critical threshold for number of usable time sources. ntp_timeout | **Optional.** Seconds before connection times out (default: 10). ntp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. ntp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### passive Specialised check command object for passive checks executing the `check_dummy` plugin with appropriate default values. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- dummy_state | **Optional.** The state. Can be one of 0 (ok), 1 (warning), 2 (critical) and 3 (unknown). Defaults to 3. dummy_text | **Optional.** Plugin output. Defaults to "No Passive Check Result Received.". ### pgsql The [check_pgsql](https://www.monitoring-plugins.org/doc/man/check_pgsql.html) plugin tests a PostgreSQL DBMS to determine whether it is active and accepting queries. If a query is specified using the `pgsql_query` attribute, it will be executed after connecting to the server. The result from the query has to be numeric in order to compare it against the query thresholds if set. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|--------------------------------------------------------------- pgsql_hostname | **Optional.** Host name, IP Address, or unix socket (must be an absolute path). pgsql_port | **Optional.** Port number (default: 5432). pgsql_database | **Optional.** Database to check (default: template1). pgsql_username | **Optional.** Login name of user. pgsql_password | **Optional.** Password (BIG SECURITY ISSUE). pgsql_options | **Optional.** Connection parameters (keyword = value), see below. pgsql_warning | **Optional.** Response time to result in warning status (seconds). pgsql_critical | **Optional.** Response time to result in critical status (seconds). pgsql_timeout | **Optional.** Seconds before connection times out (default: 10). pgsql_query | **Optional.** SQL query to run. Only first column in first row will be read. pgsql_query_warning | **Optional.** SQL query value to result in warning status (double). pgsql_query_critical | **Optional.** SQL query value to result in critical status (double). ### ping The [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin uses the ping command to probe the specified host for packet loss (percentage) and round trip average (milliseconds). This command uses the host's `address` attribute if available and falls back to using the `address6` attribute if the `address` attribute is not set. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### ping4 The [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin uses the ping command to probe the specified host for packet loss (percentage) and round trip average (milliseconds). This command uses the host's `address` attribute if not explicitly specified using the `ping_address` attribute. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's IPv4 address. Defaults to "$address$". ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### ping6 The [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin uses the ping command to probe the specified host for packet loss (percentage) and round trip average (milliseconds). This command uses the host's `address6` attribute if not explicitly specified using the `ping_address` attribute. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ping_address | **Optional.** The host's IPv6 address. Defaults to "$address6$". ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 100. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 5. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 200. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 15. ping_packets | **Optional.** The number of packets to send. Defaults to 5. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### pop The [check_pop](https://www.monitoring-plugins.org/doc/man/check_pop.html) plugin tests POP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------|-------------- pop_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. pop_port | **Optional.** The port that should be checked. Defaults to 110. pop_escape | **Optional.** Can use \\n, \\r, \\t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\r\\n added to end of quit. pop_send | **Optional.** String to send to the server. pop_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. pop_all | **Optional.** All expect strings need to occur in server response. Default is any. pop_quit | **Optional.** String to send server to initiate a clean close of the connection. pop_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit (default: crit). pop_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit (default: warn). pop_jail | **Optional.** Hide output from TCP socket. pop_maxbytes | **Optional.** Close connection once more than this number of bytes are received. pop_delay | **Optional.** Seconds to wait between sending string and polling for response. pop_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. pop_ssl | **Optional.** Use SSL for the connection. pop_warning | **Optional.** Response time to result in warning status (seconds). pop_critical | **Optional.** Response time to result in critical status (seconds). pop_timeout | **Optional.** Seconds before connection times out (default: 10). pop_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. pop_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### procs The [check_procs](https://www.monitoring-plugins.org/doc/man/check_procs.html) plugin checks all processes and generates WARNING or CRITICAL states if the specified metric is outside the required threshold ranges. The metric defaults to number of processes. Search filters can be applied to limit the processes to check. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------|-------------- procs_warning | **Optional.** The process count warning threshold. Defaults to 250. procs_critical | **Optional.** The process count critical threshold. Defaults to 400. procs_metric | **Optional.** Check thresholds against metric. procs_timeout | **Optional.** Seconds before plugin times out. procs_traditional | **Optional.** Filter own process the traditional way by PID instead of /proc/pid/exe. Defaults to false. procs_state | **Optional.** Only scan for processes that have one or more of the status flags you specify. procs_ppid | **Optional.** Only scan for children of the parent process ID indicated. procs_vsz | **Optional.** Only scan for processes with VSZ higher than indicated. procs_rss | **Optional.** Only scan for processes with RSS higher than indicated. procs_pcpu | **Optional.** Only scan for processes with PCPU higher than indicated. procs_user | **Optional.** Only scan for processes with user name or ID indicated. procs_argument | **Optional.** Only scan for processes with args that contain STRING. procs_argument_regex | **Optional.** Only scan for processes with args that contain the regex STRING. procs_command | **Optional.** Only scan for exact matches of COMMAND (without path). procs_nokthreads | **Optional.** Only scan for non kernel threads. Defaults to false. ### radius The [check_radius](https://www.monitoring-plugins.org/doc/man/check_radius.html) plugin checks a RADIUS server to see if it is accepting connections. The server to test must be specified in the invocation, as well as a user name and password. A configuration file may also be present. The format of the configuration file is described in the radiusclient library sources. The password option presents a substantial security issue because the password can possibly be determined by careful watching of the command line in a process listing. This risk is exacerbated because the plugin will typically be executed at regular predictable intervals. Please be sure that the password used does not allow access to sensitive system resources. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------|-------------- radius_address | **Optional.** The radius server's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. radius_config_file | **Required.** The radius configuration file. radius_username | **Required.** The radius username to test. radius_password | **Required.** The radius password to test. radius_port | **Optional.** The radius port number (default 1645). radius_nas_id | **Optional.** The NAS identifier. radius_nas_address | **Optional.** The NAS IP address. radius_expect | **Optional.** The response string to expect from the server. radius_retries | **Optional.** The number of times to retry a failed connection. radius_timeout | **Optional.** The number of seconds before connection times out (default: 10). ### simap The [check_simap](https://www.monitoring-plugins.org/doc/man/check_simap.html) plugin tests SIMAP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------|-------------- simap_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. simap_port | **Optional.** The port that should be checked. Defaults to 993. simap_escape | **Optional.** Can use \\n, \\r, \\t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\r\\n added to end of quit. simap_send | **Optional.** String to send to the server. simap_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. simap_all | **Optional.** All expect strings need to occur in server response. Default is any. simap_quit | **Optional.** String to send server to initiate a clean close of the connection. simap_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit (default: crit). simap_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit (default: warn). simap_jail | **Optional.** Hide output from TCP socket. simap_maxbytes | **Optional.** Close connection once more than this number of bytes are received. simap_delay | **Optional.** Seconds to wait between sending string and polling for response. simap_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. simap_ssl | **Optional.** Use SSL for the connection. simap_warning | **Optional.** Response time to result in warning status (seconds). simap_critical | **Optional.** Response time to result in critical status (seconds). simap_timeout | **Optional.** Seconds before connection times out (default: 10). simap_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. simap_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### smart The [check_ide_smart](https://www.monitoring-plugins.org/doc/man/check_ide_smart.html) plugin checks a local hard drive with the (Linux specific) SMART interface. Requires installation of `smartctl`. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- smart_device | **Required.** The name of a local hard drive to monitor. ### smtp The [check_smtp](https://www.monitoring-plugins.org/doc/man/check_smtp.html) plugin will attempt to open an SMTP connection with the host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------------|-------------- smtp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. smtp_port | **Optional.** The port that should be checked. Defaults to 25. smtp_mail_from | **Optional.** Test a MAIL FROM command with the given email address. smtp_expect | **Optional.** String to expect in first line of server response (default: '220'). smtp_command | **Optional.** SMTP command (may be used repeatedly). smtp_response | **Optional.** Expected response to command (may be used repeatedly). smtp_helo_fqdn | **Optional.** FQDN used for HELO smtp_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. smtp_starttls | **Optional.** Use STARTTLS for the connection. smtp_authtype | **Optional.** SMTP AUTH type to check (default none, only LOGIN supported). smtp_authuser | **Optional.** SMTP AUTH username. smtp_authpass | **Optional.** SMTP AUTH password. smtp_ignore_quit | **Optional.** Ignore failure when sending QUIT command to server. smtp_warning | **Optional.** Response time to result in warning status (seconds). smtp_critical | **Optional.** Response time to result in critical status (seconds). smtp_timeout | **Optional.** Seconds before connection times out (default: 10). smtp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. smtp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### snmp The [check_snmp](https://www.monitoring-plugins.org/doc/man/check_snmp.html) plugin checks the status of remote machines and obtains system information via SNMP. **Note**: This plugin uses the `snmpget` command included with the NET-SNMP package. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_oid | **Required.** The SNMP OID. snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port. Defaults to "161". snmp_retries | **Optional.** Number of retries to be used in the SNMP requests. snmp_warn | **Optional.** The warning threshold. snmp_crit | **Optional.** The critical threshold. snmp_string | **Optional.** Return OK state if the string matches exactly with the output value snmp_ereg | **Optional.** Return OK state if extended regular expression REGEX matches with the output value snmp_eregi | **Optional.** Return OK state if case-insensitive extended REGEX matches with the output value snmp_label | **Optional.** Prefix label for output value snmp_invert_search | **Optional.** Invert search result and return CRITICAL state if found snmp_units | **Optional.** Units label(s) for output value (e.g., 'sec.'). snmp_version | **Optional.** Version to use. E.g. 1, 2, 2c or 3. snmp_miblist | **Optional.** MIB's to use, comma separated. Defaults to "ALL". snmp_rate_multiplier | **Optional.** Converts rate per second. For example, set to 60 to convert to per minute. snmp_rate | **Optional.** Boolean. Enable rate calculation. snmp_getnext | **Optional.** Boolean. Use SNMP GETNEXT. Defaults to false. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 10 seconds. snmp_offset | **Optional.** Add/subtract the specified OFFSET to numeric sensor data. snmp_output_delimiter | **Optional.** Separates output on multiple OID requests. snmp_perf_oids | **Optional.** Label performance data with OIDs instead of --label's. ### snmpv3 Check command object for the [check_snmp](https://www.monitoring-plugins.org/doc/man/check_snmp.html) plugin, using SNMPv3 authentication and encryption options. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------|-------------- snmpv3_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmpv3_getnext | **Optional.** Use SNMP GETNEXT instead of SNMP GET. snmpv3_seclevel | **Optional.** The security level. Defaults to authPriv. snmpv3_auth_alg | **Optional.** The authentication algorithm. Defaults to SHA. snmpv3_user | **Required.** The username to log in with. snmpv3_auth_key | **Required,** The authentication key. Required if `snmpv3_seclevel` is set to `authPriv` otherwise optional. snmpv3_priv_key | **Required.** The encryption key. snmpv3_oid | **Required.** The SNMP OID. snmpv3_priv_alg | **Optional.** The encryption algorithm. Defaults to AES. snmpv3_warn | **Optional.** The warning threshold. snmpv3_crit | **Optional.** The critical threshold. snmpv3_string | **Optional.** Return OK state (for that OID) if STRING is an exact match. snmpv3_ereg | **Optional.** Return OK state (for that OID) if extended regular expression REGEX matches. snmpv3_eregi | **Optional.** Return OK state (for that OID) if case-insensitive extended REGEX matches. snmpv3_invert_search | **Optional.** Invert search result and return CRITICAL if found snmpv3_label | **Optional.** Prefix label for output value. snmpv3_units | **Optional.** Units label(s) for output value (e.g., 'sec.'). snmpv3_rate_multiplier | **Optional.** Converts rate per second. For example, set to 60 to convert to per minute. snmpv3_rate | **Optional.** Boolean. Enable rate calculation. snmpv3_timeout | **Optional.** The command timeout in seconds. Defaults to 10 seconds. ### snmp-uptime Check command object for the [check_snmp](https://www.monitoring-plugins.org/doc/man/check_snmp.html) plugin, using the uptime OID by default. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_oid | **Optional.** The SNMP OID. Defaults to "1.3.6.1.2.1.1.3.0". snmp_community | **Optional.** The SNMP community. Defaults to "public". ### spop The [check_spop](https://www.monitoring-plugins.org/doc/man/check_spop.html) plugin tests SPOP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------------|-------------- spop_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. spop_port | **Optional.** The port that should be checked. Defaults to 995. spop_escape | **Optional.** Can use \\n, \\r, \\t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\r\\n added to end of quit. spop_send | **Optional.** String to send to the server. spop_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. spop_all | **Optional.** All expect strings need to occur in server response. Default is any. spop_quit | **Optional.** String to send server to initiate a clean close of the connection. spop_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit (default: crit). spop_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit (default: warn). spop_jail | **Optional.** Hide output from TCP socket. spop_maxbytes | **Optional.** Close connection once more than this number of bytes are received. spop_delay | **Optional.** Seconds to wait between sending string and polling for response. spop_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. spop_ssl | **Optional.** Use SSL for the connection. spop_warning | **Optional.** Response time to result in warning status (seconds). spop_critical | **Optional.** Response time to result in critical status (seconds). spop_timeout | **Optional.** Seconds before connection times out (default: 10). spop_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. spop_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### ssh The [check_ssh](https://www.monitoring-plugins.org/doc/man/check_ssh.html) plugin connects to an SSH server at a specified host and port. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ssh_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ssh_port | **Optional.** The port that should be checked. Defaults to 22. ssh_timeout | **Optional.** Seconds before connection times out. Defaults to 10. ssh_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. ssh_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### ssl Check command object for the [check_tcp](https://www.monitoring-plugins.org/doc/man/check_tcp.html) plugin, using ssl-related options. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------------|-------------- ssl_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ssl_port | **Optional.** The port that should be checked. Defaults to 443. ssl_timeout | **Optional.** Timeout in seconds for the connect and handshake. The plugin default is 10 seconds. ssl_cert_valid_days_warn | **Optional.** Warning threshold for days before the certificate will expire. When used, the default for ssl_cert_valid_days_critical is 0. ssl_cert_valid_days_critical | **Optional.** Critical threshold for days before the certificate will expire. When used, ssl_cert_valid_days_warn must also be set. ssl_sni | **Optional.** The `server_name` that is send to select the SSL certificate to check. Important if SNI is used. ### ssmtp The [check_ssmtp](https://www.monitoring-plugins.org/doc/man/check_ssmtp.html) plugin tests SSMTP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------|-------------- ssmtp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ssmtp_port | **Optional.** The port that should be checked. Defaults to 465. ssmtp_escape | **Optional.** Can use \\n, \\r, \\t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\r\\n added to end of quit. ssmtp_send | **Optional.** String to send to the server. ssmtp_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. ssmtp_all | **Optional.** All expect strings need to occur in server response. Default is any. ssmtp_quit | **Optional.** String to send server to initiate a clean close of the connection. ssmtp_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit (default: crit). ssmtp_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit (default: warn). ssmtp_jail | **Optional.** Hide output from TCP socket. ssmtp_maxbytes | **Optional.** Close connection once more than this number of bytes are received. ssmtp_delay | **Optional.** Seconds to wait between sending string and polling for response. ssmtp_certificate_age | **Optional.** Minimum number of days a certificate has to be valid. ssmtp_ssl | **Optional.** Use SSL for the connection. ssmtp_warning | **Optional.** Response time to result in warning status (seconds). ssmtp_critical | **Optional.** Response time to result in critical status (seconds). ssmtp_timeout | **Optional.** Seconds before connection times out (default: 10). ssmtp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. ssmtp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### swap The [check_swap](https://www.monitoring-plugins.org/doc/man/check_swap.html) plugin checks the swap space on a local machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- swap_wfree | **Optional.** The free swap space warning threshold in % (enable `swap_integer` for number values). Defaults to `50%`. swap_cfree | **Optional.** The free swap space critical threshold in % (enable `swap_integer` for number values). Defaults to `25%`. swap_integer | **Optional.** Specifies whether the thresholds are passed as number or percent value. Defaults to false (percent values). swap_allswaps | **Optional.** Conduct comparisons for all swap partitions, one by one. Defaults to false. swap_noswap | **Optional.** Resulting state when there is no swap regardless of thresholds. Possible values are "ok", "warning", "critical", "unknown". Defaults to "critical". ### tcp The [check_tcp](https://www.monitoring-plugins.org/doc/man/check_tcp.html) plugin tests TCP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- tcp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. tcp_port | **Required.** The port that should be checked. tcp_expect | **Optional.** String to expect in server response. Multiple strings must be defined as array. tcp_all | **Optional.** All expect strings need to occur in server response. Defaults to false. tcp_escape_send | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in send string. tcp_send | **Optional.** String to send to the server. tcp_escape_quit | **Optional.** Enable usage of \\n, \\r, \\t or \\\\ in quit string. tcp_quit | **Optional.** String to send server to initiate a clean close of the connection. tcp_refuse | **Optional.** Accept TCP refusals with states ok, warn, crit. Defaults to crit. tcp_mismatch | **Optional.** Accept expected string mismatches with states ok, warn, crit. Defaults to warn. tcp_jail | **Optional.** Hide output from TCP socket. tcp_maxbytes | **Optional.** Close connection once more than this number of bytes are received. tcp_delay | **Optional.** Seconds to wait between sending string and polling for response. tcp_certificate | **Optional.** Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma. tcp_ssl | **Optional.** Use SSL for the connection. Defaults to false. tcp_wtime | **Optional.** Response time to result in warning status (seconds). tcp_ctime | **Optional.** Response time to result in critical status (seconds). tcp_timeout | **Optional.** Seconds before connection times out. Defaults to 10. tcp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. tcp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### udp The [check_udp](https://www.monitoring-plugins.org/doc/man/check_udp.html) plugin tests UDP connections with the specified host (or unix socket). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- udp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. udp_port | **Required.** The port that should be checked. udp_send | **Required.** The payload to send in the UDP datagram. udp_expect | **Required.** The payload to expect in the response datagram. udp_quit | **Optional.** The payload to send to 'close' the session. udp_ipv4 | **Optional.** Use IPv4 connection. Defaults to false. udp_ipv6 | **Optional.** Use IPv6 connection. Defaults to false. ### ups The [check_ups](https://www.monitoring-plugins.org/doc/man/check_ups.html) plugin tests the UPS service on the specified host. [Network UPS Tools](http://www.networkupstools.org) must be running for this plugin to work. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- ups_address | **Required.** The address of the host running upsd. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ups_name | **Required.** The UPS name. Defaults to `ups`. ups_port | **Optional.** The port to which to connect. Defaults to 3493. ups_variable | **Optional.** The variable to monitor. Must be one of LINE, TEMP, BATTPCT or LOADPCT. If this is not set, the check only relies on the value of `ups.status`. ups_warning | **Optional.** The warning threshold for the selected variable. ups_critical | **Optional.** The critical threshold for the selected variable. ups_celsius | **Optional.** Display the temperature in degrees Celsius instead of Fahrenheit. Defaults to `false`. ups_timeout | **Optional.** The number of seconds before the connection times out. Defaults to 10. ### users The [check_users](https://www.monitoring-plugins.org/doc/man/check_users.html) plugin checks the number of users currently logged in on the local system and generates an error if the number exceeds the thresholds specified. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- users_wgreater | **Optional.** The user count warning threshold. Defaults to 20. users_cgreater | **Optional.** The user count critical threshold. Defaults to 50. ## Windows Plugins for Icinga 2 To allow a basic monitoring of Windows clients Icinga 2 comes with a set of Windows only plugins. While trying to mirror the functionalities of their linux cousins from the monitoring-plugins package, the differences between Windows and Linux are too big to be able use the same CheckCommands for both systems. A check-commands-windows.conf comes with Icinga 2, it assumes that the Windows Plugins are installed in the PluginDir set in your constants.conf. To enable them the following include directive is needed in you icinga2.conf: include One of the differences between the Windows plugins and their linux counterparts is that they consistently do not require thresholds to run, functioning like dummies without. ### Threshold syntax So not specified differently the thresholds for the plugins all follow the same pattern Threshold | Meaning :------------|:---------- "29" | The threshold is 29. "!29" | The threshold is 29, but the negative of the result is returned. "[10-40]" | The threshold is a range from (including) 10 to 40, a value inside means the threshold has been exceeded. "![10-40]" | Same as above, but the result is inverted. ### disk-windows Check command object for the `check_disk.exe` plugin. Aggregates the disk space of all volumes and mount points it can find, or the ones defined in `disk_win_path`. Ignores removable storage like flash drives and discs (CD, DVD etc.). The data collection is instant and free disk space (default, see `disk_win_show_used`) is used for threshold computation. > **Note** > > Percentage based thresholds can be used by adding a '%' to the threshold > value. Custom attributes: Name | Description :---------------------|:------------ disk\_win\_warn | **Optional**. The warning threshold. disk\_win\_crit | **Optional**. The critical threshold. disk\_win\_path | **Optional**. Check only these paths, default checks all. disk\_win\_unit | **Optional**. Use this unit to display disk space, thresholds are interpreted in this unit. Defaults to "mb", possible values are: b, kb, mb, gb and tb. disk\_win\_exclude | **Optional**. Exclude these drives from check. disk\_win\_show\_used | **Optional**. Use used instead of free space. ### load-windows Check command object for the `check_load.exe` plugin. This plugin collects the inverse of the performance counter `\Processor(_Total)\% Idle Time` two times, with a wait time of one second between the collection. To change this wait time use [`perfmon-windows`](10-icinga-template-library.md#windows-plugins-load-windows). Custom attributes: Name | Description :---------------|:------------ load\_win\_warn | **Optional**. The warning threshold. load\_win\_crit | **Optional**. The critical threshold. ### memory-windows Check command object for the `check_memory.exe` plugin. The memory collection is instant and free memory is used for threshold computation. > **Note** > > Percentage based thresholds can be used by adding a '%' to the threshold > value. Keep in mind that memory\_win\_unit is applied before the > value is calculated. Custom attributes: Name | Description :-----------------|:------------ memory\_win\_warn | **Optional**. The warning threshold. memory\_win\_crit | **Optional**. The critical threshold. memory\_win\_unit | **Optional**. The unit to display the received value in, thresholds are interpreted in this unit. Defaults to "mb" (megabyte), possible values are: b, kb, mb, gb and tb. ### network-windows Check command object for the `check_network.exe` plugin. Collects the total Bytes inbound and outbound for all interfaces in one second, to itemise interfaces or use a different collection interval use [`perfmon-windows`](10-icinga-template-library.md#windows-plugins-load-windows). Custom attributes: Name | Description :-------------------|:------------ network\_win\_warn | **Optional**. The warning threshold. network\_win\_crit | **Optional**. The critical threshold. network\_no\_isatap | **Optional**. Do not print ISATAP interfaces. ### perfmon-windows Check command object for the `check_perfmon.exe` plugin. This plugins allows to collect data from a Performance Counter. After the first data collection a second one is done after `perfmon_win_wait` milliseconds. When you know `perfmon_win_counter` only requires one set of data to provide valid data you can set `perfmon_win_wait` to `0`. To receive a list of possible Performance Counter Objects run `check_perfmon.exe --print-objects` and to view an objects instances and counters run `check_perfmon.exe --print-object-info -P "name of object"` Custom attributes: Name | Description :---------------------|:------------ perfmon\_win\_warn | **Optional**. The warning threshold. perfmon\_win\_crit | **Optional**. The critical threshold. perfmon\_win\_counter | **Required**. The Performance Counter to use. Ex. `\Processor(_Total)\% Idle Time`. perfmon\_win\_wait | **Optional**. Time in milliseconds to wait between data collection (default: 1000). perfmon\_win\_type | **Optional**. Format in which to expect performance values. Possible are: long, int64 and double (default). perfmon\_win\_syntax | **Optional**. Use this in the performance output instead of `perfmon\_win\_counter`. Exists for graphics compatibility reasons. ### ping-windows Check command object for the `check_ping.exe` plugin. ping-windows should automatically detect whether `ping_win_address` is an IPv4 or IPv6 address. If not, use ping4-windows and ping6-windows. Also note that check\_ping.exe waits at least `ping_win_timeout` milliseconds between the pings. Custom attributes: Name | Description :------------------|:------------ ping\_win\_warn | **Optional**. The warning threshold. RTA and package loss separated by comma. ping\_win\_crit | **Optional**. The critical threshold. RTA and package loss separated by comma. ping\_win\_address | **Required**. An IPv4 or IPv6 address. ping\_win\_packets | **Optional**. Number of packages to send. Default: 5. ping\_win\_timeout | **Optional**. The timeout in milliseconds. Default: 1000 ### procs-windows Check command object for `check_procs.exe` plugin. When using `procs_win_user` this plugins needs administrative privileges to access the processes of other users, to just enumerate them no additional privileges are required. Custom attributes: Name | Description :----------------|:------------ procs\_win\_warn | **Optional**. The warning threshold. procs\_win\_crit | **Optional**. The critical threshold. procs\_win\_user | **Optional**. Count this users processes. ### service-windows Check command object for `check_service.exe` plugin. This checks thresholds work different since the binary decision whether a service is running or not does not allow for three states. As a default `check_service.exe` will return CRITICAL when `service_win_service` is not running, the `service_win_warn` flag changes this to WARNING. Custom attributes: Name | Description :-------------------------|:------------ service\_win\_warn | **Optional**. Warn when service is not running. service\_win\_description | **Optional**. If this is set, `service\_win\_service` looks at the service description. service\_win\_service | **Required**. Name of the service to check. ### swap-windows Check command object for `check_swap.exe` plugin. The data collection is instant. Custom attributes: Name | Description :---------------|:------------ swap\_win\_warn | **Optional**. The warning threshold. swap\_win\_crit | **Optional**. The critical threshold. swap\_win\_unit | **Optional**. The unit to display the received value in, thresholds are interpreted in this unit. Defaults to "mb" (megabyte). ### update-windows Check command object for `check_update.exe` plugin. Querying Microsoft for Windows updates can take multiple seconds to minutes. An update is treated as important when it has the WSUS flag for SecurityUpdates or CriticalUpdates. > **Note** > > The Network Services Account which runs Icinga 2 by default does not have the required > permissions to run this check. Custom attributes: Name | Description :-------------------|:------------ update\_win\_warn | **Optional**. If set, returns warning when important updates are available. update\_win\_crit | **Optional**. If set, return critical when important updates that require a reboot are available. update\_win\_reboot | **Optional**. Set to treat 'may need update' as 'definitely needs update'. Please Note that this is true for almost every update and is therefore not recommended. In contrast to most other plugins, the values of check_update's custom attributes do not set thresholds, but just enable/disable the behavior described in the table above. It can be enabled/disabled for example by setting them to "true" or "false", "1" or "0" would also work. Thresholds will always be "1". > **Note** > > If they are enabled, performance data will be shown in the web interface. > If run without the optional parameters, the plugin will output critical if any important updates are available. ### uptime-windows Check command object for `check_uptime.exe` plugin. Uses GetTickCount64 to get the uptime, so boot time is not included. Custom attributes: Name | Description :-----------------|:------------ uptime\_win\_warn | **Optional**. The warning threshold. uptime\_win\_crit | **Optional**. The critical threshold. uptime\_win\_unit | **Optional**. The unit to display the received value in, thresholds are interpreted in this unit. Defaults to "s"(seconds), possible values are ms (milliseconds), s, m (minutes), h (hours). ### users-windows Check command object for `check_users.exe` plugin. Custom attributes: Name | Description :----------------|:------------ users\_win\_warn | **Optional**. The warning threshold. users\_win\_crit | **Optional**. The critical threshold. ## Plugin Check Commands for NSClient++ There are two methods available for querying NSClient++: * Query the [HTTP API](10-icinga-template-library.md#nscp-check-api) locally or remotely (requires a running NSClient++ service) * Run a [local CLI check](10-icinga-template-library.md#nscp-check-local) (does not require NSClient++ as a service) Both methods have their advantages and disadvantages. One thing to note: If you rely on performance counter delta calculations such as CPU utilization, please use the HTTP API instead of the CLI sample call. ### nscp_api `check_nscp_api` is part of the Icinga 2 plugins. This plugin is available for both, Windows and Linux/Unix. Verify that the ITL CheckCommand is included in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file: vim /etc/icinga2/icinga2.conf include `check_nscp_api` runs queries against the NSClient++ API. Therefore NSClient++ needs to have the `webserver` module enabled, configured and loaded. You can install the webserver using the following CLI commands: ./nscp.exe web install ./nscp.exe web password — –set icinga Now you can define specific [queries](https://docs.nsclient.org/reference/check/CheckHelpers.html#queries) and integrate them into Icinga 2. The check plugin `check_nscp_api` can be integrated with the `nscp_api` CheckCommand object: Custom attributes: Name | Description :----------------------|:---------------------- nscp\_api\_host | **Required**. NSCP API host address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. nscp\_api\_port | **Optional**. NSCP API port. Defaults to `8443`. nscp\_api\_password | **Required**. NSCP API password. Please check the NSCP documentation for setup details. nscp\_api\_query | **Required**. NSCP API query endpoint. Refer to the NSCP documentation for possible values. nscp\_api\_arguments | **Optional**. NSCP API arguments dictionary either as single strings or key-value pairs using `=`. Refer to the NSCP documentation. `nscp_api_arguments` can be used to pass required thresholds to the executed check. The example below checks the CPU utilization and specifies warning and critical thresholds. ``` check_nscp_api --host 10.0.10.148 --password icinga --query check_cpu --arguments show-all warning='load>40' critical='load>30' check_cpu CRITICAL: critical(5m: 48%, 1m: 36%), 5s: 0% | 'total 5m'=48%;40;30 'total 1m'=36%;40;30 'total 5s'=0%;40;30 ``` ### nscp-local Icinga 2 can use the `nscp client` command to run arbitrary NSClient++ checks locally on the client. You can enable these check commands by adding the following the include directive in your [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file: include You can also optionally specify an alternative installation directory for NSClient++ by adding the NscpPath constant in your [constants.conf](04-configuring-icinga-2.md#constants-conf) configuration file: const NscpPath = "C:\\Program Files (x86)\\NSClient++" By default Icinga 2 uses the Microsoft Installer API to determine where NSClient++ is installed. It should not be necessary to manually set this constant. Note that it is not necessary to run NSClient++ as a Windows service for these commands to work. The check command object for NSClient++ is available as `nscp-local`. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------- nscp_log_level | **Optional.** The log level. Defaults to "critical". nscp_load_all | **Optional.** Whether to load all modules. Defaults to false. nscp_modules | **Optional.** An array of NSClient++ modules to load. Defaults to `[ "CheckSystem" ]`. nscp_boot | **Optional.** Whether to use the --boot option. Defaults to true. nscp_query | **Required.** The NSClient++ query. Try `nscp client -q x` for a list. nscp_arguments | **Optional.** An array of query arguments. nscp_showall | **Optional.** Shows more details in plugin output, default to false. ### nscp-local-cpu Check command object for the `check_cpu` NSClient++ plugin. Name | Description --------------------|------------------ nscp_cpu_time | **Optional.** Calculate average usage for the given time intervals. Value has to be an array, default to [ "1m", "5m", "15m" ]. nscp_cpu_warning | **Optional.** Threshold for WARNING state in percent, default to 80. nscp_cpu_critical | **Optional.** Threshold for CRITICAL state in percent, default to 90. nscp_cpu_arguments | **Optional.** Additional arguments. nscp_cpu_showall | **Optional.** Shows more details in plugin output, default to false. ### nscp-local-memory Check command object for the `check_memory` NSClient++ plugin. Name | Description ----------------------|------------------ nscp_memory_committed | **Optional.** Check for committed memory, default to false. nscp_memory_physical | **Optional.** Check for physical memory, default to true. nscp_memory_free | **Optional.** Switch between checking free (true) or used memory (false), default to false. nscp_memory_warning | **Optional.** Threshold for WARNING state in percent or absolute (use MB, GB, ...), default to 80 (free=false) or 20 (free=true). nscp_memory_critical | **Optional.** Threshold for CRITICAL state in percent or absolute (use MB, GB, ...), default to 90 (free=false) or 10 (free=true). nscp_memory_arguments | **Optional.** Additional arguments. nscp_memory_showall | **Optional.** Shows more details in plugin output, default to false. ### nscp-local-os-version Check command object for the `check_os_version` NSClient++ plugin. This command has the same custom attributes like the `nscp-local` check command. ### nscp-local-pagefile Check command object for the `check_pagefile` NSClient++ plugin. This command has the same custom attributes like the `nscp-local` check command. ### nscp-local-process Check command object for the `check_process` NSClient++ plugin. This command has the same custom attributes like the `nscp-local` check command. ### nscp-local-service Check command object for the `check_service` NSClient++ plugin. Name | Description -----------------------|------------------ nscp_service_name | **Required.** Name of service to check. nscp_service_type | **Optional.** Type to check, default to state. nscp_service_ok | **Optional.** State for return an OK, i.e. for type=state running, stopped, ... nscp_service_otype | **Optional.** Dedicate type for nscp_service_ok, default to nscp_service_state. nscp_service_warning | **Optional.** State for return an WARNING. nscp_service_wtype | **Optional.** Dedicate type for nscp_service_warning, default to nscp_service_state. nscp_service_critical | **Optional.** State for return an CRITICAL. nscp_service_ctype | **Optional.** Dedicate type for nscp_service_critical, default to nscp_service_state. nscp_service_arguments | **Optional.** Additional arguments. nscp_service_showall | **Optional.** Shows more details in plugin output, default to true. ### nscp-local-uptime Check command object for the `check_uptime` NSClient++ plugin. This command has the same custom attributes like the `nscp-local` check command. ### nscp-local-version Check command object for the `check_version` NSClient++ plugin. This command has the same custom attributes like the `nscp-local` check command. In addition to that the default value for `nscp_modules` is set to `[ "CheckHelpers" ]`. ### nscp-local-disk Check command object for the `check_drivesize` NSClient++ plugin. Name | Description -----------------------|------------------ nscp_disk_drive | **Optional.** Drive character, default to all drives. nscp_disk_free | **Optional.** Switch between checking free space (free=true) or used space (free=false), default to false. nscp_disk_warning | **Optional.** Threshold for WARNING in percent or absolute (use MB, GB, ...), default to 80 (used) or 20 percent (free). nscp_disk_critical | **Optional.** Threshold for CRITICAL in percent or absolute (use MB, GB, ...), default to 90 (used) or 10 percent (free). nscp_disk_arguments | **Optional.** Additional arguments. nscp_disk_showall | **Optional.** Shows more details in plugin output, default to true. nscp_modules | **Optional.** An array of NSClient++ modules to load. Defaults to `[ "CheckDisk" ]`. ### nscp-local-counter Check command object for the `check_pdh` NSClient++ plugin. Name | Description -----------------------|------------------ nscp_counter_name | **Required.** Performance counter name. nscp_counter_warning | **Optional.** WARNING Threshold. nscp_counter_critical | **Optional.** CRITICAL Threshold. nscp_counter_arguments | **Optional.** Additional arguments. nscp_counter_showall | **Optional.** Shows more details in plugin output, default to false. nscp_counter_perfsyntax | **Optional.** Apply performance data label, e.g. `Total Processor Time` to avoid special character problems. Defaults to `nscp_counter_name`. ## Plugin Check Commands for Manubulon SNMP The `SNMP Manubulon Plugin Check Commands` provide configuration for plugin check commands provided by the [SNMP Manubulon project](http://nagios.manubulon.com/index_snmp.html). **Note:** Some plugin parameters are only available in Debian packages or in a [forked repository](https://github.com/dnsmichi/manubulon-snmp) with patches applied. The SNMP manubulon plugin check commands assume that the global constant named `ManubulonPluginDir` is set to the path where the Manubublon SNMP plugins are installed. You can enable these plugin check commands by adding the following the include directive in your [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file: include ### Checks by Host Type **N/A** : Not available for this type. **SNMP** : Available for simple SNMP query. **??** : Untested. **Specific** : Script name for platform specific checks. Host type | Interface | storage | load/cpu | mem | process | env | specific ------------------------|------------|----------|-----------|-----|----------|-----|------------------------- Linux | Yes | Yes | Yes | Yes | Yes | No | Windows | Yes | Yes | Yes | Yes | Yes | No | check_snmp_win.pl Cisco router/switch | Yes | N/A | Yes | Yes | N/A | Yes | HP router/switch | Yes | N/A | Yes | Yes | N/A | No | Bluecoat proxy | Yes | SNMP | Yes | SNMP| No | Yes | CheckPoint on SPLAT | Yes | Yes | Yes | Yes | Yes | No | check_snmp_cpfw.pl CheckPoint on Nokia IP | Yes | Yes | Yes | No | ?? | No | check_snmp_vrrp.pl Boostedge | Yes | Yes | Yes | Yes | ?? | No | check_snmp_boostedge.pl AS400 | Yes | Yes | Yes | Yes | No | No | NetsecureOne Netbox | Yes | Yes | Yes | ?? | Yes | No | Radware Linkproof | Yes | N/A | SNMP | SNMP| No | No | check_snmp_linkproof_nhr
check_snmp_vrrp.pl IronPort | Yes | SNMP | SNMP | SNMP| No | Yes | Cisco CSS | Yes | ?? | Yes | Yes | No | ?? | check_snmp_css.pl ### snmp-env Check command object for the [check_snmp_env.pl](http://nagios.manubulon.com/snmp_env.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol| **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_env_type | **Optional.** Environment Type [cisco|nokia|bc|iron|foundry|linux]. Defaults to "cisco". snmp_env_fan | **Optional.** Minimum fan rpm value (only needed for 'iron' & 'linux') snmp_env_celsius | **Optional.** Maximum temp in degrees celsius (only needed for 'iron' & 'linux') snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. ### snmp-load Check command object for the [check_snmp_load.pl](http://nagios.manubulon.com/snmp_load.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol| **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_warn | **Optional.** The warning threshold. Change the `snmp_load_type` var to "netsl" for using 3 values. snmp_crit | **Optional.** The critical threshold. Change the `snmp_load_type` var to "netsl" for using 3 values. snmp_load_type | **Optional.** Load type. Defaults to "stand". Check all available types in the [snmp load](http://nagios.manubulon.com/snmp_load.html) documentation. snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. ### snmp-memory Check command object for the [check_snmp_mem.pl](http://nagios.manubulon.com/snmp_mem.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol| **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_warn | **Optional.** The warning threshold. snmp_crit | **Optional.** The critical threshold. snmp_is_cisco | **Optional.** Change OIDs for Cisco switches. Defaults to false. snmp_is_hp | **Optional.** Change OIDs for HP/Procurve switches. Defaults to false. snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. ### snmp-storage Check command object for the [check_snmp_storage.pl](http://nagios.manubulon.com/snmp_storage.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol| **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_warn | **Optional.** The warning threshold. snmp_crit | **Optional.** The critical threshold. snmp_storage_name | **Optional.** Storage name. Default to regex "^/$$". More options available in the [snmp storage](http://nagios.manubulon.com/snmp_storage.html) documentation. snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. ### snmp-interface Check command object for the [check_snmp_int.pl](http://nagios.manubulon.com/snmp_int.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol | **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_warn | **Optional.** The warning threshold. snmp_crit | **Optional.** The critical threshold. snmp_interface | **Optional.** Network interface name. Default to regex "eth0". snmp_interface_inverse | **Optional.** Inverse Interface check, down is ok. Defaults to false as it is missing. snmp_interface_perf | **Optional.** Check the input/output bandwidth of the interface. Defaults to true. snmp_interface_label | **Optional.** Add label before speed in output: in=, out=, errors-out=, etc. snmp_interface_bits_bytes | **Optional.** Output performance data in bits/s or Bytes/s. **Depends** on snmp_interface_kbits set to true. Defaults to true. snmp_interface_percent | **Optional.** Output performance data in % of max speed. Defaults to false. snmp_interface_kbits | **Optional.** Make the warning and critical levels in KBits/s. Defaults to true. snmp_interface_megabytes | **Optional.** Make the warning and critical levels in Mbps or MBps. **Depends** on snmp_interface_kbits set to true. Defaults to true. snmp_interface_64bit | **Optional.** Use 64 bits counters instead of the standard counters when checking bandwidth & performance data for interface >= 1Gbps. Defaults to false. snmp_interface_errors | **Optional.** Add error & discard to Perfparse output. Defaults to true. snmp_interface_noregexp | **Optional.** Do not use regexp to match interface name in description OID. Defaults to false. snmp_interface_delta | **Optional.** Delta time of perfcheck. Defaults to "300" (5 min). snmp_interface_warncrit_percent | **Optional.** Make the warning and critical levels in % of reported interface speed. If set, **snmp_interface_megabytes** needs to be set to false. Defaults to false. snmp_interface_ifname | **Optional.** Switch from IF-MIB::ifDescr to IF-MIB::ifName when looking up the interface's name. snmp_interface_ifalias | **Optional.** Switch from IF-MIB::ifDescr to IF-MIB::ifAlias when looking up the interface's name. snmp_interface_weathermap | **Optional.** Output data for ["weathermap" lines](http://docs.nagvis.org/1.9/en_US/lines_weathermap_style.html) in NagVis. **Depends** on `snmp_interface_perf` set to true. Defaults to `false`. **Note**: Available in `check_snmp_int.pl v2.1.0`. snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. ### snmp-process Check command object for the [check_snmp_process.pl](http://nagios.manubulon.com/snmp_process.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol | **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default.. snmp_warn | **Optional.** The warning threshold. snmp_crit | **Optional.** The critical threshold. snmp_process_name | **Optional.** Name of the process (regexp). No trailing slash!. Defaults to ".*". snmp_perf | **Optional.** Enable perfdata values. Defaults to true. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. snmp_process_use_params | **Optional.** Add process parameters to process name for regexp matching. Example: "named.*-t /var/named/chroot" will only select named process with this parameter. Defaults to false. snmp_process_mem_usage | **Optional.** Define to check memory usage for the process. Defaults to false. snmp_process_mem_threshold | **Optional.** Defines the warning and critical thresholds in Mb when snmp_process_mem_usage set to true. Example "512,1024". Defaults to "0,0". snmp_process_cpu_usage | **Optional.** Define to check CPU usage for the process. Defaults to false. snmp_process_cpu_threshold | **Optional.** Defines the warning and critical thresholds in % when snmp_process_cpu_usage set to true. If more than one CPU, value can be > 100% : 100%=1 CPU. Example "15,50". Defaults to "0,0". ### snmp-service Check command object for the [check_snmp_win.pl](http://nagios.manubulon.com/snmp_windows.html) plugin. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------|-------------- snmp_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. snmp_nocrypt | **Optional.** Define SNMP encryption. If set to `false`, `snmp_v3` needs to be enabled. Defaults to `true` (no encryption). snmp_community | **Optional.** The SNMP community. Defaults to "public". snmp_port | **Optional.** The SNMP port connection. snmp_v2 | **Optional.** SNMP version to 2c. Defaults to false. snmp_v3 | **Optional.** SNMP version to 3. Defaults to false. snmp_login | **Optional.** SNMP version 3 username. Defaults to "snmpuser". snmp_password | **Required.** SNMP version 3 password. No value defined as default. snmp_v3_use_privpass | **Optional.** Define to use SNMP version 3 priv password. Defaults to false. snmp_v3_use_authprotocol | **Optional.** Define to use SNMP version 3 authentication protocol. Defaults to false. snmp_authprotocol | **Optional.** SNMP version 3 authentication protocol. Defaults to "md5,des". snmp_privpass | **Required.** SNMP version 3 priv password. No value defined as default. snmp_timeout | **Optional.** The command timeout in seconds. Defaults to 5 seconds. snmp_service_name | **Optional.** Comma separated names of services (perl regular expressions can be used for every one). By default, it is not case sensitive. eg. ^dns$. Defaults to ".*". snmp_service_count | **Optional.** Compare matching services with a specified number instead of the number of names provided. snmp_service_showall | **Optional.** Show all services in the output, instead of only the non-active ones. Defaults to false. snmp_service_noregexp | **Optional.** Do not use regexp to match NAME in service description. Defaults to false. ## Contributed Plugin Check Commands The contributed Plugin Check Commands provides various additional command definitions contributed by community members. These check commands assume that the global constant named `PluginContribDir` is set to the path where the user installs custom plugins and can be enabled by uncommenting the corresponding line in [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf): ``` vim /etc/icinga2/icinga2.conf include ``` This is enabled by default since Icinga 2 2.5.0. ### Databases This category contains plugins for various database servers. #### db2_health The [check_db2_health](https://labs.consol.de/nagios/check_db2_health/) plugin uses the `DBD::DB2` Perl library to monitor a [DB2](https://www.ibm.com/support/knowledgecenter/SSEPGG_11.1.0/) database. The Git repository is located on [GitHub](https://github.com/lausser/check_db2_health). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ db2_health_database | **Required.** The name of the database. (If it was catalogued locally, this parameter is the only you need. Otherwise you must specify database, hostname and port) db2_health_username | **Optional.** The username for the database connection. db2_health_password | **Optional.** The password for the database connection. db2_health_port | **Optional.** The port where DB2 is listening. db2_health_warning | **Optional.** The warning threshold depending on the mode. db2_health_critical | **Optional.** The critical threshold depending on the mode. db2_health_mode | **Required.** The mode uses predefined keywords for the different checks. For example "connection-time", "database-usage" or "sql". db2_health_method | **Optional.** This tells the plugin how to connect to the database. The only method implemented yet is “dbi” which is the default. (It means, the plugin uses the perl module DBD::DB2). db2_health_name | **Optional.** The tablespace, datafile, wait event, latch, enqueue depending on the mode or SQL statement to be executed with "db2_health_mode" sql. db2_health_name2 | **Optional.** If "db2_health_name" is a sql statement, "db2_health_name2" can be used to appear in the output and the performance data. db2_health_regexp | **Optional.** If set to true, "db2_health_name" will be interpreted as a regular expression. Defaults to false. db2_health_units | **Optional.** This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free. Possible values are "%", "KB", "MB" and "GB". db2_health_maxinactivity | **Optional.** Used for the maximum amount of time a certain event has not happened. db2_health_mitigation | **Optional.** Classifies the severity of an offline tablespace. db2_health_lookback | **Optional.** How many days in the past db2_health check should look back to calculate exitcode. db2_health_report | **Optional.** Report can be used to output only the bad news. Possible values are "short", "long", "html". Defaults to `short`. db2_health_env_db2_home | **Required.** Specifies the location of the db2 client libraries as environment variable `DB2_HOME`. Defaults to "/opt/ibm/db2/V10.5". db2_health_env_db2_version | **Optional.** Specifies the DB2 version as environment variable `DB2_VERSION`. #### mssql_health The [check_mssql_health](https://labs.consol.de/nagios/check_mssql_health/index.html) plugin uses the `DBD::Sybase` Perl library based on [FreeTDS](http://www.freetds.org/) to monitor a [MS SQL](https://www.microsoft.com/en-us/sql-server/) server. The Git repository is located on [GitHub](https://github.com/lausser/check_mssql_health). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ mssql_health_hostname | **Optional.** Specifies the database hostname or address. No default because you typically use "mssql_health_server". mssql_health_username | **Optional.** The username for the database connection. mssql_health_password | **Optional.** The password for the database connection. mssql_health_port | **Optional.** Specifies the database port. No default because you typically use "mssql_health_server". mssql_health_server | **Optional.** The name of a predefined connection (in freetds.conf). mssql_health_currentdb | **Optional.** The name of a database which is used as the current database for the connection. mssql_health_offlineok | **Optional.** Set this to true if offline databases are perfectly ok for you. Defaults to false. mssql_health_nooffline | **Optional.** Set this to true to ignore offline databases. Defaults to false. mssql_health_dbthresholds | **Optional.** With this parameter thresholds are read from the database table check_mssql_health_thresholds. mssql_health_notemp | **Optional.** Set this to true to ignore temporary databases/tablespaces. Defaults to false. mssql_health_commit | **Optional.** Set this to true to turn on autocommit for the dbd::sybase module. Defaults to false. mssql_health_method | **Optional.** How the plugin should connect to the database (dbi for the perl module `DBD::Sybase` (default) and `sqlrelay` for the SQLRelay proxy). mssql_health_mode | **Required.** The mode uses predefined keywords for the different checks. For example "connection-time", "database-free" or "sql". mssql_health_regexp | **Optional.** If set to true, "mssql_health_name" will be interpreted as a regular expression. Defaults to false. mssql_health_warning | **Optional.** The warning threshold depending on the mode. mssql_health_critical | **Optional.** The critical threshold depending on the mode. mssql_health_warningx | **Optional.** A possible override for the warning threshold. mssql_health_criticalx | **Optional.** A possible override for the critical threshold. mssql_health_units | **Optional.** This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free. Possible values are "%", "KB", "MB" and "GB". mssql_health_name | **Optional.** Depending on the mode this could be the database name or a SQL statement. mssql_health_name2 | **Optional.** If "mssql_health_name" is a sql statement, "mssql_health_name2" can be used to appear in the output and the performance data. mssql_health_name3 | **Optional.** Additional argument used for 'database-file-free' mode for example. mssql_health_extraopts | **Optional.** Read command line arguments from an external file. mssql_health_blacklist | **Optional.** Blacklist some (missing/failed) components mssql_health_mitigation | **Optional.** The parameter allows you to change a critical error to a warning. mssql_health_lookback | **Optional.** The amount of time you want to look back when calculating average rates. mssql_health_environment | **Optional.** Add a variable to the plugin's environment. mssql_health_negate | **Optional.** Emulate the negate plugin. --negate warning=critical --negate unknown=critical. mssql_health_morphmessage | **Optional.** Modify the final output message. mssql_health_morphperfdata | **Optional.** The parameter allows you to change performance data labels. mssql_health_selectedperfdata | **Optional.** The parameter allows you to limit the list of performance data. mssql_health_report | **Optional.** Report can be used to output only the bad news. Possible values are "short", "long", "html". Defaults to `short`. mssql_health_multiline | **Optional.** Multiline output. mssql_health_withmymodulesdyndir | **Optional.** Add-on modules for the my-modes will be searched in this directory. mssql_health_statefilesdir | **Optional.** An alternate directory where the plugin can save files. mssql_health_isvalidtime | **Optional.** Signals the plugin to return OK if now is not a valid check time. mssql_health_timeout | **Optional.** Plugin timeout. Defaults to 15s. #### mysql_health The [check_mysql_health](https://labs.consol.de/nagios/check_mysql_health/index.html) plugin uses the `DBD::MySQL` Perl library to monitor a [MySQL](https://dev.mysql.com/downloads/mysql/) or [MariaDB](https://mariadb.org/about/) database. The Git repository is located on [GitHub](https://github.com/lausser/check_mysql_health). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ mysql_health_hostname | **Required.** Specifies the database hostname or address. Defaults to "$address$" or "$address6$" if the `address` attribute is not set. mysql_health_port | **Optional.** Specifies the database port. Defaults to 3306 (or 1186 for "mysql_health_mode" cluster). mysql_health_socket | **Optional.** Specifies the database unix socket. No default. mysql_health_username | **Optional.** The username for the database connection. mysql_health_password | **Optional.** The password for the database connection. mysql_health_database | **Optional.** The database to connect to. Defaults to information_schema. mysql_health_warning | **Optional.** The warning threshold depending on the mode. mysql_health_critical | **Optional.** The critical threshold depending on the mode. mysql_health_warningx | **Optional.** The extended warning thresholds depending on the mode. mysql_health_criticalx | **Optional.** The extended critical thresholds depending on the mode. mysql_health_mode | **Required.** The mode uses predefined keywords for the different checks. For example "connection-time", "slave-lag" or "sql". mysql_health_method | **Optional.** How the plugin should connect to the database (`dbi` for using DBD::Mysql (default), `mysql` for using the mysql-Tool). mysql_health_commit | **Optional.** Turns on autocommit for the dbd::\* module. mysql_health_notemp | **Optional.** Ignore temporary databases/tablespaces. mysql_health_nooffline | **Optional.** Skip the offline databases. mysql_health_regexp | **Optional.** Parameter name/name2/name3 will be interpreted as (perl) regular expression. mysql_health_name | **Optional.** The name of a specific component to check. mysql_health_name2 | **Optional.** The secondary name of a component. mysql_health_name3 | **Optional.** The tertiary name of a component. mysql_health_units | **Optional.** This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free. Possible values are "%", "KB", "MB" and "GB". mysql_health_labelformat | **Optional.** One of those formats pnp4nagios or groundwork. Defaults to pnp4nagios. mysql_health_extraopts | **Optional.** Read command line arguments from an external file. mysql_health_blacklist | **Optional.** Blacklist some (missing/failed) components mysql_health_mitigation | **Optional.** The parameter allows you to change a critical error to a warning. mysql_health_lookback | **Optional.** The amount of time you want to look back when calculating average rates. mysql_health_environment | **Optional.** Add a variable to the plugin's environment. mysql_health_morphmessage | **Optional.** Modify the final output message. mysql_health_morphperfdata | **Optional.** The parameter allows you to change performance data labels. mysql_health_selectedperfdata | **Optional.** The parameter allows you to limit the list of performance data. mysql_health_report | **Optional.** Can be used to shorten the output. mysql_health_multiline | **Optional.** Multiline output. mysql_health_negate | **Optional.** Emulate the negate plugin. --negate warning=critical --negate unknown=critical. mysql_health_withmymodulesdyndir | **Optional.** Add-on modules for the my-modes will be searched in this directory. mysql_health_statefilesdir | **Optional.** An alternate directory where the plugin can save files. mysql_health_isvalidtime | **Optional.** Signals the plugin to return OK if now is not a valid check time. mysql_health_timeout | **Optional.** Plugin timeout. Defaults to 60s. #### oracle_health The [check_oracle_health](https://labs.consol.de/nagios/check_oracle_health/index.html) plugin uses the `DBD::Oracle` Perl library to monitor an [Oracle](https://www.oracle.com/database/) database. The Git repository is located on [GitHub](https://github.com/lausser/check_oracle_health). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ oracle_health_connect | **Required.** Specifies the database connection string (from tnsnames.ora). oracle_health_username | **Optional.** The username for the database connection. oracle_health_password | **Optional.** The password for the database connection. oracle_health_warning | **Optional.** The warning threshold depending on the mode. oracle_health_critical | **Optional.** The critical threshold depending on the mode. oracle_health_mode | **Required.** The mode uses predefined keywords for the different checks. For example "connection-time", "flash-recovery-area-usage" or "sql". oracle_health_method | **Optional.** How the plugin should connect to the database (`dbi` for using DBD::Oracle (default), `sqlplus` for using the sqlplus-Tool). oracle_health_name | **Optional.** The tablespace, datafile, wait event, latch, enqueue depending on the mode or SQL statement to be executed with "oracle_health_mode" sql. oracle_health_name2 | **Optional.** If "oracle_health_name" is a sql statement, "oracle_health_name2" can be used to appear in the output and the performance data. oracle_health_regexp | **Optional.** If set to true, "oracle_health_name" will be interpreted as a regular expression. Defaults to false. oracle_health_units | **Optional.** This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free. Possible values are "%", "KB", "MB" and "GB". oracle_health_ident | **Optional.** If set to true, outputs instance and database names. Defaults to false. oracle_health_commit | **Optional.** Set this to true to turn on autocommit for the dbd::oracle module. Defaults to false. oracle_health_noperfdata | **Optional.** Set this to true if you want to disable perfdata. Defaults to false. oracle_health_timeout | **Optional.** Plugin timeout. Defaults to 60s. oracle_health_report | **Optional.** Select the plugin output format. Can be short or long. Default to long. Environment Macros: Name | Description --------------------|------------------------------------------------------------------------------------------------------------------------------------------ ORACLE_HOME | **Required.** Specifies the location of the oracle instant client libraries. Defaults to "/usr/lib/oracle/11.2/client64/lib". Can be overridden by setting "oracle_home". TNS_ADMIN | **Required.** Specifies the location of the tnsnames.ora including the database connection strings. Defaults to "/etc/icinga2/plugin-configs". Can be overridden by setting "oracle_tns_admin". #### postgres The [check_postgres](https://bucardo.org/wiki/Check_postgres) plugin uses the `psql` binary to monitor a [PostgreSQL](https://www.postgresql.org/about/) database. The Git repository is located on [GitHub](https://github.com/bucardo/check_postgres). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ postgres_host | **Optional.** Specifies the database hostname or address. Defaults to "$address$" or "$address6$" if the `address` attribute is not set. If "postgres_unixsocket" is set to true, falls back to unix socket. postgres_port | **Optional.** Specifies the database port. Defaults to 5432. postgres_dbname | **Optional.** Specifies the database name to connect to. Defaults to "postgres" or "template1". postgres_dbuser | **Optional.** The username for the database connection. Defaults to "postgres". postgres_dbpass | **Optional.** The password for the database connection. You can use a .pgpass file instead. postgres_dbservice | **Optional.** Specifies the service name to use inside of pg_service.conf. postgres_warning | **Optional.** Specifies the warning threshold, range depends on the action. postgres_critical | **Optional.** Specifies the critical threshold, range depends on the action. postgres_include | **Optional.** Specifies name(s) items to specifically include (e.g. tables), depends on the action. postgres_exclude | **Optional.** Specifies name(s) items to specifically exclude (e.g. tables), depends on the action. postgres_includeuser | **Optional.** Include objects owned by certain users. postgres_excludeuser | **Optional.** Exclude objects owned by certain users. postgres_standby | **Optional.** Assume that the server is in continuous WAL recovery mode if set to true. Defaults to false. postgres_production | **Optional.** Assume that the server is in production mode if set to true. Defaults to false. postgres_action | **Required.** Determines the test executed. postgres_unixsocket | **Optional.** If "postgres_unixsocket" is set to true, the unix socket is used instead of an address. Defaults to false. postgres_query | **Optional.** Query for "custom_query" action. postgres_valtype | **Optional.** Value type of query result for "custom_query". postgres_reverse | **Optional.** If "postgres_reverse" is set, warning and critical values are reversed for "custom_query" action. postgres_tempdir | **Optional.** Specify directory for temporary files. The default directory is dependent on the OS. More details [here](https://perldoc.perl.org/File/Spec.html). #### mongodb The [check_mongodb.py](https://github.com/mzupan/nagios-plugin-mongodb) plugin uses the `pymongo` Python library to monitor a [MongoDB](https://docs.mongodb.com/manual/) instance. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|------------------------------------------------------------------------------------------------------------------------------ mongodb_host | **Required.** Specifies the hostname or address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. mongodb_port | **Required.** The port mongodb is running on. mongodb_user | **Optional.** The username you want to login as. mongodb_passwd | **Optional.** The password you want to use for that user. mongodb_warning | **Optional.** The warning threshold we want to set. mongodb_critical | **Optional.** The critical threshold we want to set. mongodb_action | **Required.** The action you want to take. mongodb_maxlag | **Optional.** Get max replication lag (for replication_lag action only). mongodb_mappedmemory | **Optional.** Get mapped memory instead of resident (if resident memory can not be read). mongodb_perfdata | **Optional.** Enable output of Nagios performance data. mongodb_database | **Optional.** Specify the database to check. mongodb_alldatabases | **Optional.** Check all databases (action database_size). mongodb_ssl | **Optional.** Connect using SSL. mongodb_replicaset | **Optional.** Connect to replicaset. mongodb_replcheck | **Optional.** If set to true, will enable the mongodb_replicaset value needed for "replica_primary" check. mongodb_querytype | **Optional.** The query type to check [query\|insert\|update\|delete\|getmore\|command] from queries_per_second. mongodb_collection | **Optional.** Specify the collection to check. mongodb_sampletime | **Optional.** Time used to sample number of pages faults. #### elasticsearch The [check_elasticsearch](https://github.com/anchor/nagios-plugin-elasticsearch) plugin uses the HTTP API to monitor an [Elasticsearch](https://www.elastic.co/products/elasticsearch) node. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------------|------------------------------------------------------------------------------------------------------- elasticsearch_host | **Optional.** Hostname or network address to probe. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. elasticsearch_failuredomain | **Optional.** A comma-separated list of ElasticSearch attributes that make up your cluster's failure domain. elasticsearch_masternodes | **Optional.** Issue a warning if the number of master-eligible nodes in the cluster drops below this number. By default, do not monitor the number of nodes in the cluster. elasticsearch_port | **Optional.** TCP port to probe. The ElasticSearch API should be listening here. Defaults to 9200. elasticsearch_prefix | **Optional.** Optional prefix (e.g. 'es') for the ElasticSearch API. Defaults to ''. elasticsearch_yellowcritical | **Optional.** Instead of issuing a 'warning' for a yellow cluster state, issue a 'critical' alert. Defaults to false. #### redis The [check_redis.pl](https://github.com/willixix/naglio-plugins/blob/master/check_redis.pl) plugin uses the `Redis` Perl library to monitor a [Redis](https://redis.io/) instance. The plugin can measure response time, hitrate, memory utilization, check replication synchronization, etc. It is also possible to test data in a specified key and calculate averages or summaries on ranges. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------------------|-------------------------------------------------------------------------------------------------------------- redis_hostname | **Required.** Hostname or IP Address to check. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. redis_port | **Optional.** Port number to query. Default to "6379". redis_database | **Optional.** Database name (usually a number) to query, needed for **redis_query**. redis_password | **Optional.** Password for Redis authentication. Safer alternative is to put them in a file and use **redis_credentials**. redis_credentials | **Optional.** Credentials file to read for Redis authentication. redis_timeout | **Optional.** Allows to set timeout for execution of this plugin. redis_variables | **Optional.** List of variables from info data to do threshold checks on. redis_warn | **Optional.** This option can only be used if **redis_variables** is used and the number of values listed here must exactly match number of variables specified. redis_crit | **Optional.** This option can only be used if **redis_variables** is used and the number of values listed here must exactly match number of variables specified. redis_perfparse | **Optional.** This should only be used with variables and causes variable data not only to be printed as part of main status line but also as perfparse compatible output. Defaults to false. redis_perfvars | **Optional.** This allows to list variables which values will go only into perfparse output (and not for threshold checking). redis_prev_perfdata | **Optional.** If set to true, previous performance data are used to calculate rate of change for counter statistics variables and for proper calculation of hitrate. Defaults to false. redis_rate_label | **Optional.** Prefix or Suffix label used to create a new variable which has rate of change of another base variable. You can specify PREFIX or SUFFIX or both as one string separated by ",". Default if not specified is suffix "_rate". redis_query | **Optional.** Option specifies key to query and optional variable name to assign the results to after. redis_option | **Optional.** Specifiers are separated by "," and must include NAME or PATTERN. redis_response_time | **Optional.** If this is used, plugin will measure and output connection response time in seconds. With **redis_perfparse** this would also be provided on perf variables. redis_hitrate | **Optional.** Calculates Hitrate and specify values are interpreted as WARNING and CRITICAL thresholds. redis_memory_utilization | **Optional.** This calculates percent of total memory on system used by redis. Total_memory on server must be specified with **redis_total_memory**. If you specify by itself, the plugin will just output this info. Parameter values are interpreted as WARNING and CRITICAL thresholds. redis_total_memory | **Optional.** Amount of memory on a system for memory utilization calculation. Use system memory or max_memory setting of redis. redis_replication_delay | **Optional.** Allows to set threshold on replication delay info. ### Hardware This category includes all plugin check commands for various hardware checks. #### hpasm The [check_hpasm](https://labs.consol.de/de/nagios/check_hpasm/index.html) plugin monitors the hardware health of HP Proliant Servers, provided that the `hpasm` (HP Advanced Server Management) software is installed. It is also able to monitor the system health of HP Bladesystems and storage systems. The plugin can run in two different ways: 1. Local execution using the `hpasmcli` command line tool. 2. Remote SNMP query which invokes the HP Insight Tools on the remote node. You can either set or omit `hpasm_hostname` custom attribute and select the corresponding node. The `hpasm_remote` attribute enables the plugin to execute remote SNMP queries if set to `true`. For compatibility reasons this attribute uses `true` as default value, and ensures that specifying the `hpasm_hostname` always enables remote checks. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|----------------------------------------------------------------------- hpasm_hostname | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. hpasm_community | **Optional.** SNMP community of the server (SNMP v1/2 only). hpasm_protocol | **Optional.** The SNMP protocol to use (default: 2c, other possibilities: 1,3). hpasm_port | **Optional.** The SNMP port to use (default: 161). hpasm_blacklist | **Optional.** Blacklist some (missing/failed) components. hpasm_ignore-dimms | **Optional.** Ignore "N/A"-DIMM status on misc. servers (e.g. older DL320). hpasm_ignore-fan-redundancy | **Optional.** Ignore missing redundancy partners. hpasm_customthresholds | **Optional.** Use custom thresholds for certain temperatures. hpasm_eventrange | **Optional.** Period of time before critical IML events respectively become warnings or vanish. A range is described as a number and a unit (s, m, h, d), e.g. --eventrange 1h/20m. hpasm_perfdata | **Optional.** Output performance data. If your performance data string becomes too long and is truncated by Nagios, then you can use --perfdata=short instead. This will output temperature tags without location information. hpasm_username | **Optional.** The securityName for the USM security model (SNMPv3 only). hpasm_authpassword | **Optional.** The authentication password for SNMPv3. hpasm_authprotocol | **Optional.** The authentication protocol for SNMPv3 (md5\|sha). hpasm_privpassword | **Optional.** The password for authPriv security level. hpasm_privprotocol | **Optional.** The private protocol for SNMPv3 (des\|aes\|aes128\|3des\|3desde). hpasm_servertype | **Optional.** The type of the server: proliant (default) or bladesystem. hpasm_eval-nics | **Optional.** Check network interfaces (and groups). Try it and report me whyt you think about it. I need to build up some know how on this subject. If you get an error and think, it is not justified for your configuration, please tell me about it. (always send the output of "snmpwalk -On .... 1.3.6.1.4.1.232" and a description how you setup your nics and why it is correct opposed to the plugins error message. hpasm_remote | **Optional.** Run remote SNMP checks if enabled. Otherwise checks are executed locally using the `hpasmcli` binary. Defaults to `true`. #### adaptec-raid The [check_adaptec_raid](https://github.com/thomas-krenn/check_adaptec_raid) plugin uses the `arcconf` binary to monitor Adaptec RAID controllers. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|----------------------------------------------------------------------- adaptec_controller_number | **Required.** Controller number to monitor. arcconf_path | **Required.** Path to the `arcconf` binary, e.g. "/sbin/arcconf". #### lsi-raid The [check_lsi_raid](https://github.com/thomas-krenn/check_lsi_raid) plugin uses the `storcli` binary to monitor MegaRAID RAID controllers. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|----------------------------------------------------------------------- lsi_controller_number | **Required.** Controller number to monitor. storcli_path | **Required.** Path to the `storcli` binary, e.g. "/usr/sbin/storcli". #### smart-attributes The [check_smart_attributes](https://github.com/thomas-krenn/check_smart_attributes) plugin uses the `smartctl` binary to monitor SMART values of SSDs and HDDs. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|----------------------------------------------------------------------- smart_attributes_config_path | **Required.** Path to the smart attributes config file (e.g. check_smartdb.json). smart_attributes_device | **Required.** Device name (e.g. /dev/sda) to monitor. ### IcingaCLI This category includes all plugins using the icingacli provided by Icinga Web 2. #### Business Process This subcommand is provided by the [business process module](https://exchange.icinga.com/icinga/Business+Process) and executed as `icingacli businessprocess` CLI command. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------------------------|----------------------------------------------------------------------------------------- icingacli_businessprocess_process | **Required.** Business process to monitor. icingacli_businessprocess_config | **Optional.** Configuration file containing your business process without file extension. icingacli_businessprocess_details | **Optional.** Get details for root cause analysis. Defaults to false. icingacli_businessprocess_statetype | **Optional.** Define which state type to look at, `soft` or `hard`. Overrides the default value inside the businessprocess module, if configured. ### IPMI Devices This category includes all plugins for IPMI devices. #### ipmi-sensor The [check_ipmi_sensor](https://github.com/thomas-krenn/check_ipmi_sensor_v3) plugin uses the `ipmimonitoring` binary to monitor sensor data for IPMI devices. Please read the [documentation](https://www.thomas-krenn.com/en/wiki/IPMI_Sensor_Monitoring_Plugin) for installation and configuration details. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|----------------------------------------------------------------------------------------------------- ipmi_address | **Required.** Specifies the remote host (IPMI device) to check. Defaults to "$address$". ipmi_config_file | **Optional.** Path to the FreeIPMI configuration file. It should contain IPMI username, IPMI password, and IPMI privilege-level. ipmi_username | **Optional.** The IPMI username. ipmi_password | **Optional.** The IPMI password. ipmi_privilege_level | **Optional.** The IPMI privilege level of the IPMI user. ipmi_backward_compatibility_mode | **Optional.** Enable backward compatibility mode, useful for FreeIPMI 0.5.\* (this omits FreeIPMI options "--quiet-cache" and "--sdr-cache-recreate"). ipmi_sensor_type | **Optional.** Limit sensors to query based on IPMI sensor type. Examples for IPMI sensor types are 'Fan', 'Temperature' and 'Voltage'. ipmi_sel_type | **Optional.** Limit SEL entries to specific types, run 'ipmi-sel -L' for a list of types. All sensors are populated to the SEL and per default all sensor types are monitored. ipmi_exclude_sensor_id | **Optional.** Exclude sensor matching ipmi_sensor_id. ipmi_exclude_sensor | **Optional.** Exclude sensor based on IPMI sensor type. (Comma-separated) ipmi_exclude_sel | **Optional.** Exclude SEL entries of specific sensor types. (comma-separated list). ipmi_sensor_id | **Optional.** Include sensor matching ipmi_sensor_id. ipmi_protocol_lan_version | **Optional.** Change the protocol LAN version. Defaults to "LAN_2_0". ipmi_number_of_active_fans | **Optional.** Number of fans that should be active. Otherwise a WARNING state is returned. ipmi_show_fru | **Optional.** Print the product serial number if it is available in the IPMI FRU data. ipmi_no_sel_checking | **Optional.** Turn off system event log checking via ipmi-sel. ipmi_no_thresholds | **Optional.** Turn off performance data thresholds from output-sensor-thresholds. ipmi_verbose | **Optional.** Be Verbose multi line output, also with additional details for warnings. ipmi_debug | **Optional.** Be Verbose debugging output, followed by normal multi line output. #### ipmi-alive The `ipmi-alive` check commands allows you to create a ping check for the IPMI Interface. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------------|----------------------------------------------------------------------------------------------------- ping_address | **Optional.** The address of the IPMI interface. Defaults to "$address$" if the IPMI interface's `address` attribute is set, "$address6$" otherwise. ping_wrta | **Optional.** The RTA warning threshold in milliseconds. Defaults to 5000. ping_wpl | **Optional.** The packet loss warning threshold in %. Defaults to 100. ping_crta | **Optional.** The RTA critical threshold in milliseconds. Defaults to 5000. ping_cpl | **Optional.** The packet loss critical threshold in %. Defaults to 100. ping_packets | **Optional.** The number of packets to send. Defaults to 1. ping_timeout | **Optional.** The plugin timeout in seconds. Defaults to 0 (no timeout). ### Log Management This category includes all plugins for log management, for example [Logstash](https://www.elastic.co/products/logstash). #### logstash The [logstash](https://github.com/widhalmt/check_logstash) plugin connects to the Node API of Logstash. This plugin requires at least Logstash version 5.0.x. The Node API is not activated by default. You have to configure your Logstash installation in order to allow plugin connections. Name | Description ---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ logstash_hostname | **Optional.** Hostname where Logstash is running. Defaults to `check_address` logstash_port | **Optional.** Port where Logstash is listening for API requests. Defaults to 9600 logstash_filedesc_warn | **Optional.** Warning threshold of file descriptor usage in percent. Defaults to 85 (percent). logstash_filedesc_crit | **Optional.** Critical threshold of file descriptor usage in percent. Defaults to 95 (percent). logstash_heap_warn | **Optional.** Warning threshold of heap usage in percent. Defaults to 70 (percent). logstash_heap_crit | **Optional.** Critical threshold of heap usage in percent Defaults to 80 (percent). logstash_inflight_warn | **Optional.** Warning threshold of inflight events. logstash_inflight_crit | **Optional.** Critical threshold of inflight events. logstash_cpu_warn | **Optional.** Warning threshold for cpu usage in percent. logstash_cpu_crit | **Optional.** Critical threshold for cpu usage in percent. ### Metrics This category includes all plugins for metric-based checks. #### graphite The [check_graphite](https://github.com/obfuscurity/nagios-scripts) plugin uses the `rest-client` Ruby library to monitor a [Graphite](https://graphiteapp.org) instance. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------------------|----------------------------------------------------------------------------------------------------- graphite_url | **Required.** Target url. graphite_metric | **Required.** Metric path string. graphite_shortname | **Optional.** Metric short name (used for performance data). graphite_duration | **Optional.** Length, in minute of data to parse (default: 5). graphite_function | **Optional.** Function applied to metrics for thresholds (default: average). graphite_warning | **Required.** Warning threshold. graphite_critical | **Required.** Critical threshold. graphite_units | **Optional.** Adds a text tag to the metric count in the plugin output. Useful to identify the metric units. Doesn't affect data queries. graphite_message | **Optional.** Text message to output (default: "metric count:"). graphite_zero_on_error | **Optional.** Return 0 on a graphite 500 error. graphite_link_graph | **Optional.** Add a link in the plugin output, showing a 24h graph for this metric in graphite. ### Network Components This category includes all plugins for various network components like routers, switches and firewalls. #### interfacetable The [check_interfacetable_v3t](http://www.tontonitch.com/tiki/tiki-index.php?page=Nagios+plugins+-+interfacetable_v3t) plugin generates a html page containing information about the monitored node and all of its interfaces. The Git repository is located on [GitHub](https://github.com/Tontonitch/interfacetable_v3t). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------------------|----------------------------------------------------------------------------------------------------- interfacetable_hostquery | **Required.** Specifies the remote host to poll. Defaults to "$address$". interfacetable_hostdisplay | **Optional.** Specifies the hostname to display in the HTML link. Defaults to "$host.display_name$". interfacetable_regex | **Optional.** Interface names and property names for some other options will be interpreted as regular expressions. Defaults to false. interfacetable_outputshort | **Optional.** Reduce the verbosity of the plugin output. Defaults to false. interfacetable_exclude | **Optional.** Comma separated list of interfaces globally excluded from the monitoring. interfacetable_include | **Optional.** Comma separated list of interfaces globally included in the monitoring. interfacetable_aliasmatching | **Optional.** Allow you to specify alias in addition to interface names. Defaults to false. interfacetable_excludetraffic | **Optional.** Comma separated list of interfaces excluded from traffic checks. interfacetable_includetraffic | **Optional.** Comma separated list of interfaces included for traffic checks. interfacetable_warningtraffic | **Optional.** Interface traffic load percentage leading to a warning alert. interfacetable_criticaltraffic | **Optional.** Interface traffic load percentage leading to a critical alert. interfacetable_pkt | **Optional.** Add unicast/non-unicast pkt stats for each interface. interfacetable_trafficwithpkt | **Optional.** Enable traffic calculation using pkt counters instead of octet counters. Useful when using 32-bit counters to track the load on > 1GbE interfaces. Defaults to false. interfacetable_trackproperty | **Optional.** List of tracked properties. interfacetable_excludeproperty | **Optional.** Comma separated list of interfaces excluded from the property tracking. interfacetable_includeproperty | **Optional.** Comma separated list of interfaces included in the property tracking. interfacetable_community | **Optional.** Specifies the snmp v1/v2c community string. Defaults to "public" if using snmp v1/v2c, ignored using v3. interfacetable_snmpv2 | **Optional.** Use snmp v2c. Defaults to false. interfacetable_login | **Optional.** Login for snmpv3 authentication. interfacetable_passwd | **Optional.** Auth password for snmpv3 authentication. interfacetable_privpass | **Optional.** Priv password for snmpv3 authentication. interfacetable_protocols | **Optional.** Authentication protocol,Priv protocol for snmpv3 authentication. interfacetable_domain | **Optional.** SNMP transport domain. interfacetable_contextname | **Optional.** Context name for the snmp requests. interfacetable_port | **Optional.** SNMP port. Defaults to standard port. interfacetable_64bits | **Optional.** Use SNMP 64-bits counters. Defaults to false. interfacetable_maxrepetitions | **Optional.** Increasing this value may enhance snmp query performances by gathering more results at one time. interfacetable_snmptimeout | **Optional.** Define the Transport Layer timeout for the snmp queries. interfacetable_snmpretries | **Optional.** Define the number of times to retry sending a SNMP message. interfacetable_snmpmaxmsgsize | **Optional.** Size of the SNMP message in octets, useful in case of too long responses. Be careful with network filters. Range 484 - 65535. Apply only to netsnmp perl bindings. The default is 1472 octets for UDP/IPv4, 1452 octets for UDP/IPv6, 1460 octets for TCP/IPv4, and 1440 octets for TCP/IPv6. interfacetable_unixsnmp | **Optional.** Use unix snmp utilities for snmp requests. Defaults to false, which means use the perl bindings. interfacetable_enableperfdata | **Optional.** Enable port performance data. Defaults to false. interfacetable_perfdataformat | **Optional.** Define which performance data will be generated. Possible values are "full" (default), "loadonly", "globalonly". interfacetable_perfdatathreshold | **Optional.** Define which thresholds are printed in the generated performance data. Possible values are "full" (default), "loadonly", "globalonly". interfacetable_perfdatadir | **Optional.** When specified, the performance data are also written directly to a file, in the specified location. interfacetable_perfdataservicedesc | **Optional.** Specify additional parameters for output performance data to PNP. Defaults to "$service.name$", only affects **interfacetable_perfdatadir**. interfacetable_grapher | **Optional.** Specify the used graphing solution. Possible values are "pnp4nagios" (default), "nagiosgrapher", "netwaysgrapherv2" and "ingraph". interfacetable_grapherurl | **Optional.** Graphing system url. Default depends on **interfacetable_grapher**. interfacetable_portperfunit | **Optional.** Traffic could be reported in bits (counters) or in bps (calculated value). interfacetable_nodetype | **Optional.** Specify the node type, for specific information to be printed / specific oids to be used. Possible values: "standard" (default), "cisco", "hp", "netscreen", "netapp", "bigip", "bluecoat", "brocade", "brocade-nos", "nortel", "hpux". interfacetable_duplex | **Optional.** Add the duplex mode property for each interface in the interface table. Defaults to false. interfacetable_stp | **Optional.** Add the stp state property for each interface in the interface table. Defaults to false. interfacetable_vlan | **Optional.** Add the vlan attribution property for each interface in the interface table. Defaults to false. This option is available only for the following nodetypes: "cisco", "hp", "nortel" interfacetable_noipinfo | **Optional.** Remove the ip information for each interface from the interface table. Defaults to false. interfacetable_alias | **Optional.** Add the alias information for each interface in the interface table. Defaults to false. interfacetable_accessmethod | **Optional.** Access method for a shortcut to the host in the HTML page. Format is : [:] Where method can be: ssh, telnet, http or https. interfacetable_htmltablelinktarget | **Optional.** Specifies the windows or the frame where the [details] link will load the generated html page. Possible values are: "_blank", "_self" (default), "_parent", "_top", or a frame name. interfacetable_delta | **Optional.** Set the delta used for interface throughput calculation in seconds. interfacetable_ifs | **Optional.** Input field separator. Defaults to ",". interfacetable_cache | **Optional.** Define the retention time of the cached data in seconds. interfacetable_noifloadgradient | **Optional.** Disable color gradient from green over yellow to red for the load percentage. Defaults to false. interfacetable_nohuman | **Optional.** Do not translate bandwidth usage in human readable format. Defaults to false. interfacetable_snapshot | **Optional.** Force the plugin to run like if it was the first launch. Defaults to false. interfacetable_timeout | **Optional.** Define the global timeout limit of the plugin in seconds. Defaults to "15s". interfacetable_css | **Optional.** Define the css stylesheet used by the generated html files. Possible values are "classic", "icinga" or "icinga-alternate1". interfacetable_config | **Optional.** Specify a config file to load. interfacetable_noconfigtable | **Optional.** Disable configuration table on the generated HTML page. Defaults to false. interfacetable_notips | **Optional.** Disable the tips in the generated html tables. Defaults to false. interfacetable_defaulttablesorting | **Optional.** Default table sorting can be "index" (default) or "name". interfacetable_tablesplit | **Optional.** Generate multiple interface tables, one per interface type. Defaults to false. interfacetable_notype | **Optional.** Remove the interface type for each interface. Defaults to false. #### iftraffic The [check_iftraffic](https://exchange.icinga.com/exchange/iftraffic) plugin checks the utilization of a given interface name using the SNMP protocol. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|--------------------------------------------------------- iftraffic_address | **Required.** Specifies the remote host. Defaults to "$address$". iftraffic_community | **Optional.** SNMP community. Defaults to "public'" if omitted. iftraffic_interface | **Required.** Queried interface name. iftraffic_bandwidth | **Required.** Interface maximum speed in kilo/mega/giga/bits per second. iftraffic_units | **Optional.** Interface units can be one of these values: `g` (gigabits/s),`m` (megabits/s), `k` (kilobits/s),`b` (bits/s) iftraffic_warn | **Optional.** Percent of bandwidth usage necessary to result in warning status (defaults to `85`). iftraffic_crit | **Optional.** Percent of bandwidth usage necessary to result in critical status (defaults to `98`). iftraffic_max_counter | **Optional.** Maximum counter value of net devices in kilo/mega/giga/bytes. #### iftraffic64 The [check_iftraffic64](https://exchange.icinga.com/exchange/iftraffic64) plugin checks the utilization of a given interface name using the SNMP protocol. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|--------------------------------------------------------- iftraffic64_address | **Required.** Specifies the remote host. Defaults to "$address$". iftraffic64_community | **Optional.** SNMP community. Defaults to "public'" if omitted. iftraffic64_interface | **Required.** Queried interface name. iftraffic64_bandwidth | **Required.** Interface maximum speed in kilo/mega/giga/bits per second. iftraffic64_units | **Optional.** Interface units can be one of these values: `g` (gigabits/s),`m` (megabits/s), `k` (kilobits/s),`b` (bits/s) iftraffic64_warn | **Optional.** Percent of bandwidth usage necessary to result in warning status (defaults to `85`). iftraffic64_crit | **Optional.** Percent of bandwidth usage necessary to result in critical status (defaults to `98`). iftraffic64_max_counter | **Optional.** Maximum counter value of net devices in kilo/mega/giga/bytes. #### interfaces The [check_interfaces](https://git.netways.org/plugins/check_interfaces) plugin uses SNMP to monitor network interfaces and their utilization. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------|--------------------------------------------------------- interfaces_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. interfaces_regex | **Optional.** Interface list regexp. interfaces_exclude_regex | **Optional.** Interface list negative regexp. interfaces_errors | **Optional.** Number of in errors (CRC errors for cisco) to consider a warning (default 50). interface_out_errors | **Optional.** Number of out errors (collisions for cisco) to consider a warning (default same as in errors). interfaces_perfdata | **Optional.** perfdata from last check result. interfaces_prefix | **Optional.** Prefix interface names with this label. interfaces_lastcheck | **Optional.** Last checktime (unixtime). interfaces_bandwidth | **Optional.** Bandwidth warn level in percent. interfaces_speed | **Optional.** Override speed detection with this value (bits per sec). interfaces_trim | **Optional.** Cut this number of characters from the start of interface descriptions. interfaces_mode | **Optional.** Special operating mode (default,cisco,nonbulk,bintec). interfaces_auth_proto | **Optional.** SNMPv3 Auth Protocol (SHA\|MD5) interfaces_auth_phrase | **Optional.** SNMPv3 Auth Phrase interfaces_priv_proto | **Optional.** SNMPv3 Privacy Protocol (AES\|DES) interfaces_priv_phrase | **Optional.** SNMPv3 Privacy Phrase interfaces_user | **Optional.** SNMPv3 User interfaces_down_is_ok | **Optional.** Disables critical alerts for down interfaces. interfaces_aliases | **Optional.** Retrieves the interface description. interfaces_match_aliases | **Optional.** Also match against aliases (Option --aliases automatically enabled). interfaces_timeout | **Optional.** Sets the SNMP timeout (in ms). interfaces_sleep | **Optional.** Sleep between every SNMP query (in ms). interfaces_names | **Optional.** If set to true, use ifName instead of ifDescr. #### nwc_health The [check_nwc_health](https://labs.consol.de/de/nagios/check_nwc_health/index.html) plugin uses SNMP to monitor network components. The plugin is able to generate interface statistics, check hardware (CPU, memory, fan, power, etc.), monitor firewall policies, HRSP, load-balancer pools, processor and memory usage. Currently the following network components are supported: Cisco IOS, Cisco Nexus, Cisco ASA, Cisco PIX, F5 BIG-IP, CheckPoint Firewall1, Juniper NetScreen, HP Procurve, Nortel, Brocade 4100/4900, EMC DS 4700, EMC DS 24, Allied Telesyn. Blue Coat SG600, Cisco Wireless Lan Controller 5500, Brocade ICX6610-24-HPOE, Cisco UC Telefonzeugs, FOUNDRY-SN-AGENT-MIB, FRITZ!BOX 7390, FRITZ!DECT 200, Juniper IVE, Pulse-Gateway MAG4610, Cisco IronPort AsyncOS, Foundry, etc. A complete list can be found in the plugin [documentation](https://labs.consol.de/nagios/check_nwc_health/index.html). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|--------------------------------------------------------- nwc_health_hostname | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. nwc_health_mode | **Optional.** The plugin mode. A list of all available modes can be found in the [plugin documentation](https://labs.consol.de/nagios/check_nwc_health/index.html). nwc_health_timeout | **Optional.** Seconds before plugin times out (default: 15) nwc_health_blacklist | **Optional.** Blacklist some (missing/failed) components. nwc_health_port | **Optional.** The SNMP port to use (default: 161). nwc_health_domain | **Optional.** The transport domain to use (default: udp/ipv4, other possible values: udp6, udp/ipv6, tcp, tcp4, tcp/ipv4, tcp6, tcp/ipv6). nwc_health_protocol | **Optional.** The SNMP protocol to use (default: 2c, other possibilities: 1,3). nwc_health_community | **Optional.** SNMP community of the server (SNMP v1/2 only). nwc_health_username | **Optional.** The securityName for the USM security model (SNMPv3 only). nwc_health_authpassword | **Optional.** The authentication password for SNMPv3. nwc_health_authprotocol | **Optional.** The authentication protocol for SNMPv3 (md5\|sha). nwc_health_privpassword | **Optional.** The password for authPriv security level. nwc_health_privprotocol | **Optional.** The private protocol for SNMPv3 (des\|aes\|aes128\|3des\|3desde). nwc_health_contextengineid | **Optional.** The context engine id for SNMPv3 (10 to 64 hex characters). nwc_health_contextname | **Optional.** The context name for SNMPv3 (empty represents the default context). nwc_health_name | **Optional.** The name of an interface (ifDescr). nwc_health_drecksptkdb | **Optional.** This parameter must be used instead of --name, because Devel::ptkdb is stealing the latter from the command line. nwc_health_alias | **Optional.** The alias name of a 64bit-interface (ifAlias) nwc_health_regexp | **Optional.** A flag indicating that --name is a regular expression nwc_health_ifspeedin | **Optional.** Override the ifspeed oid of an interface (only inbound) nwc_health_ifspeedout | **Optional.** Override the ifspeed oid of an interface (only outbound) nwc_health_ifspeed | **Optional.** Override the ifspeed oid of an interface nwc_health_units | **Optional.** One of %, B, KB, MB, GB, Bit, KBi, MBi, GBi. (used for e.g. mode interface-usage) nwc_health_name2 | **Optional.** The secondary name of a component. nwc_health_role | **Optional.** The role of this device in a hsrp group (active/standby/listen). nwc_health_report | **Optional.** Can be used to shorten the output. Possible values are: 'long' (default), 'short' (to shorten if available), or 'html' (to produce some html outputs if available) nwc_health_lookback | **Optional.** The amount of time you want to look back when calculating average rates. Use it for mode interface-errors or interface-usage. Without --lookback the time between two runs of check_nwc_health is the base for calculations. If you want your checkresult to be based for example on the past hour, use --lookback 3600. nwc_health_warning | **Optional.** The warning threshold nwc_health_critical | **Optional.** The critical threshold nwc_health_warningx | **Optional.** The extended warning thresholds nwc_health_criticalx | **Optional.** The extended critical thresholds nwc_health_mitigation | **Optional.** The parameter allows you to change a critical error to a warning (1) or ok (0). nwc_health_selectedperfdata | **Optional.** The parameter allows you to limit the list of performance data. It's a perl regexp. Only matching perfdata show up in the output. nwc_health_morphperfdata | **Optional.** The parameter allows you to change performance data labels. It's a perl regexp and a substitution. --morphperfdata '(.*)ISATAP(.*)'='$1patasi$2' nwc_health_negate | **Optional.** The parameter allows you to map exit levels, such as warning=critical. nwc_health_mymodules-dyn-dir | **Optional.** A directory where own extensions can be found. nwc_health_servertype | **Optional.** The type of the network device: cisco (default). Use it if auto-detection is not possible. nwc_health_statefilesdir | **Optional.** An alternate directory where the plugin can save files. nwc_health_oids | **Optional.** A list of oids which are downloaded and written to a cache file. Use it together with --mode oidcache. nwc_health_offline | **Optional.** The maximum number of seconds since the last update of cache file before it is considered too old. nwc_health_multiline | **Optional.** Multiline output ### Operating System This category contains plugins which receive details about your operating system or the guest system. #### mem The [check_mem.pl](https://github.com/justintime/nagios-plugins) plugin checks the memory usage on linux and unix hosts. It is able to count cache memory as free when compared to thresholds. More details can be found on [this blog entry](http://sysadminsjourney.com/content/2009/06/04/new-and-improved-checkmempl-nagios-plugin). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -------------|----------------------------------------------------------------------------------------------------------------------- mem_used | **Optional.** Tell the plugin to check for used memory in opposite of **mem_free**. Must specify one of these as true. mem_free | **Optional.** Tell the plugin to check for free memory in opposite of **mem_used**. Must specify one of these as true. mem_cache | **Optional.** If set to true, plugin will count cache as free memory. Defaults to false. mem_warning | **Required.** Specify the warning threshold as number interpreted as percent. mem_critical | **Required.** Specify the critical threshold as number interpreted as percent. #### running_kernel The [check_running_kernel](https://packages.debian.org/stretch/nagios-plugins-contrib) plugin is provided by the `nagios-plugin-contrib` package on Debian/Ubuntu. Custom attributes: Name | Description ---------------------------|------------- running\_kernel\_use\_sudo | Whether to run the plugin with `sudo`. Defaults to false except on Ubuntu where it defaults to true. #### iostats The [check_iostats](https://github.com/dnsmichi/icinga-plugins/blob/master/scripts/check_iostats) plugin uses the `iostat` binary to monitor I/O on a Linux host. The default thresholds are rather high so you can use a grapher for baselining before setting your own. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------|----------------------------------------------------------------------------------------------------------------------- iostats\_disk | **Required.** The device to monitor without path. e.g. sda or vda. (default: sda). iostats\_warning\_tps | **Required.** Warning threshold for tps (default: 3000). iostats\_warning\_read | **Required.** Warning threshold for KB/s reads (default: 50000). iostats\_warning\_write | **Required.** Warning threshold for KB/s writes (default: 10000). iostats\_warning\_wait | **Required.** Warning threshold for % iowait (default: 50). iostats\_critical\_tps | **Required.** Critical threshold for tps (default: 5000). iostats\_critical\_read | **Required.** Critical threshold for KB/s reads (default: 80000). iostats\_critical\_write | **Required.** Critical threshold for KB/s writes (default: 25000). iostats\_critical\_wait | **Required.** Critical threshold for % iowait (default: 80). #### iostat The [check_iostat](https://github.com/dnsmichi/icinga-plugins/blob/master/scripts/check_iostat) plugin uses the `iostat` binary to monitor disk I/O on a Linux host. The default thresholds are rather high so you can use a grapher for baselining before setting your own. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------|----------------------------------------------------------------------------------------------------------------------- iostat\_disk | **Required.** The device to monitor without path. e.g. sda or vda. (default: sda). iostat\_wtps | **Required.** Warning threshold for tps (default: 100). iostat\_wread | **Required.** Warning threshold for KB/s reads (default: 100). iostat\_wwrite | **Required.** Warning threshold for KB/s writes (default: 100). iostat\_ctps | **Required.** Critical threshold for tps (default: 200). iostat\_cread | **Required.** Critical threshold for KB/s reads (default: 200). iostat\_cwrite | **Required.** Critical threshold for KB/s writes (default: 200). #### yum The [check_yum](https://github.com/calestyo/check_yum) plugin checks the YUM package management system for package updates. The plugin requires the `yum-plugin-security` package to differentiate between security and normal updates. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yum_all_updates | **Optional.** Set to true to not distinguish between security and non-security updates, but returns critical for any available update. This may be used if the YUM security plugin is absent or you want to maintain every single package at the latest version. You may want to use **yum_warn_on_any_update** instead of this option. Defaults to false. yum_warn_on_any_update | **Optional.** Set to true to warn if there are any (non-security) package updates available. Defaults to false. yum_cache_only | **Optional.** If set to true, plugin runs entirely from cache and does not update the cache when running YUM. Useful if you have `yum makecache` cronned. Defaults to false. yum_no_warn_on_lock | **Optional.** If set to true, returns OK instead of WARNING when YUM is locked and fails to check for updates due to another instance running. Defaults to false. yum_no_warn_on_updates | **Optional.** If set to true, returns OK instead of WARNING even when updates are available. The plugin output still shows the number of available updates. Defaults to false. yum_enablerepo | **Optional.** Explicitly enables a repository when calling YUM. Can take a comma separated list of repositories. Note that enabling repositories can lead to unexpected results, for example when protected repositories are enabled. yum_disablerepo | **Optional.** Explicitly disables a repository when calling YUM. Can take a comma separated list of repositories. Note that enabling repositories can lead to unexpected results, for example when protected repositories are enabled. yum_installroot | **Optional.** Specifies another installation root directory (for example a chroot). yum_timeout | **Optional.** Set a timeout in seconds after which the plugin will exit (defaults to 55 seconds). ### Storage This category includes all plugins for various storage and object storage technologies. #### glusterfs The [glusterfs](https://www.unixadm.org/software/nagios-stuff/checks/check_glusterfs) plugin is used to check the GlusterFS storage health on the server. The plugin requires `sudo` permissions. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ glusterfs_perfdata | **Optional.** Print perfdata of all or the specified volume. glusterfs_warnonfailedheal | **Optional.** Warn if the *heal-failed* log contains entries. The log can be cleared by restarting glusterd. glusterfs_volume | **Optional.** Only check the specified *VOLUME*. If --volume is not set, all volumes are checked. glusterfs_disk_warning | **Optional.** Warn if disk usage is above *DISKWARN*. Defaults to 90 (percent). glusterfs_disk_critical | **Optional.** Return a critical error if disk usage is above *DISKCRIT*. Defaults to 95 (percent). glusterfs_inode_warning | **Optional.** Warn if inode usage is above *DISKWARN*. Defaults to 90 (percent). glusterfs_inode_critical | **Optional.** Return a critical error if inode usage is above *DISKCRIT*. Defaults to 95 (percent). ### Virtualization This category includes all plugins for various virtualization technologies. #### esxi_hardware The [check_esxi_hardware.py](https://www.claudiokuenzler.com/nagios-plugins/check_esxi_hardware.php) plugin uses the [pywbem](https://pywbem.github.io/pywbem/) Python library to monitor the hardware of ESXi servers through the [VMWare API](https://www.vmware.com/support/pubs/sdk_pubs.html) and CIM service. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ esxi_hardware_host | **Required.** Specifies the host to monitor. Defaults to "$address$". esxi_hardware_user | **Required.** Specifies the user for polling. Must be a local user of the root group on the system. Can also be provided as a file path file:/path/to/.passwdfile, then first string of file is used. esxi_hardware_pass | **Required.** Password of the user. Can also be provided as a file path file:/path/to/.passwdfile, then second string of file is used. esxi_hardware_port | **Optional.** Specifies the CIM port to connect to. Defaults to 5989. esxi_hardware_vendor | **Optional.** Defines the vendor of the server: "auto", "dell", "hp", "ibm", "intel", "unknown" (default). esxi_hardware_html | **Optional.** Add web-links to hardware manuals for Dell servers (use your country extension). Only useful with **esxi_hardware_vendor** = dell. esxi_hardware_ignore | **Optional.** Comma separated list of elements to ignore. esxi_hardware_perfdata | **Optional.** Add performcedata for graphers like PNP4Nagios to the output. Defaults to false. esxi_hardware_nopower | **Optional.** Do not collect power performance data, when **esxi_hardware_perfdata** is set to true. Defaults to false. esxi_hardware_novolts | **Optional.** Do not collect voltage performance data, when **esxi_hardware_perfdata** is set to true. Defaults to false. esxi_hardware_nocurrent | **Optional.** Do not collect current performance data, when **esxi_hardware_perfdata** is set to true. Defaults to false. esxi_hardware_notemp | **Optional.** Do not collect temperature performance data, when **esxi_hardware_perfdata** is set to true. Defaults to false. esxi_hardware_nofan | **Optional.** Do not collect fan performance data, when **esxi_hardware_perfdata** is set to true. Defaults to false. esxi_hardware_nolcd | **Optional.** Do not collect lcd/display status data. Defaults to false. #### VMware Check commands for the [check_vmware_esx](https://github.com/BaldMansMojo/check_vmware_esx) plugin. **vmware-esx-dc-volumes** Check command object for the `check_vmware_esx` plugin. Shows all datastore volumes info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_subselect | **Optional.** Volume name to be checked the free space. vmware_gigabyte | **Optional.** Output in GB instead of MB. vmware_usedspace | **Optional.** Output used space instead of free. Defaults to "false". vmware_alertonly | **Optional.** List only alerting volumes. Defaults to "false". vmware_exclude | **Optional.** Blacklist volumes name. No value defined as default. vmware_include | **Optional.** Whitelist volumes name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_dc_volume_used | **Optional.** Output used space instead of free. Defaults to "true". vmware_warn | **Optional.** The warning threshold for volumes. Defaults to "80%". vmware_crit | **Optional.** The critical threshold for volumes. Defaults to "90%". **vmware-esx-dc-runtime-info** Check command object for the `check_vmware_esx` plugin. Shows all runtime info for the datacenter/Vcenter. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-dc-runtime-listvms** Check command object for the `check_vmware_esx` plugin. List of vmware machines and their power state. BEWARE!! In larger environments systems can cause trouble displaying the informations needed due to the mass of data. Use **vmware_alertonly** to avoid this. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_alertonly | **Optional.** List only alerting VMs. Important here to avoid masses of data. vmware_exclude | **Optional.** Blacklist VMs name. No value defined as default. vmware_include | **Optional.** Whitelist VMs name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-dc-runtime-listhost** Check command object for the `check_vmware_esx` plugin. List of VMware ESX hosts and their power state. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_alertonly | **Optional.** List only alerting hosts. Important here to avoid masses of data. vmware_exclude | **Optional.** Blacklist VMware ESX hosts. No value defined as default. vmware_include | **Optional.** Whitelist VMware ESX hosts. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-dc-runtime-listcluster** Check command object for the `check_vmware_esx` plugin. List of VMware clusters and their states. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_alertonly | **Optional.** List only alerting hosts. Important here to avoid masses of data. vmware_exclude | **Optional.** Blacklist VMware cluster. No value defined as default. vmware_include | **Optional.** Whitelist VMware cluster. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-dc-runtime-issues** Check command object for the `check_vmware_esx` plugin. All issues for the host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist issues. No value defined as default. vmware_include | **Optional.** Whitelist issues. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-dc-runtime-status** Check command object for the `check_vmware_esx` plugin. Overall object status (gray/green/red/yellow). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-dc-runtime-tools** Check command object for the `check_vmware_esx` plugin. Vmware Tools status. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Required.** Datacenter/vCenter hostname. vmware_cluster | **Optional.** ESX or ESXi clustername. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_poweredonly | **Optional.** List only VMs which are powered on. No value defined as default. vmware_alertonly | **Optional.** List only alerting VMs. Important here to avoid masses of data. vmware_exclude | **Optional.** Blacklist VMs. No value defined as default. vmware_include | **Optional.** Whitelist VMs. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. vmware_openvmtools | **Optional** Prevent CRITICAL state for installed and running Open VM Tools. **vmware-esx-soap-host-check** Check command object for the `check_vmware_esx` plugin. Simple check to verify a successful connection to VMware SOAP API. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-uptime** Check command object for the `check_vmware_esx` plugin. Displays uptime of the VMware host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-cpu** Check command object for the `check_vmware_esx` plugin. CPU usage in percentage. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. Defaults to "80%". vmware_crit | **Optional.** The critical threshold in percent. Defaults to "90%". **vmware-esx-soap-host-cpu-ready** Check command object for the `check_vmware_esx` plugin. Percentage of time that the virtual machine was ready, but could not get scheduled to run on the physical CPU. CPU ready time is dependent on the number of virtual machines on the host and their CPU loads. High or growing ready time can be a hint CPU bottlenecks. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-cpu-wait** Check command object for the `check_vmware_esx` plugin. CPU time spent in wait state. The wait total includes time spent the CPU idle, CPU swap wait, and CPU I/O wait states. High or growing wait time can be a hint I/O bottlenecks. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-cpu-usage** Check command object for the `check_vmware_esx` plugin. Actively used CPU of the host, as a percentage of the total available CPU. Active CPU is approximately equal to the ratio of the used CPU to the available CPU. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. Defaults to "80%". vmware_crit | **Optional.** The critical threshold in percent. Defaults to "90%". **vmware-esx-soap-host-mem** Check command object for the `check_vmware_esx` plugin. All mem info(except overall and no thresholds). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-mem-usage** Check command object for the `check_vmware_esx` plugin. Average mem usage in percentage. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. Defaults to "80%". vmware_crit | **Optional.** The critical threshold in percent. Defaults to "90%". **vmware-esx-soap-host-mem-consumed** Check command object for the `check_vmware_esx` plugin. Amount of machine memory used on the host. Consumed memory includes Includes memory used by the Service Console, the VMkernel vSphere services, plus the total consumed metrics for all running virtual machines in MB. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. No value defined as default. vmware_crit | **Optional.** The critical threshold in percent. No value defined as default. **vmware-esx-soap-host-mem-swapused** Check command object for the `check_vmware_esx` plugin. Amount of memory that is used by swap. Sum of memory swapped of all powered on VMs and vSphere services on the host in MB. In case of an error all VMs with their swap used will be displayed. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. No value defined as default. vmware_crit | **Optional.** The critical threshold in percent. No value defined as default. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-mem-overhead** Check command object for the `check_vmware_esx` plugin. Additional mem used by VM Server in MB. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Auhentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. No value defined as default. vmware_crit | **Optional.** The critical threshold in percent. No value defined as default. **vmware-esx-soap-host-mem-memctl** Check command object for the `check_vmware_esx` plugin. The sum of all vmmemctl values in MB for all powered-on virtual machines, plus vSphere services on the host. If the balloon target value is greater than the balloon value, the VMkernel inflates the balloon, causing more virtual machine memory to be reclaimed. If the balloon target value is less than the balloon value, the VMkernel deflates the balloon, which allows the virtual machine to consume additional memory if needed (used by VM memory control driver). In case of an error all VMs with their vmmemctl values will be displayed. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in percent. No value defined as default. vmware_crit | **Optional.** The critical threshold in percent. No value defined as default. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-net** Check command object for the `check_vmware_esx` plugin. Shows net info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist NICs. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist expression as regexp. **vmware-esx-soap-host-net-usage** Check command object for the `check_vmware_esx` plugin. Overall network usage in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in KBps(Kilobytes per Second). No value defined as default. vmware_crit | **Optional.** The critical threshold in KBps(Kilobytes per Second). No value defined as default. **vmware-esx-soap-host-net-receive** Check command object for the `check_vmware_esx` plugin. Data receive in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in KBps(Kilobytes per Second). No value defined as default. vmware_crit | **Optional.** The critical threshold in KBps(Kilobytes per Second). No value defined as default. **vmware-esx-soap-host-net-send** Check command object for the `check_vmware_esx` plugin. Data send in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold in KBps(Kilobytes per Second). No value defined as default. vmware_crit | **Optional.** The critical threshold in KBps(Kilobytes per Second). No value defined as default. **vmware-esx-soap-host-net-nic** Check command object for the `check_vmware_esx` plugin. Check all active NICs. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist NICs. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist expression as regexp. **vmware-esx-soap-host-volumes** Check command object for the `check_vmware_esx` plugin. Shows all datastore volumes info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_subselect | **Optional.** Volume name to be checked the free space. vmware_gigabyte | **Optional.** Output in GB instead of MB. vmware_usedspace | **Optional.** Output used space instead of free. Defaults to "false". vmware_alertonly | **Optional.** List only alerting volumes. Defaults to "false". vmware_exclude | **Optional.** Blacklist volumes name. No value defined as default. vmware_include | **Optional.** Whitelist volumes name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_warn | **Optional.** The warning threshold for volumes. Defaults to "80%". vmware_crit | **Optional.** The critical threshold for volumes. Defaults to "90%". vmware_spaceleft | **Optional.** This has to be used in conjunction with thresholds as mentioned above. **vmware-esx-soap-host-io** Check command object for the `check_vmware_esx` plugin. Shows all disk io info. Without subselect no thresholds can be given. All I/O values are aggregated from historical intervals over the past 24 hours with a 5 minute sample rate. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-io-aborted** Check command object for the `check_vmware_esx` plugin. Number of aborted SCSI commands. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-resets** Check command object for the `check_vmware_esx` plugin. Number of SCSI bus resets. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-read** Check command object for the `check_vmware_esx` plugin. Average number of kilobytes read from the disk each second. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-read-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) to process a SCSI read command issued from the Guest OS to the virtual machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-write** Check command object for the `check_vmware_esx` plugin. Average number of kilobytes written to disk each second. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-write-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) taken to process a SCSI write command issued by the Guest OS to the virtual machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-usage** Check command object for the `check_vmware_esx` plugin. Aggregated disk I/O rate. For hosts, this metric includes the rates for all virtual machines running on the host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-kernel-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) spent by VMkernel processing each SCSI command. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-device-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) to complete a SCSI command from the physical device. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-queue-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) spent in the VMkernel queue. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-io-total-latency** Check command object for the `check_vmware_esx` plugin. Average amount of time (ms) taken during the collection interval to process a SCSI command issued by the guest OS to the virtual machine. The sum of kernelWriteLatency and deviceWriteLatency. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-host-media** Check command object for the `check_vmware_esx` plugin. List vm's with attached host mounted media like cd,dvd or floppy drives. This is important for monitoring because a virtual machine with a mount cd or dvd drive can not be moved to another host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist VMs name. No value defined as default. vmware_include | **Optional.** Whitelist VMs name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-service** Check command object for the `check_vmware_esx` plugin. Shows host service info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist services name. No value defined as default. vmware_include | **Optional.** Whitelist services name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-runtime** Check command object for the `check_vmware_esx` plugin. Shows runtime info: VMs, overall status, connection state, health, storagehealth, temperature and sensor are represented as one value and without thresholds. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-runtime-con** Check command object for the `check_vmware_esx` plugin. Shows connection state. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-runtime-listvms** Check command object for the `check_vmware_esx` plugin. List of VMware machines and their status. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist VMs name. No value defined as default. vmware_include | **Optional.** Whitelist VMs name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-runtime-status** Check command object for the `check_vmware_esx` plugin. Overall object status (gray/green/red/yellow). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-host-runtime-health** Check command object for the `check_vmware_esx` plugin. Checks cpu/storage/memory/sensor status. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist status name. No value defined as default. vmware_include | **Optional.** Whitelist status name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. **vmware-esx-soap-host-runtime-health-listsensors** Check command object for the `check_vmware_esx` plugin. List all available sensors(use for listing purpose only). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist status name. No value defined as default. vmware_include | **Optional.** Whitelist status name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. **vmware-esx-soap-host-runtime-health-nostoragestatus** Check command object for the `check_vmware_esx` plugin. This is to avoid a double alarm if you use **vmware-esx-soap-host-runtime-health** and **vmware-esx-soap-host-runtime-storagehealth**. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist status name. No value defined as default. vmware_include | **Optional.** Whitelist status name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. **vmware-esx-soap-host-runtime-storagehealth** Check command object for the `check_vmware_esx` plugin. Local storage status check. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist storage name. No value defined as default. vmware_include | **Optional.** Whitelist storage name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-runtime-temp** Check command object for the `check_vmware_esx` plugin. Lists all temperature sensors. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist sensor name. No value defined as default. vmware_include | **Optional.** Whitelist sensor name. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-runtime-issues** Check command object for the `check_vmware_esx` plugin. Lists all configuration issues for the host. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist configuration issues. No value defined as default. vmware_include | **Optional.** Whitelist configuration issues. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-storage** Check command object for the `check_vmware_esx` plugin. Shows Host storage info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist adapters, luns and paths. No value defined as default. vmware_include | **Optional.** Whitelist adapters, luns and paths. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. **vmware-esx-soap-host-storage-adapter** Check command object for the `check_vmware_esx` plugin. List host bus adapters. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist adapters. No value defined as default. vmware_include | **Optional.** Whitelist adapters. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-storage-lun** Check command object for the `check_vmware_esx` plugin. List SCSI logical units. The listing will include: LUN, canonical name of the disc, all of displayed name which is not part of the canonical name and status. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_exclude | **Optional.** Blacklist luns. No value defined as default. vmware_include | **Optional.** Whitelist luns. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. **vmware-esx-soap-host-storage-path** Check command object for the `check_vmware_esx` plugin. List multipaths and the associated paths. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_host | **Required.** ESX or ESXi hostname. vmware_datacenter | **Optional.** Datacenter/vCenter hostname. In case the check is done through a Datacenter/vCenter host. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_alertonly | **Optional.** List only alerting units. Important here to avoid masses of data. Defaults to "false". vmware_exclude | **Optional.** Blacklist paths. No value defined as default. vmware_include | **Optional.** Whitelist paths. No value defined as default. vmware_isregexp | **Optional.** Treat blacklist and whitelist expressions as regexp. vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. vmware_standbyok | **Optional.** For storage systems where a standby multipath is ok and not a warning. Defaults to false. **vmware-esx-soap-vm-cpu** Check command object for the `check_vmware_esx` plugin. Shows all CPU usage info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-cpu-ready** Check command object for the `check_vmware_esx` plugin. Percentage of time that the virtual machine was ready, but could not get scheduled to run on the physical CPU. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-cpu-wait** Check command object for the `check_vmware_esx` plugin. CPU time spent in wait state. The wait total includes time spent the CPU idle, CPU swap wait, and CPU I/O wait states. High or growing wait time can be a hint I/O bottlenecks. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-cpu-usage** Check command object for the `check_vmware_esx` plugin. Amount of actively used virtual CPU, as a percentage of total available CPU. This is the host's view of the CPU usage, not the guest operating system view. It is the average CPU utilization over all available virtual CPUs in the virtual machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** Warning threshold in percent. Defaults to "80%". vmware_crit | **Optional.** Critical threshold in percent. Defaults to "90%". **vmware-esx-soap-vm-mem** Check command object for the `check_vmware_esx` plugin. Shows all memory info, except overall. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-mem-usage** Check command object for the `check_vmware_esx` plugin. Average mem usage in percentage of configured virtual machine "physical" memory. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** Warning threshold in percent. Defaults to "80%". vmware_crit | **Optional.** Critical threshold in percent. Defaults to "90%". **vmware-esx-soap-vm-mem-consumed** Check command object for the `check_vmware_esx` plugin. Amount of guest physical memory in MB consumed by the virtual machine for guest memory. Consumed memory does not include overhead memory. It includes shared memory and memory that might be reserved, but not actually used. Use this metric for charge-back purposes.
**vm consumed memory = memory granted -- memory saved** Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-mem-memctl** Check command object for the `check_vmware_esx` plugin. Amount of guest physical memory that is currently reclaimed from the virtual machine through ballooning. This is the amount of guest physical memory that has been allocated and pinned by the balloon driver. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-net** Check command object for the `check_vmware_esx` plugin. Shows net info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-net-usage** Check command object for the `check_vmware_esx` plugin. Overall network usage in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-net-receive** Check command object for the `check_vmware_esx` plugin. Receive in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-net-send** Check command object for the `check_vmware_esx` plugin. Send in KBps(Kilobytes per Second). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-io** Check command object for the `check_vmware_esx` plugin. Shows all disk io info. Without subselect no thresholds can be given. All I/O values are aggregated from historical intervals over the past 24 hours with a 5 minute sample rate. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-io-read** Check command object for the `check_vmware_esx` plugin. Average number of kilobytes read from the disk each second. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session - IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-io-write** Check command object for the `check_vmware_esx` plugin. Average number of kilobytes written to disk each second. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-io-usage** Check command object for the `check_vmware_esx` plugin. Aggregated disk I/O rate. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-runtime** Check command object for the `check_vmware_esx` plugin. Shows virtual machine runtime info. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-runtime-con** Check command object for the `check_vmware_esx` plugin. Shows the connection state. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-runtime-powerstate** Check command object for the `check_vmware_esx` plugin. Shows virtual machine power state: poweredOn, poweredOff or suspended. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-runtime-status** Check command object for the `check_vmware_esx` plugin. Overall object status (gray/green/red/yellow). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-runtime-consoleconnections** Check command object for the `check_vmware_esx` plugin. Console connections to virtual machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_warn | **Optional.** The warning threshold. No value defined as default. vmware_crit | **Optional.** The critical threshold. No value defined as default. **vmware-esx-soap-vm-runtime-gueststate** Check command object for the `check_vmware_esx` plugin. Guest OS status. Needs VMware Tools installed and running. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd **vmware-esx-soap-vm-runtime-tools** Check command object for the `check_vmware_esx` plugin. Guest OS status. VMware tools status. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_openvmtools | **Optional** Prevent CRITICAL state for installed and running Open VM Tools. **vmware-esx-soap-vm-runtime-issues** Check command object for the `check_vmware_esx` plugin. All issues for the virtual machine. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- vmware_datacenter | **Optional.** Datacenter/vCenter hostname. Conflicts with **vmware_host**. vmware_host | **Optional.** ESX or ESXi hostname. Conflicts with **vmware_datacenter**. vmware_vmname | **Required.** Virtual machine name. vmware_sslport | **Optional.** SSL port connection. Defaults to "443". vmware_ignoreunknown | **Optional.** Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3). Defaults to "false". vmware_ignorewarning | **Optional.** Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view). With this option the plugin will return OK (0) instead of WARNING (1). Defaults to "false". vmware_timeout | **Optional.** Seconds before plugin times out. Defaults to "90". vmware_trace | **Optional.** Set verbosity level of vSphere API request/respond trace. vmware_sessionfile | **Optional.** Session file name enhancement. vmware_sessionfiledir | **Optional.** Path to store the **vmware_sessionfile** file. Defaults to "/var/spool/icinga2/tmp". vmware_nosession | **Optional.** No auth session -- IT SHOULD BE USED FOR TESTING PURPOSES ONLY!. Defaults to "false". vmware_username | **Optional.** The username to connect to Host or vCenter server. No value defined as default. vmware_password | **Optional.** The username's password. No value defined as default. vmware_authfile | **Optional.** Use auth file instead username/password to session connect. No effect if **vmware_username** and **vmware_password** are defined
**Authentication file content:**
username=vmuser
password=p@ssw0rd vmware_multiline | **Optional.** Multiline output in overview. This mean technically that a multiline output uses a HTML **\** for the GUI. No value defined as default. ### Web This category includes all plugins for web-based checks. #### apache_status The [check_apache_status.pl](https://github.com/lbetz/check_apache_status) plugin uses the [/server-status](https://httpd.apache.org/docs/current/mod/mod_status.html) HTTP endpoint to monitor status metrics for the Apache webserver. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|---------------------------------------------------------------------------------- apache_status_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, `address6` otherwise. apache_status_port | **Optional.** the http port. apache_status_url | **Optional.** URL to use, instead of the default (http://`apache_status_address`/server-status). apache_status_ssl | **Optional.** set to use ssl connection apache_status_timeout | **Optional.** timeout in seconds apache_status_warning | **Optional.** Warning threshold (number of open slots, busy workers and idle workers that will cause a WARNING) like ':20,50,:50'. apache_status_critical | **Optional.** Critical threshold (number of open slots, busy workers and idle workers that will cause a CRITICAL) like ':10,25,:20'. ### cert The [check_ssl_cert](https://github.com/matteocorti/check_ssl_cert) plugin uses the openssl binary (and optional curl) to check a X.509 certificate. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------|-------------- ssl_cert_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. ssl_cert_port | **Optional.** TCP port number (default: 443). ssl_cert_file | **Optional.** Local file path. Works only if `ssl_cert_address` is set to "localhost". ssl_cert_warn | **Optional.** Minimum number of days a certificate has to be valid. ssl_cert_critical | **Optional.** Minimum number of days a certificate has to be valid to issue a critical status. ssl_cert_cn | **Optional.** Pattern to match the CN of the certificate. ssl_cert_altnames | **Optional.** Matches the pattern specified in -n with alternate ssl_cert_issuer | **Optional.** Pattern to match the issuer of the certificate. ssl_cert_org | **Optional.** Pattern to match the organization of the certificate. ssl_cert_email | **Optional.** Pattern to match the email address contained in the certificate. ssl_cert_serial | **Optional.** Pattern to match the serial number. ssl_cert_noauth | **Optional.** Ignore authority warnings (expiration only) ssl_cert_match_host | **Optional.** Match CN with the host name. ssl_cert_selfsigned | **Optional.** Allow self-signed certificate. ssl_cert_sni | **Optional.** Sets the TLS SNI (Server Name Indication) extension. ssl_cert_timeout | **Optional.** Seconds before connection times out (default: 15) ssl_cert_protocol | **Optional.** Use the specific protocol {http,smtp,pop3,imap,ftp,xmpp,irc,ldap} (default: http). ssl_cert_clientcert | **Optional.** Use client certificate to authenticate. ssl_cert_clientpass | **Optional.** Set passphrase for client certificate. ssl_cert_ssllabs | **Optional.** SSL Labs assessment ssl_cert_ssllabs_nocache | **Optional.** Forces a new check by SSL Labs ssl_cert_rootcert | **Optional.** Root certificate or directory to be used for certificate validation. ssl_cert_ignore_signature | **Optional.** Do not check if the certificate was signed with SHA1 od MD5. ssl_cert_ssl_version | **Optional.** Force specific SSL version out of {ssl2,ssl3,tls1,tls1_1,tls1_2}. ssl_cert_disable_ssl_versions | **Optional.** Disable specific SSL versions out of {ssl2,ssl3,tls1,tls1_1,tls1_2}. Multiple versions can be given as array. ssl_cert_cipher | **Optional.** Cipher selection: force {ecdsa,rsa} authentication. ssl_cert_ignore_expiration | **Optional.** Ignore expiration date. ssl_cert_ignore_ocsp | **Optional.** Do not check revocation with OCSP. #### jmx4perl The [check_jmx4perl](http://search.cpan.org/~roland/jmx4perl/scripts/check_jmx4perl) plugin uses the HTTP API exposed by the [Jolokia](https://jolokia.org) web application and queries Java message beans on an application server. It is part of the `JMX::Jmx4Perl` Perl module which includes detailed [documentation](http://search.cpan.org/~roland/jmx4perl/scripts/check_jmx4perl). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description -----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------- jmx4perl_url | **Required.** URL to agent web application. Defaults to "http://$address$:8080/jolokia". jmx4perl_product | **Optional.** Name of app server product (e.g. jboss), by default is uses an auto detection facility. jmx4perl_alias | **Optional.** Alias name for attribute (e.g. MEMORY_HEAP_USED). All available aliases can be viewed by executing `jmx4perl aliases` on the command line. jmx4perl_mbean | **Optional.** MBean name (e.g. java.lang:type=Memory). jmx4perl_attribute | **Optional.** Attribute name (e.g. HeapMemoryUsage). jmx4perl_operation | **Optional.** Operation to execute. jmx4perl_value | **Optional.** Shortcut for specifying mbean/attribute/path. Slashes within names must be escaped with backslash. jmx4perl_delta | **Optional.** Switches on incremental mode. Optional argument are seconds used for normalizing. jmx4perl_path | **Optional.** Inner path for extracting a single value from a complex attribute or return value (e.g. used). jmx4perl_target | **Optional.** JSR-160 Service URL specifing the target server. jmx4perl_target_user | **Optional.** Username to use for JSR-160 connection. jmx4perl_target_password | **Optional.** Password to use for JSR-160 connection. jmx4perl_proxy | **Optional.** Proxy to use. jmx4perl_user | **Optional.** User for HTTP authentication. jmx4perl_password | **Optional.** Password for HTTP authentication. jmx4perl_name | **Optional.** Name to use for output, by default a standard value based on the MBean and attribute will be used. jmx4perl_method | **Optional.** HTTP method to use, either get or post. By default a method is determined automatically based on the request type. jmx4perl_base | **Optional.** Base name, which when given, interprets critical and warning values as relative in the range 0 .. 100%. Must be given in the form mbean/attribute/path. jmx4perl_base_mbean | **Optional.** Base MBean name, interprets critical and warning values as relative in the range 0 .. 100%. Requires "jmx4perl_base_attribute". jmx4perl_base_attribute | **Optional.** Base attribute for a relative check. Requires "jmx4perl_base_mbean". jmx4perl_base_path | **Optional.** Base path for relative checks, where this path is used on the base attribute's value. jmx4perl_unit | **Optional.** Unit of measurement of the data retrieved. Recognized values are [B\|KB\|MN\|GB\|TB] for memory values and [us\|ms\|s\|m\|h\|d] for time values. jmx4perl_null | **Optional.** Value which should be used in case of a null return value of an operation or attribute. Defaults to null. jmx4perl_string | **Optional.** Force string comparison for critical and warning checks. Defaults to false. jmx4perl_numeric | **Optional.** Force numeric comparison for critical and warning checks. Defaults to false. jmx4perl_critical | **Optional.** Critical threshold for value. jmx4perl_warning | **Optional.** Warning threshold for value. jmx4perl_label | **Optional.** Label to be used for printing out the result of the check. For placeholders which can be used see the documentation. jmx4perl_perfdata | **Optional.** Whether performance data should be omitted, which are included by default. Defaults to "on" for numeric values, to "off" for strings. jmx4perl_unknown_is_critical | **Optional.** Map UNKNOWN errors to errors with a CRITICAL status. Defaults to false. jmx4perl_timeout | **Optional.** Seconds before plugin times out. Defaults to "15". jmx4perl_config | **Optional.** Path to configuration file. jmx4perl_server | **Optional.** Symbolic name of server url to use, which needs to be configured in the configuration file. jmx4perl_check | **Optional.** Name of a check configuration as defined in the configuration file, use array if you need arguments. #### kdc The [check_kdc](https://exchange.nagios.org/directory/Plugins/Security/check_kdc/details) plugin uses the Kerberos `kinit` binary to monitor Kerberos 5 KDC by acquiring a ticket. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------------------------------------------------------------------- kdc_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, `address6` otherwise. kdc_port | **Optional** Port on which KDC runs (default 88). kdc_principal | **Required** Principal name to authenticate as (including realm). kdc_keytab | **Required** Keytab file containing principal's key. #### nginx_status The [check_nginx_status.pl](https://github.com/regilero/check_nginx_status) plugin uses the [/nginx_status](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html) HTTP endpoint which provides metrics for monitoring Nginx. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description --------------------------------|---------------------------------------------------------------------------------- nginx_status_host_address | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, `address6` otherwise. nginx_status_port | **Optional.** the http port. nginx_status_url | **Optional.** URL to use, instead of the default (http://`nginx_status_hostname`/nginx_status). nginx_status_servername | **Optional.** ServerName to use if you specified an IP to match the good Virtualhost in your target. nginx_status_ssl | **Optional.** set to use ssl connection. nginx_status_disable_sslverify | **Optional.** set to disable SSL hostname verification. nginx_status_user | **Optional.** Username for basic auth. nginx_status_pass | **Optional.** Password for basic auth. nginx_status_realm | **Optional.** Realm for basic auth. nginx_status_maxreach | **Optional.** Number of max processes reached (since last check) that should trigger an alert. nginx_status_timeout | **Optional.** timeout in seconds. nginx_status_warn | **Optional.** Warning threshold (number of active connections, ReqPerSec or ConnPerSec that will cause a WARNING) like '10000,100,200'. nginx_status_critical | **Optional.** Critical threshold (number of active connections, ReqPerSec or ConnPerSec that will cause a CRITICAL) like '20000,200,300'. #### rbl The [check_rbl](https://github.com/matteocorti/check_rbl) plugin uses the `Net::DNS` Perl library to check whether your SMTP server is blacklisted. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ----------------|-------------------------------------------------------------------------- rbl_hostname | **Optional.** The address or name of the SMTP server to check. Defaults to "$address$" if the host's `address` attribute is set, `address6` otherwise. rbl_server | **Required** List of RBL servers as an array. rbl_warning | **Optional** Number of blacklisting servers for a warning. rbl_critical | **Optional** Number of blacklisting servers for a critical. tbl_timeout | **Optional** Seconds before plugin times out (default: 15). #### squid The [check_squid](https://exchange.icinga.com/exchange/check_squid) plugin uses the `squidclient` binary to monitor a [Squid proxy](http://www.squid-cache.org). Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|---------------------------------------------------------------------------------- squid_hostname | **Optional.** The host's address. Defaults to "$address$" if the host's `address` attribute is set, "$address6$" otherwise. squid_data | **Optional.** Data to fetch (default: Connections) available data: Connections Cache Resources Memory FileDescriptors. squid_port | **Optional.** Port number (default: 3128). squid_user | **Optional.** WWW user. squid_password | **Optional.** WWW password. squid_warning | **Optional.** Warning threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format. squid_critical | **Optional.** Critical threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format. squid_client | **Optional.** Path of squidclient (default: /usr/bin/squidclient). squid_timeout | **Optional.** Seconds before plugin times out (default: 15). #### webinject The [check_webinject](https://labs.consol.de/de/nagios/check_webinject/index.html) plugin uses [WebInject](http://www.webinject.org/manual.html) to test web applications and web services in an automated fashion. It can be used to test individual system components that have HTTP interfaces (JSP, ASP, CGI, PHP, AJAX, Servlets, HTML Forms, XML/SOAP Web Services, REST, etc), and can be used as a test harness to create a suite of HTTP level automated functional, acceptance, and regression tests. A test harness allows you to run many test cases and collect/report your results. WebInject offers real-time results display and may also be used for monitoring system response times. Custom attributes passed as [command parameters](03-monitoring-basics.md#command-passing-parameters): Name | Description ------------------------|-------------- webinject_config_file | **Optional.** There is a configuration file named 'config.xml' that is used to store configuration settings for your project. You can use this to specify which test case files to run and to set some constants and settings to be used by WebInject. webinject_output | **Optional.** This option is followed by a directory name or a prefix to prepended to the output files. This is used to specify the location for writing output files (http.log, results.html, and results.xml). If a directory name is supplied (use either an absolute or relative path and make sure to add the trailing slash), all output files are written to this directory. If the trailing slash is omitted, it is assumed to a prefix and this will be prepended to the output files. You may also use a combination of a directory and prefix. webinject_no_output | **Optional.** Suppresses all output to STDOUT except the results summary. webinject_timeout | **Optional.** The value [given in seconds] will be compared to the global time elapsed to run all the tests. If the tests have all been successful, but have taken more time than the 'globaltimeout' value, a warning message is sent back to Icinga. webinject_report_type | **Optional.** This setting is used to enable output formatting that is compatible for use with specific external programs. The available values you can set this to are: nagios, mrtg, external and standard. webinject_testcase_file | **Optional.** When you launch WebInject in console mode, you can optionally supply an argument for a testcase file to run. It will look for this file in the directory that webinject.pl resides in. If no filename is passed from the command line, it will look in config.xml for testcasefile declarations. If no files are specified, it will look for a default file named 'testcases.xml' in the current [webinject] directory. If none of these are found, the engine will stop and give you an error. icinga2-2.8.1/doc/11-cli-commands.md000066400000000000000000000656341322762156600167420ustar00rootroot00000000000000# Icinga 2 CLI Commands Icinga 2 comes with a number of CLI commands which support bash autocompletion. These CLI commands will allow you to use certain functionality provided by and around Icinga 2. Each CLI command provides its own help and usage information, so please make sure to always run them with the `--help` parameter. Run `icinga2` without any arguments to get a list of all available global options. ``` # icinga2 icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 [] Supported commands: * api setup (setup for api) * ca list (lists all certificate signing requests) * ca sign (signs an outstanding certificate request) * console (Icinga console) * daemon (starts Icinga 2) * feature disable (disables specified feature) * feature enable (enables specified feature) * feature list (lists all available features) * node setup (set up node) * node wizard (wizard for node setup) * object list (lists all objects) * pki new-ca (sets up a new CA) * pki new-cert (creates a new CSR) * pki request (requests a certificate) * pki save-cert (saves another Icinga 2 instance's certificate) * pki sign-csr (signs a CSR) * pki ticket (generates a ticket) * troubleshoot (collect information for troubleshooting) * variable get (gets a variable) * variable list (lists all variables) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## Icinga 2 CLI Bash Autocompletion Bash Auto-Completion (pressing ``) is provided only for the corresponding context. While `--config` suggests and auto-completes files and directories on disk, `feature enable` only suggests disabled features. RPM and Debian packages install the bash completion files into `/etc/bash_completion.d/icinga2`. You need to install the `bash-completion` package if not already installed. RHEL/CentOS/Fedora: ``` # yum install bash-completion ``` SUSE: ``` # zypper install bash-completion ``` Debian/Ubuntu: ``` # apt-get install bash-completion ``` Ensure that the `bash-completion.d` directory is added to your shell environment. You can manually source the icinga2 bash-completion file into your current session and test it: ``` # source /etc/bash-completion.d/icinga2 ``` ## Icinga 2 CLI Global Options ### Application Type By default the `icinga2` binary loads the `icinga` library. A different application type can be specified with the `--app` command-line option. Note: This is not needed by the average Icinga user, only developers. ### Libraries Instead of loading libraries using the [`library` config directive](17-language-reference.md#library) you can also use the `--library` command-line option. Note: This is not needed by the average Icinga user, only developers. ### Constants [Global constants](17-language-reference.md#constants) can be set using the `--define` command-line option. ### Config Include Path When including files you can specify that the include search path should be checked. You can do this by putting your configuration file name in angle brackets like this: ``` include ``` This causes Icinga 2 to search its include path for the configuration file `test.conf`. By default the installation path for the [Icinga Template Library](10-icinga-template-library.md#icinga-template-library) is the only search directory. Using the `--include` command-line option additional search directories can be added. ## CLI command: Api Provides the setup CLI command to enable the REST API. More details in the [Icinga 2 API](12-icinga2-api.md#icinga2-api-setup) chapter. ``` # icinga2 api --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 [] Supported commands: * api setup (setup for api) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## CLI command: Ca List and manage incoming certificate signing requests. More details can be found in the [signing methods](06-distributed-monitoring.md#distributed-monitoring-setup-sign-certificates-master) chapter. This CLI command is available since v2.8. ``` # icinga2 ca --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 [] Supported commands: * ca list (lists all certificate signing requests) * ca sign (signs an outstanding certificate request) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## CLI command: Console The CLI command `console` can be used to debug and evaluate Icinga 2 config expressions, e.g. to test [functions](17-language-reference.md#functions) in your local sandbox. ``` $ icinga2 console Icinga 2 (version: v2.8.0) <1> => function test(name) { <1> .. log("Hello " + name) <1> .. } null <2> => test("World") information/config: Hello World null <3> => ``` Further usage examples can be found in the [library reference](18-library-reference.md#library-reference) chapter. ``` # icinga2 console --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 console [] Interprets Icinga script expressions. Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Command options: -c [ --connect ] arg connect to an Icinga 2 instance -e [ --eval ] arg evaluate expression and terminate -r [ --file ] arg evaluate a file and terminate --syntax-only only validate syntax (requires --eval or --file) --sandbox enable sandbox mode Report bugs at Icinga home page: ``` On operating systems without the `libedit` library installed there is no support for line-editing or a command history. However you can use the `rlwrap` program if you require those features: ``` $ rlwrap icinga2 console ``` The debug console can be used to connect to a running Icinga 2 instance using the [REST API](12-icinga2-api.md#icinga2-api). [API permissions](12-icinga2-api.md#icinga2-api-permissions) are required for executing config expressions and auto-completion. > **Note** > > The debug console does not currently support SSL certificate verification. > > Runtime modifications are not validated and might cause the Icinga 2 > daemon to crash or behave in an unexpected way. Use these runtime changes > at your own risk and rather *inspect and debug objects read-only*. You can specify the API URL using the `--connect` parameter. Although the password can be specified there process arguments on UNIX platforms are usually visible to other users (e.g. through `ps`). In order to securely specify the user credentials the debug console supports two environment variables: Environment variable | Description ---------------------|------------- ICINGA2_API_USERNAME | The API username. ICINGA2_API_PASSWORD | The API password. Here's an example: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' Icinga 2 (version: v2.8.0) <1> => ``` Once connected you can inspect variables and execute other expressions by entering them at the prompt: ``` <1> => var h = get_host("icinga2-client1.localdomain") null <2> => h.last_check_result { active = true check_source = "icinga2-client1.localdomain" command = [ "/usr/local/sbin/check_ping", "-H", "127.0.0.1", "-c", "5000,100%", "-w", "3000,80%" ] execution_end = 1446653527.174983 execution_start = 1446653523.152673 exit_status = 0.000000 output = "PING OK - Packet loss = 0%, RTA = 0.11 ms" performance_data = [ "rta=0.114000ms;3000.000000;5000.000000;0.000000", "pl=0%;80;100;0" ] schedule_end = 1446653527.175133 schedule_start = 1446653583.150000 state = 0.000000 type = "CheckResult" vars_after = { attempt = 1.000000 reachable = true state = 0.000000 state_type = 1.000000 } vars_before = { attempt = 1.000000 reachable = true state = 0.000000 state_type = 1.000000 } } <3> => ``` You can use the `--eval` parameter to evaluate a single expression in batch mode. Using the `--file` option you can specify a file which should be evaluated. The output format for batch mode is JSON. The `--syntax-only` option can be used in combination with `--eval` or `--file` to check a script for syntax errors. In this mode the script is parsed to identify syntax errors but not evaluated. Here's an example that retrieves the command that was used by Icinga to check the `icinga2-client1.localdomain` host: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' --eval 'get_host("icinga2-client1.localdomain").last_check_result.command' | python -m json.tool [ "/usr/local/sbin/check_ping", "-H", "127.0.0.1", "-c", "5000,100%", "-w", "3000,80%" ] ``` ## CLI command: Daemon The CLI command `daemon` provides the functionality to start/stop Icinga 2. Furthermore it allows to run the [configuration validation](11-cli-commands.md#config-validation). ``` # icinga2 daemon --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 daemon [] Starts Icinga 2. Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Command options: -c [ --config ] arg parse a configuration file -z [ --no-config ] start without a configuration file -C [ --validate ] exit after validating the configuration -e [ --errorlog ] arg log fatal errors to the specified log file (only works in combination with --daemonize) -d [ --daemonize ] detach from the controlling terminal Report bugs at Icinga home page: ``` ### Config Files You can specify one or more configuration files with the `--config` option. Configuration files are processed in the order they're specified on the command-line. When no configuration file is specified and the `--no-config` is not used Icinga 2 automatically falls back to using the configuration file `SysconfDir + "/icinga2/icinga2.conf"` (where SysconfDir is usually `/etc`). ### Config Validation The `--validate` option can be used to check if configuration files contain errors. If any errors are found, the exit status is 1, otherwise 0 is returned. More details in the [configuration validation](11-cli-commands.md#config-validation) chapter. ## CLI command: Feature The `feature enable` and `feature disable` commands can be used to enable and disable features: ``` # icinga2 feature disable --app --define --include --log-level --version checker graphite mainlog --color --help --library --script-debugger api command ido-mysql notification ``` ``` # icinga2 feature enable --app --define --include --log-level --version debuglog ido-pgsql livestatus perfdata syslog --color --help --library --script-debugger compatlog gelf influxdb opentsdb statusdata ``` The `feature list` command shows which features are currently enabled: ``` # icinga2 feature list Disabled features: compatlog debuglog gelf ido-pgsql influxdb livestatus opentsdb perfdata statusdata syslog Enabled features: api checker command graphite ido-mysql mainlog notification ``` ## CLI command: Node Provides the functionality to setup master and client nodes in a [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) scenario. ``` # icinga2 node --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 [] Supported commands: * node setup (set up node) * node wizard (wizard for node setup) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## CLI command: Object The `object` CLI command can be used to list all configuration objects and their attributes. The command also shows where each of the attributes was modified and as such provides debug information for further configuration problem analysis. That way you can also identify which objects have been created from your [apply rules](17-language-reference.md#apply). Runtime modifications via the [REST API](12-icinga2-api.md#icinga2-api-config-objects) are not immediately updated. Furthermore there is a known issue with [group assign expressions](17-language-reference.md#group-assign) which are not reflected in the host object output. You need to restart Icinga 2 in order to update the `icinga2.debug` cache file. More information can be found in the [troubleshooting](15-troubleshooting.md#troubleshooting-list-configuration-objects) section. ``` # icinga2 object --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.7.1-196-g23e8a6253; debug) Usage: icinga2 [] Supported commands: * object list (lists all objects) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## CLI command: Pki Provides the CLI commands to * generate a new certificate authority (CA) * generate a new CSR or self-signed certificate * sign a CSR and return a certificate * save a master certificate manually * request a signed certificate from the master * generate a new ticket for the client setup This functionality is used by the [node setup/wizard](11-cli-commands.md#cli-command-node) CLI commands. You will need them in the [distributed monitoring chapter](06-distributed-monitoring.md#distributed-monitoring). ``` # icinga2 pki --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 [] Supported commands: * pki new-ca (sets up a new CA) * pki new-cert (creates a new CSR) * pki request (requests a certificate) * pki save-cert (saves another Icinga 2 instance's certificate) * pki sign-csr (signs a CSR) * pki ticket (generates a ticket) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## CLI command: Troubleshoot Collects basic information like version, paths, log files and crash reports for troubleshooting purposes and prints them to a file or the console. See [troubleshooting](15-troubleshooting.md#troubleshooting-information-required). Its output defaults to a file named `troubleshooting-[TIMESTAMP].log` so it won't overwrite older troubleshooting files. Keep in mind that this tool can not collect information from other icinga2 nodes, you will have to run it on each of one of you instances. This is only a tool to collect information to help others help you, it will not attempt to fix anything. ``` # icinga2 troubleshoot --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0) Usage: icinga2 troubleshoot [] Collect logs and other relevant information for troubleshooting purposes. Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Command options: -c [ --console ] print to console instead of file -o [ --output ] arg path to output file --include-objects Print the whole objectfile (like `object list`) --include-vars Print all Variables (like `variable list`) Report bugs at Icinga home page: ``` ## CLI command: Variable Lists all configured variables (constants) in a similar fashion like [object list](11-cli-commands.md#cli-command-object). ``` # icinga2 variable --help icinga2 - The Icinga 2 network monitoring daemon (version: v2.8.0; debug) Usage: icinga2 [] Supported commands: * variable get (gets a variable) * variable list (lists all variables) Global options: -h [ --help ] show this help message -V [ --version ] show version information --color use VT100 color codes even when stdout is not a terminal -D [ --define ] arg define a constant -a [ --app ] arg application library name (default: icinga) -l [ --library ] arg load a library -I [ --include ] arg add include search directory -x [ --log-level ] arg specify the log level for the console log. The valid value is either debug, notice, information (default), warning, or critical -X [ --script-debugger ] whether to enable the script debugger Report bugs at Icinga home page: ``` ## Enabling/Disabling Features Icinga 2 provides configuration files for some commonly used features. These are installed in the `/etc/icinga2/features-available` directory and can be enabled and disabled using the `icinga2 feature enable` and `icinga2 feature disable` [CLI commands](11-cli-commands.md#cli-command-feature), respectively. The `icinga2 feature enable` CLI command creates symlinks in the `/etc/icinga2/features-enabled` directory which is included by default in the example configuration file. You can view a list of enabled and disabled features: ``` # icinga2 feature list Disabled features: api command compatlog debuglog graphite icingastatus ido-mysql ido-pgsql livestatus notification perfdata statusdata syslog Enabled features: checker mainlog notification ``` Using the `icinga2 feature enable` command you can enable features: ``` # icinga2 feature enable graphite Enabling feature graphite. Make sure to restart Icinga 2 for these changes to take effect. ``` You can disable features using the `icinga2 feature disable` command: ``` # icinga2 feature disable ido-mysql livestatus Disabling feature ido-mysql. Make sure to restart Icinga 2 for these changes to take effect. Disabling feature livestatus. Make sure to restart Icinga 2 for these changes to take effect. ``` The `icinga2 feature enable` and `icinga2 feature disable` commands do not restart Icinga 2. You will need to restart Icinga 2 using the init script after enabling or disabling features. ## Configuration Validation Once you've edited the configuration files make sure to tell Icinga 2 to validate the configuration changes. Icinga 2 will log any configuration error including a hint on the file, the line number and the affected configuration line itself. The following example creates an apply rule without any `assign` condition. ``` apply Service "my-ping4" { import "generic-service" check_command = "ping4" //assign where host.address } ``` Validate the configuration: ``` # icinga2 daemon -C [2014-05-22 17:07:25 +0200] critical/ConfigItem: Location: /etc/icinga2/conf.d/tests/my.conf(5): } /etc/icinga2/conf.d/tests/my.conf(6): /etc/icinga2/conf.d/tests/my.conf(7): apply Service "my-ping4" { ^^^^^^^^^^^^^ /etc/icinga2/conf.d/tests/my.conf(8): import "test-generic-service" /etc/icinga2/conf.d/tests/my.conf(9): check_command = "ping4" Config error: 'apply' is missing 'assign' [2014-05-22 17:07:25 +0200] critical/ConfigItem: 1 errors, 0 warnings. Icinga 2 detected configuration errors. ``` If you encounter errors during configuration validation, please make sure to read the [troubleshooting](15-troubleshooting.md#troubleshooting) chapter. You can also use the [CLI command](11-cli-commands.md#cli-command-object) `icinga2 object list` after validation passes to analyze object attributes, inheritance or created objects by apply rules. Find more on troubleshooting with `object list` in [this chapter](15-troubleshooting.md#troubleshooting-list-configuration-objects). ## Reload on Configuration Changes Every time you have changed your configuration you should first tell Icinga 2 to [validate](11-cli-commands.md#config-validation). If there are no validation errors, you can safely reload the Icinga 2 daemon. ``` # systemctl reload icinga2 ``` The `reload` action will send the `SIGHUP` signal to the Icinga 2 daemon which will validate the configuration in a separate process and not stop the other events like check execution, notifications, etc. icinga2-2.8.1/doc/12-icinga2-api.md000066400000000000000000002652261322762156600164570ustar00rootroot00000000000000# Icinga 2 API ## Setting up the API You can run the CLI command `icinga2 api setup` to enable the `api` [feature](11-cli-commands.md#enable-features) and set up certificates as well as a new API user `root` with an auto-generated password in the `/etc/icinga2/conf.d/api-users.conf` configuration file: # icinga2 api setup Make sure to restart Icinga 2 to enable the changes you just made: # service icinga2 restart If you prefer to set up the API manually, you will have to perform the following steps: * Set up X.509 certificates for Icinga 2 * Enable the `api` feature (`icinga2 feature enable api`) * Create an `ApiUser` object for authentication The next chapter provides a quick overview of how you can use the API. ## Introduction The Icinga 2 API allows you to manage configuration objects and resources in a simple, programmatic way using HTTP requests. The URL endpoints are logically separated allowing you to easily make calls to * query, create, modify and delete [config objects](12-icinga2-api.md#icinga2-api-config-objects) * perform [actions](12-icinga2-api.md#icinga2-api-actions) (reschedule checks, etc.) * subscribe to [event streams](12-icinga2-api.md#icinga2-api-event-streams) * [manage configuration packages](12-icinga2-api.md#icinga2-api-config-management) * evaluate [script expressions](12-icinga2-api.md#icinga2-api-console) ### Requests Any tool capable of making HTTP requests can communicate with the API, for example [curl](https://curl.haxx.se/). Requests are only allowed to use the HTTPS protocol so that traffic remains encrypted. By default the Icinga 2 API listens on port `5665` which is shared with the cluster stack. The port can be changed by setting the `bind_port` attribute for the [ApiListener](09-object-types.md#objecttype-apilistener) object in the `/etc/icinga2/features-available/api.conf` configuration file. Supported request methods: Method | Usage -------|-------- GET | Retrieve information about configuration objects. Any request using the GET method is read-only and does not affect any objects. POST | Update attributes of a specified configuration object. PUT | Create a new object. The PUT request must include all attributes required to create a new object. DELETE | Remove an object created by the API. The DELETE method is idempotent and does not require any check if the object actually exists. All requests apart from `GET` require that the following `Accept` header is set: Accept: application/json Each URL is prefixed with the API version (currently "/v1"). ### Responses Successful requests will send back a response body containing a `results` list. Depending on the number of affected objects in your request, the `results` list may contain more than one entry. The output will be sent back as a JSON object: { "results": [ { "code": 200.0, "status": "Object was created." } ] } Tip: If you are working on the CLI with curl you can also use [jq](https://stedolan.github.io/jq/) to format the returned JSON output in a readable manner. The documentation prefers `python -m json.tool` as Python is available nearly everywhere. > **Note** > > Future versions of Icinga 2 might set additional fields. Your application > should gracefully handle fields it is not familiar with, for example by > ignoring them. ### HTTP Statuses The API will return standard [HTTP statuses](https://www.ietf.org/rfc/rfc2616.txt) including error codes. When an error occurs, the response body will contain additional information about the problem and its source. A status code between 200 and 299 generally means that the request was successful. Return codes within the 400 range indicate that there was a problem with the request. Either you did not authenticate correctly, you are missing the authorization for your requested action, the requested object does not exist or the request was malformed. A status in the range of 500 generally means that there was a server-side problem and Icinga 2 is unable to process your request. ### Authentication There are two different ways for authenticating against the Icinga 2 API: * username and password using HTTP basic auth * X.509 certificate In order to configure a new API user you'll need to add a new [ApiUser](09-object-types.md#objecttype-apiuser) configuration object. In this example `root` will be the basic auth username and the `password` attribute contains the basic auth password. # vim /etc/icinga2/conf.d/api-users.conf object ApiUser "root" { password = "icinga" } Alternatively you can use X.509 client certificates by specifying the `client_cn` the API should trust. The X.509 certificate has to be signed by the CA certificate that is configured in the [ApiListener](09-object-types.md#objecttype-apilistener) object. # vim /etc/icinga2/conf.d/api-users.conf object ApiUser "root" { client_cn = "CertificateCommonName" } An `ApiUser` object can have both authentication methods configured. You can test authentication by sending a GET request to the API: $ curl -k -s -u root:icinga 'https://localhost:5665/v1' In case you get an error message make sure to check the API user credentials. When using client certificates for authentication you'll need to pass your client certificate and private key to the curl call: $ curl -k --cert example.localdomain.crt --key example.localdomain.key 'https://example.localdomain:5665/v1/status' In case of an error make sure to verify the client certificate and CA. The curl parameter `-k` disables certificate verification and should therefore only be used for testing. In order to securely check each connection you'll need to specify the trusted CA certificate using the curl parameter`--cacert`: $ curl -u root:icinga --cacert ca.crt 'icinga2.node1.localdomain:5665/v1' Read the next chapter on [API permissions](12-icinga2-api.md#icinga2-api-permissions) in order to configure authorization settings for your newly created API user. ### Permissions By default an API user does not have any permissions to perform actions on the URL endpoints. Permissions for API users must be specified in the `permissions` attribute as array. The array items can be a list of permission strings with wildcard matches. Example for an API user with all permissions: permissions = [ "*" ] Note that you can use wildcards. Here's another example that only allows the user to perform read-only object queries for hosts and services: permissions = [ "objects/query/Host", "objects/query/Service" ] You can also further restrict permissions by specifying a filter expression. The filter expression has to be a [lambda function](17-language-reference.md#nullary-lambdas) which must return a boolean value. The following example allows the API user to query all hosts and services which have a custom attribute `os` that matches the regular expression `^Linux`. The [regex function](18-library-reference.md#global-functions-regex) is available as global function. permissions = [ { permission = "objects/query/Host" filter = {{ regex("^Linux", host.vars.os) }} }, { permission = "objects/query/Service" filter = {{ regex("^Linux", service.vars.os) }} } ] More information about filters can be found in the [filters](12-icinga2-api.md#icinga2-api-filters) chapter. Available permissions for specific URL endpoints: Permissions | URL Endpoint | Supports Filters ------------------------------|---------------|----------------- actions/<action> | /v1/actions | Yes config/query | /v1/config | No config/modify | /v1/config | No console | /v1/console | No events/<type> | /v1/events | No objects/query/<type> | /v1/objects | Yes objects/create/<type> | /v1/objects | No objects/modify/<type> | /v1/objects | Yes objects/delete/<type> | /v1/objects | Yes status/query | /v1/status | Yes templates/<type> | /v1/templates | Yes types | /v1/types | Yes variables | /v1/variables | Yes The required actions or types can be replaced by using a wildcard match ("\*"). ### Parameters Depending on the request method there are two ways of passing parameters to the request: * JSON object as request body (all request methods other than `GET`) * Query string as URL parameter (all request methods) Reserved characters by the HTTP protocol must be [URL-encoded](https://en.wikipedia.org/wiki/Percent-encoding) as query string, e.g. a space character becomes `%20`. Example for a URL-encoded query string: /v1/objects/hosts?filter=match(%22example.localdomain*%22,host.name)&attrs=name&attrs=state Here are the exact same query parameters as a JSON object: { "filter": "match(\"example.localdomain*\",host.name)", "attrs": [ "host.name", "host.state" ] } The [match function](18-library-reference.md#global-functions-match) is available as global function in Icinga 2. ### Request Method Override `GET` requests do not allow you to send a request body. In case you cannot pass everything as URL parameters (e.g. complex filters or JSON-encoded dictionaries) you can use the `X-HTTP-Method-Override` header. This comes in handy when you are using HTTP proxies disallowing `PUT` or `DELETE` requests too. Query an existing object by sending a `POST` request with `X-HTTP-Method-Override: GET` as request header: $ curl -k -s -u 'root:icinga' -H 'Accept: application/json' -X POST -H 'X-HTTP-Method-Override: GET' 'https://localhost:5665/v1/objects/hosts' Delete an existing object by sending a `POST` request with `X-HTTP-Method-Override: DELETE` as request header: $ curl -k -s -u 'root:icinga' -H 'Accept: application/json' -X POST -H 'X-HTTP-Method-Override: DELETE' 'https://localhost:5665/v1/objects/hosts/example.localdomain' ### Filters #### Simple Filters By default actions and queries operate on all objects unless further restricted by the user. For example, the following query returns all `Host` objects: https://localhost:5665/v1/objects/hosts If you're only interested in a single object, you can limit the output to that object by specifying its name: https://localhost:5665/v1/objects/hosts?host=localhost **The name of the URL parameter is the lower-case version of the type the query applies to.** For example, for `Host` objects the URL parameter therefore is `host`, for `Service` objects it is `service` and so on. You can also specify multiple objects: https://localhost:5665/v1/objects/hosts?hosts=first-host&hosts=second-host Again -- like in the previous example -- the name of the URL parameter is the lower-case version of the type. However, because we're specifying multiple objects here the **plural form** of the type is used. When specifying names for objects which have composite names like for example services the full name has to be used: https://localhost:5665/v1/objects/services?service=localhost!ping6 The full name of an object can be obtained by looking at the `__name` attribute. #### Advanced Filters Most of the information provided in this chapter applies to both permission filters (as used when configuring `ApiUser` objects) and filters specified in queries. Advanced filters allow users to filter objects using lambda expressions. The syntax for these filters is the same like for [apply rule expressions](03-monitoring-basics.md#using-apply-expressions). > **Note** > > Filters used as URL parameter must be URL-encoded. The following examples > are **not URL-encoded** for better readability. Example matching all services in NOT-OK state: https://localhost:5665/v1/objects/services?filter=service.state!=ServiceOK Example [matching](18-library-reference.md#global-functions-match) all hosts by a name string pattern: https://localhost:5665/v1/objects/hosts?filter=match("example.localdomain*",host.name) Example for all hosts which are in the host group `linux-servers`: https://localhost:5665/v1/objects/hosts?filter="linux-servers" in host.groups User-specified filters are run in a sandbox environment which ensures that filters cannot modify Icinga's state, for example object attributes or global variables. When querying objects of a specific type the filter expression is evaluated for each object of that type. The object is made available to the filter expression as a variable whose name is the lower-case version of the object's type name. For example when querying objects of type `Host` the variable in the filter expression is named `host`. Additionally related objects such as the host's check command are also made available (e.g., via the `check_command` variable). The variable names are the exact same as for the `joins` query parameter; see [object query joins](12-icinga2-api.md#icinga2-api-config-objects-query-joins) for details. The object is also made available via the `obj` variable. This makes it easier to build filters which can be used for more than one object type (e.g., for permissions). Some queries can be performed for more than just one object type. One example is the 'reschedule-check' action which can be used for both hosts and services. When using advanced filters you will also have to specify the type using the `type` parameter: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/reschedule-check' \ -d '{ "type": "Service", "filter": "service.name==\"ping6\"" }' | python -m json.tool When building filters you have to ensure that values such as `"linux-servers"` are escaped properly according to the rules of the Icinga 2 configuration language. To make using the API in scripts easier you can use the `filter_vars` attribute to specify variables which should be made available to your filter expression. This way you don't have to worry about escaping values: $ curl -k -s -u 'root:icinga' -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/hosts' \ -d '{ "filter": "host.vars.os == os", "filter_vars": { "os": "Linux" } }' We're using [X-HTTP-Method-Override](12-icinga2-api.md#icinga2-api-requests-method-override) here because the HTTP specification does not allow message bodies for GET requests. The `filters_vars` attribute can only be used inside the request body, but not as a URL parameter because there is no way to specify a dictionary in a URL. ## Config Objects Provides methods to manage configuration objects: * [creating objects](12-icinga2-api.md#icinga2-api-config-objects-create) * [querying objects](12-icinga2-api.md#icinga2-api-config-objects-query) * [modifying objects](12-icinga2-api.md#icinga2-api-config-objects-modify) * [deleting objects](12-icinga2-api.md#icinga2-api-config-objects-delete) ### API Objects and Cluster Config Sync Newly created or updated objects can be synced throughout your Icinga 2 cluster. Set the `zone` attribute to the zone this object belongs to and let the API and cluster handle the rest. Objects without a zone attribute are only synced in the same zone the Icinga instance belongs to. > **Note** > > Cluster nodes must accept configuration for creating, modifying > and deleting objects. Ensure that `accept_config` is set to `true` > in the [ApiListener](09-object-types.md#objecttype-apilistener) object > on each node. If you add a new cluster instance, or reconnect an instance which has been offline for a while, Icinga 2 takes care of the initial object sync for all objects created by the API. ### Querying Objects You can request information about configuration objects by sending a `GET` query to the `/v1/objects/` URL endpoint. ` Each response entry in the results array contains the following attributes: Attribute | Type | Description -----------|------------|-------------- name | String | Full object name. type | String | Object type. attrs | Dictionary | Object attributes (can be filtered using the URL parameter `attrs`). joins | Dictionary | [Joined object types](12-icinga2-api.md#icinga2-api-config-objects-query-joins) as key, attributes as nested dictionary. Disabled by default. meta | Dictionary | Contains `used_by` object references. Disabled by default, enable it using `?meta=used_by` as URL parameter. #### Object Query Joins Icinga 2 knows about object relations. For example it can optionally return information about the host when querying service objects. The following query retrieves all host attributes: https://localhost:5665/v1/objects/services?joins=host Instead of requesting all host attributes you can also limit the output to specific attributes: https://localhost:5665/v1/objects/services?joins=host.name&joins=host.address You can request that all available joins are returned in the result set by using the `all_joins` query parameter. https://localhost:5665/v1/objects/services?all_joins=1 > **Note** > > For performance reasons you should only request attributes which your application > requires. The following joins are available: Object Type | Object Relations (`joins` prefix name) -------------|------------------------------------------ Service | host, check\_command, check\_period, event\_command, command\_endpoint Host | check\_command, check\_period, event\_command, command\_endpoint Notification | host, service, command, period Dependency | child\_host, child\_service, parent\_host, parent\_service, period User | period Zones | parent Here's an example that retrieves all service objects for hosts which have had their `os` custom attribute set to `Linux`. The result set contains the `display_name` and `check_command` attributes for the service. The query also returns the host's `name` and `address` attribute via a join: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/services?attrs=display_name&attrs=check_command&joins=host.name&joins=host.address&filter=host.vars.os==%22Linux%22' | python -m json.tool { "results": [ { "attrs": { "check_command": "ping4", "display_name": "ping4" }, "joins": { "host": { "address": "192.168.1.1", "name": "example.localdomain" } }, "meta": {}, "name": "example.localdomain!ping4", "type": "Service" }, { "attrs": { "check_command": "ssh", "display_name": "ssh" }, "joins": { "host": { "address": "192.168.1.1", "name": "example.localdomain" } }, "meta": {}, "name": "example.localdomain!ssh", "type": "Service" } ] } In case you want to fetch all [comments](09-object-types.md#objecttype-comment) for hosts and services, you can use the following query URL (similar example for downtimes): https://localhost:5665/v1/objects/comments?joins=host&joins=service This is another example for listing all service objects which are unhandled problems (state is not OK and no downtime or acknowledgement set). We're using [X-HTTP-Method-Override](12-icinga2-api.md#icinga2-api-requests-method-override) here because we want to pass all query attributes in the request body. $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://127.0.0.1:5665/v1/objects/services' \ -d '{ "joins": [ "host.name", "host.address" ], "attrs": [ "name", "state", "downtime_depth", "acknowledgement" ], "filter": "service.state != ServiceOK && service.downtime_depth == 0.0 && service.acknowledgement == 0.0" }' | python -m json.tool { "results": [ { "attrs": { "acknowledgement": 0.0, "downtime_depth": 0.0, "name": "10807-service", "state": 3.0 }, "joins": { "host": { "address": "", "name": "10807-host" } }, "meta": {}, "name": "10807-host!10807-service", "type": "Service" } ] } In order to list all acknowledgements without expire time, you query the `/v1/objects/comments` URL endpoint with `joins` and `filter` request parameters using the [X-HTTP-Method-Override](12-icinga2-api.md#icinga2-api-requests-method-override) method: $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/comments' \ -d '{ "joins": [ "service.name", "service.acknowledgement", "service.acknowledgement_expiry" ], "attrs": [ "author", "text" ], "filter": "service.acknowledgement!=0 && service.acknowledgement_expiry==0" }' | python -m json.tool { "results": [ { "attrs": { "author": "icingaadmin", "text": "maintenance work" }, "joins": { "service": { "__name": "example.localdomain!disk /", "acknowledgement": 1.0, "acknowledgement_expiry": 0.0 } }, "meta": {}, "name": "example.localdomain!disk /!example.localdomain-1495457222-0", "type": "Comment" } ] } ### Creating Config Objects New objects must be created by sending a PUT request. The following parameters need to be passed inside the JSON body: Parameters | Type | Description -----------|--------------|-------------------------- templates | Array | **Optional.** Import existing configuration templates for this object type. Note: These templates must either be statically configured or provided in [config packages](12-icinga2-api.md#icinga2-api-config-management)- attrs | Dictionary | **Required.** Set specific object attributes for this [object type](09-object-types.md#object-types). The object name must be specified as part of the URL path. For objects with composite names (e.g. services) the full name (e.g. `example.localdomain!http`) must be specified. If attributes are of the Dictionary type, you can also use the indexer format. This might be necessary to only override specific custom variables and keep all other existing custom variables (e.g. from templates): "attrs": { "vars.os": "Linux" } Example for creating the new host object `example.localdomain`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/hosts/example.localdomain' \ -d '{ "templates": [ "generic-host" ], "attrs": { "address": "192.168.1.1", "check_command": "hostalive", "vars.os" : "Linux" } }' \ | python -m json.tool { "results": [ { "code": 200.0, "status": "Object was created." } ] } If the configuration validation fails, the new object will not be created and the response body contains a detailed error message. The following example is missing the `check_command` attribute which is required for host objects: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/hosts/example.localdomain' \ -d '{ "attrs": { "address": "192.168.1.1", "vars.os" : "Linux" } }' \ | python -m json.tool { "results": [ { "code": 500.0, "errors": [ "Error: Validation failed for object 'example.localdomain' of type 'Host'; Attribute 'check_command': Attribute must not be empty." ], "status": "Object could not be created." } ] } Service objects must be created using their full name ("hostname!servicename") referencing an existing host object: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/services/example.localdomain!realtime-load' \ -d '{ "templates": [ "generic-service" ], "attrs": { "check_command": "load", "check_interval": 1,"retry_interval": 1 } }' Example for a new CheckCommand object: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X PUT 'https://localhost:5665/v1/objects/checkcommands/mytest' \ -d '{ "templates": [ "plugin-check-command" ], "attrs": { "command": [ "/usr/local/sbin/check_http" ], "arguments": { "-I": "$mytest_iparam$" } } }' ### Modifying Objects Existing objects must be modified by sending a `POST` request. The following parameters need to be passed inside the JSON body: Parameters | Type | Description -----------|------------|--------------------------- attrs | Dictionary | **Required.** Set specific object attributes for this [object type](09-object-types.md#object-types). In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) should be provided. > **Note**: > > Modified attributes do not trigger a re-evaluation of existing > static [apply rules](03-monitoring-basics.md#using-apply) and [group assignments](03-monitoring-basics.md#group-assign-intro). > Delete and re-create the objects if you require such changes. > > Furthermore you cannot modify templates which have already been resolved > during [object creation](12-icinga2-api.md#icinga2-api-config-objects-create). > There are attributes which can only be set for [PUT requests](12-icinga2-api.md#icinga2-api-config-objects-create) such as `groups` > or `zone`. A complete list of `no_user_modify` attributes can be fetched from the [types](12-icinga2-api.md#icinga2-api-types) URL endpoint. If attributes are of the Dictionary type, you can also use the indexer format: "attrs": { "vars.os": "Linux" } The following example updates the `address` attribute and the custom attribute `os` for the `example.localdomain` host: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/hosts/example.localdomain' \ -d '{ "attrs": { "address": "192.168.1.2", "vars.os" : "Windows" } }' \ | python -m json.tool { "results": [ { "code": 200.0, "name": "example.localdomain", "status": "Attributes updated.", "type": "Host" } ] } ### Deleting Objects You can delete objects created using the API by sending a `DELETE` request. Parameters | Type | Description -----------|---------|--------------- cascade | Boolean | **Optional.** Delete objects depending on the deleted objects (e.g. services on a host). In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) should be provided. Example for deleting the host object `example.localdomain`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X DELETE 'https://localhost:5665/v1/objects/hosts/example.localdomain?cascade=1' | python -m json.tool { "results": [ { "code": 200.0, "name": "example.localdomain", "status": "Object was deleted.", "type": "Host" } ] } ## Config Templates Provides methods to manage configuration templates: * [querying templates](12-icinga2-api.md#icinga2-api-config-templates-query) Creation, modification and deletion of templates at runtime is not supported. ### Querying Templates You can request information about configuration templates by sending a `GET` query to the `/v1/templates/` URL endpoint. ` Provides methods to manage global variables: * [querying variables](12-icinga2-api.md#icinga2-api-variables-query) ### Querying Variables You can request information about global variables by sending a `GET` query to the `/v1/variables/` URL endpoint: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/variables' A [filter](12-icinga2-api.md#icinga2-api-filters) may be provided for this query type. The variable information object can be accessed in the filter using the `variable` variable. The `filter` attribute is passed inside the request body thus requiring to use [X-HTTP-Method-Override](12-icinga2-api.md#icinga2-api-requests-method-override) here. $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5661/v1/variables' \ -d '{ "filter": "variable.type in [ \"String\", \"Number\" ]" }' Instead of using a filter you can optionally specify the variable name in the URL path when querying a single variable: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/variables/PrefixDir' The result set contains the type, name and value of the global variable. ## Actions There are several actions available for Icinga 2 provided by the `/v1/actions` URL endpoint. You can run actions by sending a `POST` request. In case you have been using the [external commands](14-features.md#external-commands) in the past, the API actions provide a similar interface with filter capabilities for some of the more common targets which do not directly change the configuration. All actions return a 200 `OK` or an appropriate error code for each action performed on each object matching the supplied filter. Actions which affect the Icinga Application itself such as disabling notification on a program-wide basis must be applied by updating the [IcingaApplication object](12-icinga2-api.md#icinga2-api-config-objects) called `app`. $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/objects/icingaapplications/app' -d '{ "attrs": { "enable_notifications": false } }' ### process-check-result Process a check result for a host or a service. Send a `POST` request to the URL endpoint `/v1/actions/process-check-result`. Parameter | Type | Description ------------------|--------------|-------------- exit\_status | Number | **Required.** For services: 0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN, for hosts: 0=OK, 1=CRITICAL. plugin\_output | String | **Required.** One or more lines of the plugin main output. Does **not** contain the performance data. performance\_data | Array | **Optional.** The performance data. check\_command | Array | **Optional.** 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. check\_source | String | **Optional.** Usually the name of the `command_endpoint` execution\_start | Timestamp | **Optional.** The timestamp where a script/process started its execution. execution\_end | Timestamp | **Optional.** The timestamp where a script/process ended its execution. This timestamp is used in features to determine e.g. the metric timestamp. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. Example for the service `passive-ping6`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/process-check-result?service=example.localdomain!passive-ping6' \ -d '{ "exit_status": 2, "plugin_output": "PING CRITICAL - Packet loss = 100%", "performance_data": [ "rta=5000.000000ms;3000.000000;5000.000000;0.000000", "pl=100%;80;100;0" ], "check_source": "example.localdomain" }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully processed check result for object 'localdomain!passive-ping6'." } ] } Example for using the `Host` type and filter by the host name: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/process-check-result' \ -d '{ "filter": "host.name==\"example.localdomain\"", "type": "Host", "exit_status": 1, "plugin_output": "Host is not available." }' You can avoid URL encoding of white spaces in object names by using the `filter` attribute in the request body. > **Note** > > Multi-line plugin output requires the following format: The first line is treated as `short` plugin output corresponding > to the first line of the plugin output. Subsequent lines are treated as `long` plugin output. Please note that the > performance data is separated from the plugin output and has to be passed as `performance_data` attribute. ### reschedule-check Reschedule a check for hosts and services. The check can be forced if required. Send a `POST` request to the URL endpoint `/v1/actions/reschedule-check`. Parameter | Type | Description -------------|-----------|-------------- next\_check | Timestamp | **Optional.** The next check will be run at this time. If omitted, the current time is used. force\_check | Boolean | **Optional.** Defaults to `false`. If enabled, the checks are executed regardless of time period restrictions and checks being disabled per object or on a global basis. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. The example reschedules all services with the name "ping6" to immediately perform a check (`next_check` default), ignoring any time periods or whether active checks are allowed for the service (`force_check=true`). $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/reschedule-check' \ -d '{ "type": "Service", "filter": "service.name==\"ping6\"", "force_check": true }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully rescheduled check for object 'example.localdomain!ping6'." } ] } ### send-custom-notification Send a custom notification for hosts and services. This notification type can be forced being sent to all users. Send a `POST` request to the URL endpoint `/v1/actions/send-custom-notification`. Parameter | Type | Description ----------|---------|-------------- author | String | **Required.** Name of the author, may be empty. comment | String | **Required.** Comment text, may be empty. force | Boolean | **Optional.** Default: false. If true, the notification is sent regardless of downtimes or whether notifications are enabled or not. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. Example for a custom host notification announcing a global maintenance to host owners: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/send-custom-notification' \ -d '{ "type": "Host", "author": "icingaadmin", "comment": "System is going down for maintenance", "force": true }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully sent custom notification for object 'host0'." }, { "code": 200.0, "status": "Successfully sent custom notification for object 'host1'." } } ### delay-notification Delay notifications for a host or a service. Note that this will only have an effect if the service stays in the same problem state that it is currently in. If the service changes to another state, a new notification may go out before the time you specify in the `timestamp` argument. Send a `POST` request to the URL endpoint `/v1/actions/delay-notification`. Parameter | Type | Description ----------|-----------|-------------- timestamp | Timestamp | **Required.** Delay notifications until this timestamp. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/delay-notification' \ -d '{ "type": "Service", "timestamp": 1446389894 }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully delayed notifications for object 'host0!service0'." }, { "code": 200.0, "status": "Successfully delayed notifications for object 'host1!service1'." } } ### acknowledge-problem Allows you to acknowledge the current problem for hosts or services. By acknowledging the current problem, future notifications (for the same state if `sticky` is set to `false`) are disabled. Send a `POST` request to the URL endpoint `/v1/actions/acknowledge-problem`. Parameter | Type | Description ---------------------|-----------|-------------- author | String | **Required.** Name of the author, may be empty. comment | String | **Required.** Comment text, may be empty. expiry | Timestamp | **Optional.** Whether the acknowledgement will be removed at the timestamp. sticky | Boolean | **Optional.** Whether the acknowledgement will be set until the service or host fully recovers. Defaults to `false`. notify | Boolean | **Optional.** Whether a notification of the `Acknowledgement` type will be sent. Defaults to `false`. persistent | Boolean | **Optional.** When the comment is of type `Acknowledgement` and this is set to `true`, the comment will remain after the acknowledgement recovers or expires. Defaults to `false`. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. The following example acknowledges all services which are in a hard critical state and sends out a notification for them: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/acknowledge-problem?type=Service&filter=service.state==2&service.state_type=1' \ -d '{ "author": "icingaadmin", "comment": "Global outage. Working on it.", "notify": true }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully acknowledged problem for object 'example2.localdomain!ping4'." }, { "code": 200.0, "status": "Successfully acknowledged problem for object 'example.localdomain!ping4'." } } ### remove-acknowledgement Removes the acknowledgements for services or hosts. Once the acknowledgement has been removed notifications will be sent out again. Send a `POST` request to the URL endpoint `/v1/actions/remove-acknowledgement`. A [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. The example removes all service acknowledgements: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-acknowledgement?type=Service' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed acknowledgement for object 'host0!service0'." }, { "code": 200.0, "status": "Successfully removed acknowledgement for object 'example2.localdomain!aws-health'." } } ### add-comment Adds a `comment` from an `author` to services or hosts. Send a `POST` request to the URL endpoint `/v1/actions/add-comment`. Parameter | Type | Description ----------|--------|-------------- author | string | **Required.** Name of the author, may be empty. comment | string | **Required.** Comment text, may be empty. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. The following example adds a comment for all `ping4` services: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/add-comment?type=Service&filter=service.name==%22ping4%22' -d '{ "author": "icingaadmin", "comment": "Troubleticket #123456789 opened." }' | python -m json.tool { "results": [ { "code": 200.0, "legacy_id": 26.0, "name": "example.localdomain!ping4!example.localdomain-1446824161-0", "status": "Successfully added comment 'example.localdomain!ping4!example.localdomain-1446824161-0' for object 'example.localdomain!ping4'." }, { "code": 200.0, "legacy_id": 27.0, "name": "example2.localdomain!ping4!example.localdomain-1446824161-1", "status": "Successfully added comment 'example2.localdomain!ping4!example.localdomain-1446824161-1' for object 'example2.localdomain!ping4'." } ] } ### remove-comment Remove the comment using its `name` attribute , returns `OK` if the comment did not exist. **Note**: This is **not** the legacy ID but the comment name returned by Icinga 2 when [adding a comment](12-icinga2-api.md#icinga2-api-actions-add-comment). Send a `POST` request to the URL endpoint `/v1/actions/remove-comment`. A [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host`, `Service` and `Comment`. Example for a simple filter using the `comment` URL parameter: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-comment?comment=example2.localdomain!ping4!mbmif.local-1446986367-0' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed comment 'example2.localdomain!ping4!mbmif.local-1446986367-0'." } ] } Example for removing all service comments using a service name filter for `ping4`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-comment?filter=service.name==%22ping4%22&type=Service' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed all comments for object 'example2.localdomain!ping4'." }, { "code": 200.0, "status": "Successfully removed all comments for object 'example.localdomain!ping4'." } ] } ### schedule-downtime Schedule a downtime for hosts and services. Send a `POST` request to the URL endpoint `/v1/actions/schedule-downtime`. Parameter | Type | Description --------------|-----------|-------------- author | String | **Required.** Name of the author. comment | String | **Required.** Comment text. start\_time | Timestamp | **Required.** Timestamp marking the beginning of the downtime. end\_time | Timestamp | **Required.** Timestamp marking the end of the downtime. fixed | Boolean | **Optional.** Defaults to `true`. If true, the downtime is `fixed` otherwise `flexible`. See [downtimes](08-advanced-topics.md#downtimes) for more information. duration | Number | **Required for flexible downtimes.** Duration of the downtime in seconds if `fixed` is set to false. trigger\_name | String | **Optional.** Sets the trigger for a triggered downtime. See [downtimes](08-advanced-topics.md#downtimes) for more information on triggered downtimes. child\_options | Number | **Optional.** Schedule child downtimes. `0` does not do anything, `1` schedules child downtimes triggered by this downtime, `2` schedules non-triggered downtimes. Defaults to `0`. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host` and `Service`. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/schedule-downtime?type=Service&filter=service.name==%22ping4%22' -d '{ "start_time": 1446388806, "end_time": 1446389806, "duration": 1000, "author": "icingaadmin", "comment": "IPv4 network maintenance" }' | python -m json.tool { "results": [ { "code": 200.0, "legacy_id": 2.0, "name": "example2.localdomain!ping4!example.localdomain-1446822004-0", "status": "Successfully scheduled downtime 'example2.localdomain!ping4!example.localdomain-1446822004-0' for object 'example2.localdomain!ping4'." }, { "code": 200.0, "legacy_id": 3.0, "name": "example.localdomain!ping4!example.localdomain-1446822004-1", "status": "Successfully scheduled downtime 'example.localdomain!ping4!example.localdomain-1446822004-1' for object 'example.localdomain!ping4'." } ] } ### remove-downtime Remove the downtime using its `name` attribute , returns `OK` if the downtime did not exist. **Note**: This is **not** the legacy ID but the downtime name returned by Icinga 2 when [scheduling a downtime](12-icinga2-api.md#icinga2-api-actions-schedule-downtime). Send a `POST` request to the URL endpoint `/v1/actions/remove-downtime`. A [filter](12-icinga2-api.md#icinga2-api-filters) must be provided. The valid types for this action are `Host`, `Service` and `Downtime`. Example for a simple filter using the `downtime` URL parameter: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-downtime?downtime=example.localdomain!ping4!mbmif.local-1446979168-6' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed downtime 'example.localdomain!ping4!mbmif.local-1446979168-6'." } ] } Example for removing all host downtimes using a host name filter for `example.localdomain`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-downtime?filter=host.name==%22example.localdomain%22&type=Host' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed all downtimes for object 'example.localdomain'." } ] } Example for removing a downtime from a host but not the services filtered by the author name. This example uses filter variables explained in the [advanced filters](12-icinga2-api.md#icinga2-api-advanced-filters) chapter. $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/remove-downtime' \ -d $'{ "type": "Downtime", "filter": "host.name == filterHost && !service && downtime.author == filterAuthor", "filter_vars": { "filterHost": "example.localdomain", "filterAuthor": "icingaadmin" } }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Successfully removed downtime 'example.localdomain!mbmif.local-1463043129-3'." } ] } ### shutdown-process Shuts down Icinga2. May or may not return. Send a `POST` request to the URL endpoint `/v1/actions/shutdown-process`. This action does not support a target type or filter. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/shutdown-process' | python -m json.tool { "results": [ { "code": 200.0, "status": "Shutting down Icinga 2." } ] } ### restart-process Restarts Icinga2. May or may not return. Send a `POST` request to the URL endpoint `/v1/actions/restart-process`. This action does not support a target type or filter. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/restart-process' | python -m json.tool { "results": [ { "code": 200.0, "status": "Restarting Icinga 2." } ] } ### generate-ticket Generates a PKI ticket for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). This can be used in combination with satellite/client setups requesting this ticket number. Send a `POST` request to the URL endpoint `/v1/actions/generate-ticket`. Parameter | Type | Description --------------|-----------|-------------- cn | String | **Required.** The host's common name for which the ticket should be geenerated. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/generate-ticket' \ -d '{ "cn": "icinga2-client1.localdomain" }' | python -m json.tool { "results": [ { "code": 200.0, "status": "Generated PKI ticket '4f75d2ecd253575fe9180938ebff7cbca262f96e' for common name 'icinga2-client1.localdomain'.", "ticket": "4f75d2ecd253575fe9180938ebff7cbca262f96e" } ] } ## Event Streams You can subscribe to event streams by sending a `POST` request to the URL endpoint `/v1/events`. The following parameters need to be specified (either as URL parameters or in a JSON-encoded message body): Parameter | Type | Description -----------|--------------|------------- types | Array | **Required.** Event type(s). Multiple types as URL parameters are supported. queue | String | **Required.** Unique queue name. Multiple HTTP clients can use the same queue as long as they use the same event types and filter. filter | String | **Optional.** Filter for specific event attributes using [filter expressions](12-icinga2-api.md#icinga2-api-filters). ### Event Stream Types The following event stream types are available: Type | Description -----------------------|-------------- CheckResult | Check results for hosts and services. StateChange | Host/service state changes. Notification | Notification events including notified users for hosts and services. AcknowledgementSet | Acknowledgement set on hosts and services. AcknowledgementCleared | Acknowledgement cleared on hosts and services. CommentAdded | Comment added for hosts and services. CommentRemoved | Comment removed for hosts and services. DowntimeAdded | Downtime added for hosts and services. DowntimeRemoved | Downtime removed for hosts and services. DowntimeStarted | Downtime started for hosts and services. DowntimeTriggered | Downtime triggered for hosts and services. Note: Each type requires [API permissions](12-icinga2-api.md#icinga2-api-permissions) being set. Example for all downtime events: &types=DowntimeAdded&types=DowntimeRemoved&types=DowntimeTriggered #### Event Stream Type: CheckResult Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `CheckResult`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host check result. check\_result | CheckResult | Serialized [CheckResult](08-advanced-topics.md#advanced-value-types-checkresult) value type. #### Event Stream Type: StateChange Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `StateChange`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host state change. state | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state. state\_type | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state type. check\_result | CheckResult | Serialized [CheckResult](08-advanced-topics.md#advanced-value-types-checkresult) value type. #### Event Stream Type: Notification Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `Notification`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host notification. users | Array | List of notified [user](09-object-types.md#objecttype-user) names. notification\_type | String | [$notification.type$](03-monitoring-basics.md#notification-runtime-macros) runtime macro value. author | String | [$notification.author$](03-monitoring-basics.md#notification-runtime-macros) runtime macro value. text | String | [$notification.comment$](03-monitoring-basics.md#notification-runtime-macros) runtime macro value. check\_result | CheckResult | Serialized [CheckResult](08-advanced-topics.md#advanced-value-types-checkresult) value type. #### Event Stream Type: Flapping Name | Type | Description ------------------|---------------|-------------------------- type | String | Event type `Flapping`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host flapping event. state | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state. state\_type | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state type. is\_flapping | Boolean | Whether this object is flapping. current\_flapping | Number | Current flapping value in percent (added in 2.8). threshold\_low | Number | Low threshold in percent (added in 2.8). threshold\_high | Number | High threshold in percent (added in 2.8). #### Event Stream Type: AcknowledgementSet Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `AcknowledgementSet`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host acknowledgement. state | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state. state\_type | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state type. author | String | Acknowledgement author set via [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) action. comment | String | Acknowledgement comment set via [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) action. acknowledgement\_type | Number | 0 = None, 1 = Normal, 2 = Sticky. `sticky` can be set via [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) action. notify | Boolean | Notifications were enabled via [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) action. expiry | Timestamp | Acknowledgement expire time set via [acknowledge-problem](12-icinga2-api.md#icinga2-api-actions-acknowledge-problem) action. #### Event Stream Type: AcknowledgementCleared Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `AcknowledgementCleared`. timestamp | Timestamp | Unix timestamp when the event happened. host | String | [Host](09-object-types.md#objecttype-host) name. service | String | [Service](09-object-types.md#objecttype-service) name. Optional if this is a host acknowledgement. state | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state. state\_type | Number | [Host](09-object-types.md#objecttype-host) or [service](09-object-types.md#objecttype-service) state type. #### Event Stream Type: CommentAdded Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `CommentAdded`. timestamp | Timestamp | Unix timestamp when the event happened. comment | Dictionary | Serialized [Comment](09-object-types.md#objecttype-comment) object. #### Event Stream Type: CommentRemoved Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `CommentRemoved`. timestamp | Timestamp | Unix timestamp when the event happened. comment | Dictionary | Serialized [Comment](09-object-types.md#objecttype-comment) object. #### Event Stream Type: DowntimeAdded Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `DowntimeAdded`. timestamp | Timestamp | Unix timestamp when the event happened. downtime | Dictionary | Serialized [Comment](09-object-types.md#objecttype-downtime) object. #### Event Stream Type: DowntimeRemoved Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `DowntimeRemoved`. timestamp | Timestamp | Unix timestamp when the event happened. downtime | Dictionary | Serialized [Comment](09-object-types.md#objecttype-downtime) object. #### Event Stream Type: DowntimeStarted Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `DowntimeStarted`. timestamp | Timestamp | Unix timestamp when the event happened. downtime | Dictionary | Serialized [Comment](09-object-types.md#objecttype-downtime) object. #### Event Stream Type: DowntimeTriggered Name | Type | Description --------------|---------------|-------------------------- type | String | Event type `DowntimeTriggered`. timestamp | Timestamp | Unix timestamp when the event happened. downtime | Dictionary | Serialized [Comment](09-object-types.md#objecttype-downtime) object. ### Event Stream Filter Event streams can be filtered by attributes using the prefix `event.`. Example for the `CheckResult` type with the `exit_code` set to `2`: &types=CheckResult&filter=event.check_result.exit_status==2 Example for the `CheckResult` type with the service [matching](18-library-reference.md#global-functions-match) the string pattern "random\*": &types=CheckResult&filter=match%28%22random*%22,event.service%29 ### Event Stream Response The event stream response is separated with new lines. The HTTP client must support long-polling and HTTP/1.1. HTTP/1.0 is not supported. Example: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=michi&types=CheckResult&filter=event.check_result.exit_status==2' {"check_result":{ ... },"host":"example.localdomain","service":"ping4","timestamp":1445421319.7226390839,"type":"CheckResult"} {"check_result":{ ... },"host":"example.localdomain","service":"ping4","timestamp":1445421324.7226390839,"type":"CheckResult"} {"check_result":{ ... },"host":"example.localdomain","service":"ping4","timestamp":1445421329.7226390839,"type":"CheckResult"} ## Status and Statistics Send a `GET` request to the URL endpoint `/v1/status` to retrieve status information and statistics for Icinga 2. Example: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/status' | python -m json.tool { "results": [ { "name": "ApiListener", "perfdata": [ ... ], "status": [ ... ] }, ... { "name": "IcingaAplication", "perfdata": [ ... ], "status": [ ... ] }, ... ] } You can limit the output by specifying a status type in the URL, e.g. `IcingaApplication`: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/status/IcingaApplication' | python -m json.tool { "results": [ { "perfdata": [], "status": { "icingaapplication": { "app": { "enable_event_handlers": true, "enable_flapping": true, "enable_host_checks": true, "enable_notifications": true, "enable_perfdata": true, "enable_service_checks": true, "node_name": "example.localdomain", "pid": 59819.0, "program_start": 1443019345.093372, "version": "v2.3.0-573-g380a131" } } } } ] } ## Configuration Management The main idea behind configuration management is to allow external applications creating configuration packages and stages based on configuration files and directory trees. This replaces any additional SSH connection and whatnot to dump configuration files to Icinga 2 directly. 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. ### Creating a Config Package Send a `POST` request to a new config package called `example-cmdb` in this example. This will create a new empty configuration package. $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST \ 'https://localhost:5665/v1/config/packages/example-cmdb' | python -m json.tool { "results": [ { "code": 200.0, "package": "example-cmdb", "status": "Created package." } ] } Package names starting with an underscore are reserved for internal packages and must not be used. ### Uploading configuration for a Config Package Configuration files in packages are managed in stages. Stages provide a way to maintain multiple configuration versions for a package. Send a `POST` request to the URL endpoint `/v1/config/stages` and add the name of an existing configuration package to the URL path (e.g. `example-cmdb`). The request body must contain the `files` attribute with the value being a dictionary of file targets and their content. You can also specify an optional `reload` attribute that will tell icinga2 to reload after stage config validation. By default this is set to `true`. The file path requires one of these two directories inside its path: Directory | Description ------------|------------------------------------ conf.d | Local configuration directory. zones.d | Configuration directory for cluster zones, each zone must be put into its own zone directory underneath. Supports the [cluster config sync](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync). Example for a local configuration in the `conf.d` directory: "files": { "conf.d/host1.conf": "object Host \"local-host\" { address = \"127.0.0.1\", check_command = \"hostalive\" }" } Example for a host configuration inside the `satellite` zone in the `zones.d` directory: "files": { "zones.d/satellite/host2.conf": "object Host \"satellite-host\" { address = \"192.168.1.100\", check_command = \"hostalive\" }" } The example below will create a new file called `test.conf` in the `conf.d` directory. Note: This example contains an error (`chec_command`). This is intentional. $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST \ -d '{ "files": { "conf.d/test.conf": "object Host \"cmdb-host\" { chec_command = \"dummy\" }" } }' \ 'https://localhost:5665/v1/config/stages/example-cmdb' | python -m json.tool { "results": [ { "code": 200.0, "package": "example-cmdb", "stage": "example.localdomain-1441625839-0", "status": "Created stage. Icinga2 will reload." } ] } The Icinga 2 API returns the `package` name this stage was created for, and also generates a unique name for the `stage` attribute you'll need for later requests. Icinga 2 automatically restarts the daemon in order to activate the new config stage. This can be disabled by setting `reload` to `false` in the request. If the validation for the new config stage failed, the old stage and its configuration objects will remain active. > **Note** > > Old stages are not purged automatically. You can [remove stages](12-icinga2-api.md#icinga2-api-config-management-delete-config-stage) that are no longer in use. Icinga 2 will create the following files in the configuration package stage after configuration validation: File | Description ------------|-------------- status | Contains the [configuration validation](11-cli-commands.md#config-validation) exit code (everything else than 0 indicates an error). startup.log | Contains the [configuration validation](11-cli-commands.md#config-validation) output. You can [fetch these files](12-icinga2-api.md#icinga2-api-config-management-fetch-config-package-stage-files) in order to verify that the new configuration was deployed successfully. ### List Configuration Packages and their Stages A list of packages and their stages can be retrieved by sending a `GET` request to the URL endpoint `/v1/config/packages`. The following example contains one configuration package `example-cmdb`. The package does not currently have an active stage. $ curl -k -s -u root:icinga 'https://localhost:5665/v1/config/packages' | python -m json.tool { "results": [ { "active-stage": "", "name": "example-cmdb", "stages": [ "example.localdomain-1441625839-0" ] } ] } ### List Configuration Packages and their Stages In order to retrieve a list of files for a stage you can send a `GET` request to the URL endpoint `/v1/config/stages`. You need to include the package name (`example-cmdb`) and stage name (`example.localdomain-1441625839-0`) in the URL: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/config/stages/example-cmdb/example.localdomain-1441625839-0' | python -m json.tool { "results": [ ... { "name": "startup.log", "type": "file" }, { "name": "status", "type": "file" }, { "name": "conf.d", "type": "directory" }, { "name": "zones.d", "type": "directory" }, { "name": "conf.d/test.conf", "type": "file" } ] } ### Fetch Configuration Package Stage Files Send a `GET` request to the URL endpoint `/v1/config/files` and add the package name, the stage name and the relative path to the file to the URL path. > **Note** > > The returned files are plain-text instead of JSON-encoded. The following example fetches the configuration file `conf.d/test.conf`: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/config/files/example-cmdb/example.localdomain-1441625839-0/conf.d/test.conf' object Host "cmdb-host" { chec_command = "dummy" } You can fetch a [list of existing files](12-icinga2-api.md#icinga2-api-config-management-list-config-package-stage-files) in a configuration stage and then specifically request their content. ### Configuration Package Stage Errors Now that we don't have an active stage for `example-cmdb` yet seen [here](12-icinga2-api.md#icinga2-api-config-management-list-config-packages), there must have been an error. In order to check for validation errors you can fetch the `startup.log` file by sending a `GET` request to the URL endpoint `/v1/config/files`. You must include the package name, stage name and the `startup.log` in the URL path. $ curl -k -s -u root:icinga 'https://localhost:5665/v1/config/files/example-cmdb/example.localdomain-1441133065-1/startup.log' ... critical/config: Error: Attribute 'chec_command' does not exist. Location: /var/lib/icinga2/api/packages/example-cmdb/example.localdomain-1441133065-1/conf.d/test.conf(1): object Host "cmdb-host" { chec_command = "dummy" } ^^^^^^^^^^^^^^^^^^^^^^ critical/config: 1 error The output is similar to the manual [configuration validation](11-cli-commands.md#config-validation). > **Note** > > The returned output is plain-text instead of JSON-encoded. ### Deleting Configuration Package Stage You can send a `DELETE` request to the URL endpoint `/v1/config/stages` in order to purge a configuration stage. You must include the package and stage name inside the URL path. The following example removes the failed configuration stage `example.localdomain-1441133065-1` in the `example-cmdb` configuration package: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X DELETE \ 'https://localhost:5665/v1/config/stages/example-cmdb/example.localdomain-1441133065-1' | python -m json.tool { "results": [ { "code": 200.0, "status": "Stage deleted." } ] } ### Deleting Configuration Package In order to completely purge a configuration package and its stages you can send a `DELETE` request to the URL endpoint `/v1/config/packages` with the package name in the URL path. This example entirely deletes the configuration package `example-cmdb`: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X DELETE \ 'https://localhost:5665/v1/config/packages/example-cmdb' | python -m json.tool { "results": [ { "code": 200.0, "package": "example-cmdb", "status": "Deleted package." } ] } ## Types You can retrieve the configuration object types by sending a `GET` request to URL endpoint `/v1/types`. Each response entry in the results array contains the following attributes: Attribute | Type | Description ----------------|--------------|--------------------- name | String | The type name. plural\_name | String | The plural type name. fields | Dictionary | Available fields including details on e.g. the type and attribute accessibility. abstract | Boolean | Whether objects can be instantiated for this type. base | Boolean | The base type (e.g. `Service` inherits fields and prototype methods from `Checkable`). prototype\_keys | Array | Available prototype methods. In order to view a specific configuration object type specify its name inside the URL path: $ curl -k -s -u root:icinga 'https://localhost:5665/v1/types/Object' | python -m json.tool { "results": [ { "abstract": false, "fields": { "type": { "array_rank": 0.0, "attributes": { "config": false, "navigation": false, "no_user_modify": false, "no_user_view": false, "required": false, "state": false }, "id": 0.0, "type": "String" } }, "name": "Object", "plural_name": "Objects", "prototype_keys": [ "clone", "notify_attribute", "to_string" ] } ] } ## Console You can inspect variables and execute other expressions by sending a `POST` request to the URL endpoint `/v1/console/execute-script`. In order to receive auto-completion suggestions, send a `POST` request to the URL endpoint `/v1/console/auto-complete-script`. The following parameters need to be specified (either as URL parameters or in a JSON-encoded message body): Parameter | Type | Description -----------|--------------|------------- session | String | **Optional.** The session ID. Ideally this should be a GUID or some other unique identifier. command | String | **Required.** Command expression for execution or auto-completion. sandboxed | Number | **Optional.** Whether runtime changes are allowed or forbidden. Defaults to disabled. The [API permission](12-icinga2-api.md#icinga2-api-permissions) `console` is required for executing expressions. > **Note** > > Runtime modifications via `execute-script` calls are not validated and might cause the Icinga 2 > daemon to crash or behave in an unexpected way. Use these runtime changes at your own risk. If you specify a session identifier, the same script context can be reused for multiple requests. This allows you to, for example, set a local variable in a request and use that local variable in another request. Sessions automatically expire after a set period of inactivity (currently 30 minutes). Example for fetching the command line from the local host's last check result: $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/console/execute-script?command=get_host(NodeName).last_check_result.command&sandboxed=0&session=bb75fd7c-c686-407d-9688-582c04227756' | python -m json.tool { "results": [ { "code": 200.0, "result": [ "/usr/local/sbin/check_ping", "-H", "127.0.0.1", "-c", "5000,100%", "-w", "3000,80%" ], "status": "Executed successfully." } ] } Example for fetching auto-completion suggestions for the `Host.` type. This works in a similar fashion when pressing TAB inside the [console CLI command](11-cli-commands.md#cli-command-console): $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/console/auto-complete-script?command=Host.&sandboxed=0&session=bb75fd7c-c686-407d-9688-582c04227756' | python -m json.tool { "results": [ { "code": 200.0, "status": "Auto-completed successfully.", "suggestions": [ "Host.type", "Host.name", "Host.prototype", "Host.base", "Host.register_attribute_handler", "Host.clone", "Host.notify_attribute", "Host.to_string" ] } ] } ## API Clients There are a couple of existing clients which can be used with the Icinga 2 API: * [curl](https://curl.haxx.se/) or any other HTTP client really * [Icinga 2 console (CLI command)](12-icinga2-api.md#icinga2-api-clients-cli-console) * [Icinga Studio](12-icinga2-api.md#icinga2-api-clients-icinga-studio) * [Icinga Web 2 Director](https://www.icinga.com/products/icinga-web-2-modules/) Demo cases: * [Dashing](https://github.com/Icinga/dashing-icinga2) * [API examples](https://github.com/Icinga/icinga2-api-examples) Additional [programmatic examples](12-icinga2-api.md#icinga2-api-clients-programmatic-examples) will help you getting started using the Icinga 2 API in your environment. ### Icinga Studio Icinga Studio is a graphical application to query configuration objects provided by the API. ![Icinga Studio Connection](images/icinga2-api/icinga2_api_icinga_studio_connect.png) ![Icinga Studio Overview](images/icinga2-api/icinga2_api_icinga_studio_overview.png) Please check the package repository of your distribution for available packages. > **Note** > Icinga Studio does not currently support SSL certificate verification. The Windows installer already includes Icinga Studio. On Debian and Ubuntu the package `icinga2-studio` can be used to install Icinga Studio. ### Icinga 2 Console By default the [console CLI command](11-cli-commands.md#cli-command-console) evaluates expressions in a local interpreter, i.e. independently from your Icinga 2 daemon. Add the `--connect` parameter to debug and evaluate expressions via the API. ### API Clients Programmatic Examples The programmatic examples use HTTP basic authentication and SSL certificate verification. The CA file is expected in `pki/icinga2-ca.crt` but you may adjust the examples for your likings. The [request method](icinga2-api-requests) is `POST` using [X-HTTP-Method-Override: GET](12-icinga2-api.md#icinga2-api-requests-method-override) which allows you to send a JSON request body. The examples request specific service attributes joined with host attributes. `attrs` and `joins` are therefore specified as array. The `filter` attribute [matches](18-library-reference.md#global-functions-match) on all services with `ping` in their name. #### Example API Client in Python The following example uses **Python** and the `requests` and `json` module: # pip install requests # pip install json $ vim icinga2-api-example.py #!/usr/bin/env python import requests, json # Replace 'localhost' with your FQDN and certificate CN # for SSL verification request_url = "https://localhost:5665/v1/objects/services" headers = { 'Accept': 'application/json', 'X-HTTP-Method-Override': 'GET' } data = { "attrs": [ "name", "state", "last_check_result" ], "joins": [ "host.name", "host.state", "host.last_check_result" ], "filter": "match(\"ping*\", service.name)", } r = requests.post(request_url, headers=headers, auth=('root', 'icinga'), data=json.dumps(data), verify="pki/icinga2-ca.crt") print "Request URL: " + str(r.url) print "Status code: " + str(r.status_code) if (r.status_code == 200): print "Result: " + json.dumps(r.json()) else: print r.text r.raise_for_status() $ python icinga2-api-example.py #### Example API Client in Ruby The following example uses **Ruby** and the `rest_client` gem: # gem install rest_client $ vim icinga2-api-example.rb #!/usr/bin/ruby require 'rest_client' # Replace 'localhost' with your FQDN and certificate CN # for SSL verification request_url = "https://localhost:5665/v1/objects/services" headers = { "Accept" => "application/json", "X-HTTP-Method-Override" => "GET" } data = { "attrs" => [ "name", "state", "last_check_result" ], "joins" => [ "host.name", "host.state", "host.last_check_result" ], "filter" => "match(\"ping*\", service.name)", } r = RestClient::Resource.new( URI.encode(request_url), :headers => headers, :user => "root", :password => "icinga", :ssl_ca_file => "pki/icinga2-ca.crt") begin response = r.post(data.to_json) rescue => e response = e.response end puts "Status: " + response.code.to_s if response.code == 200 puts "Result: " + (JSON.pretty_generate JSON.parse(response.body)) else puts "Error: " + response end $ ruby icinga2-api-example.rb A more detailed example can be found in the [Dashing demo](https://github.com/Icinga/dashing-icinga2). #### Example API Client in PHP The following example uses **PHP** and its `curl` library: $ vim icinga2-api-example.php #!/usr/bin/env php array('name', 'state', 'last_check_result'), joins => array('host.name', 'host.state', 'host.last_check_result'), filter => 'match("ping*", service.name)', ); $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => $request_url, CURLOPT_HTTPHEADER => $headers, CURLOPT_USERPWD => $username . ":" . $password, CURLOPT_RETURNTRANSFER => true, CURLOPT_CAINFO => "pki/icinga2-ca.crt", CURLOPT_POST => count($data), CURLOPT_POSTFIELDS => json_encode($data) )); $response = curl_exec($ch); if ($response === false) { print "Error: " . curl_error($ch) . "(" . $response . ")\n"; } $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); print "Status: " . $code . "\n"; if ($code == 200) { $response = json_decode($response, true); print_r($response); } ?> $ php icinga2-api-example.php #### Example API Client in Perl The following example uses **Perl** and the `Rest::Client` module: # perl -MCPAN -e 'install REST::Client' # perl -MCPAN -e 'install JSON' # perl -MCPAN -e 'install MIME::Base64' # perl -MCPAN -e 'install Data::Dumper' $ vim icinga2-api-example.pl #!/usr/bin/env perl use strict; use warnings; use REST::Client; use MIME::Base64; use JSON; use Data::Dumper; # Replace 'localhost' with your FQDN and certificate CN # for SSL verification my $request_host = "https://localhost:5665"; my $userpass = "root:icinga"; my $client = REST::Client->new(); $client->setHost($request_host); $client->setCa("pki/icinga2-ca.crt"); $client->addHeader("Accept", "application/json"); $client->addHeader("X-HTTP-Method-Override", "GET"); $client->addHeader("Authorization", "Basic " . encode_base64($userpass)); my %json_data = ( attrs => ['name', 'state', 'last_check_result'], joins => ['host.name', 'host.state', 'host.last_check_result'], filter => 'match("ping*", service.name)', ); my $data = encode_json(\%json_data); $client->POST("/v1/objects/services", $data); my $status = $client->responseCode(); print "Status: " . $status . "\n"; my $response = $client->responseContent(); if ($status == 200) { print "Result: " . Dumper(decode_json($response)) . "\n"; } else { print "Error: " . $response . "\n"; } $ perl icinga2-api-example.pl icinga2-2.8.1/doc/13-addons.md000066400000000000000000000203151322762156600156310ustar00rootroot00000000000000# Icinga 2 Addons ## Graphing ### PNP [PNP](https://www.pnp4nagios.org) is a graphing addon. [PNP](https://www.pnp4nagios.org) is an addon which adds a graphical representation of the performance data collected by the monitoring plugins. The data is stored as rrd (round robin database) files. Use your distribution's package manager to install the `pnp4nagios` package. If you're planning to use it, configure it to use the [bulk mode with npcd and npcdmod](https://docs.pnp4nagios.org/pnp-0.6/modes#bulk_mode_with_npcd_and_npcdmod) in combination with Icinga 2's [PerfdataWriter](14-features.md#performance-data). NPCD collects the performance data files which Icinga 2 generates. Enable performance data writer in icinga 2 # icinga2 feature enable perfdata Configure npcd to use the performance data created by Icinga 2: vim /etc/pnp4nagios/npcd.cfg Set `perfdata_spool_dir = /var/spool/icinga2/perfdata` and restart the `npcd` daemon. There's also an Icinga Web 2 module for direct PNP graph integration available at [Icinga Exchange](https://exchange.icinga.com/icinga/PNP). More information on [action_url as attribute](13-addons.md#addons-graphing-pnp-action-url) and [graph template names](13-addons.md#addons-graphing-pnp-custom-templates). ### Graphite [Graphite](https://graphite.readthedocs.org/en/latest/) is a time-series database storing collected metrics and making them available through restful apis and web interfaces. Graphite consists of 3 software components: * carbon -- a Twisted daemon that listens for time-series data * whisper -- a simple database library for storing time-series data (similar in design to RRD) * graphite webapp -- a Django webapp that renders graphs on-demand using Cairo Use the [GraphiteWriter](14-features.md#graphite-carbon-cache-writer) feature for sending real-time metrics from Icinga 2 to Graphite. # icinga2 feature enable graphite There are Graphite addons available for collecting the performance data files too (e.g. `Graphios`). A popular alternative frontend for Graphite is for example [Grafana](https://grafana.org). ### InfluxDB [InfluxDB](https://influxdb.com) is a time series, metrics, and analytics database. It’s written in Go and has no external dependencies. Use the [InfluxdbWriter](14-features.md#influxdb-writer) feature for sending real-time metrics from Icinga 2 to InfluxDB. # icinga2 feature enable influxdb A popular frontend for InfluxDB is for example [Grafana](https://grafana.org). ## Visualization ### Icinga Reporting By enabling the [DB IDO](14-features.md#db-ido) feature you can use the [Icinga Reporting package](https://docs.icinga.com/latest/en/reporting.html). ### NagVis By using either [Livestatus](14-features.md#setting-up-livestatus) or [DB IDO](14-features.md#db-ido) as a backend you can create your own network maps based on your monitoring configuration and status data using [NagVis](https://www.nagvis.org). The configuration in nagvis.ini.php should look like this for Livestatus for example: [backend_live_1] backendtype="mklivestatus" socket="unix:/var/run/icinga2/cmd/livestatus" If you are planning an integration into Icinga Web 2, look at [this module](https://github.com/Icinga/icingaweb2-module-nagvis). ### Thruk [Thruk](https://www.thruk.org) is an alternative web interface which can be used with Icinga 2 and the [Livestatus](14-features.md#setting-up-livestatus) feature. ## Log Monitoring Using [Logstash](https://www.elastic.co/guide/en/logstash/current/introduction.html) or [Graylog](https://www.graylog.org) in your infrastructure and correlate events with your monitoring is even simpler these days. * Use the `GelfWriter` feature to write Icinga 2's check and notification events to Graylog or Logstash. * Configure the logstash `nagios` output to send passive traps to Icinga 2 using the external command pipe. * Execute a plugin to check Graylog alert streams. More details can be found in [this blog post](https://www.icinga.com/2014/12/02/team-icinga-at-osmc-2014/). ## Notification Scripts and Interfaces There's a variety of resources available, for example different notification scripts such as: * E-Mail ([examples](03-monitoring-basics.md#alert-notifications) provided) * SMS * Pager (XMPP, etc.) * Twitter * IRC * Ticket systems * etc. Additionally external services can be [integrated with Icinga 2](https://www.icinga.com/products/integrations/): * [Pagerduty](https://www.icinga.com/partners/pagerduty/) * [VictorOps](https://www.icinga.com/partners/victorops/) * [StackStorm](https://www.icinga.com/partners/stackstorm/) More information can be found on the [Icinga Website](https://www.icinga.com/). ## Configuration Management Tools If you require your favourite configuration tool to export the Icinga 2 configuration, please get in touch with their developers. The Icinga project does not provide a configuration web interface yet. Follow the [Icinga Blog](https://www.icinga.com/blog/) for updates on this topic. If you're looking for puppet manifests, chef cookbooks, ansible recipes, etc. -- we're happy to integrate them upstream, so please get in touch with the [Icinga team](https://www.icinga.com/community/get-involved/). These tools are currently in development and require feedback and tests: * [Ansible Roles](https://github.com/Icinga/icinga2-ansible) * [Puppet Module](https://github.com/Icinga/puppet-icinga2) * [Chef Cookbook](https://github.com/Icinga/chef-icinga2) ## More Addon Integration Hints ### PNP Action Url They work in a similar fashion for Icinga 2 and are used for 1.x web interfaces (Icinga Web 2 doesn't require the action url attribute in its own module). template Host "pnp-hst" { action_url = "/pnp4nagios/graph?host=$HOSTNAME$" } template Service "pnp-svc" { action_url = "/pnp4nagios/graph?host=$HOSTNAME$&srv=$SERVICEDESC$" } ### PNP Custom Templates with Icinga 2 PNP automatically determines the graph template from the check command name (or the argument's name). This behavior changed in Icinga 2 compared to Icinga 1.x. Though there are certain possibilities to fix this: * Create a symlink for example from the `templates.dist/check_ping.php` template to the actual check name in Icinga 2 (`templates/ping4.php`) * Pass the check command name inside the [format template configuration](14-features.md#writing-performance-data-files) The latter becomes difficult with agent based checks like NRPE or SSH where the first command argument acts as graph template identifier. There is the possibility to define the pnp template name as custom attribute and use that inside the formatting templates as `SERVICECHECKCOMMAND` for instance. Example for services: # vim /etc/icinga2/features-enabled/perfdata.conf service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tSERVICEDESC::$service.name$\tSERVICEPERFDATA::$service.perfdata$\tSERVICECHECKCOMMAND::$service.check_command$$pnp_check_arg1$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$\tSERVICESTATE::$service.state$\tSERVICESTATETYPE::$service.state_type$" # vim /etc/icinga2/conf.d/services.conf template Service "pnp-svc" { action_url = "/pnp4nagios/graph?host=$HOSTNAME$&srv=$SERVICEDESC$" vars.pnp_check_arg1 = "" } apply Service "nrpe-check" { import "pnp-svc" check_command = nrpe vars.nrpe_command = "check_disk" vars.pnp_check_arg1 = "!$nrpe_command$" } If there are warnings about unresolved macros, make sure to specify a default value for `vars.pnp_check_arg1` inside the In PNP, the custom template for nrpe is then defined in `/etc/pnp4nagios/custom/nrpe.cfg` and the additional command arg string will be seen in the xml too for other templates. icinga2-2.8.1/doc/14-features.md000066400000000000000000000654671322762156600162210ustar00rootroot00000000000000# Icinga 2 Features ## Logging Icinga 2 supports three different types of logging: * File logging * Syslog (on Linux/UNIX) * Console logging (`STDOUT` on tty) You can enable additional loggers using the `icinga2 feature enable` and `icinga2 feature disable` commands to configure loggers: Feature | Description ---------|------------ debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher) mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher) syslog | Syslog (severity: `warning` or higher) By default file the `mainlog` feature is enabled. When running Icinga 2 on a terminal log messages with severity `information` or higher are written to the console. Packages will install a configuration file for logrotate on supported platforms. This configuration ensures that the `icinga2.log`, `error.log` and `debug.log` files are rotated on a daily basis. ## DB IDO The IDO (Icinga Data Output) modules for Icinga 2 take care of exporting all configuration and status information into a database. The IDO database is used by Icinga Web 2. Details on the installation can be found in the [Configuring DB IDO](02-getting-started.md#configuring-db-ido-mysql) chapter. Details on the configuration can be found in the [IdoMysqlConnection](09-object-types.md#objecttype-idomysqlconnection) and [IdoPgsqlConnection](09-object-types.md#objecttype-idopgsqlconnection) object configuration documentation. The DB IDO feature supports [High Availability](06-distributed-monitoring.md#distributed-monitoring-high-availability-db-ido) in the Icinga 2 cluster. The following example query checks the health of the current Icinga 2 instance writing its current status to the DB IDO backend table `icinga_programstatus` every 10 seconds. By default it checks 60 seconds into the past which is a reasonable amount of time -- adjust it for your requirements. If the condition is not met, the query returns an empty result. > **Tip** > > Use [check plugins](05-service-monitoring.md#service-monitoring-plugins) to monitor the backend. Replace the `default` string with your instance name if different. Example for MySQL: # mysql -u root -p icinga -e "SELECT status_update_time FROM icinga_programstatus ps JOIN icinga_instances i ON ps.instance_id=i.instance_id WHERE (UNIX_TIMESTAMP(ps.status_update_time) > UNIX_TIMESTAMP(NOW())-60) AND i.instance_name='default';" +---------------------+ | status_update_time | +---------------------+ | 2014-05-29 14:29:56 | +---------------------+ Example for PostgreSQL: # export PGPASSWORD=icinga; psql -U icinga -d icinga -c "SELECT ps.status_update_time FROM icinga_programstatus AS ps JOIN icinga_instances AS i ON ps.instance_id=i.instance_id WHERE ((SELECT extract(epoch from status_update_time) FROM icinga_programstatus) > (SELECT extract(epoch from now())-60)) AND i.instance_name='default'"; status_update_time ------------------------ 2014-05-29 15:11:38+02 (1 Zeile) A detailed list on the available table attributes can be found in the [DB IDO Schema documentation](24-appendix.md#schema-db-ido). ## External Commands > **Note** > > Please use the [REST API](12-icinga2-api.md#icinga2-api) as modern and secure alternative > for external actions. Icinga 2 provides an external command pipe for processing commands triggering specific actions (for example rescheduling a service check through the web interface). In order to enable the `ExternalCommandListener` configuration use the following command and restart Icinga 2 afterwards: # icinga2 feature enable command Icinga 2 creates the command pipe file as `/var/run/icinga2/cmd/icinga2.cmd` using the default configuration. Web interfaces and other Icinga addons are able to send commands to Icinga 2 through the external command pipe, for example for rescheduling a forced service check: # /bin/echo "[`date +%s`] SCHEDULE_FORCED_SVC_CHECK;localhost;ping4;`date +%s`" >> /var/run/icinga2/cmd/icinga2.cmd # tail -f /var/log/messages Oct 17 15:01:25 icinga-server icinga2: Executing external command: [1382014885] SCHEDULE_FORCED_SVC_CHECK;localhost;ping4;1382014885 Oct 17 15:01:25 icinga-server icinga2: Rescheduling next check for service 'ping4' A list of currently supported external commands can be found [here](24-appendix.md#external-commands-list-detail). Detailed information on the commands and their required parameters can be found on the [Icinga 1.x documentation](https://docs.icinga.com/latest/en/extcommands2.html). ## Performance Data When a host or service check is executed plugins should provide so-called `performance data`. Next to that additional check performance data can be fetched using Icinga 2 runtime macros such as the check latency or the current service state (or additional custom attributes). The performance data can be passed to external applications which aggregate and store them in their backends. These tools usually generate graphs for historical reporting and trending. Well-known addons processing Icinga performance data are [PNP4Nagios](13-addons.md#addons-graphing-pnp), [Graphite](13-addons.md#addons-graphing-graphite) or [OpenTSDB](14-features.md#opentsdb-writer). ### Writing Performance Data Files PNP4Nagios and Graphios use performance data collector daemons to fetch the current performance files for their backend updates. Therefore the Icinga 2 [PerfdataWriter](09-object-types.md#objecttype-perfdatawriter) feature allows you to define the output template format for host and services helped with Icinga 2 runtime vars. host_format_template = "DATATYPE::HOSTPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tHOSTPERFDATA::$host.perfdata$\tHOSTCHECKCOMMAND::$host.check_command$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$" service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tSERVICEDESC::$service.name$\tSERVICEPERFDATA::$service.perfdata$\tSERVICECHECKCOMMAND::$service.check_command$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$\tSERVICESTATE::$service.state$\tSERVICESTATETYPE::$service.state_type$" The default templates are already provided with the Icinga 2 feature configuration which can be enabled using # icinga2 feature enable perfdata By default all performance data files are rotated in a 15 seconds interval into the `/var/spool/icinga2/perfdata/` directory as `host-perfdata.` and `service-perfdata.`. External collectors need to parse the rotated performance data files and then remove the processed files. ### Graphite Carbon Cache Writer While there are some [Graphite](13-addons.md#addons-graphing-graphite) collector scripts and daemons like Graphios available for Icinga 1.x it's more reasonable to directly process the check and plugin performance in memory in Icinga 2. Once there are new metrics available, Icinga 2 will directly write them to the defined Graphite Carbon daemon tcp socket. You can enable the feature using # icinga2 feature enable graphite By default the [GraphiteWriter](09-object-types.md#objecttype-graphitewriter) feature expects the Graphite Carbon Cache to listen at `127.0.0.1` on TCP port `2003`. #### Current Graphite Schema The current naming schema is defined as follows. The [Icinga Web 2 Graphite module](https://github.com/icinga/icingaweb2-module-graphite) depends on this schema. The default prefix for hosts and services is configured using [runtime macros](03-monitoring-basics.md#runtime-macros)like this: icinga2.$host.name$.host.$host.check_command$ icinga2.$host.name$.services.$service.name$.$service.check_command$ You can customize the prefix name by using the `host_name_template` and `service_name_template` configuration attributes. The additional levels will allow fine granular filters and also template capabilities, e.g. by using the check command `disk` for specific graph templates in web applications rendering the Graphite data. The following characters are escaped in prefix labels: Character | Escaped character --------------|-------------------------- whitespace | _ . | _ \ | _ / | _ Metric values are stored like this: .perfdata..value The following characters are escaped in perfdata labels: Character | Escaped character --------------|-------------------------- whitespace | _ \ | _ / | _ :: | . Note that perfdata labels may contain dots (`.`) allowing to add more subsequent levels inside the Graphite tree. `::` adds support for [multi performance labels](http://my-plugin.de/wiki/projects/check_multi/configuration/performance) and is therefore replaced by `.`. By enabling `enable_send_thresholds` Icinga 2 automatically adds the following threshold metrics: .perfdata..min .perfdata..max .perfdata..warn .perfdata..crit By enabling `enable_send_metadata` Icinga 2 automatically adds the following metadata metrics: .metadata.current_attempt .metadata.downtime_depth .metadata.acknowledgement .metadata.execution_time .metadata.latency .metadata.max_check_attempts .metadata.reachable .metadata.state .metadata.state_type Metadata metric overview: metric | description -------------------|------------------------------------------ current_attempt | current check attempt max_check_attempts | maximum check attempts until the hard state is reached reachable | checked object is reachable downtime_depth | number of downtimes this object is in acknowledgement | whether the object is acknowledged or not execution_time | check execution time latency | check latency state | current state of the checked object state_type | 0=SOFT, 1=HARD state The following example illustrates how to configure the storage schemas for Graphite Carbon Cache. [icinga2_default] # intervals like PNP4Nagios uses them per default pattern = ^icinga2\. retentions = 1m:2d,5m:10d,30m:90d,360m:4y ### InfluxDB Writer Once there are new metrics available, Icinga 2 will directly write them to the defined InfluxDB HTTP API. You can enable the feature using # icinga2 feature enable influxdb By default the [InfluxdbWriter](09-object-types.md#objecttype-influxdbwriter) feature expects the InfluxDB daemon to listen at `127.0.0.1` on port `8086`. Measurement names and tags are fully configurable by the end user. The InfluxdbWriter object will automatically add a `metric` tag to each data point. This correlates to the perfdata label. Fields (value, warn, crit, min, max) are created from data if available and the configuration allows it. If a value associated with a tag is not able to be resolved, it will be dropped and not sent to the target host. Backslashes are allowed in tag keys, tag values and field keys, however they are also escape characters when followed by a space or comma, but cannot be escaped themselves. As a result all trailling slashes in these fields are replaced with an underscore. This predominantly affects Windows paths e.g. `C:\` becomes `C:_`. The database is assumed to exist so this object will make no attempt to create it currently. More configuration details can be found [here](09-object-types.md#objecttype-influxdbwriter). #### Instance Tagging Consider the following service check: ``` apply Service "disk" for (disk => attributes in host.vars.disks) { import "generic-service" check_command = "disk" display_name = "Disk " + disk vars.disk_partitions = disk assign where host.vars.disks } ``` This is a typical pattern for checking individual disks, NICs, SSL certificates etc associated with a host. What would be useful is to have the data points tagged with the specific instance for that check. This would allow you to query time series data for a check on a host and for a specific instance e.g. /dev/sda. To do this quite simply add the instance to the service variables: ``` apply Service "disk" for (disk => attributes in host.vars.disks) { ... vars.instance = disk ... } ``` Then modify your writer configuration to add this tag to your data points if the instance variable is associated with the service: ``` object InfluxdbWriter "influxdb" { ... service_template = { measurement = "$service.check_command$" tags = { hostname = "$host.name$" service = "$service.name$" instance = "$service.vars.instance$" } } ... } ``` ### Elastic Stack Integration [Icingabeat](https://github.com/icinga/icingabeat) is an Elastic Beat that fetches data from the Icinga 2 API and sends it either directly to [Elasticsearch](https://www.elastic.co/products/elasticsearch) or [Logstash](https://www.elastic.co/products/logstash). More integrations: * [Logstash output](https://github.com/Icinga/logstash-output-icinga) for the Icinga 2 API. * [Logstash Grok Pattern](https://github.com/Icinga/logstash-grok-pattern) for Icinga 2 logs. #### Elasticsearch Writer This feature forwards check results, state changes and notification events to an [Elasticsearch](https://www.elastic.co/products/elasticsearch) installation over its HTTP API. The check results include parsed performance data metrics if enabled. > **Note** > > Elasticsearch 5.x is required. This feature has been successfully tested with Elasticsearch 5.6.4. Enable the feature and restart Icinga 2. ``` # icinga2 feature enable elasticsearch ``` The default configuration expects an Elasticsearch instance running on `localhost` on port `9200 and writes to an index called `icinga2`. More configuration details can be found [here](09-object-types.md#objecttype-elasticsearchwriter). #### Current Elasticsearch Schema The following event types are written to Elasticsearch: * icinga2.event.checkresult * icinga2.event.statechange * icinga2.event.notification Performance data metrics must be explicitly enabled with the `enable_send_perfdata` attribute. Metric values are stored like this: check_result.perfdata..value The following characters are escaped in perfdata labels: Character | Escaped character --------------|-------------------------- whitespace | _ \ | _ / | _ :: | . Note that perfdata labels may contain dots (`.`) allowing to add more subsequent levels inside the tree. `::` adds support for [multi performance labels](http://my-plugin.de/wiki/projects/check_multi/configuration/performance) and is therefore replaced by `.`. Icinga 2 automatically adds the following threshold metrics if existing: check_result.perfdata..min check_result.perfdata..max check_result.perfdata..warn check_result.perfdata..crit ### Graylog Integration #### GELF Writer The `Graylog Extended Log Format` (short: [GELF](http://docs.graylog.org/en/latest/pages/gelf.html)) can be used to send application logs directly to a TCP socket. While it has been specified by the [Graylog](https://www.graylog.org) project as their [input resource standard](http://docs.graylog.org/en/latest/pages/sending_data.html), other tools such as [Logstash](https://www.elastic.co/products/logstash) also support `GELF` as [input type](https://www.elastic.co/guide/en/logstash/current/plugins-inputs-gelf.html). You can enable the feature using # icinga2 feature enable gelf By default the `GelfWriter` object expects the GELF receiver to listen at `127.0.0.1` on TCP port `12201`. The default `source` attribute is set to `icinga2`. You can customize that for your needs if required. Currently these events are processed: * Check results * State changes * Notifications ### OpenTSDB Writer While there are some OpenTSDB collector scripts and daemons like tcollector available for Icinga 1.x it's more reasonable to directly process the check and plugin performance in memory in Icinga 2. Once there are new metrics available, Icinga 2 will directly write them to the defined TSDB TCP socket. You can enable the feature using # icinga2 feature enable opentsdb By default the `OpenTsdbWriter` object expects the TSD to listen at `127.0.0.1` on port `4242`. The current naming schema is icinga.host. icinga.service.. for host and service checks. The tag host is always applied. To make sure Icinga 2 writes a valid metric into OpenTSDB some characters are replaced with `_` in the target name: \ (and space) The resulting name in OpenTSDB might look like: www-01 / http-cert / response time icinga.http_cert.response_time In addition to the performance data retrieved from the check plugin, Icinga 2 sends internal check statistic data to OpenTSDB: metric | description -------------------|------------------------------------------ current_attempt | current check attempt max_check_attempts | maximum check attempts until the hard state is reached reachable | checked object is reachable downtime_depth | number of downtimes this object is in acknowledgement | whether the object is acknowledged or not execution_time | check execution time latency | check latency state | current state of the checked object state_type | 0=SOFT, 1=HARD state While reachable, state and state_type are metrics for the host or service the other metrics follow the current naming schema icinga.check. with the following tags tag | description --------|------------------------------------------ type | the check type, one of [host, service] host | hostname, the check ran on service | the service name (if type=service) > **Note** > > You might want to set the tsd.core.auto_create_metrics setting to `true` > in your opentsdb.conf configuration file. ## Livestatus The [MK Livestatus](https://mathias-kettner.de/checkmk_livestatus.html) project implements a query protocol that lets users query their Icinga instance for status information. It can also be used to send commands. The Livestatus component that is distributed as part of Icinga 2 is a re-implementation of the Livestatus protocol which is compatible with MK Livestatus. > **Tip** > > Only install the Livestatus feature if your web interface or addon requires > you to do so. > [Icinga Web 2](02-getting-started.md#setting-up-icingaweb2) does not need > Livestatus. Details on the available tables and attributes with Icinga 2 can be found in the [Livestatus Schema](24-appendix.md#schema-livestatus) section. You can enable Livestatus using icinga2 feature enable: # icinga2 feature enable livestatus After that you will have to restart Icinga 2: # systemctl restart icinga2 By default the Livestatus socket is available in `/var/run/icinga2/cmd/livestatus`. In order for queries and commands to work you will need to add your query user (e.g. your web server) to the `icingacmd` group: # usermod -a -G icingacmd www-data The Debian packages use `nagios` as the user and group name. Make sure to change `icingacmd` to `nagios` if you're using Debian. Change `www-data` to the user you're using to run queries. In order to use the historical tables provided by the livestatus feature (for example, the `log` table) you need to have the `CompatLogger` feature enabled. By default these logs are expected to be in `/var/log/icinga2/compat`. A different path can be set using the `compat_log_path` configuration attribute. # icinga2 feature enable compatlog ### Livestatus Sockets Other to the Icinga 1.x Addon, Icinga 2 supports two socket types * Unix socket (default) * TCP socket Details on the configuration can be found in the [LivestatusListener](09-object-types.md#objecttype-livestatuslistener) object configuration. ### Livestatus GET Queries > **Note** > > All Livestatus queries require an additional empty line as query end identifier. > The `nc` tool (`netcat`) provides the `-U` parameter to communicate using > a unix socket. There also is a Perl module available in CPAN for accessing the Livestatus socket programmatically: [Monitoring::Livestatus](http://search.cpan.org/~nierlein/Monitoring-Livestatus-0.74/) Example using the unix socket: # echo -e "GET services\n" | /usr/bin/nc -U /var/run/icinga2/cmd/livestatus Example using the tcp socket listening on port `6558`: # echo -e 'GET services\n' | netcat 127.0.0.1 6558 # cat servicegroups < A list of available external commands and their parameters can be found [here](24-appendix.md#external-commands-list-detail) $ echo -e 'COMMAND ' | netcat 127.0.0.1 6558 ### Livestatus Filters and, or, negate Operator | Negate | Description ----------|------------------------ = | != | Equality ~ | !~ | Regex match =~ | !=~ | Equality ignoring case ~~ | !~~ | Regex ignoring case < | | Less than > | | Greater than <= | | Less than or equal >= | | Greater than or equal ### Livestatus Stats Schema: "Stats: aggregatefunction aggregateattribute" Aggregate Function | Description -------------------|-------------- sum |   min |   max |   avg | sum / count std | standard deviation suminv | sum (1 / value) avginv | suminv / count count | ordinary default for any stats query if not aggregate function defined Example: GET hosts Filter: has_been_checked = 1 Filter: check_type = 0 Stats: sum execution_time Stats: sum latency Stats: sum percent_state_change Stats: min execution_time Stats: min latency Stats: min percent_state_change Stats: max execution_time Stats: max latency Stats: max percent_state_change OutputFormat: json ResponseHeader: fixed16 ### Livestatus Output * CSV CSV output uses two levels of array separators: The members array separator is a comma (1st level) while extra info and host|service relation separator is a pipe (2nd level). Separators can be set using ASCII codes like: Separators: 10 59 44 124 * JSON Default separators. ### Livestatus Error Codes Code | Description ----------|-------------- 200 | OK 404 | Table does not exist 452 | Exception on query ### Livestatus Tables Table | Join |Description --------------|-----------|---------------------------- hosts |   | host config and status attributes, services counter hostgroups |   | hostgroup config, status attributes and host/service counters services | hosts | service config and status attributes servicegroups |   | servicegroup config, status attributes and service counters contacts |   | contact config and status attributes contactgroups |   | contact config, members commands |   | command name and line status |   | programstatus, config and stats comments | services | status attributes downtimes | services | status attributes timeperiods |   | name and is inside flag endpoints |   | config and status attributes log | services, hosts, contacts, commands | parses [compatlog](09-object-types.md#objecttype-compatlogger) and shows log attributes statehist | hosts, services | parses [compatlog](09-object-types.md#objecttype-compatlogger) and aggregates state change attributes hostsbygroup | hostgroups | host attributes grouped by hostgroup and its attributes servicesbygroup | servicegroups | service attributes grouped by servicegroup and its attributes servicesbyhostgroup | hostgroups | service attributes grouped by hostgroup and its attributes The `commands` table is populated with `CheckCommand`, `EventCommand` and `NotificationCommand` objects. A detailed list on the available table attributes can be found in the [Livestatus Schema documentation](24-appendix.md#schema-livestatus). ## Status Data Files Icinga 1.x writes object configuration data and status data in a cyclic interval to its `objects.cache` and `status.dat` files. Icinga 2 provides the `StatusDataWriter` object which dumps all configuration objects and status updates in a regular interval. # icinga2 feature enable statusdata If you are not using any web interface or addon which uses these files, you can safely disable this feature. ## Compat Log Files The Icinga 1.x log format is considered being the `Compat Log` in Icinga 2 provided with the `CompatLogger` object. These logs are used for informational representation in external web interfaces parsing the logs, but also to generate SLA reports and trends. The [Livestatus](14-features.md#setting-up-livestatus) feature uses these logs for answering queries to historical tables. The `CompatLogger` object can be enabled with # icinga2 feature enable compatlog By default, the Icinga 1.x log file called `icinga.log` is located in `/var/log/icinga2/compat`. Rotated log files are moved into `var/log/icinga2/compat/archives`. ## Check Result Files Icinga 1.x writes its check result files to a temporary spool directory where they are processed in a regular interval. While this is extremely inefficient in performance regards it has been rendered useful for passing passive check results directly into Icinga 1.x skipping the external command pipe. Several clustered/distributed environments and check-aggregation addons use that method. In order to support step-by-step migration of these environments, Icinga 2 supports the `CheckResultReader` object. There is no feature configuration available, but it must be defined on-demand in your Icinga 2 objects configuration. object CheckResultReader "reader" { spool_dir = "/data/check-results" } icinga2-2.8.1/doc/15-troubleshooting.md000066400000000000000000001174601322762156600176220ustar00rootroot00000000000000# Icinga 2 Troubleshooting ## Required Information Please ensure to provide any detail which may help reproduce and understand your issue. Whether you ask on the community channels or you create an issue at [GitHub](https://github.com/Icinga), make sure that others can follow your explanations. If necessary, draw a picture and attach it for better illustration. This is especially helpful if you are troubleshooting a distributed setup. We've come around many community questions and compiled this list. Add your own findings and details please. * Describe the expected behavior in your own words. * Describe the actual behavior in one or two sentences. * Ensure to provide general information such as: * How was Icinga 2 installed (and which repository in case) and which distribution are you using * `icinga2 --version` * `icinga2 feature list` * `icinga2 daemon -C` * [Icinga Web 2](https://www.icinga.com/products/icinga-web-2/) version (screenshot from System - About) * [Icinga Web 2 modules](https://www.icinga.com/products/icinga-web-2-modules/) e.g. the Icinga Director (optional) * Configuration insights: * Provide complete configuration snippets explaining your problem in detail * Your [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) file * If you run multiple Icinga 2 instances, the [zones.conf](04-configuring-icinga-2.md#zones-conf) file (or `icinga2 object list --type Endpoint` and `icinga2 object list --type Zone`) from all affected nodes. * Logs * Relevant output from your main and [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) in `/var/log/icinga2`. Please add step-by-step explanations with timestamps if required. * The newest Icinga 2 crash log if relevant, located in `/var/log/icinga2/crash` * Additional details * If the check command failed, what's the output of your manual plugin tests? * In case of [debugging](21-development.md#development) Icinga 2, the full back traces and outputs ## Analyze your Environment There are many components involved on a server running Icinga 2. When you analyze a problem, keep in mind that basic system administration knowledge is also key to identify bottlenecks and issues. > **Tip** > > [Monitor Icinga 2](08-advanced-topics.md#monitoring-icinga) and use the hints for further analysis. * Analyze the system's performance and dentify bottlenecks and issues. * Collect details about all applications (e.g. Icinga 2, MySQL, Apache, Graphite, Elastic, etc.). * If data is exchanged via network (e.g. central MySQL cluster) ensure to monitor the bandwidth capabilities too. * Add graphs and screenshots to your issue description Install tools which help you to do so. Opinions differ, let us know if you have any additions here! ### Analyse your Linux/Unix Environment [htop](https://hisham.hm/htop/) is a better replacement for `top` and helps to analyze processes interactively. ``` yum install htop apt-get install htop ``` If you are for example experiencing performance issues, open `htop` and take a screenshot. Add it to your question and/or bug report. Analyse disk I/O performance in Grafana, take a screenshot and obfuscate any sensitive details. Attach it when posting a question to the community channels. The [sysstat](https://github.com/sysstat/sysstat) package provides a number of tools to analyze the performance on Linux. On FreeBSD you could use `systat` for example. ``` yum install sysstat apt-get install sysstat ``` Example for `vmstat` (summary of memory, processes, etc.): ``` // summary vmstat -s // print timestamps, format in MB, stats every 1 second, 5 times vmstat -t -S M 1 5 ``` Example for `iostat`: ``` watch -n 1 iostat ``` Example for `sar`: ``` sar //cpu sar -r //ram sar -q //load avg sar -b //I/O ``` `sysstat` also provides the `iostat` binary. On FreeBSD you could use `systat` for example. If you are missing checks and metrics found in your analysis, add them to your monitoring! ### Analyze your Windows Environment A good tip for Windows are the tools found inside the [Sysinternals Suite](https://technet.microsoft.com/en-us/sysinternals/bb842062.aspx). You can also start `perfmon` and analyze specific performance counters. Keep notes which could be important for your monitoring, and add service checks later on. ## Enable Debug Output ### Enable Debug Output on Linux/Unix Enable the `debuglog` feature: ``` # icinga2 feature enable debuglog # service icinga2 restart ``` The debug log file can be found in `/var/log/icinga2/debug.log`. Alternatively you may run Icinga 2 in the foreground with debugging enabled. Specify the console log severity as an additional parameter argument to `-x`. ``` # /usr/sbin/icinga2 daemon -x notice ``` The [log severity](09-object-types.md#objecttype-filelogger) can be one of `critical`, `warning`, `information`, `notice` and `debug`. ### Enable Debug Output on Windows Open a command prompt with administrative privileges and enable the debug log feature. ``` C:> icinga2.exe feature enable debuglog ``` Ensure that the Icinga 2 service already writes the main log into `C:\ProgramData\icinga2\var\log\icinga2`. Restart the Icinga 2 service and open the newly created `debug.log` file. ``` C:> net stop icinga2 C:> net start icinga2 ``` ## Configuration Troubleshooting ### List Configuration Objects The `icinga2 object list` CLI command can be used to list all configuration objects and their attributes. The tool also shows where each of the attributes was modified. > **Tip** > > Use the Icinga 2 API to access [config objects at runtime](12-icinga2-api.md#icinga2-api-config-objects) directly. That way you can also identify which objects have been created from your [apply rules](17-language-reference.md#apply). ``` # icinga2 object list Object 'localhost!ssh' of type 'Service': * __name = 'localhost!ssh' * check_command = 'ssh' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 5:3-5:23 * check_interval = 60 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 24:3-24:21 * host_name = 'localhost' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 4:3-4:25 * max_check_attempts = 3 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 23:3-23:24 * name = 'ssh' * retry_interval = 30 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 25:3-25:22 * templates = [ 'ssh', 'generic-service' ] % += modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 1:0-7:1 % += modified in '/etc/icinga2/conf.d/templates.conf', lines 22:1-26:1 * type = 'Service' * vars % += modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 6:3-6:19 * sla = '24x7' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 6:3-6:19 [...] ``` You can also filter by name and type: ``` # icinga2 object list --name *ssh* --type Service Object 'localhost!ssh' of type 'Service': * __name = 'localhost!ssh' * check_command = 'ssh' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 5:3-5:23 * check_interval = 60 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 24:3-24:21 * host_name = 'localhost' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 4:3-4:25 * max_check_attempts = 3 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 23:3-23:24 * name = 'ssh' * retry_interval = 30 % = modified in '/etc/icinga2/conf.d/templates.conf', lines 25:3-25:22 * templates = [ 'ssh', 'generic-service' ] % += modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 1:0-7:1 % += modified in '/etc/icinga2/conf.d/templates.conf', lines 22:1-26:1 * type = 'Service' * vars % += modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 6:3-6:19 * sla = '24x7' % = modified in '/etc/icinga2/conf.d/hosts/localhost/ssh.conf', lines 6:3-6:19 Found 1 Service objects. [2014-10-15 14:27:19 +0200] information/cli: Parsed 175 objects. ``` Runtime modifications via the [REST API](12-icinga2-api.md#icinga2-api-config-objects) are not immediately updated. Furthermore there is a known issue with [group assign expressions](17-language-reference.md#group-assign) which are not reflected in the host object output. You need to restart Icinga 2 in order to update the `icinga2.debug` cache file. ### Apply rules do not match You can analyze apply rules and matching objects by using the [script debugger](20-script-debugger.md#script-debugger). ### Where are the check command definitions? Icinga 2 features a number of built-in [check command definitions](10-icinga-template-library.md#icinga-template-library) which are included with ``` include include ``` in the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) configuration file. These files are not considered configuration files and will be overridden on upgrade, so please send modifications as proposed patches upstream. The default include path is set to `LocalStateDir + "/share/icinga2/includes"`. You should add your own command definitions to a new file in `conf.d/` called `commands.conf` or similar. ### Configuration is ignored * Make sure that the line(s) are not [commented out](17-language-reference.md#comments) (starting with `//` or `#`, or encapsulated by `/* ... */`). * Is the configuration file included in [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf)? Run the [configuration validation](11-cli-commands.md#config-validation) and add `notice` as log severity. Search for the file which should be included i.e. using the `grep` CLI command. ``` # icinga2 daemon -C -x notice | grep command ``` ### Configuration attributes are inherited from Icinga 2 allows you to import templates using the [import](17-language-reference.md#template-imports) keyword. If these templates contain additional attributes, your objects will automatically inherit them. You can override or modify these attributes in the current object. The [object list](15-troubleshooting.md#troubleshooting-list-configuration-objects) CLI command allows you to verify the attribute origin. ### Configuration Value with Single Dollar Sign In case your configuration validation fails with a missing closing dollar sign error message, you did not properly escape the single dollar sign preventing its usage as [runtime macro](03-monitoring-basics.md#runtime-macros). ``` critical/config: Error: Validation failed for Object 'ping4' (Type: 'Service') at /etc/icinga2/zones.d/global-templates/windows.conf:24: Closing $ not found in macro format string 'top-syntax=${list}'. ``` Correct the custom attribute value to ``` "top-syntax=$${list}" ``` ## Checks Troubleshooting ### Executed Command for Checks * Use the Icinga 2 API to [query](12-icinga2-api.md#icinga2-api-config-objects-query) host/service objects for their check result containing the executed shell command. * Use the Icinga 2 [console cli command](11-cli-commands.md#cli-command-console) to fetch the checkable object, its check result and the executed shell command. * Alternatively enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) and look for the executed command. Example for a service object query using a [regex match](18-library-reference.md#global-functions-regex) on the name: ``` $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/services' \ -d '{ "filter": "regex(pattern, service.name)", "filter_vars": { "pattern": "^http" }, "attrs": [ "__name", "last_check_result" ] }' | python -m json.tool { "results": [ { "attrs": { "__name": "example.localdomain!http", "last_check_result": { "active": true, "check_source": "example.localdomain", "command": [ "/usr/local/sbin/check_http", "-I", "127.0.0.1", "-u", "/" ], ... } }, "joins": {}, "meta": {}, "name": "example.localdomain!http", "type": "Service" } ] } ``` Example for using the `icinga2 console` CLI command evaluation functionality: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' \ --eval 'get_service("example.localdomain", "http").last_check_result.command' | python -m json.tool [ "/usr/local/sbin/check_http", "-I", "127.0.0.1", "-u", "/" ] ``` Example for searching the debug log: ``` # icinga2 feature enable debuglog # systemctl restart icinga2 # tail -f /var/log/icinga2/debug.log | grep "notice/Process" ``` ### Checks are not executed * Check the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) to see if the check command gets executed. * Verify that failed depedencies do not prevent command execution. * Make sure that the plugin is executable by the Icinga 2 user (run a manual test). * Make sure the [checker](11-cli-commands.md#enable-features) feature is enabled. * Use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event-streams) to receive live check result streams. Examples: ``` # sudo -u icinga /usr/lib/nagios/plugins/check_ping -4 -H 127.0.0.1 -c 5000,100% -w 3000,80% # icinga2 feature enable checker The feature 'checker' is already enabled. ``` Fetch all check result events matching the `event.service` name `random`: ``` $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=debugchecks&types=CheckResult&filter=match%28%22random*%22,event.service%29' ``` ### Analyze Check Source Sometimes checks are not executed on the remote host, but on the master and so on. This could lead into unwanted results or NOT-OK states. The `check_source` attribute is the best indication where a check command was actually executed. This could be a satellite with synced configuration or a client as remote command bridge -- both will return the check source as where the plugin is called. Example for retrieving the check source from all `disk` services using a [regex match](18-library-reference.md#global-functions-regex) on the name: ``` $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/services' \ -d '{ "filter": "regex(pattern, service.name)", "filter_vars": { "pattern": "^disk" }, "attrs": [ "__name", "last_check_result" ] }' | python -m json.tool { "results": [ { "attrs": { "__name": "icinga2-client1.localdomain!disk", "last_check_result": { "active": true, "check_source": "icinga2-client1.localdomain", ... } }, "joins": {}, "meta": {}, "name": "icinga2-client1.localdomain!disk", "type": "Service" } ] } ``` Example for using the `icinga2 console` CLI command evaluation functionality: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' \ --eval 'get_service("icinga2-client1.localdomain", "disk").last_check_result.check_source' | python -m json.tool "icinga2-client1.localdomain" ``` ### NSClient++ Check Errors with nscp-local The [nscp-local](10-icinga-template-library.md#nscp-check-local) CheckCommand object definitions call the local `nscp.exe` command. If a Windows client service check fails to find the `nscp.exe` command, the log output would look like this: ``` Command ".\nscp.exe" "client" "-a" "drive=d" "-a" "show-all" "-b" "-q" "check_drivesize" failed to execute: 2, "The system cannot find the file specified." ``` or ``` Command ". scp.exe" "client" "-a" "drive=d" "-a" "show-all" "-b" "-q" "check_drivesize" failed to execute: 2, "The system cannot find the file specified." ``` The above actually prints `.\\nscp.exe` where the escaped `\n` character gets interpreted as new line. Both errors lead to the assumption that the `NscpPath` constant is empty or set to a `.` character. This could mean the following: * The command is **not executed on the Windows client**. Check the [check_source](15-troubleshooting.md#checks-check-source) attribute from the check result. * You are using an outdated NSClient++ version (0.3.x or 0.4.x) which is not compatible with Icinga 2. * You are using a custom NSClient++ installer which does not register the correct GUID for NSClient++ More troubleshooting: Retrieve the `NscpPath` constant on your Windows client: ``` C:\Program Files\ICINGA2\sbin\icinga2.exe variable get NscpPath ``` If the variable is returned empty, manually test how Icinga 2 would resolve its path (this can be found inside the ITL): ``` C:\Program Files\ICINGA2\sbin\icinga2.exe console --eval "dirname(msi_get_component_path(\"{5C45463A-4AE9-4325-96DB-6E239C034F93}\"))" ``` If this command does not return anything, NSClient++ is not properly installed. Verify that inside the `Programs and Features` (`appwiz.cpl`) control panel. You can run the bundled NSClient++ installer from the Icinga 2 Windows package. The msi package is located in `C:\Program Files\ICINGA2\sbin`. The bundled NSClient++ version has properly been tested with Icinga 2. Keep that in mind when using a different package. ### Check Thresholds Not Applied This could happen with [clients as command endpoint execution](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint). If you have for example a client host `icinga2-client1.localdomain` and a service `disk` check defined on the master, the warning and critical thresholds are sometimes to applied and unwanted notification alerts are raised. This happens because the client itself includes a host object with its `NodeName` and a basic set of checks in the [conf.d](04-configuring-icinga-2.md#conf-d) directory, i.e. `disk` with the default thresholds. Clients which have the `checker` feature enabled will attempt to execute checks for local services and send their results back to the master. If you now have the same host and service objects on the master you will receive wrong check results from the client. Solution: * Disable the `checker` feature on clients: `icinga2 feature disable checker`. * Remove the inclusion of [conf.d](04-configuring-icinga-2.md#conf-d) as suggested in the [client setup docs](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint). ### Check Fork Errors Newer versions of Systemd on Linux limit spawned processes for services. * v227 introduces the `TasksMax` setting to units which allows to specify the spawned process limit. * v228 adds `DefaultTasksMax` in the global `systemd-system.conf` with a default setting of 512 processes. * v231 changes the default value to 15% This can cause problems with Icinga 2 in large environments with many commands executed in parallel starting with Systemd v228. Some distributions also may have changed the defaults. The error message could look like this: ``` 2017-01-12T11:55:40.742685+01:00 icinga2-master1 kernel: [65567.582895] cgroup: fork rejected by pids controller in /system.slice/icinga2.service ``` In order to solve the problem, increase the value for `DefaultTasksMax` or set it to `infinity`. ``` mkdir /etc/systemd/system/icinga2.service.d cat >/etc/systemd/system/icinga2.service.d/limits.conf < [Icinga Web 2](https://www.icinga.com/products/icinga-web-2/) provides a dashboard overview for `overdue checks`. The REST API provides the [status](12-icinga2-api.md#icinga2-api-status) URL endpoint with some generic metrics on Icinga and its features. ``` # curl -k -s -u root:icinga 'https://localhost:5665/v1/status' | python -m json.tool | less ``` You can also calculate late check results via the REST API: * Fetch the `last_check` timestamp from each object * Compare the timestamp with the current time and add `check_interval` multiple times (change it to see which results are really late, like five times check_interval) You can use the [icinga2 console](11-cli-commands.md#cli-command-console) to connect to the instance, fetch all data and calculate the differences. More infos can be found in [this blogpost](https://www.icinga.com/2016/08/11/analyse-icinga-2-problems-using-the-console-api/). ``` # ICINGA2_API_USERNAME=root ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://localhost:5665/' <1> => var res = []; for (s in get_objects(Service).filter(s => s.last_check < get_time() - 2 * s.check_interval)) { res.add([s.__name, DateTime(s.last_check).to_string()]) }; res [ [ "10807-host!10807-service", "2016-06-10 15:54:55 +0200" ], [ "mbmif.int.netways.de!disk /", "2016-01-26 16:32:29 +0100" ] ] ``` Or if you are just interested in numbers, call [len](18-library-reference.md#array-len) on the result array `res`: ``` <2> => var res = []; for (s in get_objects(Service).filter(s => s.last_check < get_time() - 2 * s.check_interval)) { res.add([s.__name, DateTime(s.last_check).to_string()]) }; res.len() 2.000000 ``` If you need to analyze that problem multiple times, just add the current formatted timestamp and repeat the commands. ``` <23> => DateTime(get_time()).to_string() "2017-04-04 16:09:39 +0200" <24> => var res = []; for (s in get_objects(Service).filter(s => s.last_check < get_time() - 2 * s.check_interval)) { res.add([s.__name, DateTime(s.last_check).to_string()]) }; res.len() 8287.000000 ``` More details about the Icinga 2 DSL and its possibilities can be found in the [language](17-language-reference.md#language-reference) and [library](18-library-reference.md#library-reference) reference chapters. ### Late Check Results in Distributed Environments When it comes to a distributed HA setup, each node is responsible for a load-balanced amount of checks. Host and Service objects provide the attribute `paused`. If this is set to `false`, the current node actively attempts to schedule and execute checks. Otherwise the node does not feel responsible. ``` <3> => var res = {}; for (s in get_objects(Service).filter(s => s.last_check < get_time() - 2 * s.check_interval)) { res[s.paused] += 1 }; res { @false = 2.000000 @true = 1.000000 } ``` You may ask why this analysis is important? Fair enough - if the numbers are not inverted in a HA zone with two members, this may give a hint that the cluster nodes are in a split-brain scenario, or you've found a bug in the cluster. If you are running a cluster setup where the master/satellite executes checks on the client via [top down command endpoint](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) mode, you might want to know which zones are affected. This analysis assumes that clients which are not connected, have the string `connected` in their service check result output and their state is `UNKNOWN`. ``` <4> => var res = {}; for (s in get_objects(Service)) { if (s.state==3) { if (match("*connected*", s.last_check_result.output)) { res[s.zone] += [s.host_name] } } }; for (k => v in res) { res[k] = len(v.unique()) }; res { Asia = 31.000000 Europe = 214.000000 USA = 207.000000 } ``` The result set shows the configured zones and their affected hosts in a unique list. The output also just prints the numbers but you can adjust this by omitting the `len()` call inside the for loop. ## Notifications Troubleshooting ### Notifications are not sent * Check the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) to see if a notification is triggered. * If yes, verify that all conditions are satisfied. * Are any errors on the notification command execution logged? Please ensure to add these details with your own description to any question or issue posted to the community channels. Verify the following configuration: * Is the host/service `enable_notifications` attribute set, and if so, to which value? * Do the [notification](09-object-types.md#objecttype-notification) attributes `states`, `types`, `period` match the notification conditions? * Do the [user](09-object-types.md#objecttype-user) attributes `states`, `types`, `period` match the notification conditions? * Are there any notification `begin` and `end` times configured? * Make sure the [notification](11-cli-commands.md#enable-features) feature is enabled. * Does the referenced NotificationCommand work when executed as Icinga user on the shell? If notifications are to be sent via mail, make sure that the mail program specified inside the [NotificationCommand object](09-object-types.md#objecttype-notificationcommand) exists. The name and location depends on the distribution so the preconfigured setting might have to be changed on your system. Examples: ``` # icinga2 feature enable notification The feature 'notification' is already enabled. ``` ``` # icinga2 feature enable debuglog # systemctl restart icinga2 # grep Notification /var/log/icinga2/debug.log > /root/analyze_notification_problem.log ``` You can use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event-streams) to receive live notification streams: ``` $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=debugnotifications&types=Notification' ``` ## Feature Troubleshooting ### Feature is not working * Make sure that the feature configuration is enabled by symlinking from `features-available/` to `features-enabled` and that the latter is included in [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf). * Are the feature attributes set correctly according to the documentation? * Any errors on the logs? Look up the [object type](09-object-types.md#object-types) for the required feature and verify it is enabled: ``` # icinga2 object list --type ``` Example for the `graphite` feature: ``` # icinga2 object list --type GraphiteWriter ``` Look into the log and check whether the feature logs anything specific for this matter. ``` grep GraphiteWriter /var/log/icinga2/icinga2.log ``` ## Certificate Troubleshooting ### Certificate Verification If the TLS handshake fails when a client connects to the cluster or the REST API, ensure to verify the used certificates. Print the CA and client certificate and ensure that the following attributes are set: * Version must be 3. * Serial number is a hex-encoded string. * Issuer should be your certificate authority (defaults to `Icinga CA` for all CLI commands). * Validity, meaning to say the certificate is not expired. * Subject with the common name (CN) matches the client endpoint name and its FQDN. * v3 extensions must set the basic constraint for `CA:TRUE` (ca.crt) or `CA:FALSE` (client certificate). * Subject Alternative Name is set to a proper DNS name (required for REST API and browsers). ``` # cd /var/lib/icinga2/certs/ ``` CA certificate: ``` # openssl x509 -in ca.crt -text Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=Icinga CA Validity Not Before: Feb 23 14:45:32 2016 GMT Not After : Feb 19 14:45:32 2031 GMT Subject: CN=Icinga CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: ... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE Signature Algorithm: sha256WithRSAEncryption ... ``` Client public certificate: ``` # openssl x509 -in icinga2-client1.localdomain.crt -text Certificate: Data: Version: 3 (0x2) Serial Number: 86:47:44:65:49:c6:65:6b:5e:6d:4f:a5:fe:6c:76:05:0b:1a:cf:34 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=Icinga CA Validity Not Before: Aug 20 16:20:05 2016 GMT Not After : Aug 17 16:20:05 2031 GMT Subject: CN=icinga2-client1.localdomain Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: ... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: DNS:icinga2-client1.localdomain Signature Algorithm: sha256WithRSAEncryption ... ``` Make sure to verify the client's certificate and its received `ca.crt` in `/var/lib/icinga2/certs` and ensure that both instances are signed by the **same CA**. ``` # openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-master1.localdomain.crt icinga2-master1.localdomain.crt: OK # openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-client1.localdomain.crt icinga2-client1.localdomain.crt: OK ``` Fetch the `ca.crt` file from the client node and compare it to your master's `ca.crt` file: ``` # scp icinga2-client1:/var/lib/icinga2/certs/ca.crt test-client-ca.crt # diff -ur /var/lib/icinga2/certs/ca.crt test-client-ca.crt ``` On SLES11 you'll need to use the `openssl1` command instead of `openssl`. ### Certificate Problems with OpenSSL 1.1.0 Users have reported problems with SSL certificates inside a distributed monitoring setup when they * updated their Icinga 2 package to 2.7.0 on Windows or * upgraded their distribution which included an update to OpenSSL 1.1.0. Example during startup on a Windows client: ``` critical/SSL: Error loading and verifying locations in ca key file 'C:\ProgramData\icinga2\etc/icinga2/pki/ca.crt': 219029726, "error:0D0E20DE:asn1 encoding routines:c2i_ibuf:illegal zero content" critical/config: Error: Cannot make SSL context for cert path: 'C:\ProgramData\icinga2\etc/icinga2/pki/client.crt' key path: 'C:\ProgramData\icinga2\etc/icinga2/pki/client.key' ca path: 'C:\ProgramData\icinga2\etc/icinga2/pki/ca.crt'. ``` A technical analysis and solution for re-creating the public CA certificate is available in [this advisory](https://www.icinga.com/2017/08/30/advisory-for-ssl-problems-with-leading-zeros-on-openssl-1-1-0/). ## Cluster and Clients Troubleshooting This applies to any Icinga 2 node in a [distributed monitoring setup](06-distributed-monitoring.md#distributed-monitoring-scenarios). You should configure the [cluster health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks) if you haven't done so already. > **Note** > > Some problems just exist due to wrong file permissions or applied packet filters. Make > sure to check these in the first place. ### Cluster Troubleshooting Connection Errors General connection errors could be one of the following problems: * Incorrect network configuration * Packet loss * Firewall rules preventing traffic Use tools like `netstat`, `tcpdump`, `nmap`, etc. to make sure that the cluster communication works (default port is `5665`). ``` # tcpdump -n port 5665 -i any # netstat -tulpen | grep icinga # nmap icinga2-client1.localdomain ``` ### Cluster Troubleshooting SSL Errors If the cluster communication fails with SSL error messages, make sure to check the following * File permissions on the SSL certificate files * Does the used CA match for all cluster endpoints? * Verify the `Issuer` being your trusted CA * Verify the `Subject` containing your endpoint's common name (CN) * Check the validity of the certificate itself Try to manually connect from `icinga2-client1.localdomain` to the master node `icinga2-master1.localdomain`: ``` # openssl s_client -CAfile /var/lib/icinga2/certs/ca.crt -cert /var/lib/icinga2/certs/icinga2-client1.localdomain.crt -key /var/lib/icinga2/certs/icinga2-client1.localdomain.key -connect icinga2-master1.localdomain:5665 CONNECTED(00000003) --- ... ``` If the connection attempt fails or your CA does not match, [verify the certificates](15-troubleshooting.md#troubleshooting-certificate-verification). #### Cluster Troubleshooting Unauthenticated Clients Unauthenticated nodes are able to connect. This is required for client setups. Master: ``` [2015-07-13 18:29:25 +0200] information/ApiListener: New client connection for identity 'icinga2-client1.localdomain' (unauthenticated) ``` Client as command execution bridge: ``` [2015-07-13 18:29:26 +1000] notice/ClusterEvents: Discarding 'execute command' message from 'icinga2-master1.localdomain': Invalid endpoint origin (client not allowed). ``` If these messages do not go away, make sure to [verify the master and client certificates](15-troubleshooting.md#troubleshooting-certificate-verification). ### Cluster Troubleshooting Message Errors When the network connection is broken or gone, the Icinga 2 instances will be disconnected. If the connection can't be re-established between endpoints in the same HA zone, they remain in a Split-Brain-mode and history may differ. Although the Icinga 2 cluster protocol stores historical events in a [replay log](15-troubleshooting.md#troubleshooting-cluster-replay-log) for later synchronisation, you should make sure to check why the network connection failed. Ensure to setup [cluster health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks) to monitor all endpoints and zones connectivity. ### Cluster Troubleshooting Command Endpoint Errors Command endpoints can be used [for clients](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint) as well as inside an [High-Availability cluster](06-distributed-monitoring.md#distributed-monitoring-scenarios). There is no cli command for manually executing the check, but you can verify the following (e.g. by invoking a forced check from the web interface): * `/var/log/icinga2/icinga2.log` contains connection and execution errors. * The ApiListener is not enabled to [accept commands](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint). * `CheckCommand` definition not found on the remote client. * Referenced check plugin not found on the remote client. * Runtime warnings and errors, e.g. unresolved runtime macros or configuration problems. * Specific error messages are also populated into `UNKNOWN` check results including a detailed error message in their output. * Verify the `check_source` object attribute. This is populated by the node executing the check. * More verbose logs are found inside the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output). * Use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event-streams) to receive live check result streams. Fetch all check result events matching the `event.service` name `remote-client`: ``` $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=debugcommandendpoint&types=CheckResult&filter=match%28%22remote-client*%22,event.service%29' ``` ### Cluster Troubleshooting Config Sync If the cluster zones do not sync their configuration, make sure to check the following: * Within a config master zone, only one configuration master is allowed to have its config in `/etc/icinga2/zones.d`. ** The master syncs the configuration to `/var/lib/icinga2/api/zones/` during startup and only syncs valid configuration to the other nodes. ** The other nodes receive the configuration into `/var/lib/icinga2/api/zones/`. * The `icinga2.log` log file in `/var/log/icinga2` will indicate whether this ApiListener [accepts config](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync), or not. Verify the object's [version](09-object-types.md#object-types) attribute on all nodes to check whether the config update and reload was successful or not. ### Cluster Troubleshooting Overdue Check Results If your master does not receive check results (or any other events) from the child zones (satellite, clients, etc.), make sure to check whether the client sending in events is allowed to do so. > **Tip** > > General troubleshooting hints on late check results are documented [here](15-troubleshooting.md#late-check-results). The [distributed monitoring conventions](06-distributed-monitoring.md#distributed-monitoring-conventions) apply. So, if there's a mismatch between your client node's endpoint name and its provided certificate's CN, the master will deny all events. > **Tip** > > [Icinga Web 2](02-getting-started.md#setting-up-icingaweb2) provides a dashboard view > for overdue check results. Enable the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) on the master for more verbose insights. If the client cannot authenticate, it's a more general [problem](15-troubleshooting.md#troubleshooting-cluster-unauthenticated-clients). The client's endpoint is not configured on nor trusted by the master node: ``` Discarding 'check result' message from 'icinga2-client1.localdomain': Invalid endpoint origin (client not allowed). ``` The check result message sent by the client does not belong to the zone the checkable object is in on the master: ``` Discarding 'check result' message from 'icinga2-client1.localdomain': Unauthorized access. ``` ### Cluster Troubleshooting Replay Log If your `/var/lib/icinga2/api/log` directory grows, it generally means that your cluster cannot replay the log on connection loss and re-establishment. A master node for example will store all events for not connected endpoints in the same and child zones. Check the following: * All clients are connected? (e.g. [cluster health check](06-distributed-monitoring.md#distributed-monitoring-health-checks)). * Check your [connection](15-troubleshooting.md#troubleshooting-cluster-connection-errors) in general. * Does the log replay work, e.g. are all events processed and the directory gets cleared up over time? * Decrease the `log_duration` attribute value for that specific [endpoint](09-object-types.md#objecttype-endpoint). icinga2-2.8.1/doc/16-upgrading-icinga-2.md000066400000000000000000000265751322762156600177510ustar00rootroot00000000000000# Upgrading Icinga 2 Upgrading Icinga 2 is usually quite straightforward. Ordinarily the only manual steps involved are scheme updates for the IDO database. Specific version upgrades are described below. Please note that version updates are incremental. An upgrade from v2.6 to v2.8 requires to follow the instructions for v2.7 too. ## Upgrading to v2.8 ### DB IDO Schema Update to 2.8.0 There are additional indexes and schema fixes which require an update. Please proceed here for [MySQL](16-upgrading-icinga-2.md#upgrading-mysql-db) or [PostgreSQL](16-upgrading-icinga-2.md#upgrading-postgresql-db). > **Note** > > `2.8.1.sql` fixes a unique constraint problem with fresh 2.8.0 installations. > You don't need this update if you are upgrading from an older version. ### Changed Certificate Paths The default certificate path was changed from `/etc/icinga2/pki` to `/var/lib/icinga2/certs`. Old Path | New Path ---------------------------------------------------|--------------------------------------------------- `/etc/icinga2/pki/icinga2-client1.localdomain.crt` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.crt` `/etc/icinga2/pki/icinga2-client1.localdomain.key` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.key` `/etc/icinga2/pki/ca.crt` | `/var/lib/icinga2/certs/ca.crt` This applies to Windows clients in the same way: `%ProgramData%\etc\icinga2\pki` was moved to `%ProgramData%\var\lib\icinga2\certs`. Old Path | New Path ----------------------------------------------------------------|---------------------------------------------------------------- `%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.crt` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.crt` `%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.key` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.key` `%ProgramData%\etc\icinga2\pki\ca.crt` | `%ProgramData%\var\lib\icinga2\certs\ca.crt` > **Note** > > The default expected path for client certificates is `/var/lib/icinga2/certs/ + NodeName + {.crt,.key}`. > The `NodeName` constant is usually the FQDN and certificate common name (CN). Check the [conventions](06-distributed-monitoring.md#distributed-monitoring-conventions) > section inside the Distributed Monitoring chapter. The [setup CLI commands](06-distributed-monitoring.md#distributed-monitoring-setup-master) and the default [ApiListener configuration](06-distributed-monitoring.md#distributed-monitoring-apilistener) have been adjusted to these paths too. The [ApiListener](09-object-types.md#objecttype-apilistener) object attributes `cert_path`, `key_path` and `ca_path` have been deprecated and removed from the example configuration. #### Migration Path > **Note** > > Icinga 2 automatically migrates the certificates to the new default location if they > are configured and detected in `/etc/icinga2/pki`. During startup, the migration kicks in and ensures to copy the certificates to the new location. This will also happen if someone updates the certificate files in `/etc/icinga2/pki` to ensure that the new certificate location always has the latest files. This has been implemented in the Icinga 2 binary to ensure it works on both Linux/Unix and the Windows platform. If you are not using the built-in CLI commands and setup wizards to deploy the client certificates, please ensure to update your deployment tools/scripts. This mainly affects * Puppet modules * Ansible playbooks * Chef cookbooks * Salt recipes * Custom scripts, e.g. Windows Powershell or self-made implementations In order to support a smooth migration between versions older than 2.8 and future releases, the built-in certificate migration path is planned to exist as long as the deprecated `ApiListener` object attributes exist. You are safe to use the existing configuration paths inside the `api` feature. If you plan your migration, look at the following example taken from the Director Linux deployment script for clients. * Ensure that the default certificate path is changed from `/etc/icinga2/pki` to `/var/lib/icinga2/certs`. ``` -ICINGA2_SSL_DIR="${ICINGA2_CONF_DIR}/pki" +ICINGA2_SSL_DIR="${ICINGA2_STATE_DIR}/lib/icinga2/certs" ``` * Remove the ApiListener configuration attributes. ``` object ApiListener "api" { - cert_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.crt" - key_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.key" - ca_path = SysconfDir + "/icinga2/pki/ca.crt" accept_commands = true accept_config = true } ``` Test the script with a fresh client installation before putting it into production. > **Tip** > > Please support module and script developers in their migration. If you find > any project which would require these changes, create an issue or a patchset in a PR > and help them out. Thanks in advance! ### On-Demand Signing and CA Proxy Icinga 2 v2.8 supports the following features inside the cluster: * Forward signing requests from clients through a satellite instance to a signing master ("CA Proxy"). * Signing requests without a ticket. The master instance allows to list and sign CSRs ("On-Demand Signing"). In order to use these features, **all instances must be upgraded to v2.8**. More details in [this chapter](06-distributed-monitoring.md#distributed-monitoring-setup-sign-certificates-master). ### Windows Client Windows versions older than Windows 10/Server 2016 require the [Universal C Runtime for Windows](https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows). ### Removed Bottom Up Client Mode This client mode was deprecated in 2.6 and was removed in 2.8. The node CLI command does not provide `list` or `update-config` anymore. > **Note** > > The old migration guide can be found on [GitHub](https://github.com/Icinga/icinga2/blob/v2.7.0/doc/06-distributed-monitoring.md#bottom-up-migration-to-top-down-). The clients don't need to have a local `conf.d` directory included. Icinga 2 continues to run with the generated and imported configuration. You are advised to [migrate](https://github.com/Icinga/icinga2/issues/4798) any existing configuration to the "top down" mode with the help of the Icinga Director or config management tools such as Puppet, Ansible, etc. ### Removed Classic UI Config Package The config meta package `classicui-config` and the configuration files have been removed. You need to manually configure this legacy interface. Create a backup of the configuration before upgrading and re-configure it afterwards. ### Flapping Configuration Icinga 2 v2.8 implements a new flapping detection algorithm which splits the threshold configuration into low and high settings. `flapping_threshold` is deprecated and does not have any effect when flapping is enabled. Please remove `flapping_threshold` from your configuration. This attribute will be removed in v2.9. Instead you need to use the `flapping_threshold_low` and `flapping_threshold_high` attributes. More details can be found [here](08-advanced-topics.md#check-flapping). ### Deprecated Configuration Attributes Object | Attribute --------------|------------------ ApiListener | cert\_path (migration happens) ApiListener | key\_path (migration happens) ApiListener | ca\_path (migration happens) Host, Service | flapping\_threshold (has no effect) ## Upgrading to v2.7 v2.7.0 provided new notification scripts and commands. Please ensure to update your configuration accordingly. An advisory has been published [here](https://www.icinga.com/2017/08/23/advisory-for-icinga-2-v2-7-update-and-mail-notification-scripts/). In case are having troubles with OpenSSL 1.1.0 and the public CA certificates, please read [this advisory](https://www.icinga.com/2017/08/30/advisory-for-ssl-problems-with-leading-zeros-on-openssl-1-1-0/) and check the [troubleshooting chapter](15-troubleshooting.md#troubleshooting). If Icinga 2 fails to start with an empty reference to `$ICINGA2_CACHE_DIR` ensure to set it inside `/etc/sysconfig/icinga2` (RHEL) or `/etc/default/icinga2` (Debian). RPM packages will put a file called `/etc/sysconfig/icinga2.rpmnew` if you have modified the original file. Example on CentOS 7: ``` vim /etc/sysconfig/icinga2 ICINGA2_CACHE_DIR=/var/cache/icinga2 systemctl restart icinga2 ``` ## Upgrading the MySQL database If you want to upgrade an existing Icinga 2 instance, check the `/usr/share/icinga2-ido-mysql/schema/upgrade` directory for incremental schema upgrade file(s). > **Note** > > If there isn't an upgrade file for your current version available, there's nothing to do. Apply all database schema upgrade files incrementally. ``` # mysql -u root -p icinga < /usr/share/icinga2-ido-mysql/schema/upgrade/.sql ``` The Icinga 2 DB IDO feature checks the required database schema version on startup and generates an log message if not satisfied. **Example:** You are upgrading Icinga 2 from version `2.4.0` to `2.8.0`. Look into the `upgrade` directory: ``` $ ls /usr/share/icinga2-ido-mysql/schema/upgrade/ 2.0.2.sql 2.1.0.sql 2.2.0.sql 2.3.0.sql 2.4.0.sql 2.5.0.sql 2.6.0.sql 2.8.0.sql ``` There are two new upgrade files called `2.5.0.sql`, `2.6.0.sql` and `2.8.0.sql` which must be applied incrementally to your IDO database. ``` # mysql -u root -p icinga < /usr/share/icinga2-ido-mysql/schema/upgrade/2.5.0.sql # mysql -u root -p icinga < /usr/share/icinga2-ido-mysql/schema/upgrade/2.6.0.sql # mysql -u root -p icinga < /usr/share/icinga2-ido-mysql/schema/upgrade/2.8.0.sql ``` ## Upgrading the PostgreSQL database If you want to upgrade an existing Icinga 2 instance, check the `/usr/share/icinga2-ido-pgsql/schema/upgrade` directory for incremental schema upgrade file(s). > **Note** > > If there isn't an upgrade file for your current version available, there's nothing to do. Apply all database schema upgrade files incrementally. ``` # export PGPASSWORD=icinga # psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/upgrade/.sql ``` The Icinga 2 DB IDO feature checks the required database schema version on startup and generates an log message if not satisfied. **Example:** You are upgrading Icinga 2 from version `2.4.0` to `2.8.0`. Look into the `upgrade` directory: ``` $ ls /usr/share/icinga2-ido-pgsql/schema/upgrade/ 2.0.2.sql 2.1.0.sql 2.2.0.sql 2.3.0.sql 2.4.0.sql 2.5.0.sql 2.6.0.sql 2.8.0.sql ``` There are two new upgrade files called `2.5.0.sql`, `2.6.0.sql` and `2.8.0.sql` which must be applied incrementally to your IDO database. ``` # export PGPASSWORD=icinga # psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/upgrade/2.5.0.sql # psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/upgrade/2.6.0.sql # psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/upgrade/2.8.0.sql ``` icinga2-2.8.1/doc/17-language-reference.md000066400000000000000000001023171322762156600201070ustar00rootroot00000000000000# Language Reference ## Object Definition Icinga 2 features an object-based configuration format. You can define new objects using the `object` keyword: object Host "host1.example.org" { display_name = "host1" address = "192.168.0.1" address6 = "::1" } In general you need to write each statement on a new line. Expressions started with `{`, `(` and `[` extend until the matching closing character and can be broken up into multiple lines. Alternatively you can write multiple statements on a single line by separating them with a semicolon: object Host "host1.example.org" { display_name = "host1" address = "192.168.0.1"; address6 = "::1" } Each object is uniquely identified by its type (`Host`) and name (`host1.example.org`). Some types have composite names, e.g. the `Service` type which uses the `host_name` attribute and the name you specified to generate its object name. Exclamation marks (!) are not permitted in object names. Objects can contain a comma-separated list of property declarations. Instead of commas semicolons may also be used. The following data types are available for property values: All objects have at least the following attributes: Attribute | Description ---------------------|----------------------------- name | The name of the object. This attribute can be modified in the object definition to override the name specified with the `object` directive. type | The type of the object. ## Expressions The following expressions can be used on the right-hand side of assignments. ### Numeric Literals A floating-point number. Example: 27.3 ### Duration Literals Similar to floating-point numbers except for the fact that they support suffixes to help with specifying time durations. Example: 2.5m Supported suffixes include ms (milliseconds), s (seconds), m (minutes), h (hours) and d (days). Duration literals are converted to seconds by the config parser and are treated like numeric literals. ### String Literals A string. Example: "Hello World!" #### String Literals Escape Sequences Certain characters need to be escaped. The following escape sequences are supported: Character | Escape sequence --------------------------|------------------------------------ " | \\" \\ | \\\\ <TAB> | \\t <CARRIAGE-RETURN> | \\r <LINE-FEED> | \\n <BEL> | \\b <FORM-FEED> | \\f In addition to these pre-defined escape sequences you can specify arbitrary ASCII characters using the backslash character (\\) followed by an ASCII character in octal encoding. ### Multi-line String Literals Strings spanning multiple lines can be specified by enclosing them in {{{ and }}}. Example: {{{This is a multi-line string.}}} Unlike in ordinary strings special characters do not have to be escaped in multi-line string literals. ### Boolean Literals The keywords `true` and `false` are used to denote truth values. ### Null Value The `null` keyword can be used to specify an empty value. ### Dictionary An unordered list of key-value pairs. Keys must be unique and are compared in a case-sensitive manner. Individual key-value pairs must either be comma-separated or on separate lines. The comma after the last key-value pair is optional. Example: { address = "192.168.0.1" port = 443 } Identifiers may not contain certain characters (e.g. space) or start with certain characters (e.g. digits). If you want to use a dictionary key that is not a valid identifier, you can enclose the key in double quotes. ### Array An ordered list of values. Individual array elements must be comma-separated. The comma after the last element is optional. Example: [ "hello", 42 ] An array may simultaneously contain values of different types, such as strings and numbers. ### Operators The following operators are supported in expressions. The operators are by descending precedence. Operator | Precedence | Examples (Result) | Description ---------|------------|-----------------------------------------------|-------------------------------- () | 1 | (3 + 3) * 5 | Groups sub-expressions () | 1 | Math.random() | Calls a function [] | 1 | a[3] | Array subscript . | 1 | a.b | Element access ! | 2 | !"Hello" (false), !false (true) | Logical negation of the operand ~ | 2 | ~true (false) | Bitwise negation of the operand + | 2 | +3 | Unary plus - | 2 | -3 | Unary minus * | 3 | 5m * 10 (3000) | Multiplies two numbers / | 3 | 5m / 5 (60) | Divides two numbers % | 3 | 17 % 12 (5) | Remainder after division + | 4 | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings - | 4 | 3 - 1 (2) | Subtracts two numbers << | 5 | 4 << 8 (1024) | Left shift >> | 5 | 1024 >> 4 (64) | Right shift < | 6 | 3 < 5 (true) | Less than > | 6 | 3 > 5 (false) | Greater than <= | 6 | 3 <= 3 (true) | Less than or equal >= | 6 | 3 >= 3 (true) | Greater than or equal in | 7 | "foo" in [ "foo", "bar" ] (true) | Element contained in array !in | 7 | "foo" !in [ "bar", "baz" ] (true) | Element not contained in array == | 8 | "hello" == "hello" (true), 3 == 5 (false) | Equal to != | 8 | "hello" != "world" (true), 3 != 3 (false) | Not equal to & | 9 | 7 & 3 (3) | Binary AND ^ | 10 | 17 ^ 12 (29) | Bitwise XOR | | 11 | 2 | 3 (3) | Binary OR && | 13 | true && false (false), 3 && 7 (7), 0 && 7 (0) | Logical AND || | 14 | true || false (true), 0 || 7 (7)| Logical OR = | 12 | a = 3 | Assignment => | 15 | x => x * x (function with arg x) | Lambda, for loop ### Function Calls Functions can be called using the `()` operator: const MyGroups = [ "test1", "test" ] { check_interval = len(MyGroups) * 1m } A list of available functions is available in the [Library Reference](18-library-reference.md#library-reference) chapter. ## Assignments In addition to the `=` operator shown above a number of other operators to manipulate attributes are supported. Here's a list of all available operators: ### Operator = Sets an attribute to the specified value. Example: { a = 5 a = 7 } In this example `a` has the value `7` after both instructions are executed. ### Operator += The += operator is a shortcut. The following expression: { a = [ "hello" ] a += [ "world" ] } is equivalent to: { a = [ "hello" ] a = a + [ "world" ] } ### Operator -= The -= operator is a shortcut. The following expression: { a = 10 a -= 5 } is equivalent to: { a = 10 a = a - 5 } ### Operator \*= The *= operator is a shortcut. The following expression: { a = 60 a *= 5 } is equivalent to: { a = 60 a = a * 5 } ### Operator /= The /= operator is a shortcut. The following expression: { a = 300 a /= 5 } is equivalent to: { a = 300 a = a / 5 } ## Indexer The indexer syntax provides a convenient way to set dictionary elements. Example: { hello.key = "world" } Example (alternative syntax): { hello["key"] = "world" } This is equivalent to writing: { hello += { key = "world" } } If the `hello` attribute does not already have a value, it is automatically initialized to an empty dictionary. ## Template Imports Objects can import attributes from other objects. Example: template Host "default-host" { vars.colour = "red" } template Host "test-host" { import "default-host" vars.colour = "blue" } object Host "localhost" { import "test-host" address = "127.0.0.1" address6 = "::1" } The `default-host` and `test-host` objects are marked as templates using the `template` keyword. Unlike ordinary objects templates are not instantiated at run-time. Parent objects do not necessarily have to be templates, however in general they are. The `vars` dictionary for the `localhost` object contains all three custom attributes and the custom attribute `colour` has the value `"blue"`. Parent objects are resolved in the order they're specified using the `import` keyword. Default templates which are automatically imported into all object definitions can be specified using the `default` keyword: template CheckCommand "plugin-check-command" default { // ... } Default templates are imported before any other user-specified statement in an object definition is evaluated. If there are multiple default templates the order in which they are imported is unspecified. ## Constants Global constants can be set using the `const` keyword: const VarName = "some value" Once defined a constant can be accessed from any file. Constants cannot be changed once they are set. > **Tip** > > Best practice is to manage constants in the [constants.conf](04-configuring-icinga-2.md#constants-conf) file. ### Icinga 2 Specific Constants Icinga 2 provides a number of special global constants. Some of them can be overridden using the `--define` command line parameter: Variable |Description --------------------|------------------- PrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to "/usr/local". SysconfDir |**Read-only.** Contains the path of the sysconf directory. Defaults to PrefixDir + "/etc". ZonesDir |**Read-only.** Contains the path of the zones.d directory. Defaults to SysconfDir + "/zones.d". LocalStateDir |**Read-only.** Contains the path of the local state directory. Defaults to PrefixDir + "/var". RunDir |**Read-only.** Contains the path of the run directory. Defaults to LocalStateDir + "/run". PkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to PrefixDir + "/share/icinga2". StatePath |**Read-write.** Contains the path of the Icinga 2 state file. Defaults to LocalStateDir + "/lib/icinga2/icinga2.state". ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects file. Defaults to LocalStateDir + "/cache/icinga2/icinga2.debug". PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to RunDir + "/icinga2/icinga2.pid". Vars |**Read-write.** Contains a dictionary with global custom attributes. Not set by default. NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. PlatformName |**Read-only.** The name of the operating system, e.g. "Ubuntu". PlatformVersion |**Read-only.** The version of the operating system, e.g. "14.04.3 LTS". PlatformKernel |**Read-only.** The name of the operating system kernel, e.g. "Linux". PlatformKernelVersion|**Read-only.** The version of the operating system kernel, e.g. "3.13.0-63-generic". BuildCompilerName |**Read-only.** The name of the compiler Icinga was built with, e.g. "Clang". BuildCompilerVersion|**Read-only.** The version of the compiler Icinga was built with, e.g. "7.3.0.7030031". BuildHostName |**Read-only.** The name of the host Icinga was built on, e.g. "acheron". Advanced runtime constants. Please only use them if advised by support or developers. Variable |Description --------------------|------------------- EventEngine |**Read-write.** The name of the socket event engine, can be `poll` or `epoll`. The epoll interface is only supported on Linux. AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to `false`. RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. ## Apply The `apply` keyword can be used to create new objects which are associated with another group of objects. apply Service "ping" to Host { import "generic-service" check_command = "ping4" assign where host.name == "localhost" } In this example the `assign where` condition is a boolean expression which is evaluated for all objects of type `Host` and a new service with name "ping" is created for each matching host. [Expression operators](17-language-reference.md#expression-operators) may be used in `assign where` conditions. The `to` keyword and the target type may be omitted if there is only one target type, e.g. for the `Service` type. Depending on the object type used in the `apply` expression additional local variables may be available for use in the `where` condition: Source Type | Target Type | Variables ------------------|-------------|-------------- Service | Host | host Dependency | Host | host Dependency | Service | host, service Notification | Host | host Notification | Service | host, service ScheduledDowntime | Host | host ScheduledDowntime | Service | host, service Any valid config attribute can be accessed using the `host` and `service` variables. For example, `host.address` would return the value of the host's "address" attribute -- or null if that attribute isn't set. More usage examples are documented in the [monitoring basics](03-monitoring-basics.md#using-apply-expressions) chapter. ## Apply For [Apply](17-language-reference.md#apply) rules can be extended with the [for loop](17-language-reference.md#for-loops) keyword. apply Service "prefix-" for (key => value in host.vars.dictionary) to Host { import "generic-service" check_command = "ping4" vars.host_value = value } Any valid config attribute can be accessed using the `host` and `service` variables. The attribute must be of the Array or Dictionary type. In this example `host.vars.dictionary` is of the Dictionary type which needs a key-value-pair as iterator. In this example all generated service object names consist of `prefix-` and the value of the `key` iterator. The prefix string can be omitted if not required. The `key` and `value` variables can be used for object attribute assignment, e.g. for setting the `check_command` attribute or custom attributes as command parameters. `apply for` rules are first evaluated against all objects matching the `for loop` list and afterwards the `assign where` and `ignore where` conditions are evaluated. It is not necessary to check attributes referenced in the `for loop` expression for their existance using an additional `assign where` condition. More usage examples are documented in the [monitoring basics](03-monitoring-basics.md#using-apply-for) chapter. ## Group Assign Group objects can be assigned to specific member objects using the `assign where` and `ignore where` conditions. object HostGroup "linux-servers" { display_name = "Linux Servers" assign where host.vars.os == "Linux" } In this example the `assign where` condition is a boolean expression which is evaluated for all objects of the type `Host`. Each matching host is added as member to the host group with the name "linux-servers". Membership exclusion can be controlled using the `ignore where` condition. [Expression operators](17-language-reference.md#expression-operators) may be used in `assign where` and `ignore where` conditions. Source Type | Variables ------------------|-------------- HostGroup | host ServiceGroup | host, service UserGroup | user ## Boolean Values The `assign where`, `ignore where`, `if` and `while` statements, the `!` operator as well as the `bool()` function convert their arguments to a boolean value based on the following rules: Description | Example Value | Boolean Value ---------------------|-------------------|-------------- Empty value | null | false Zero | 0 | false Non-zero integer | -23945 | true Empty string | "" | false Non-empty string | "Hello" | true Empty array | [] | false Non-empty array | [ "Hello" ] | true Empty dictionary | {} | false Non-empty dictionary | { key = "value" } | true For a list of supported expression operators for `assign where` and `ignore where` statements, see [expression operators](17-language-reference.md#expression-operators). ## Comments The Icinga 2 configuration format supports C/C++-style and shell-style comments. Example: /* This is a comment. */ object Host "localhost" { check_interval = 30 // this is also a comment. retry_interval = 15 # yet another comment } ## Includes Other configuration files can be included using the `include` directive. Paths must be relative to the configuration file that contains the `include` directive. Example: include "some/other/file.conf" include "conf.d/*.conf" Wildcard includes are not recursive. Icinga also supports include search paths similar to how they work in a C/C++ compiler: include Note the use of angle brackets instead of double quotes. This causes the config compiler to search the include search paths for the specified file. By default $PREFIX/share/icinga2/include is included in the list of search paths. Additional include search paths can be added using [command-line options](11-cli-commands.md#config-include-path). Wildcards are not permitted when using angle brackets. ## Recursive Includes The `include_recursive` directive can be used to recursively include all files in a directory which match a certain pattern. Example: include_recursive "conf.d", "*.conf" include_recursive "templates" The first parameter specifies the directory from which files should be recursively included. The file names need to match the pattern given in the second parameter. When no pattern is specified the default pattern "*.conf" is used. ## Zone Includes The `include_zones` recursively includes all subdirectories for the given path. In addition to that it sets the `zone` attribute for all objects created in these subdirectories to the name of the subdirectory. Example: include_zones "etc", "zones.d", "*.conf" include_zones "puppet", "puppet-zones" The first parameter specifies a tag name for this directive. Each `include_zones` invocation should use a unique tag name. When copying the zones' configuration files Icinga uses the tag name as the name for the destination directory in `/var/lib/icinga2/api/config`. The second parameter specifies the directory which contains the subdirectories. The file names need to match the pattern given in the third parameter. When no pattern is specified the default pattern "*.conf" is used. ## Library directive The `library` directive can be used to manually load additional libraries. Libraries can be used to provide additional object types and functions. Example: library "snmphelper" ## Functions Functions can be defined using the `function` keyword. Example: function multiply(a, b) { return a * b } When encountering the `return` keyword further execution of the function is terminated and the specified value is supplied to the caller of the function: log(multiply(3, 5)) In this example the `multiply` function we declared earlier is invoked with two arguments (3 and 5). The function computes the product of those arguments and makes the result available to the function's caller. When no value is supplied for the `return` statement the function returns `null`. Functions which do not have a `return` statement have their return value set to the value of the last expression which was performed by the function. For example, we could have also written our `multiply` function like this: function multiply(a, b) { a * b } Anonymous functions can be created by omitting the name in the function definition. The resulting function object can be used like any other value: var fn = function() { 3 } fn() /* Returns 3 */ ## Lambda Expressions Functions can also be declared using the alternative lambda syntax. Example: f = (x) => x * x Multiple statements can be used by putting the function body into braces: f = (x) => { log("Lambda called") x * x } Just like with ordinary functions the return value is the value of the last statement. For lambdas which take exactly one argument the braces around the arguments can be omitted: f = x => x * x ## Abbreviated Lambda Syntax Lambdas which take no arguments can also be written using the abbreviated lambda syntax. Example: f = {{ 3 }} This creates a new function which returns the value 3. ## Variable Scopes When setting a variable Icinga checks the following scopes in this order whether the variable already exists there: * Local Scope * `this` Scope * Global Scope The local scope contains variables which only exist during the invocation of the current function, object or apply statement. Local variables can be declared using the `var` keyword: function multiply(a, b) { var temp = a * b return temp } Each time the `multiply` function is invoked a new `temp` variable is used which is in no way related to previous invocations of the function. When setting a variable which has not previously been declared as local using the `var` keyword the `this` scope is used. The `this` scope refers to the current object which the function or object/apply statement operates on. object Host "localhost" { check_interval = 5m } In this example the `this` scope refers to the "localhost" object. The `check_interval` attribute is set for this particular host. You can explicitly access the `this` scope using the `this` keyword: object Host "localhost" { var check_interval = 5m /* This explicitly specifies that the attribute should be set * for the host, if we had omitted `this.` the (poorly named) * local variable `check_interval` would have been modified instead. */ this.check_interval = 1m } Similarly the keywords `locals` and `globals` are available to access the local and global scope. Functions also have a `this` scope. However unlike for object/apply statements the `this` scope for a function is set to whichever object was used to invoke the function. Here's an example: hm = { h_word = null function init(word) { h_word = word } } /* Let's invoke the init() function */ hm.init("hello") We're using `hm.init` to invoke the function which causes the value of `hm` to become the `this` scope for this function call. ## Closures By default `function`s, `object`s and `apply` rules do not have access to variables declared outside of their scope (except for global variables). In order to access variables which are defined in the outer scope the `use` keyword can be used: function MakeHelloFunction(name) { return function() use(name) { log("Hello, " + name) } } In this case a new variable `name` is created inside the inner function's scope which has the value of the `name` function argument. Alternatively a different value for the inner variable can be specified: function MakeHelloFunction(name) { return function() use (greeting = "Hello, " + name) { log(greeting) } } ## Conditional Statements Sometimes it can be desirable to only evaluate statements when certain conditions are met. The if/else construct can be used to accomplish this. Example: a = 3 if (a < 5) { a *= 7 } else if (a > 10) { a *= 5 } else { a *= 2 } An if/else construct can also be used in place of any other value. The value of an if/else statement is the value of the last statement which was evaluated for the branch which was taken: a = if (true) { log("Taking the 'true' branch") 7 * 3 } else { log("Taking the 'false' branch") 9 } This example prints the log message "Taking the 'true' branch" and the `a` variable is set to 21 (7 * 3). The value of an if/else construct is null if the condition evaluates to false and no else branch is given. ## While Loops The `while` statement checks a condition and executes the loop body when the condition evaluates to `true`. This is repeated until the condition is no longer true. Example: var num = 5 while (num > 5) { log("Test") num -= 1 } The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword breaks out of the loop. ## For Loops The `for` statement can be used to iterate over arrays and dictionaries. Example: var list = [ "a", "b", "c" ] for (item in list) { log("Item: " + item) } The loop body is evaluated once for each item in the array. The variable `item` is declared as a local variable just as if the `var` keyword had been used. Iterating over dictionaries can be accomplished in a similar manner: var dict = { a = 3, b = 7 } for (key => value in dict) { log("Key: " + key + ", Value: " + value) } The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword breaks out of the loop. ## Constructors In order to create a new value of a specific type constructor calls may be used. Example: var pd = PerfdataValue() pd.label = "test" pd.value = 10 You can also try to convert an existing value to another type by specifying it as an argument for the constructor call. Example: var s = String(3) /* Sets s to "3". */ ## Throwing Exceptions Built-in commands may throw exceptions to signal errors such as invalid arguments. User scripts can throw exceptions using the `throw` keyword. Example: throw "An error occurred." ## Handling Exceptions Exceptions can be handled using the `try` and `except` keywords. When an exception occurs while executing code in the `try` clause no further statements in the `try` clause are evaluated and the `except` clause is executed instead. Example: try { throw "Test" log("This statement won't get executed.") } except { log("An error occurred in the try clause.") } ## Breakpoints The `debugger` keyword can be used to insert a breakpoint. It may be used at any place where an assignment would also be a valid expression. By default breakpoints have no effect unless Icinga is started with the `--script-debugger` command-line option. When the script debugger is enabled Icinga stops execution of the script when it encounters a breakpoint and spawns a console which lets the user inspect the current state of the execution environment. ## Types All values have a static type. The `typeof` function can be used to determine the type of a value: typeof(3) /* Returns an object which represents the type for numbers */ The following built-in types are available: Type | Examples | Description -----------|-------------------|------------------------ Number | 3.7 | A numerical value. Boolean | true, false | A boolean value. String | "hello" | A string. Array | [ "a", "b" ] | An array. Dictionary | { a = 3 } | A dictionary. Depending on which libraries are loaded additional types may become available. The `icinga` library implements a whole bunch of other [object types](09-object-types.md#object-types), e.g. Host, Service, CheckCommand, etc. Each type has an associated type object which describes the type's semantics. These type objects are made available using global variables which match the type's name: /* This logs 'true' */ log(typeof(3) == Number) The type object's `prototype` property can be used to find out which methods a certain type supports: /* This returns: ["contains","find","len","lower","replace","reverse","split","substr","to_string","trim","upper"] */ keys(String.prototype) Additional documentation on type methods is available in the [library reference](18-library-reference.md#library-reference). ## Location Information The location of the currently executing script can be obtained using the `current_filename` and `current_line` keywords. Example: log("Hello from '" + current_filename + "' in line " + current_line) ## Reserved Keywords These keywords are reserved and must not be used as constants or custom attributes. object template include include_recursive include_zones library null true false const var this globals locals use default ignore_on_error current_filename current_line apply to where import assign ignore function return break continue for if else while throw try except in You can escape reserved keywords using the `@` character. The following example tries to set `vars.include` which references a reserved keyword and generates an error: [2014-09-15 17:24:00 +0200] critical/config: Location: /etc/icinga2/conf.d/hosts/localhost.conf(13): vars.sla = "24x7" /etc/icinga2/conf.d/hosts/localhost.conf(14): /etc/icinga2/conf.d/hosts/localhost.conf(15): vars.include = "some cmdb export field" ^^^^^^^ /etc/icinga2/conf.d/hosts/localhost.conf(16): } /etc/icinga2/conf.d/hosts/localhost.conf(17): Config error: in /etc/icinga2/conf.d/hosts/localhost.conf: 15:8-15:14: syntax error, unexpected include (T_INCLUDE), expecting T_IDENTIFIER [2014-09-15 17:24:00 +0200] critical/config: 1 errors, 0 warnings. You can escape the `include` keyword by prefixing it with an additional `@` character: object Host "localhost" { import "generic-host" address = "127.0.0.1" address6 = "::1" vars.os = "Linux" vars.sla = "24x7" vars.@include = "some cmdb export field" } icinga2-2.8.1/doc/18-library-reference.md000066400000000000000000001101461322762156600177700ustar00rootroot00000000000000# Library Reference ## Global functions These functions are globally available in [assign/ignore where expressions](03-monitoring-basics.md#using-apply-expressions), [functions](17-language-reference.md#functions), [API filters](12-icinga2-api.md#icinga2-api-filters) and the [Icinga 2 debug console](11-cli-commands.md#cli-command-console). You can use the [Icinga 2 debug console](11-cli-commands.md#cli-command-console) as a sandbox to test these functions before implementing them in your scenarios. ### regex Signature: function regex(pattern, value, mode) Returns true if the regular expression `pattern` matches the `value`, false otherwise. The `value` can be of the type [String](18-library-reference.md#string-type) or [Array](18-library-reference.md#array-type) (which contains string elements). The `mode` argument is optional and can be either `MatchAll` (in which case all elements for an array have to match) or `MatchAny` (in which case at least one element has to match). The default mode is `MatchAll`. **Tip**: In case you are looking for regular expression tests try [regex101](https://regex101.com). Example for string values: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.vars.os_type = "Linux/Unix" null <2> => regex("^Linux", host.vars.os_type) true <3> => regex("^Linux$", host.vars.os_type) false Example for an array of string values: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.vars.databases = [ "db-prod1", "db-prod2", "db-dev" ] null <2> => regex("^db-prod\\d+", host.vars.databases, MatchAny) true <3> => regex("^db-prod\\d+", host.vars.databases, MatchAll) false ### match Signature: function match(pattern, text, mode) Returns true if the wildcard (`?*`) `pattern` matches the `value`, false otherwise. The `value` can be of the type [String](18-library-reference.md#string-type) or [Array](18-library-reference.md#array-type) (which contains string elements). The `mode` argument is optional and can be either `MatchAll` (in which case all elements for an array have to match) or `MatchAny` (in which case at least one element has to match). The default mode is `MatchAll`. Example for string values: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var name = "db-prod-sfo-657" null <2> => match("*prod-sfo*", name) true <3> => match("*-dev-*", name) false Example for an array of string values: $ icinga2 console Icinga 2 (version: v2.7.0-28) <1> => host.vars.application_types = [ "web-wp", "web-rt", "db-local" ] null <2> => match("web-*", host.vars.application_types, MatchAll) false <3> => match("web-*", host.vars.application_types, MatchAny) true ### cidr_match Signature: function cidr_match(pattern, ip, mode) Returns true if the CIDR pattern matches the IP address, false otherwise. IPv4 addresses are converted to IPv4-mapped IPv6 addresses before being matched against the pattern. The `mode` argument is optional and can be either `MatchAll` (in which case all elements for an array have to match) or `MatchAny` (in which case at least one element has to match). The default mode is `MatchAll`. Example for a single IP address: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.address = "192.168.56.101" null <2> => cidr_match("192.168.56.0/24", host.address) true <3> => cidr_match("192.168.56.0/26", host.address) false Example for an array of IP addresses: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.vars.vhost_ips = [ "192.168.56.101", "192.168.56.102", "10.0.10.99" ] null <2> => cidr_match("192.168.56.0/24", host.vars.vhost_ips, MatchAll) false <3> => cidr_match("192.168.56.0/24", host.vars.vhost_ips, MatchAny) true ### range Signature: function range(end) function range(start, end) function range(start, end, increment) Returns an array of numbers in the specified range. If you specify one parameter, the first element starts at `0`. The following array numbers are incremented by `1` and stop before the specified end. If you specify the start and end numbers, the returned array number are incremented by `1`. They start at the specified start number and stop before the end number. Optionally you can specify the incremented step between numbers as third parameter. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => range(5) [ 0.000000, 1.000000, 2.000000, 3.000000, 4.000000 ] <2> => range(2,4) [ 2.000000, 3.000000 ] <3> => range(2,10,2) [ 2.000000, 4.000000, 6.000000, 8.000000 ] ### len Signature: function len(value) Returns the length of the value, i.e. the number of elements for an array or dictionary, or the length of the string in bytes. **Note**: Instead of using this global function you are advised to use the type's prototype method: [Array#len](18-library-reference.md#array-len), [Dictionary#len](18-library-reference.md#dictionary-len) and [String#len](18-library-reference.md#string-len). Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.groups = [ "linux-servers", "db-servers" ] null <2> => host.groups.len() 2.000000 <3> => host.vars.disks["/"] = {} null <4> => host.vars.disks["/var"] = {} null <5> => host.vars.disks.len() 2.000000 <6> => host.vars.os_type = "Linux/Unix" null <7> => host.vars.os_type.len() 10.000000 ### union Signature: function union(array, array, ...) Returns an array containing all unique elements from the specified arrays. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var dev_notification_groups = [ "devs", "slack" ] null <2> => var host_notification_groups = [ "slack", "noc" ] null <3> => union(dev_notification_groups, host_notification_groups) [ "devs", "noc", "slack" ] ### intersection Signature: function intersection(array, array, ...) Returns an array containing all unique elements which are common to all specified arrays. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var dev_notification_groups = [ "devs", "slack" ] null <2> => var host_notification_groups = [ "slack", "noc" ] null <3> => intersection(dev_notification_groups, host_notification_groups) [ "slack" ] ### keys Signature: function keys(dict) Returns an array containing the dictionary's keys. **Note**: Instead of using this global function you are advised to use the type's prototype method: [Dictionary#keys](18-library-reference.md#dictionary-keys). Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => host.vars.disks["/"] = {} null <2> => host.vars.disks["/var"] = {} null <3> => host.vars.disks.keys() [ "/", "/var" ] ### string Signature: function string(value) Converts the value to a string. **Note**: Instead of using this global function you are advised to use the type's prototype method: * [Number#to_string](18-library-reference.md#number-to_string) * [Boolean#to_string](18-library-reference.md#boolean-to_string) * [String#to_string](18-library-reference.md#string-to_string) * [Object#to_string](18-library-reference.md#object-to-string) for Array and Dictionary types * [DateTime#to_string](18-library-reference.md#datetime-tostring) Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => 5.to_string() "5" <2> => false.to_string() "false" <3> => "abc".to_string() "abc" <4> => [ "dev", "slack" ].to_string() "[ \"dev\", \"slack\" ]" <5> => { "/" = {}, "/var" = {} }.to_string() "{\n\t\"/\" = {\n\t}\n\t\"/var\" = {\n\t}\n}" <6> => DateTime(2016, 11, 25).to_string() "2016-11-25 00:00:00 +0100" ### number Signature: function number(value) Converts the value to a number. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => number(false) 0.000000 <2> => number("78") 78.000000 ### bool Signature: function bool(value) Converts the value to a bool. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => bool(1) true <2> => bool(0) false ### random Signature: function random() Returns a random value between 0 and RAND\_MAX (as defined in stdlib.h). $ icinga2 console Icinga 2 (version: v2.7.0) <1> => random() 1263171996.000000 <2> => random() 108402530.000000 ### log Signature: function log(value) Writes a message to the log. Non-string values are converted to a JSON string. Signature: function log(severity, facility, value) Writes a message to the log. `severity` can be one of `LogDebug`, `LogNotice`, `LogInformation`, `LogWarning`, and `LogCritical`. Non-string values are converted to a JSON string. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => log(LogCritical, "Console", "First line") critical/Console: First line null <2> => var groups = [ "devs", "slack" ] null <3> => log(LogCritical, "Console", groups) critical/Console: ["devs","slack"] null ### typeof Signature: function typeof(value) Returns the [Type](18-library-reference.md#type-type) object for a value. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => typeof(3) == Number true <2> => typeof("str") == String true <3> => typeof(true) == Boolean true <4> => typeof([ 1, 2, 3]) == Array true <5> => typeof({ a = 2, b = 3 }) == Dictionary true ### get_time Signature: function get_time() Returns the current UNIX timestamp as floating point number. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => get_time() 1480072135.633008 <2> => get_time() 1480072140.401207 ### parse_performance_data Signature: function parse_performance_data(pd) Parses a performance data string and returns an array describing the values. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var pd = "'time'=1480074205.197363;;;" null <2> => parse_performance_data(pd) { counter = false crit = null label = "time" max = null min = null type = "PerfdataValue" unit = "" value = 1480074205.197363 warn = null } ### dirname Signature: function dirname(path) Returns the directory portion of the specified path. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var path = "/etc/icinga2/scripts/xmpp-notification.pl" null <2> => dirname(path) "/etc/icinga2/scripts" ### basename Signature: function basename(path) Returns the filename portion of the specified path. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var path = "/etc/icinga2/scripts/xmpp-notification.pl" null <2> => basename(path) "xmpp-notification.pl" ### path\_exists Signature: function path_exists(path) Returns true if the specified path exists, false otherwise. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var path = "/etc/icinga2/scripts/xmpp-notification.pl" null <2> => path_exists(path) true ### glob Signature: function glob(pathSpec, type) Returns an array containing all paths which match the `pathSpec` argument. The `type` argument is optional and specifies which types of paths are matched. This can be a combination of the `GlobFile` and `GlobDirectory` constants. The default value is `GlobFile | GlobDirectory`. $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var pathSpec = "/etc/icinga2/conf.d/*.conf" null <2> => glob(pathSpec) [ "/etc/icinga2/conf.d/app.conf", "/etc/icinga2/conf.d/commands.conf", ... ] ### glob\_recursive Signature: function glob_recursive(path, pattern, type) Recursively descends into the specified directory and returns an array containing all paths which match the `pattern` argument. The `type` argument is optional and specifies which types of paths are matched. This can be a combination of the `GlobFile` and `GlobDirectory` constants. The default value is `GlobFile | GlobDirectory`. $ icinga2 console Icinga 2 (version: v2.7.0) <1> => var path = "/etc/icinga2/zones.d/" null <2> => var pattern = "*.conf" null <3> => glob_recursive(path, pattern) [ "/etc/icinga2/zones.d/global-templates/templates.conf", "/etc/icinga2/zones.d/master/hosts.conf", ... ] ### escape_shell_arg Signature: function escape_shell_arg(text) Escapes a string for use as a single shell argument. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => escape_shell_arg("'$host.name$' '$service.name$'") "''\\''$host.name$'\\'' '\\''$service.name$'\\'''" ### escape_shell_cmd Signature: function escape_shell_cmd(text) Escapes shell meta characters in a string. Example: $ icinga2 console Icinga 2 (version: v2.7.0) <1> => escape_shell_cmd("/bin/echo 'shell test' $ENV") "/bin/echo 'shell test' \\$ENV" ### escape_create_process_arg Signature: function escape_create_process_arg(text) Escapes a string for use as an argument for CreateProcess(). Windows only. ### sleep Signature: function sleep(interval) Sleeps for the specified amount of time (in seconds). ## Scoped Functions This chapter describes functions which are only available in a specific scope. ### macro Signature: ``` function macro("$macro_name$") ``` The `macro` function can be used to resolve [runtime macro](03-monitoring-basics.md#runtime-macros) strings into their values. The returned value depends on the attribute value which is resolved from the specified runtime macro. This function is only available in runtime evaluated functions, e.g. for [custom attributes](03-monitoring-basics.md#custom-attributes-functions) which use the [abbreviated lambda syntax](17-language-reference.md#nullary-lambdas). This example sets the `snmp_address` custom attribute based on `$address$` and `$address6`. ``` vars.snmp_address = {{ var addr_v4 = macro("$address$") var addr_v6 = macro("$address6$") if (addr_v4) { return addr_v4 } else { return "udp6:[" + addr_v6 + "]" } }} ``` More reference examples are available inside the [Icinga Template Library](10-icinga-template-library.md#icinga-template-library) and the [object accessors chapter](08-advanced-topics.md#access-object-attributes-at-runtime). ## Object Accessor Functions These functions can be used to retrieve a reference to another object by name. ### get_check_command Signature: function get_check_command(name); Returns the CheckCommand object with the specified name, or `null` if no such CheckCommand object exists. ### get_event_command Signature: function get_event_command(name); Returns the EventCommand object with the specified name, or `null` if no such EventCommand object exists. ### get_notification_command Signature: function get_notification_command(name); Returns the NotificationCommand object with the specified name, or `null` if no such NotificationCommand object exists. ### get_host Signature: function get_host(host_name); Returns the Host object with the specified name, or `null` if no such Host object exists. ### get_service Signature: function get_service(host_name, service_name); function get_service(host, service_name); Returns the Service object with the specified host name or object and service name pair, or `null` if no such Service object exists. Example in the [debug console](11-cli-commands.md#cli-command-console) which fetches the `disk` service object from the current Icinga 2 node: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' Icinga 2 (version: v2.7.0) <1> => get_service(NodeName, "disk") <2> => get_service(NodeName, "disk").__name "icinga2-master1.localdomain!disk" <3> => get_service(get_host(NodeName), "disk").__name "icinga2-master1.localdomain!disk" ``` ### get_services Signature: function get_services(host_name); function get_services(host); Returns an [array](17-language-reference.md#array) of service objects for the specified host name or object, or `null` if no such host object exists. Example in the [debug console](11-cli-commands.md#cli-command-console) which fetches all service objects from the current Icinga 2 node: ``` $ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' Icinga 2 (version: v2.7.0) <1> => get_services(NodeName).map(s => s.name) [ "disk", "disk /", "http", "icinga", "load", "ping4", "ping6", "procs", "ssh", "users" ] ``` Note: [map](18-library-reference.md#array-map) takes a [lambda function](17-language-reference.md#lambdas) as argument. In this example we only want to collect and print the `name` attribute with `s => s.name`. This works in a similar fashion for a host object where you can extract all service states in using the [map](18-library-reference.md#array-map) functionality: ``` <2> => get_services(get_host(NodeName)).map(s => s.state) [ 2.000000, 2.000000, 2.000000, 0.000000, 0.000000, 0.000000, 2.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000 ] ``` ### get_user Signature: function get_user(name); Returns the User object with the specified name, or `null` if no such User object exists. ### get_host_group Signature: function get_host_group(name); Returns the HostGroup object with the specified name, or `null` if no such HostGroup object exists. ### get_service_group Signature: function get_service_group(name); Returns the ServiceGroup object with the specified name, or `null` if no such ServiceGroup object exists. ### get_user_group Signature: function get_user_group(name); Returns the UserGroup object with the specified name, or `null` if no such UserGroup object exists. ### get_time_period Signature: function get_time_period(name); Returns the TimePeriod object with the specified name, or `null` if no such TimePeriod object exists. ### get_object Signature: function get_object(type, name); Returns the object with the specified type and name, or `null` if no such object exists. `type` must refer to a type object. ### get_objects Signature: function get_objects(type); Returns an array of objects whose type matches the specified type. `type` must refer to a type object. ## Math object The global `Math` object can be used to access a number of mathematical constants and functions. ### Math.E Euler's constant. ### Math.LN2 Natural logarithm of 2. ### Math.LN10 Natural logarithm of 10. ### Math.LOG2E Base 2 logarithm of E. ### Math.PI The mathematical constant Pi. ### Math.SQRT1_2 Square root of 1/2. ### Math.SQRT2 Square root of 2. ### Math.abs Signature: function abs(x); Returns the absolute value of `x`. ### Math.acos Signature: function acos(x); Returns the arccosine of `x`. ### Math.asin Signature: function asin(x); Returns the arcsine of `x`. ### Math.atan Signature: function atan(x); Returns the arctangent of `x`. ### Math.atan2 Signature: function atan2(y, x); Returns the arctangent of the quotient of `y` and `x`. ### Math.ceil Signature: function ceil(x); Returns the smallest integer value not less than `x`. ### Math.cos Signature: function cos(x); Returns the cosine of `x`. ### Math.exp Signature: function exp(x); Returns E raised to the `x`th power. ### Math.floor Signature: function floor(x); Returns the largest integer value not greater than `x`. ### Math.isinf Signature: function isinf(x); Returns whether `x` is infinite. ### Math.isnan Signature: function isnan(x); Returns whether `x` is NaN (not-a-number). ### Math.log Signature: function log(x); Returns the natural logarithm of `x`. ### Math.max Signature: function max(...); Returns the largest argument. A variable number of arguments can be specified. If no arguments are given, -Infinity is returned. ### Math.min Signature: function min(...); Returns the smallest argument. A variable number of arguments can be specified. If no arguments are given, +Infinity is returned. ### Math.pow Signature: function pow(x, y); Returns `x` raised to the `y`th power. ### Math.random Signature: function random(); Returns a pseudo-random number between 0 and 1. ### Math.round Signature: function round(x); Returns `x` rounded to the nearest integer value. ### Math.sign Signature: function sign(x); Returns -1 if `x` is negative, 1 if `x` is positive and 0 if `x` is 0. ### Math.sin Signature: function sin(x); Returns the sine of `x`. ### Math.sqrt Signature: function sqrt(x); Returns the square root of `x`. ### Math.tan Signature: function tan(x); Returns the tangent of `x`. ## Json object The global `Json` object can be used to encode and decode JSON. ### Json.encode Signature: function encode(x); Encodes an arbitrary value into JSON. ### Json.decode Signature: function decode(x); Decodes a JSON string. ## Number type ### Number#to_string Signature: function to_string(); The `to_string` method returns a string representation of the number. Example: var example = 7 example.to_string() /* Returns "7" */ ## Boolean type ### Boolean#to_string Signature: function to_string(); The `to_string` method returns a string representation of the boolean value. Example: var example = true example.to_string() /* Returns "true" */ ## String type ### String#find Signature: function find(str, start); Returns the zero-based index at which the string `str` was found in the string. If the string was not found, -1 is returned. `start` specifies the zero-based index at which `find` should start looking for the string (defaults to 0 when not specified). Example: "Hello World".find("World") /* Returns 6 */ ### String#contains Signature: function contains(str); Returns `true` if the string `str` was found in the string. If the string was not found, `false` is returned. Use [find](18-library-reference.md#string-find) for getting the index instead. Example: "Hello World".contains("World") /* Returns true */ ### String#len Signature function len(); Returns the length of the string in bytes. Note that depending on the encoding type of the string this is not necessarily the number of characters. Example: "Hello World".len() /* Returns 11 */ ### String#lower Signature: function lower(); Returns a copy of the string with all of its characters converted to lower-case. Example: "Hello World".lower() /* Returns "hello world" */ ### String#upper Signature: function upper(); Returns a copy of the string with all of its characters converted to upper-case. Example: "Hello World".upper() /* Returns "HELLO WORLD" */ ### String#replace Signature: function replace(search, replacement); Returns a copy of the string with all occurences of the string specified in `search` replaced with the string specified in `replacement`. ### String#split Signature: function split(delimiters); Splits a string into individual parts and returns them as an array. The `delimiters` argument specifies the characters which should be used as delimiters between parts. Example: "x-7,y".split("-,") /* Returns [ "x", "7", "y" ] */ ### String#substr Signature: function substr(start, len); Returns a part of a string. The `start` argument specifies the zero-based index at which the part begins. The optional `len` argument specifies the length of the part ("until the end of the string" if omitted). Example: "Hello World".substr(6) /* Returns "World" */ ### String#to_string Signature: function to_string(); Returns a copy of the string. ### String#reverse Signature: function reverse(); Returns a copy of the string in reverse order. ### String#trim Signature: function trim(); Removes trailing whitespaces and returns the string. ## Object type This is the base type for all types in the Icinga application. ### Object#clone Signature: function clone(); Returns a copy of the object. Note that for object elements which are reference values (e.g. objects such as arrays or dictionaries) the entire object is recursively copied. ### Object#to_string Signature: function to_string(); Returns a string representation for the object. Unless overridden this returns a string of the format "Object of type ''" where is the name of the object's type. Example: [ 3, true ].to_string() /* Returns "[ 3.000000, true ]" */ ### Object#type Signature: String type; Returns the object's type name. This attribute is read-only. Example: get_host("localhost").type /* Returns "Host" */ ## Type type Inherits methods from the [Object type](18-library-reference.md#object-type). The `Type` type provides information about the underlying type of an object or scalar value. All types are registered as global variables. For example, in order to obtain a reference to the `String` type the global variable `String` can be used. ### Type#base Signature: Type base; Returns a reference to the type's base type. This attribute is read-only. Example: Dictionary.base == Object /* Returns true, because the Dictionary type inherits directly from the Object type. */ ### Type#name Signature: String name; Returns the name of the type. ### Type#prototype Signature: Object prototype; Returns the prototype object for the type. When an attribute is accessed on an object that doesn't exist the prototype object is checked to see if an attribute with the requested name exists. If it does, the attribute's value is returned. The prototype functionality is used to implement methods. Example: 3.to_string() /* Even though '3' does not have a to_string property the Number type's prototype object does. */ ## Array type Inherits methods from the [Object type](18-library-reference.md#object-type). ### Array#add Signature: function add(value); Adds a new value after the last element in the array. ### Array#clear Signature: function clear(); Removes all elements from the array. ### Array#shallow_clone function shallow_clone(); Returns a copy of the array. Note that for elements which are reference values (e.g. objects such as arrays and dictionaries) only the references are copied. ### Array#contains Signature: function contains(value); Returns true if the array contains the specified value, false otherwise. ### Array#len Signature: function len(); Returns the number of elements contained in the array. ### Array#remove Signature: function remove(index); Removes the element at the specified zero-based index. ### Array#set Signature: function set(index, value); Sets the element at the zero-based index to the specified value. The `index` must refer to an element which already exists in the array. ### Array#get Signature: function get(index); Retrieves the element at the specified zero-based index. ### Array#sort Signature: function sort(less_cmp); Returns a copy of the array where all items are sorted. The items are compared using the `<` (less-than) operator. A custom comparator function can be specified with the `less_cmp` argument. ### Array#join Signature: function join(separator); Joins all elements of the array using the specified separator. ### Array#reverse Signature: function reverse(); Returns a new array with all elements of the current array in reverse order. ### Array#map Signature: function map(func); Calls `func(element)` for each of the elements in the array and returns a new array containing the return values of these function calls. ### Array#reduce Signature: function reduce(func); Reduces the elements of the array into a single value by calling the provided function `func` as `func(a, b)` repeatedly where `a` and `b` are elements of the array or results from previous function calls. ### Array#filter Signature: function filter(func); Returns a copy of the array containing only the elements for which `func(element)` is true. ### Array#any Signature: function any(func); Returns true if the array contains at least one element for which `func(element)` is true, false otherwise. ### Array#all Signature: function all(func); Returns true if the array contains only elements for which `func(element)` is true, false otherwise. ### Array#unique Signature: function unique(); Returns a copy of the array with all duplicate elements removed. The original order of the array is not preserved. ## Dictionary type Inherits methods from the [Object type](18-library-reference.md#object-type). ### Dictionary#shallow_clone Signature: function shallow_clone(); Returns a copy of the dictionary. Note that for elements which are reference values (e.g. objects such as arrays and dictionaries) only the references are copied. ### Dictionary#contains Signature: function contains(key); Returns true if a dictionary item with the specified `key` exists, false otherwise. ### Dictionary#len Signature: function len(); Returns the number of items contained in the dictionary. ### Dictionary#remove Signature: function remove(key); Removes the item with the specified `key`. Trying to remove an item which does not exist is a no-op. ### Dictionary#set Signature: function set(key, value); Creates or updates an item with the specified `key` and `value`. ### Dictionary#get Signature: function get(key); Retrieves the value for the specified `key`. Returns `null` if they `key` does not exist in the dictionary. ### Dictionary#keys Signature: function keys(); Returns a list of keys for all items that are currently in the dictionary. ### Dictionary#values Signature: function values(); Returns a list of values for all items that are currently in the dictionary. ## Function type Inherits methods from the [Object type](18-library-reference.md#object-type). ### Function#call Signature: function call(thisArg, ...); Invokes the function using an alternative `this` scope. The `thisArg` argument specifies the `this` scope for the function. All other arguments are passed directly to the function. Example: function set_x(val) { this.x = val } dict = {} set_x.call(dict, 7) /* Invokes set_x using `dict` as `this` */ ### Function#callv Signature: function callv(thisArg, args); Invokes the function using an alternative `this` scope. The `thisArg` argument specifies the `this` scope for the function. The items in the `args` array are passed to the function as individual arguments. Example: function set_x(val) { this.x = val } var dict = {} var args = [ 7 ] set_x.callv(dict, args) /* Invokes set_x using `dict` as `this` */ ## DateTime type Inherits methods from the [Object type](18-library-reference.md#object-type). ### DateTime constructor Signature: function DateTime() function DateTime(unixTimestamp) function DateTime(year, month, day) function DateTime(year, month, day, hours, minutes, seconds) Constructs a new DateTime object. When no arguments are specified for the constructor a new DateTime object representing the current time is created. Example: var d1 = DateTime() /* current time */ var d2 = DateTime(2016, 5, 21) /* midnight April 21st, 2016 (local time) */ ### DateTime arithmetic Subtracting two DateTime objects yields the interval between them, in seconds. Example: var delta = DateTime() - DateTime(2016, 5, 21) /* seconds since midnight April 21st, 2016 */ Subtracting a number from a DateTime object yields a new DateTime object that is further in the past: Example: var dt = DateTime() - 2 * 60 * 60 /* Current time minus 2 hours */ Adding a number to a DateTime object yields a new DateTime object that is in the future: Example: var dt = DateTime() + 24 * 60 60 /* Current time plus 24 hours */ ### DateTime#format Signature: function format(fmt) Returns a string representation for the DateTime object using the specified format string. The format string may contain format conversion placeholders as specified in strftime(3). Example: var s = DateTime(2016, 4, 21).format("%A") /* Sets s to "Thursday". */ ### DateTime#to_string Signature: function to_string() Returns a string representation for the DateTime object. Uses a suitable default format. Example: var s = DateTime(2016, 4, 21).to_string() /* Sets s to "2016-04-21 00:00:00 +0200". */ icinga2-2.8.1/doc/19-technical-concepts.md000066400000000000000000000321211322762156600201330ustar00rootroot00000000000000# Technical Concepts This chapter provides insights into specific Icinga 2 components, libraries, features and any other technical concept and design. ## Features Features are implemented in specific libraries and can be enabled using CLI commands. Features either write specific data or receive data. Examples for writing data: [DB IDO](14-features.md#db-ido), [Graphite](14-features.md#graphite-carbon-cache-writer), [InfluxDB](14-features.md#influxdb-writer). [GELF](14-features.md#gelfwriter), etc. Examples for receiving data: [REST API](12-icinga2-api.md#icinga2-api), etc. The implementation of features makes use of existing libraries and functionality. This makes the code more abstract, but shorter and easier to read. Features register callback functions on specific events they want to handle. For example the `GraphiteWriter` feature subscribes to new CheckResult events. Each time Icinga 2 receives and processes a new check result, this event is triggered and forwarded to all subscribers. The GraphiteWriter feature calls the registered function and processes the received data. Features which connect Icinga 2 to external interfaces normally parse and reformat the received data into an applicable format. The GraphiteWriter uses a TCP socket to communicate with the carbon cache daemon of Graphite. The InfluxDBWriter is instead writing bulk metric messages to InfluxDB's HTTP API. ## Cluster ### Communication Icinga 2 uses its own certificate authority (CA) by default. The public and private CA keys can be generated on the signing master. Each node certificate must be signed by the private CA key. Note: The following description uses `parent node` and `child node`. This also applies to nodes in the same cluster zone. During the connection attempt, an SSL handshake is performed. If the public certificate of a child node is not signed by the same CA, the child node is not trusted and the connection will be closed. If the SSL handshake succeeds, the parent node reads the certificate's common name (CN) of the child node and looks for a local Endpoint object name configuration. If there is no Endpoint object found, further communication (runtime and config sync, etc.) is terminated. The child node also checks the CN from the parent node's public certificate. If the child node does not find any local Endpoint object name configuration, it will not trust the parent node. Both checks prevent accepting cluster messages from an untrusted source endpoint. If an Endpoint match was found, there is one additional security mechanism in place: Endpoints belong to a Zone hierarchy. Several cluster messages can only be sent "top down", others like check results are allowed being sent from the child to the parent node. Once this check succeeds the cluster messages are exchanged and processed. ### CSR Signing In order to make things easier, Icinga 2 provides built-in methods to allow child nodes to request a signed certificate from the signing master. Icinga 2 v2.8 introduces the possibility to request certificates from indirectly connected nodes. This is required for multi level cluster environments with masters, satellites and clients. CSR Signing in general starts with the master setup. This step ensures that the master is in a working CSR signing state with: * public and private CA key in `/var/lib/icinga2/ca` * private `TicketSalt` constant defined inside the `api` feature * Cluster communication is ready and Icinga 2 listens on port 5665 The child node setup which is run with CLI commands will now attempt to connect to the parent node. This is not necessarily the signing master instance, but could also be a parent satellite node. During this process the child node asks the user to verify the parent node's public certificate to prevent MITM attacks. There are two methods to request signed certificates: * Add the ticket into the request. This ticket was generated on the master beforehand and contains hashed details for which client it has been created. The signing master uses this information to automatically sign the certificate request. * Do not add a ticket into the request. It will be sent to the signing master which stores the pending request. Manual user interaction with CLI commands is necessary to sign the request. The certificate request is sent as `pki::RequestCertificate` cluster message to the parent node. If the parent node is not the signing master, it stores the request in `/var/lib/icinga2/certificate-requests` and forwards the cluster message to its parent node. Once the message arrives on the signing master, it first verifies that the sent certificate request is valid. This is to prevent unwanted errors or modified requests from the "proxy" node. After verification, the signing master checks if the request contains a valid signing ticket. It hashes the certificate's common name and compares the value to the received ticket number. If the ticket is valid, the certificate request is immediately signed with CA key. The request is sent back to the client inside a `pki::UpdateCertificate` cluster message. If the child node was not the certificate request origin, it only updates the cached request for the child node and send another cluster message down to its child node (e.g. from a satellite to a client). If no ticket was specified, the signing master waits until the `ca sign` CLI command manually signed the certificate. > **Note** > > Push notifications for manual request signing is not yet implemented (TODO). Once the child node reconnects it synchronizes all signed certificate requests. This takes some minutes and requires all nodes to reconnect to each other. #### CSR Signing: Clients without parent connection There is an additional scenario: The setup on a child node does not necessarily need a connection to the parent node. This mode leaves the node in a semi-configured state. You need to manually copy the master's public CA key into `/var/lib/icinga2/certs/ca.crt` on the client before starting Icinga 2. The parent node needs to actively connect to the child node. Once this connections succeeds, the child node will actively request a signed certificate. The update procedure works the same way as above. ### High Availability High availability is automatically enabled between two nodes in the same cluster zone. This requires the same configuration and enabled features on both nodes. HA zone members trust each other and share event updates as cluster messages. This includes for example check results, next check timestamp updates, acknowledgements or notifications. This ensures that both nodes are synchronized. If one node goes away, the remaining node takes over and continues as normal. Cluster nodes automatically determine the authority for configuration objects. This results in activated but paused objects. You can verify that by querying the `paused` attribute for all objects via REST API or debug console. Nodes inside a HA zone calculate the object authority independent from each other. The number of endpoints in a zone is defined through the configuration. This number is used inside a local modulo calculation to determine whether the node feels responsible for this object or not. This object authority is important for selected features explained below. Since features are configuration objects too, you must ensure that all nodes inside the HA zone share the same enabled features. If configured otherwise, one might have a checker feature on the left node, nothing on the right node. This leads to late check results because one half is not executed by the right node which holds half of the object authorities. ### High Availability: Checker The `checker` feature only executes checks for `Checkable` objects (Host, Service) where it is authoritative. That way each node only executes checks for a segment of the overall configuration objects. The cluster message routing ensures that all check results are synchronized to nodes which are not authoritative for this configuration object. ### High Availability: Notifications The `notification` feature only sends notifications for `Notification` objects where it is authoritative. That way each node only executes notifications for a segment of all notification objects. Notified users and other event details are synchronized throughout the cluster. This is required if for example the DB IDO feature is active on the other node. ### High Availability: DB IDO If you don't have HA enabled for the IDO feature, both nodes will write their status and historical data to their own separate database backends. In order to avoid data separation and a split view (each node would require its own Icinga Web 2 installation on top), the high availability option was added to the DB IDO feature. This is enabled by default with the `enable_ha` setting. This requires a central database backend. Best practice is to use a MySQL cluster with a virtual IP. Both Icinga 2 nodes require the connection and credential details configured in their DB IDO feature. During startup Icinga 2 calculates whether the feature configuration object is authoritative on this node or not. The order is an alpha-numeric comparison, e.g. if you have `master1` and `master2`, Icinga 2 will enable the DB IDO feature on `master2` by default. If the connection between endpoints drops, the object authority is re-calculated. In order to prevent data duplication in a split-brain scenario where both nodes would write into the same database, there is another safety mechanism in place. The split-brain decision which node will write to the database is calculated from a quorum inside the `programstatus` table. Each node verifies whether the `endpoint_name` column is not itself on database connect. In addition to that the DB IDO feature compares the `last_update_time` column against the current timestamp plus the configured `failover_timeout` offset. That way only one active DB IDO feature writes to the database, even if they are not currently connected in a cluster zone. This prevents data duplication in historical tables. ### Health Checks #### cluster-zone This built-in check provides the possibility to check for connectivity between zones. If you for example need to know whether the `master` zone is connected and processing messages with the child zone called `satellite` in this example, you can configure the [cluster-zone](10-icinga-template-library.md#itl-icinga-cluster-zone) check as new service on all `master` zone hosts. ``` vim /etc/zones.d/master/host1.conf object Service "cluster-zone-satellite" { check_command = "cluster-zone" host_name = "host1" vars.cluster_zone = "satellite" } ``` The check itself changes to NOT-OK if one or more child endpoints in the child zone are not connected to parent zone endpoints. In addition to the overall connectivity check, the log lag is calculated based on the to-be-sent replay log. Each instance stores that for its configured endpoint objects. This health check iterates over the target zone (`cluster_zone`) and their endpoints. The log lag is greater than zero if * the replay log synchronization is in progress and not yet finished or * the endpoint is not connected, and no replay log sync happened (obviously). The final log lag value is the worst value detected. If satellite1 has a log lag of `1.5` and satellite2 only has `0.5`, the computed value will be `1.5.`. You can control the check state by using optional warning and critical thresholds for the log lag value. If this service exists multiple times, e.g. for each master host object, the log lag may differ based on the execution time. This happens for example on restart of an instance when the log replay is in progress and a health check is executed at different times. If the endpoint is not connected, both master instances may have saved a different log replay position from the last synchronisation. The lag value is returned as performance metric key `slave_lag`. Icinga 2 v2.9+ adds more performance metrics for these values: * `last_messages_sent` and `last_messages_received` as UNIX timestamp * `sum_messages_sent_per_second` and `sum_messages_received_per_second` * `sum_bytes_sent_per_second` and `sum_bytes_received_per_second` icinga2-2.8.1/doc/20-script-debugger.md000066400000000000000000000071631322762156600174530ustar00rootroot00000000000000# Script Debugger You can run the Icinga 2 daemon with the `-X` (`--script-debugger`) parameter to enable the script debugger: # icinga2 daemon -X When an exception occurs or the [debugger](17-language-reference.md#breakpoints) keyword is encountered in a user script, Icinga 2 launches a console that allows the user to debug the script. You can also attach the script debugger to the [configuration validation](11-cli-commands.md#config-validation): # icinga2 daemon -C -X Here is a list of common errors which can be diagnosed with the script debugger: * Configuration errors e.g. [apply rules](03-monitoring-basics.md#using-apply) * Errors in user-defined [functions](17-language-reference.md#functions) ## Debugging Configuration Errors The following example illustrates the problem of a service [apply rule](03-monitoring-basics.md#using-apply-for) which expects a dictionary value for `config`, but the host custom attribute only provides a string value: object Host "script-debugger-host" { check_command = "icinga" vars.http_vhosts["example.org"] = "192.168.1.100" // a string value } apply Service for (http_vhost => config in host.vars.http_vhosts) { import "generic-service" vars += config // expects a dictionary check_command = "http" } The error message on config validation will warn about the wrong value type, but does not provide any context which objects are affected. Enable the script debugger and run the config validation: # icinga2 daemon -C -X Breakpoint encountered in /etc/icinga2/conf.d/services.conf: 59:67-65:1 Exception: Error: Error while evaluating expression: Cannot convert value of type 'String' to an object. Location: /etc/icinga2/conf.d/services.conf(62): check_command = "http" /etc/icinga2/conf.d/services.conf(63): /etc/icinga2/conf.d/services.conf(64): vars += config ^^^^^^^^^^^^^^ /etc/icinga2/conf.d/services.conf(65): } /etc/icinga2/conf.d/services.conf(66): You can inspect expressions (such as variables) by entering them at the prompt. To leave the debugger and continue the program use "$continue". <1> => You can print the variables `vars` and `config` to get an idea about their values: <1> => vars null <2> => config "192.168.1.100" <3> => The `vars` attribute has to be a dictionary. Trying to set this attribute to a string caused the error in our configuration example. In order to determine the name of the host where the value of the `config` variable came from you can inspect attributes of the service object: <3> => host_name "script-debugger-host-01" <4> => name "http" Additionally you can view the service object attributes by printing the value of `this`. ## Using Breakpoints In order to halt execution in a script you can use the `debugger` keyword: object Host "script-debugger-host-02" { check_command = "dummy" check_interval = 5s vars.dummy_text = {{ var text = "Hello from " + macro("$name$") debugger return text }} } Icinga 2 will spawn a debugger console every time the function is executed: # icinga2 daemon -X ... Breakpoint encountered in /etc/icinga2/tests/script-debugger.conf: 7:5-7:12 You can inspect expressions (such as variables) by entering them at the prompt. To leave the debugger and continue the program use "$continue". <1> => text "Hello from script-debugger-host-02" <2> => $continue icinga2-2.8.1/doc/21-development.md000066400000000000000000000221751322762156600167100ustar00rootroot00000000000000# Develop Icinga 2 This chapter provides hints on Icinga 2 development especially for debugging purposes. > **Note** > > If you are planning to build your own development environment, > please consult the `INSTALL.md` file from the source tree. ## Debug Requirements Make sure that the debug symbols are available for Icinga 2. The Icinga 2 packages provide a debug package which must be installed separately for all involved binaries, like `icinga2-bin` or `icinga2-ido-mysql`. Debian/Ubuntu: # apt-get install icinga2-dbg RHEL/CentOS: # yum install icinga2-debuginfo SLES/openSUSE: # zypper install icinga2-bin-debuginfo icinga2-ido-mysql-debuginfo Furthermore, you may also have to install debug symbols for Boost and your C library. If you're building your own binaries, you should use the `-DCMAKE_BUILD_TYPE=Debug` cmake build flag for debug builds. ## GDB Install gdb: Debian/Ubuntu: # apt-get install gdb RHEL/CentOS/Fedora: # yum install gdb SLES/openSUSE: # zypper install gdb Install the `boost`, `python` and `icinga2` pretty printers. Absolute paths are required, so please make sure to update the installation paths accordingly (`pwd`). $ mkdir -p ~/.gdb_printers && cd ~/.gdb_printers Boost Pretty Printers compatible with Python 3: $ git clone https://github.com/mateidavid/Boost-Pretty-Printer.git && cd Boost-Pretty-Printer $ git checkout python-3 $ pwd /home/michi/.gdb_printers/Boost-Pretty-Printer Python Pretty Printers: $ cd ~/.gdb_printers $ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python Icinga 2 Pretty Printers: $ mkdir -p ~/.gdb_printers/icinga2 && cd ~/.gdb_printers/icinga2 $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/icingadbg.py Now you'll need to modify/setup your `~/.gdbinit` configuration file. You can download the one from Icinga 2 and modify all paths. Example on Fedora 22: $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/gdbinit -O ~/.gdbinit $ vim ~/.gdbinit set print pretty on python import sys sys.path.insert(0, '/home/michi/.gdb_printers/icinga2') from icingadbg import register_icinga_printers register_icinga_printers() end python import sys sys.path.insert(0, '/home/michi/.gdb_printers/python') from libstdcxx.v6.printers import register_libstdcxx_printers try: register_libstdcxx_printers(None) except: pass end python import sys sys.path.insert(0, '/home/michi/.gdb_printers/Boost-Pretty-Printer') import boost_print boost_print.register_printers() end If you are getting the following error when running gdb, the `libstdcxx` printers are already preloaded in your environment and you can remove the duplicate import in your `~/.gdbinit` file. RuntimeError: pretty-printer already registered: libstdc++-v6 ### GDB Run Call GDB with the binary (`/usr/sbin/icinga2` is a wrapper script calling `/usr/lib64/icinga2/sbin/icinga2` since 2.4) and all arguments and run it in foreground. # gdb --args /usr/lib64/icinga2/sbin/icinga2 daemon -x debug --no-stack-rlimit The exact path to the Icinga 2 binary differs on each distribution. On Ubuntu it is installed into `/usr/lib/x86_64-linux-gnu/icinga2/sbin/icinga2` on 64-bit systems for example. > **Note** > > If gdb tells you it's missing debug symbols, quit gdb and install > them: `Missing separate debuginfos, use: debuginfo-install ...` Run the application. (gdb) r Kill the running application. (gdb) k Continue after breakpoint. (gdb) c ### GDB Core Dump Either attach to the running process using `gdb -p PID` or start a new gdb run. (gdb) r (gdb) generate-core-file ### GDB Backtrace If Icinga 2 aborted its operation abnormally, generate a backtrace. (gdb) bt (gdb) thread apply all bt full If gdb stops at a SIGPIPE signal please disable the signal before running Icinga 2. (gdb) handle SIGPIPE nostop noprint pass (gdb) r If you create a [bug report](https://www.icinga.com/community/get-involved/), make sure to attach as much detail as possible. ### GDB Backtrace from Running Process If Icinga 2 is still running, generate a full backtrace from the running process and store it into a new file (e.g. for debugging dead locks): # gdb -p $(pidof icinga2) -batch -ex "thread apply all bt full" -ex "detach" -ex "q" > gdb_bt.log ### GDB Backtrace Stepping Identifying the problem may require stepping into the backtrace, analysing the current scope, attributes, and possible unmet requirements. `p` prints the value of the selected variable or function call result. (gdb) up (gdb) down (gdb) p checkable (gdb) p checkable.px->m_Name ### GDB Breakpoints To set a breakpoint to a specific function call, or file specific line. (gdb) b checkable.cpp:125 (gdb) b icinga::Checkable::SetEnablePerfdata GDB will ask about loading the required symbols later, select `yes` instead of `no`. Then run Icinga 2 until it reaches the first breakpoint. Continue with `c` afterwards. (gdb) run (gdb) c If you want to delete all breakpoints, use `d` and select `yes`. (gdb) d > **Tip** > > When debugging exceptions, set your breakpoint like this: `b __cxa_throw`. Breakpoint Example: (gdb) b __cxa_throw (gdb) r (gdb) up .... (gdb) up #11 0x00007ffff7cbf9ff in icinga::Utility::GlobRecursive(icinga::String const&, icinga::String const&, boost::function const&, int) (path=..., pattern=..., callback=..., type=1) at /home/michi/coding/icinga/icinga2/lib/base/utility.cpp:609 609 callback(cpath); (gdb) l 604 605 #endif /* _WIN32 */ 606 607 std::sort(files.begin(), files.end()); 608 BOOST_FOREACH(const String& cpath, files) { 609 callback(cpath); 610 } 611 612 std::sort(dirs.begin(), dirs.end()); 613 BOOST_FOREACH(const String& cpath, dirs) { (gdb) p files $3 = std::vector of length 11, capacity 16 = {{static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/agent.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/commands.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/downtimes.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/groups.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/notifications.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/satellite.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/services.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/templates.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/test.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/timeperiods.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/users.conf"}} ## Core Dump When the Icinga 2 daemon crashes with a `SIGSEGV` signal a core dump file should be written. This will help developers to analyze and fix the problem. ### Core Dump File Size Limit This requires setting the core dump file size to `unlimited`. Example for Systemd: vim /usr/lib/systemd/system/icinga2.service [Service] ... LimitCORE=infinity systemctl daemon-reload systemctl restart icinga2 Example for init script: vim /etc/init.d/icinga2 ... ulimit -c unlimited service icinga2 restart Verify that the Icinga 2 process core file size limit is set to `unlimited`. cat /proc/`pidof icinga2`/limits ... Max core file size unlimited unlimited bytes ### Core Dump Kernel Format The Icinga 2 daemon runs with the SUID bit set. Therefore you need to explicitly enable core dumps for SUID on Linux. sysctl -w fs.suid_dumpable=1 Adjust the coredump kernel format and file location on Linux: sysctl -w kernel.core_pattern=/var/lib/cores/core.%e.%p install -m 1777 -d /var/lib/cores MacOS: sysctl -w kern.corefile=/cores/core.%P chmod 777 /cores ### Core Dump Analysis Once Icinga 2 crashes again a new coredump file will be written. Please attach this file to your bug report in addition to the general details. Simple test case for a `SIGSEGV` simulation with `sleep`: ulimit -c unlimited sleep 1800& [1] kill -SEGV gdb `which sleep` /var/lib/cores/core.sleep. (gdb) bt rm /var/lib/cores/core.sleep.* Analyzing Icinga 2: gdb /usr/lib64/icinga2/sbin/icinga2 core.icinga2. (gdb) bt icinga2-2.8.1/doc/22-selinux.md000066400000000000000000000346571322762156600160660ustar00rootroot00000000000000# SELinux ## Introduction SELinux is a mandatory access control (MAC) system on Linux which adds a fine-grained permission system for access to all system resources such as files, devices, networks and inter-process communication. The most important questions are answered briefly in the [FAQ of the SELinux Project](https://selinuxproject.org/page/FAQ). For more details on SELinux and how to actually use and administrate it on your system have a look at [Red Hat Enterprise Linux 7 - SELinux User's and Administrator's Guide](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/index.html). For a simplified (and funny) introduction download the [SELinux Coloring Book](https://github.com/mairin/selinux-coloring-book). This documentation will use a format similar to the SELinux User's and Administrator's Guide. ### Policy Icinga 2 provides its own SELinux policy. Development target is a policy package for Red Hat Enterprise Linux 7 and derivatives running the targeted policy which confines Icinga 2 with all features and all checks executed. All other distributions will require some tweaks. ### Installation There are two ways of installing the SELinux Policy for Icinga 2 on Enterprise Linux 7. The preferred way is to install the package. The other option involves installing the SELinux policy manually which might be necessary if you need some fixes which haven't made their way into a release yet. If the system runs in enforcing mode and you encounter problems you can set Icinga 2's domain to permissive mode. # sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Max kernel policy version: 28 You can change the configured mode by editing `/etc/selinux/config` and the current mode by executing `setenforce 0`. #### Package installation Simply add the `icinga2-selinux` package to your installation. # yum install icinga2-selinux Ensure that the `icinga2` process is running in its own `icinga2_t` domain after installing the policy package: # systemctl restart icinga2.service # ps -eZ | grep icinga2 system_u:system_r:icinga2_t:s0 2825 ? 00:00:00 icinga2 #### Manual installation This section describes the installation to support development and testing. It assumes that Icinga 2 is already installed from packages and running on the system. As a prerequisite install the `git`, `selinux-policy-devel` and `audit` packages. Enable and start the audit daemon afterwards: # yum install git selinux-policy-devel audit # systemctl enable auditd.service # systemctl start auditd.service After that clone the icinga2 git repository: # git clone https://github.com/icinga/icinga2 To create and install the policy package run the installation script which also labels the resources. (The script assumes Icinga 2 was started once after system startup, the labeling of the port will only happen once and fail later on.) # cd tools/selinux/ # ./icinga.sh After that restart Icinga 2 and verify it running in its own domain `icinga2_t`. # systemctl restart icinga2.service # ps -eZ | grep icinga2 system_u:system_r:icinga2_t:s0 2825 ? 00:00:00 icinga2 ### General When the SELinux policy package for Icinga 2 is installed, the Icinga 2 daemon (icinga2) runs in its own domain `icinga2_t` and is separated from other confined services. Files have to be labeled correctly in order for Icinga 2 to be able to access them. For example the Icinga 2 log files have to have the `icinga2_log_t` label. Also the API port is labeled with `icinga_port_t`. Furthermore Icinga 2 can open high ports and UNIX sockets to connect to databases and features like Graphite. It executes the Nagios plugins and transitions to their context if those are labeled for example `nagios_services_plugin_exec_t` or `nagios_system_plugin_exec_t`. Additionally the Apache web server is allowed to connect to Icinga 2's command pipe in order to allow web interfaces to send commands to icinga2. This will perhaps change later on while investigating Icinga Web 2 for SELinux! ### Types The command pipe is labeled `icinga2_command_t` and other services can request access to it by using the interface `icinga2_send_commands`. The nagios plugins use their own contexts and icinga2 will transition to it. This means plugins have to be labeled correctly for their required permissions. The plugins installed from package should have set their permissions by the corresponding policy module and you can restore them using `restorecon -R -v /usr/lib64/nagios/plugins/`. To label your own plugins use `chcon -t type /path/to/plugin`, for the type have a look at table below. Type | Domain | Use case | Provided by policy package ----------------------------------|------------------------------|------------------------------------------------------------------|--------------------------- nagios_admin_plugin_exec_t | nagios_admin_plugin_t | Plugins which require require read access on all file attributes | nagios nagios_checkdisk_plugin_exec_t | nagios_checkdisk_plugin_t | Plugins which require read access to all filesystem attributes | nagios nagios_mail_plugin_exec_t | nagios_mail_plugin_t | Plugins which access the local mail service | nagios nagios_services_plugin_exec_t | nagios_services_plugin_t | Plugins monitoring network services | nagios nagios_system_plugin_exec_t | nagios_system_plugin_t | Plugins checking local system state | nagios nagios_unconfined_plugin_exec_t | nagios_unconfined_plugin_t | Plugins running without confinement | nagios nagios_eventhandler_plugin_exec_t | nagios_eventhandler_plugin_t | Eventhandler (actually running unconfined) | nagios nagios_openshift_plugin_exec_t | nagios_openshift_plugin_t | Plugins monitoring openshift | nagios nagios_notification_plugin_exec_t | nagios_notification_plugin_t | Notification commands | icinga (will be moved later) If one of those plugin domains causes problems you can set it to permissive by executing `semanage permissive -a domain`. The policy provides a role `icinga2adm_r` for confining an user which enables an administrative user managing only Icinga 2 on the system. This user will also execute the plugins in their domain instead of the users one, so you can verify their execution with the same restrictions like they have when executed by icinga2. ### Booleans SELinux is based on the least level of access required for a service to run. Using booleans you can grant more access in a defined way. The Icinga 2 policy package provides the following booleans. **icinga2_can_connect_all** Having this boolean enabled allows icinga2 to connect to all ports. This can be necessary if you use features which connect to unconfined services. **httpd_can_write_icinga2_command** Having this boolean enabled allows httpd to write to the command pipe of icinga2. This is enabled by default, if not needed you can disable it for more security. **httpd_can_connect_icinga2_api** Having this boolean enabled allows httpd to connect to the API of icinga2 (Ports labeled icinga2_port_t). This is enabled by default, if not needed you can disable it for more security. ### Configuration Examples #### Run the icinga2 service permissive If problems occur while running the system in enforcing mode and those problems are only caused by the policy of the icinga2 domain, you can set this domain to permissive instead of the complete system. This can be done by executing `semanage permissive -a icinga2_t`. Make sure to report the bugs in the policy afterwards. #### Confining a plugin Download and install a plugin, for example check_mysql_health. # wget https://labs.consol.de/download/shinken-nagios-plugins/check_mysql_health-2.1.9.2.tar.gz # tar xvzf check_mysql_health-2.1.9.2.tar.gz # cd check_mysql_health-2.1.9.2/ # ./configure --libexecdir /usr/lib64/nagios/plugins # make # make install It is labeled `nagios_unconfined_plugins_exec_t` by default, so it runs without restrictions. # ls -lZ /usr/lib64/nagios/plugins/check_mysql_health -rwxr-xr-x. root root system_u:object_r:nagios_unconfined_plugin_exec_t:s0 /usr/lib64/nagios/plugins/check_mysql_health In this case the plugin is monitoring a service, so it should be labeled `nagios_services_plugin_exec_t` to restrict its permissions. # chcon -t nagios_services_plugin_exec_t /usr/lib64/nagios/plugins/check_mysql_health # ls -lZ /usr/lib64/nagios/plugins/check_mysql_health -rwxr-xr-x. root root system_u:object_r:nagios_services_plugin_exec_t:s0 /usr/lib64/nagios/plugins/check_mysql_health The plugin still runs fine but if someone changes the script to do weird stuff it will fail to do so. #### Allow icinga to connect to all ports. You are running graphite on a different port than `2003` and want `icinga2` to connect to it. Change the port value for the graphite feature according to your graphite installation before enabling it. # cat /etc/icinga2/features-enabled/graphite.conf /** * The GraphiteWriter type writes check result metrics and * performance data to a graphite tcp socket. */ library "perfdata" object GraphiteWriter "graphite" { //host = "127.0.0.1" //port = 2003 port = 2004 } # icinga2 feature enable graphite Before you restart the icinga2 service allow it to connect to all ports by enabling the boolean ´icinga2_can_connect_all` (now and permanent). # setsebool icinga2_can_connect_all true # setsebool -P icinga2_can_connect_all true If you restart the daemon now it will successfully connect to graphite. #### Confining a user If you want to have an administrative account capable of only managing icinga2 and not the complete system, you can restrict the privileges by confining this user. This is completly optional! Start by adding the Icinga 2 administrator role `icinga2adm_r` to the administrative SELinux user `staff_u`. # semanage user -m -R "staff_r sysadm_r system_r unconfined_r icinga2adm_r" staff_u Confine your user login and create a sudo rule. # semanage login -a dirk -s staff_u # echo "dirk ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/dirk Login to the system using ssh and verify your id. $ id -Z staff_u:staff_r:staff_t:s0-s0:c0.c1023 Try to execute some commands as root using sudo. $ sudo id -Z staff_u:staff_r:staff_t:s0-s0:c0.c1023 $ sudo vi /etc/icinga2/icinga2.conf "/etc/icinga2/icinga2.conf" [Permission Denied] $ sudo cat /var/log/icinga2/icinga2.log cat: /var/log/icinga2/icinga2.log: Keine Berechtigung $ sudo systemctl reload icinga2.service Failed to get D-Bus connection: No connection to service manager. Those commands fail because you only switch to root but do not change your SELinux role. Try again but tell sudo also to switch the SELinux role and type. $ sudo -r icinga2adm_r -t icinga2adm_t id -Z staff_u:icinga2adm_r:icinga2adm_t:s0-s0:c0.c1023 $ sudo -r icinga2adm_r -t icinga2adm_t vi /etc/icinga2/icinga2.conf "/etc/icinga2/icinga2.conf" $ sudo -r icinga2adm_r -t icinga2adm_t cat /var/log/icinga2/icinga2.log [2015-03-26 20:48:14 +0000] information/DynamicObject: Dumping program state to file '/var/lib/icinga2/icinga2.state' $ sudo -r icinga2adm_r -t icinga2adm_t systemctl reload icinga2.service Now the commands will work, but you have always to remember to add the arguments, so change the sudo rule to set it by default. # echo "dirk ALL=(ALL) ROLE=icinga2adm_r TYPE=icinga2adm_t NOPASSWD: ALL" > /etc/sudoers.d/dirk Now try the commands again without providing the role and type and they will work, but if you try to read apache logs or restart apache for example it will still fail. $ sudo cat /var/log/httpd/error_log /bin/cat: /var/log/httpd/error_log: Keine Berechtigung $ sudo systemctl reload httpd.service Failed to issue method call: Access denied ## Bugreports If you experience any problems while running in enforcing mode try to reproduce it in permissive mode. If the problem persists it is not related to SELinux because in permissive mode SELinux will not deny anything. After some feedback Icinga 2 is now running in a enforced domain, but still adds also some rules for other necessary services so no problems should occure at all. But you can help to enhance the policy by testing Icinga 2 running confined by SELinux. Please add the following information to [bug reports](https://www.icinga.com/community/get-involved/): * Versions, configuration snippets, etc. * Output of `semodule -l | grep -e icinga2 -e nagios -e apache` * Output of `ps -eZ | grep icinga2` * Output of `semanage port -l | grep icinga2` * Output of `audit2allow -li /var/log/audit/audit.log` If access to a file is blocked and you can tell which one please provided the output of `ls -lZ /path/to/file` (and perhaps the directory above). If asked for full audit.log add `-w /etc/shadow -p w` to `/etc/audit/rules.d/audit.rules`, restart the audit daemon, reproduce the problem and add `/var/log/audit/audit.log` to the bug report. With the added audit rule it will include the path of files access was denied to. If asked to provide full audit log with dontaudit rules disabled executed `semodule -DB` before reproducing the problem. After that enable the rules again to prevent auditd spamming your logfile by executing `semodule -B`. icinga2-2.8.1/doc/23-migrating-from-icinga-1x.md000066400000000000000000001601751322762156600210730ustar00rootroot00000000000000# Migration from Icinga 1.x ## Configuration Migration The Icinga 2 configuration format introduces plenty of behavioural changes. In order to ease migration from Icinga 1.x, this section provides hints and tips on your migration requirements. ### Manual Config Migration For a long-term migration of your configuration you should consider re-creating your configuration based on the proposed Icinga 2 configuration paradigm. Please read the [next chapter](23-migrating-from-icinga-1x.md#differences-1x-2) to find out more about the differences between 1.x and 2. ### Manual Config Migration Hints These hints should provide you with enough details for manually migrating your configuration, or to adapt your configuration export tool to dump Icinga 2 configuration instead of Icinga 1.x configuration. The examples are taken from Icinga 1.x test and production environments and converted straight into a possible Icinga 2 format. If you found a different strategy, please let us know! If you require in-depth explanations, please check the [next chapter](23-migrating-from-icinga-1x.md#differences-1x-2). #### Manual Config Migration Hints for Intervals By default all intervals without any duration literal are interpreted as seconds. Therefore all existing Icinga 1.x `*_interval` attributes require an additional `m` duration literal. Icinga 1.x: define service { service_description service1 host_name localhost1 check_command test_customvar use generic-service check_interval 5 retry_interval 1 } Icinga 2: object Service "service1" { import "generic-service" host_name = "localhost1" check_command = "test_customvar" check_interval = 5m retry_interval = 1m } #### Manual Config Migration Hints for Services If you have used the `host_name` attribute in Icinga 1.x with one or more host names this service belongs to, you can migrate this to the [apply rules](03-monitoring-basics.md#using-apply) syntax. Icinga 1.x: define service { service_description service1 host_name localhost1,localhost2 check_command test_check use generic-service } Icinga 2: apply Service "service1" { import "generic-service" check_command = "test_check" assign where host.name in [ "localhost1", "localhost2" ] } In Icinga 1.x you would have organized your services with hostgroups using the `hostgroup_name` attribute like the following example: define service { service_description servicewithhostgroups hostgroup_name hostgroup1,hostgroup3 check_command test_check use generic-service } Using Icinga 2 you can migrate this to the [apply rules](03-monitoring-basics.md#using-apply) syntax: apply Service "servicewithhostgroups" { import "generic-service" check_command = "test_check" assign where "hostgroup1" in host.groups assign where "hostgroup3" in host.groups } #### Manual Config Migration Hints for Group Members The Icinga 1.x hostgroup `hg1` has two members `host1` and `host2`. The hostgroup `hg2` has `host3` as a member and includes all members of the `hg1` hostgroup. define hostgroup { hostgroup_name hg1 members host1,host2 } define hostgroup { hostgroup_name hg2 members host3 hostgroup_members hg1 } This can be migrated to Icinga 2 and [using group assign](17-language-reference.md#group-assign). The additional nested hostgroup `hg1` is included into `hg2` with the `groups` attribute. object HostGroup "hg1" { assign where host.name in [ "host1", "host2" ] } object HostGroup "hg2" { groups = [ "hg1" ] assign where host.name == "host3" } These assign rules can be applied for all groups: `HostGroup`, `ServiceGroup` and `UserGroup` (requires renaming from `contactgroup`). > **Tip** > > Define custom attributes and assign/ignore members based on these attribute pattern matches. #### Manual Config Migration Hints for Check Command Arguments Host and service check command arguments are separated by a `!` in Icinga 1.x. Their order is important and they are referenced as `$ARGn$` where `n` is the argument counter. define command { command_name my-ping command_line $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5 } define service { use generic-service host_name my-server service_description my-ping check_command my-ping-check!100.0,20%!500.0,60% } While you could manually migrate this like (please note the new generic command arguments and default argument values!): object CheckCommand "my-ping-check" { command = [ PluginDir + "/check_ping", "-4" ] arguments = { "-H" = "$ping_address$" "-w" = "$ping_wrta$,$ping_wpl$%" "-c" = "$ping_crta$,$ping_cpl$%" "-p" = "$ping_packets$" "-t" = "$ping_timeout$" } vars.ping_address = "$address$" vars.ping_wrta = 100 vars.ping_wpl = 5 vars.ping_crta = 200 vars.ping_cpl = 15 } object Service "my-ping" { import "generic-service" host_name = "my-server" check_command = "my-ping-check" vars.ping_wrta = 100 vars.ping_wpl = 20 vars.ping_crta = 500 vars.ping_cpl = 60 } #### Manual Config Migration Hints for Runtime Macros Runtime macros have been renamed. A detailed comparison table can be found [here](23-migrating-from-icinga-1x.md#differences-1x-2-runtime-macros). For example, accessing the service check output looks like the following in Icinga 1.x: $SERVICEOUTPUT$ In Icinga 2 you will need to write: $service.output$ Another example referencing the host's address attribute in Icinga 1.x: $HOSTADDRESS$ In Icinga 2 you'd just use the following macro to access all `address` attributes (even overridden from the service objects): $address$ #### Manual Config Migration Hints for Runtime Custom Attributes Custom variables from Icinga 1.x are available as Icinga 2 custom attributes. define command { command_name test_customvar command_line echo "Host CV: $_HOSTCVTEST$ Service CV: $_SERVICECVTEST$\n" } define host { host_name localhost1 check_command test_customvar use generic-host _CVTEST host cv value } define service { service_description service1 host_name localhost1 check_command test_customvar use generic-service _CVTEST service cv value } Can be written as the following in Icinga 2: object CheckCommand "test_customvar" { command = "echo "Host CV: $host.vars.CVTEST$ Service CV: $service.vars.CVTEST$\n"" } object Host "localhost1" { import "generic-host" check_command = "test_customvar" vars.CVTEST = "host cv value" } object Service "service1" { host_name = "localhost1" check_command = "test_customvar" vars.CVTEST = "service cv value" } If you are just defining `$CVTEST$` in your command definition, its value depends on the execution scope -- the host check command will fetch the host attribute value of `vars.CVTEST` while the service check command resolves its value to the service attribute attribute `vars.CVTEST`. > **Note** > > Custom attributes in Icinga 2 are case-sensitive. `vars.CVTEST` is not the same as `vars.CvTest`. #### Manual Config Migration Hints for Contacts (Users) Contacts in Icinga 1.x act as users in Icinga 2, but do not have any notification commands specified. This migration part is explained in the [next chapter](23-migrating-from-icinga-1x.md#manual-config-migration-hints-notifications). define contact{ contact_name testconfig-user use generic-user alias Icinga Test User service_notification_options c,f,s,u email icinga@localhost } The `service_notification_options` can be [mapped](23-migrating-from-icinga-1x.md#manual-config-migration-hints-notification-filters) into generic `state` and `type` filters, if additional notification filtering is required. `alias` gets renamed to `display_name`. object User "testconfig-user" { import "generic-user" display_name = "Icinga Test User" email = "icinga@localhost" } This user can be put into usergroups (former contactgroups) or referenced in newly migration notification objects. #### Manual Config Migration Hints for Notifications If you are migrating a host or service notification, you'll need to extract the following information from your existing Icinga 1.x configuration objects * host/service attribute `contacts` and `contact_groups` * host/service attribute `notification_options` * host/service attribute `notification_period` * host/service attribute `notification_interval` The clean approach is to refactor your current contacts and their notification command methods into a generic strategy * host or service has a notification type (for example mail) * which contacts (users) are notified by mail? * do the notification filters, periods, intervals still apply for them? (do a cleanup during migration) * assign users and groups to these notifications * Redesign the notifications into generic [apply rules](03-monitoring-basics.md#using-apply-notifications) The ugly workaround solution could look like this: Extract all contacts from the remaining groups, and create a unique list. This is required for determining the host and service notification commands involved. * contact attributes `host_notification_commands` and `service_notification_commands` (can be a comma separated list) * get the command line for each notification command and store them for later * create a new notification name and command name Generate a new notification object based on these values. Import the generic template based on the type (`host` or `service`). Assign it to the host or service and set the newly generated notification command name as `command` attribute. object Notification "" { import "mail-host-notification" host_name = "" command = "" Convert the `notification_options` attribute from Icinga 1.x to Icinga 2 `states` and `types`. Details [here](23-migrating-from-icinga-1x.md#manual-config-migration-hints-notification-filters). Add the notification period. states = [ OK, Warning, Critical ] types = [ Recovery, Problem, Custom ] period = "24x7" The current contact acts as `users` attribute. users = [ "" ] } Do this in a loop for all notification commands (depending if host or service contact). Once done, dump the collected notification commands. The result of this migration are lots of unnecessary notification objects and commands but it will unroll the Icinga 1.x logic into the revamped Icinga 2 notification object schema. If you are looking for code examples, try [LConf](https://www.netways.org). #### Manual Config Migration Hints for Notification Filters Icinga 1.x defines all notification filters in an attribute called `notification_options`. Using Icinga 2 you will have to split these values into the `states` and `types` attributes. > **Note** > > `Recovery` type requires the `Ok` state. > `Custom` and `Problem` should always be set as `type` filter. Icinga 1.x option | Icinga 2 state | Icinga 2 type ----------------------|-----------------------|------------------- o | OK (Up for hosts) | w | Warning | Problem c | Critical | Problem u | Unknown | Problem d | Down | Problem s | . | DowntimeStart / DowntimeEnd / DowntimeRemoved r | Ok | Recovery f | . | FlappingStart / FlappingEnd n | 0 (none) | 0 (none) . | . | Custom #### Manual Config Migration Hints for Escalations Escalations in Icinga 1.x are a bit tricky. By default service escalations can be applied to hosts and hostgroups and require a defined service object. The following example applies a service escalation to the service `dep_svc01` and all hosts in the `hg_svcdep2` hostgroup. The default `notification_interval` is set to `10` minutes notifying the `cg_admin` contact. After 20 minutes (`10*2`, notification_interval * first_notification) the notification is escalated to the `cg_ops` contactgroup until 60 minutes (`10*6`) have passed. define service { service_description dep_svc01 host_name dep_hostsvc01,dep_hostsvc03 check_command test2 use generic-service notification_interval 10 contact_groups cg_admin } define hostgroup { hostgroup_name hg_svcdep2 members dep_hostsvc03 } # with hostgroup_name and service_description define serviceescalation { hostgroup_name hg_svcdep2 service_description dep_svc01 first_notification 2 last_notification 6 contact_groups cg_ops } In Icinga 2 the service and hostgroup definition will look quite the same. Save the `notification_interval` and `contact_groups` attribute for an additional notification. apply Service "dep_svc01" { import "generic-service" check_command = "test2" assign where host.name == "dep_hostsvc01" assign where host.name == "dep_hostsvc03" } object HostGroup "hg_svcdep2" { assign where host.name == "dep_hostsvc03" } apply Notification "email" to Service { import "service-mail-notification" interval = 10m user_groups = [ "cg_admin" ] assign where service.name == "dep_svc01" && (host.name == "dep_hostsvc01" || host.name == "dep_hostsvc03") } Calculate the begin and end time for the newly created escalation notification: * begin = first_notification * notification_interval = 2 * 10m = 20m * end = last_notification * notification_interval = 6 * 10m = 60m = 1h Assign the notification escalation to the service `dep_svc01` on all hosts in the hostgroup `hg_svcdep2`. apply Notification "email-escalation" to Service { import "service-mail-notification" interval = 10m user_groups = [ "cg_ops" ] times = { begin = 20m end = 1h } assign where service.name == "dep_svc01" && "hg_svcdep2" in host.groups } The assign rule could be made more generic and the notification be applied to more than just this service belonging to hosts in the matched hostgroup. > **Note** > > When the notification is escalated, Icinga 1.x suppresses notifications to the default contacts. > In Icinga 2 an escalation is an additional notification with a defined begin and end time. The > `email` notification will continue as normal. #### Manual Config Migration Hints for Dependencies There are some dependency examples already in the [basics chapter](03-monitoring-basics.md#dependencies). Dependencies in Icinga 1.x can be confusing in terms of which host/service is the parent and which host/service acts as the child. While Icinga 1.x defines `notification_failure_criteria` and `execution_failure_criteria` as dependency filters, this behaviour has changed in Icinga 2. There is no 1:1 migration but generally speaking the state filter defined in the `execution_failure_criteria` defines the Icinga 2 `state` attribute. If the state filter matches, you can define whether to disable checks and notifications or not. The following example describes service dependencies. If you migrate from Icinga 1.x, you will only want to use the classic `Host-to-Host` and `Service-to-Service` dependency relationships. define service { service_description dep_svc01 hostgroup_name hg_svcdep1 check_command test2 use generic-service } define service { service_description dep_svc02 hostgroup_name hg_svcdep2 check_command test2 use generic-service } define hostgroup { hostgroup_name hg_svcdep2 members host2 } define host{ use linux-server-template host_name host1 address 192.168.1.10 } # with hostgroup_name and service_description define servicedependency { host_name host1 dependent_hostgroup_name hg_svcdep2 service_description dep_svc01 dependent_service_description * execution_failure_criteria u,c notification_failure_criteria w,u,c inherits_parent 1 } Map the dependency attributes accordingly. Icinga 1.x | Icinga 2 ----------------------|--------------------- host_name | parent_host_name dependent_host_name | child_host_name (used in assign/ignore) dependent_hostgroup_name | all child hosts in group (used in assign/ignore) service_description | parent_service_name dependent_service_description | child_service_name (used in assign/ignore) And migrate the host and services. object Host "host1" { import "linux-server-template" address = "192.168.1.10" } object HostGroup "hg_svcdep2" { assign where host.name == "host2" } apply Service "dep_svc01" { import "generic-service" check_command = "test2" assign where "hp_svcdep1" in host.groups } apply Service "dep_svc02" { import "generic-service" check_command = "test2" assign where "hp_svcdep2" in host.groups } When it comes to the `execution_failure_criteria` and `notification_failure_criteria` attribute migration, you will need to map the most common values, in this example `u,c` (`Unknown` and `Critical` will cause the dependency to fail). Therefore the `Dependency` should be ok on Ok and Warning. `inherits_parents` is always enabled. apply Dependency "all-svc-for-hg-hg_svcdep2-on-host1-dep_svc01" to Service { parent_host_name = "host1" parent_service_name = "dep_svc01" states = [ Ok, Warning ] disable_checks = true disable_notifications = true assign where "hg_svcdep2" in host.groups } Host dependencies are explained in the [next chapter](23-migrating-from-icinga-1x.md#manual-config-migration-hints-host-parents). #### Manual Config Migration Hints for Host Parents Host parents from Icinga 1.x are migrated into `Host-to-Host` dependencies in Icinga 2. The following example defines the `vmware-master` host as parent host for the guest virtual machines `vmware-vm1` and `vmware-vm2`. By default all hosts in the hostgroup `vmware` should get the parent assigned. This isn't really solvable with Icinga 1.x parents, but only with host dependencies. define host{ use linux-server-template host_name vmware-master hostgroups vmware address 192.168.1.10 } define host{ use linux-server-template host_name vmware-vm1 hostgroups vmware address 192.168.27.1 parents vmware-master } define host{ use linux-server-template host_name vmware-vm2 hostgroups vmware address 192.168.28.1 parents vmware-master } By default all hosts in the hostgroup `vmware` should get the parent assigned (but not the `vmware-master` host itself). This isn't really solvable with Icinga 1.x parents, but only with host dependencies as shown below: define hostdependency { dependent_hostgroup_name vmware dependent_host_name !vmware-master host_name vmware-master inherits_parent 1 notification_failure_criteria d,u execution_failure_criteria d,u dependency_period testconfig-24x7 } When migrating to Icinga 2, the parents must be changed to a newly created host dependency. Map the following attributes Icinga 1.x | Icinga 2 ----------------------|--------------------- host_name | parent_host_name dependent_host_name | child_host_name (used in assign/ignore) dependent_hostgroup_name | all child hosts in group (used in assign/ignore) The Icinga 2 configuration looks like this: object Host "vmware-master" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.1.10" vars.is_vmware_master = true } object Host "vmware-vm1" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.27.1" } object Host "vmware-vm2" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.28.1" } apply Dependency "vmware-master" to Host { parent_host_name = "vmware-master" assign where "vmware" in host.groups ignore where host.vars.is_vmware_master ignore where host.name == "vmware-master" } For easier identification you could add the `vars.is_vmware_master` attribute to the `vmware-master` host and let the dependency ignore that instead of the hardcoded host name. That's different to the Icinga 1.x example and a best practice hint only. Another way to express the same configuration would be something like: object Host "vmware-master" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.1.10" } object Host "vmware-vm1" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.27.1" vars.parents = [ "vmware-master" ] } object Host "vmware-vm2" { import "linux-server-template" groups += [ "vmware" ] address = "192.168.28.1" vars.parents = [ "vmware-master" ] } apply Dependency "host-to-parent-" for (parent in host.vars.parents) to Host { parent_host_name = parent } This example allows finer grained host-to-host dependency, as well as multiple dependency support. #### Manual Config Migration Hints for Distributed Setups * Icinga 2 does not use active/passive instances calling OSCP commands and requiring the NSCA daemon for passing check results between instances. * Icinga 2 does not support any 1.x NEB addons for check load distribution * If your current setup consists of instances distributing the check load, you should consider building a [load distribution](06-distributed-monitoring.md#distributed-monitoring-scenarios) setup with Icinga 2. * If your current setup includes active/passive clustering with external tools like Pacemaker/DRBD, consider the [High Availability](06-distributed-monitoring.md#distributed-monitoring-scenarios) setup. * If you have build your own custom configuration deployment and check result collecting mechanism, you should re-design your setup and re-evaluate your requirements, and how they may be fulfilled using the Icinga 2 cluster capabilities. ## Differences between Icinga 1.x and 2 ### Configuration Format Icinga 1.x supports two configuration formats: key-value-based settings in the `icinga.cfg` configuration file and object-based in included files (`cfg_dir`, `cfg_file`). The path to the `icinga.cfg` configuration file must be passed to the Icinga daemon at startup. icinga.cfg: enable_notifications=1 objects.cfg: define service { notifications_enabled 0 } Icinga 2 supports objects and (global) variables, but does not make a difference between the main configuration file or any other included file. icinga2.conf: const EnableNotifications = true object Service "test" { enable_notifications = false } #### Sample Configuration and ITL While Icinga 1.x ships sample configuration and templates spread in various object files, Icinga 2 moves all templates into the Icinga Template Library (ITL) and includes them in the sample configuration. Additional plugin check commands are shipped with Icinga 2 as well. The ITL will be updated on every release and must not be edited by the user. There are still generic templates available for your convenience which may or may not be re-used in your configuration. For instance, `generic-service` includes all required attributes except `check_command` for a service. Sample configuration files are located in the `conf.d/` directory which is included in `icinga2.conf` by default. > **Note** > > Add your own custom templates in the `conf.d/` directory as well, e.g. inside > the [templates.conf](04-configuring-icinga-2.md#templates-conf) file. ### Main Config File In Icinga 1.x there are many global configuration settings available in `icinga.cfg`. Icinga 2 only uses a small set of [global constants](17-language-reference.md#constants) allowing you to specify certain different setting such as the `NodeName` in a cluster scenario. Aside from that, the [icinga2.conf](04-configuring-icinga-2.md#icinga2-conf) should take care of including global constants, enabled [features](11-cli-commands.md#enable-features) and the object configuration. ### Include Files and Directories In Icinga 1.x the `icinga.cfg` file contains `cfg_file` and `cfg_dir` directives. The `cfg_dir` directive recursively includes all files with a `.cfg` suffix in the given directory. Only absolute paths may be used. The `cfg_file` and `cfg_dir` directives can include the same file twice which leads to configuration errors in Icinga 1.x. cfg_file=/etc/icinga/objects/commands.cfg cfg_dir=/etc/icinga/objects Icinga 2 supports wildcard includes and relative paths, e.g. for including `conf.d/*.conf` in the same directory. include "conf.d/*.conf" If you want to include files and directories recursively, you need to define a separate option and add the directory and an optional pattern. include_recursive "conf.d" A global search path for includes is available for advanced features like the Icinga Template Library (ITL) or additional monitoring plugins check command configuration. include include By convention the `.conf` suffix is used for Icinga 2 configuration files. ### Resource File and Global Macros Global macros such as for the plugin directory, usernames and passwords can be set in the `resource.cfg` configuration file in Icinga 1.x. By convention the `USER1` macro is used to define the directory for the plugins. Icinga 2 uses global constants instead. In the default config these are set in the `constants.conf` configuration file: /** * This file defines global constants which can be used in * the other configuration files. At a minimum the * PluginDir constant should be defined. */ const PluginDir = "/usr/lib/nagios/plugins" [Global macros](17-language-reference.md#constants) can only be defined once. Trying to modify a global constant will result in an error. ### Configuration Comments In Icinga 1.x comments are made using a leading hash (`#`) or a semi-colon (`;`) for inline comments. In Icinga 2 comments can either be encapsulated by `/*` and `*/` (allowing for multi-line comments) or starting with two slashes (`//`). A leading hash (`#`) could also be used. ### Object Names Object names must not contain an exclamation mark (`!`). Use the `display_name` attribute to specify user-friendly names which should be shown in UIs (supported by Icinga Web 2 for example). Object names are not specified using attributes (e.g. `service_description` for services) like in Icinga 1.x but directly after their type definition. define service { host_name localhost service_description ping4 } object Service "ping4" { host_name = "localhost" } ### Templates In Icinga 1.x templates are identified using the `register 0` setting. Icinga 2 uses the `template` identifier: template Service "ping4-template" { } Icinga 1.x objects inherit from templates using the `use` attribute. Icinga 2 uses the keyword `import` with template names in double quotes. define service { service_description testservice use tmpl1,tmpl2,tmpl3 } object Service "testservice" { import "tmpl1" import "tmpl2" import "tmpl3" } The last template overrides previously set values. ### Object attributes Icinga 1.x separates attribute and value pairs with whitespaces/tabs. Icinga 2 requires an equal sign (=) between them. define service { check_interval 5 } object Service "test" { check_interval = 5m } Please note that the default time value is seconds if no duration literal is given. `check_interval = 5` behaves the same as `check_interval = 5s`. All strings require double quotes in Icinga 2. Therefore a double quote must be escaped by a backslash (e.g. in command line). If an attribute identifier starts with a number, it must be enclosed in double quotes as well. #### Alias vs. Display Name In Icinga 1.x a host can have an `alias` and a `display_name` attribute used for a more descriptive name. A service only can have a `display_name` attribute. The `alias` is used for group, timeperiod, etc. objects too. Icinga 2 only supports the `display_name` attribute which is also taken into account by Icinga web interfaces. ### Custom Attributes Icinga 2 allows you to define custom attributes in the `vars` dictionary. The `notes`, `notes_url`, `action_url`, `icon_image`, `icon_image_alt` attributes for host and service objects are still available in Icinga 2. `2d_coords` and `statusmap_image` are not supported in Icinga 2. #### Custom Variables Icinga 1.x custom variable attributes must be prefixed using an underscore (`_`). In Icinga 2 these attributes must be added to the `vars` dictionary as custom attributes. vars.dn = "cn=icinga2-dev-host,ou=icinga,ou=main,ou=IcingaConfig,ou=LConf,dc=icinga,dc=org" vars.cv = "my custom cmdb description" These custom attributes are also used as [command parameters](03-monitoring-basics.md#command-passing-parameters). While Icinga 1.x only supports numbers and strings as custom attribute values, Icinga 2 extends that to arrays and (nested) dictionaries. For more details look [here](03-monitoring-basics.md#custom-attributes). ### Host Service Relation In Icinga 1.x a service object is associated with a host by defining the `host_name` attribute in the service definition. Alternate methods refer to `hostgroup_name` or behaviour changing regular expression. The preferred way of associating hosts with services in Icinga 2 is by using the [apply](03-monitoring-basics.md#using-apply) keyword. Direct object relations between a service and a host still allow you to use the `host_name` [Service](09-object-types.md#objecttype-service) object attribute. ### Users Contacts have been renamed to users (same for groups). A contact does not only provide (custom) attributes and notification commands used for notifications, but is also used for authorization checks in Icinga 1.x. Icinga 2 changes that behavior and makes the user an attribute provider only. These attributes can be accessed using [runtime macros](03-monitoring-basics.md#runtime-macros) inside notification command definitions. In Icinga 2 notification commands are not directly associated with users. Instead the notification command is specified inside `Notification` objects next to user and user group relations. The `StatusDataWriter`, `IdoMySqlConnection` and `LivestatusListener` types will provide the contact and contactgroups attributes for services for compatibility reasons. These values are calculated from all services, their notifications, and their users. ### Macros Various object attributes and runtime variables can be accessed as macros in commands in Icinga 1.x -- Icinga 2 supports all required [custom attributes](03-monitoring-basics.md#custom-attributes). #### Command Arguments If you have previously used Icinga 1.x, you may already be familiar with user and argument definitions (e.g., `USER1` or `ARG1`). Unlike in Icinga 1.x the Icinga 2 custom attributes may have arbitrary names and arguments are no longer specified in the `check_command` setting. In Icinga 1.x arguments are specified in the `check_command` attribute and are separated from the command name using an exclamation mark (`!`). Please check the migration hints for a detailed [migration example](23-migrating-from-icinga-1x.md#manual-config-migration-hints-check-command-arguments). > **Note** > > The Icinga 1.x feature named `Command Expander` does not work with Icinga 2. #### Environment Macros The global configuration setting `enable_environment_macros` does not exist in Icinga 2. Macros exported into the [environment](03-monitoring-basics.md#command-environment-variables) can be set using the `env` attribute in command objects. #### Runtime Macros Icinga 2 requires an object specific namespace when accessing configuration and stateful runtime macros. Custom attributes can be accessed directly. If a runtime macro from Icinga 1.x is not listed here, it is not supported by Icinga 2. Changes to user (contact) runtime macros Icinga 1.x | Icinga 2 -----------------------|---------------------- CONTACTNAME | user.name CONTACTALIAS | user.display_name CONTACTEMAIL | user.email CONTACTPAGER | user.pager `CONTACTADDRESS*` is not supported but can be accessed as `$user.vars.address1$` if set. Changes to service runtime macros Icinga 1.x | Icinga 2 -----------------------|---------------------- SERVICEDESC | service.name SERVICEDISPLAYNAME | service.display_name SERVICECHECKCOMMAND | service.check_command SERVICESTATE | service.state SERVICESTATEID | service.state_id SERVICESTATETYPE | service.state_type SERVICEATTEMPT | service.check_attempt MAXSERVICEATTEMPT | service.max_check_attempts LASTSERVICESTATE | service.last_state LASTSERVICESTATEID | service.last_state_id LASTSERVICESTATETYPE | service.last_state_type LASTSERVICESTATECHANGE | service.last_state_change SERVICEDOWNTIME | service.downtime_depth SERVICEDURATIONSEC | service.duration_sec SERVICELATENCY | service.latency SERVICEEXECUTIONTIME | service.execution_time SERVICEOUTPUT | service.output SERVICEPERFDATA | service.perfdata LASTSERVICECHECK | service.last_check SERVICENOTES | service.notes SERVICENOTESURL | service.notes_url SERVICEACTIONURL | service.action_url Changes to host runtime macros Icinga 1.x | Icinga 2 -----------------------|---------------------- HOSTNAME | host.name HOSTADDRESS | host.address HOSTADDRESS6 | host.address6 HOSTDISPLAYNAME | host.display_name HOSTALIAS | (use `host.display_name` instead) HOSTCHECKCOMMAND | host.check_command HOSTSTATE | host.state HOSTSTATEID | host.state_id HOSTSTATETYPE | host.state_type HOSTATTEMPT | host.check_attempt MAXHOSTATTEMPT | host.max_check_attempts LASTHOSTSTATE | host.last_state LASTHOSTSTATEID | host.last_state_id LASTHOSTSTATETYPE | host.last_state_type LASTHOSTSTATECHANGE | host.last_state_change HOSTDOWNTIME | host.downtime_depth HOSTDURATIONSEC | host.duration_sec HOSTLATENCY | host.latency HOSTEXECUTIONTIME | host.execution_time HOSTOUTPUT | host.output HOSTPERFDATA | host.perfdata LASTHOSTCHECK | host.last_check HOSTNOTES | host.notes HOSTNOTESURL | host.notes_url HOSTACTIONURL | host.action_url TOTALSERVICES | host.num_services TOTALSERVICESOK | host.num_services_ok TOTALSERVICESWARNING | host.num_services_warning TOTALSERVICESUNKNOWN | host.num_services_unknown TOTALSERVICESCRITICAL | host.num_services_critical Changes to command runtime macros Icinga 1.x | Icinga 2 -----------------------|---------------------- COMMANDNAME | command.name Changes to notification runtime macros Icinga 1.x | Icinga 2 -----------------------|---------------------- NOTIFICATIONTYPE | notification.type NOTIFICATIONAUTHOR | notification.author NOTIFICATIONCOMMENT | notification.comment NOTIFICATIONAUTHORNAME | (use `notification.author`) NOTIFICATIONAUTHORALIAS | (use `notification.author`) Changes to global runtime macros: Icinga 1.x | Icinga 2 -----------------------|---------------------- TIMET | icinga.timet LONGDATETIME | icinga.long_date_time SHORTDATETIME | icinga.short_date_time DATE | icinga.date TIME | icinga.time PROCESSSTARTTIME | icinga.uptime Changes to global statistic macros: Icinga 1.x | Icinga 2 ----------------------------------|---------------------- TOTALHOSTSUP | icinga.num_hosts_up TOTALHOSTSDOWN | icinga.num_hosts_down TOTALHOSTSUNREACHABLE | icinga.num_hosts_unreachable TOTALHOSTSDOWNUNHANDLED | -- TOTALHOSTSUNREACHABLEUNHANDLED | -- TOTALHOSTPROBLEMS | down TOTALHOSTPROBLEMSUNHANDLED | down-(downtime+acknowledged) TOTALSERVICESOK | icinga.num_services_ok TOTALSERVICESWARNING | icinga.num_services_warning TOTALSERVICESCRITICAL | icinga.num_services_critical TOTALSERVICESUNKNOWN | icinga.num_services_unknown TOTALSERVICESWARNINGUNHANDLED | -- TOTALSERVICESCRITICALUNHANDLED | -- TOTALSERVICESUNKNOWNUNHANDLED | -- TOTALSERVICEPROBLEMS | ok+warning+critical+unknown TOTALSERVICEPROBLEMSUNHANDLED | warning+critical+unknown-(downtime+acknowledged) ### External Commands `CHANGE_CUSTOM_CONTACT_VAR` was renamed to `CHANGE_CUSTOM_USER_VAR`. The following external commands are not supported: CHANGE_*MODATTR CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD CHANGE_HOST_NOTIFICATION_TIMEPERIOD CHANGE_SVC_NOTIFICATION_TIMEPERIOD DEL_DOWNTIME_BY_HOSTGROUP_NAME DEL_DOWNTIME_BY_START_TIME_COMMENT DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST DISABLE_CONTACT_HOST_NOTIFICATIONS DISABLE_CONTACT_SVC_NOTIFICATIONS DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS DISABLE_FAILURE_PREDICTION DISABLE_HOST_AND_CHILD_NOTIFICATIONS DISABLE_HOST_FRESHNESS_CHECKS DISABLE_NOTIFICATIONS_EXPIRE_TIME DISABLE_SERVICE_FRESHNESS_CHECKS ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST ENABLE_CONTACT_HOST_NOTIFICATIONS ENABLE_CONTACT_SVC_NOTIFICATIONS ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS ENABLE_FAILURE_PREDICTION ENABLE_HOST_AND_CHILD_NOTIFICATIONS ENABLE_HOST_FRESHNESS_CHECKS ENABLE_SERVICE_FRESHNESS_CHECKS READ_STATE_INFORMATION SAVE_STATE_INFORMATION SET_HOST_NOTIFICATION_NUMBER SET_SVC_NOTIFICATION_NUMBER START_ACCEPTING_PASSIVE_HOST_CHECKS START_ACCEPTING_PASSIVE_SVC_CHECKS START_OBSESSING_OVER_HOST START_OBSESSING_OVER_HOST_CHECKS START_OBSESSING_OVER_SVC START_OBSESSING_OVER_SVC_CHECKS STOP_ACCEPTING_PASSIVE_HOST_CHECKS STOP_ACCEPTING_PASSIVE_SVC_CHECKS STOP_OBSESSING_OVER_HOST STOP_OBSESSING_OVER_HOST_CHECKS STOP_OBSESSING_OVER_SVC STOP_OBSESSING_OVER_SVC_CHECKS ### Asynchronous Event Execution Unlike Icinga 1.x, Icinga 2 does not block when it's waiting for a command being executed -- whether if it's a check, a notification, an event handler, a performance data writing update, etc. That way you'll recognize low to zero (check) latencies with Icinga 2. ### Checks #### Check Output Icinga 2 does not make a difference between `output` (first line) and `long_output` (remaining lines) like in Icinga 1.x. Performance Data is provided separately. There is no output length restriction as known from Icinga 1.x using an [8KB static buffer](https://docs.icinga.com/latest/en/pluginapi.html#outputlengthrestrictions). The `StatusDataWriter`, `IdoMysqlConnection` and `LivestatusListener` types split the raw output into `output` (first line) and `long_output` (remaining lines) for compatibility reasons. #### Initial State Icinga 1.x uses the `max_service_check_spread` setting to specify a timerange where the initial state checks must have happened. Icinga 2 will use the `retry_interval` setting instead and `check_interval` divided by 5 if `retry_interval` is not defined. ### Comments Icinga 2 doesn't support non-persistent comments. ### Commands Unlike in Icinga 1.x there are three different command types in Icinga 2: `CheckCommand`, `NotificationCommand`, and `EventCommand`. For example in Icinga 1.x it is possible to accidentally use a notification command as an event handler which might cause problems depending on which runtime macros are used in the notification command. In Icinga 2 these command types are separated and will generate an error on configuration validation if used in the wrong context. While Icinga 2 still supports the complete command line in command objects, it's recommended to use [command arguments](03-monitoring-basics.md#command-arguments) with optional and conditional command line parameters instead. It's also possible to define default argument values for the command itself which can be overridden by the host or service then. #### Command Timeouts In Icinga 1.x there were two global options defining a host and service check timeout. This was essentially bad when there only was a couple of check plugins requiring some command timeouts to be extended. Icinga 2 allows you to specify the command timeout directly on the command. So, if your VMVware check plugin takes 15 minutes, [increase the timeout](09-object-types.md#objecttype-checkcommand) accordingly. ### Groups In Icinga 2 hosts, services, and users are added to groups using the `groups` attribute in the object. The old way of listing all group members in the group's `members` attribute is available through `assign where` and `ignore where` expressions by using [group assign](03-monitoring-basics.md#group-assign-intro). object Host "web-dev" { import "generic-host" } object HostGroup "dev-hosts" { display_name = "Dev Hosts" assign where match("*-dev", host.name) } #### Add Service to Hostgroup where Host is Member In order to associate a service with all hosts in a host group the [apply](03-monitoring-basics.md#using-apply) keyword can be used: apply Service "ping4" { import "generic-service" check_command = "ping4" assign where "dev-hosts" in host.groups } ### Notifications Notifications are a new object type in Icinga 2. Imagine the following notification configuration problem in Icinga 1.x: * Service A should notify contact X via SMS * Service B should notify contact X via Mail * Service C should notify contact Y via Mail and SMS * Contact X and Y should also be used for authorization The only way achieving a semi-clean solution is to * Create contact X-sms, set service_notification_command for sms, assign contact to service A * Create contact X-mail, set service_notification_command for mail, assign contact to service B * Create contact Y, set service_notification_command for sms and mail, assign contact to service C * Create contact X without notification commands, assign to service A and B Basically you are required to create duplicated contacts for either each notification method or used for authorization only. Icinga 2 attempts to solve that problem in this way * Create user X, set SMS and Mail attributes, used for authorization * Create user Y, set SMS and Mail attributes, used for authorization * Create notification A-SMS, set command for sms, add user X, assign notification A-SMS to service A * Create notification B-Mail, set command for mail, add user X, assign notification Mail to service B * Create notification C-SMS, set command for sms, add user Y, assign notification C-SMS to service C * Create notification C-Mail, set command for mail, add user Y, assign notification C-Mail to service C Previously in Icinga 1.x it looked like this: service -> (contact, contactgroup) -> notification command In Icinga 2 it will look like this: Service -> Notification -> NotificationCommand -> User, UserGroup #### Escalations Escalations in Icinga 1.x require a separated object matching on existing objects. Escalations happen between a defined start and end time which is calculated from the notification_interval: start = notification start + (notification_interval * first_notification) end = notification start + (notification_interval * last_notification) In theory first_notification and last_notification can be set to readable numbers. In practice users are manipulating those attributes in combination with notification_interval in order to get a start and end time. In Icinga 2 the notification object can be used as notification escalation if the start and end times are defined within the 'times' attribute using duration literals (e.g. 30m). The Icinga 2 escalation does not replace the current running notification. In Icinga 1.x it's required to copy the contacts from the service notification to the escalation to guarantee the normal notifications once an escalation happens. That's not necessary with Icinga 2 only requiring an additional notification object for the escalation itself. #### Notification Options Unlike Icinga 1.x with the 'notification_options' attribute with comma-separated state and type filters, Icinga 2 uses two configuration attributes for that. All state and type filter use long names OR'd with a pipe together notification_options w,u,c,r,f,s states = [ Warning, Unknown, Critical ] types = [ Problem, Recovery, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] Icinga 2 adds more fine-grained type filters for acknowledgements, downtime, and flapping type (start, end, ...). ### Dependencies and Parents In Icinga 1.x it's possible to define host parents to determine network reachability and keep a host's state unreachable rather than down. Furthermore there are host and service dependencies preventing unnecessary checks and notifications. A host must not depend on a service, and vice versa. All dependencies are configured as separate objects and cannot be set directly on the host or service object. A service can now depend on a host, and vice versa. A service has an implicit dependency (parent) to its host. A host to host dependency acts implicitly as host parent relation. The former `host_name` and `dependent_host_name` have been renamed to `parent_host_name` and `child_host_name` (same for the service attribute). When using apply rules the child attributes may be omitted. For detailed examples on how to use the dependencies please check the [dependencies](03-monitoring-basics.md#dependencies) chapter. Dependencies can be applied to hosts or services using the [apply rules](17-language-reference.md#apply). The `StatusDataWriter`, `IdoMysqlConnection` and `LivestatusListener` types support the Icinga 1.x schema with dependencies and parent attributes for compatibility reasons. ### Flapping The Icinga 1.x flapping detection uses the last 21 states of a service. This value is hardcoded and cannot be changed. The algorithm on determining a flapping state is as follows: flapping value = (number of actual state changes / number of possible state changes) The flapping value is then compared to the low and high flapping thresholds. The algorithm used in Icinga 2 does not store the past states but calculates the flapping threshold from a single value based on counters and half-life values. Icinga 2 compares the value with a single flapping threshold configuration attribute. ### Check Result Freshness Freshness of check results must be enabled explicitly in Icinga 1.x. The attribute `freshness_threshold` defines the threshold in seconds. Once the threshold is triggered, an active freshness check is executed defined by the `check_command` attribute. Both check methods (active and passive) use the same freshness check method. In Icinga 2 active check freshness is determined by the `check_interval` attribute and no incoming check results in that period of time (last check + check interval). Passive check freshness is calculated from the `check_interval` attribute if set. There is no extra `freshness_threshold` attribute in Icinga 2. If the freshness checks are invalid, a new service check is forced. ### Real Reload In Nagios / Icinga 1.x a daemon reload does the following: * receive reload signal SIGHUP * stop all events (checks, notifications, etc.) * read the configuration from disk and validate all config objects in a single threaded fashion * validation NOT ok: stop the daemon (cannot restore old config state) * validation ok: start with new objects, dump status.dat / ido Unlike Icinga 1.x the Icinga 2 daemon reload does not block any event execution during config validation: * receive reload signal SIGHUP * fork a child process, start configuration validation in parallel work queues * parent process continues with old configuration objects and the event scheduling (doing checks, replicating cluster events, triggering alert notifications, etc.) * validation NOT ok: child process terminates, parent process continues with old configuration state (this is **essential** for the [cluster config synchronisation](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)) * validation ok: child process signals parent process to terminate and save its current state (all events until now) into the icinga2 state file * parent process shuts down writing icinga2.state file * child process waits for parent process gone, reads the icinga2 state file and synchronizes all historical and status data * child becomes the new session leader The DB IDO configuration dump and status/historical event updates use a queue not blocking event execution. Same goes for any other enabled feature. The configuration validation itself runs in parallel allowing fast verification checks. That way your monitoring does not stop during a configuration reload. ### State Retention Icinga 1.x uses the `retention.dat` file to save its state in order to be able to reload it after a restart. In Icinga 2 this file is called `icinga2.state`. The format is **not** compatible with Icinga 1.x. ### Logging Icinga 1.x supports syslog facilities and writes its own `icinga.log` log file and archives. These logs are used in Icinga 1.x to generate historical reports. Icinga 2 compat library provides the CompatLogger object which writes the icinga.log and archive in Icinga 1.x format in order to stay compatible with addons. The native Icinga 2 logging facilities are split into three configuration objects: SyslogLogger, FileLogger, StreamLogger. Each of them has their own severity and target configuration. The Icinga 2 daemon log does not log any alerts but is considered an application log only. ### Broker Modules and Features Icinga 1.x broker modules are incompatible with Icinga 2. In order to provide compatibility with Icinga 1.x the functionality of several popular broker modules was implemented for Icinga 2: * IDOUtils * Livestatus * Cluster (allows for high availability and load balancing) ### Distributed Monitoring Icinga 1.x uses the native "obsess over host/service" method which requires the NSCA addon passing the slave's check results passively onto the master's external command pipe. While this method may be used for check load distribution, it does not provide any configuration distribution out-of-the-box. Furthermore comments, downtimes, and other stateful runtime data is not synced between the master and slave nodes. There are addons available solving the check and configuration distribution problems Icinga 1.x distributed monitoring currently suffers from. Icinga 2 implements a new built-in [distributed monitoring architecture](06-distributed-monitoring.md#distributed-monitoring-scenarios), including config and check distribution, IPv4/IPv6 support, SSL certificates and zone support for DMZ. High Availability and load balancing are also part of the Icinga 2 Cluster feature, next to local replay logs on connection loss ensuring that the event history is kept in sync. icinga2-2.8.1/doc/24-appendix.md000066400000000000000000001172441322762156600162030ustar00rootroot00000000000000# Appendix ## External Commands List Additional details can be found in the [Icinga 1.x Documentation](https://docs.icinga.com/latest/en/extcommands2.html) Command name | Parameters | Description ------------------------------------------|-----------------------------------|-------------------------- PROCESS_HOST_CHECK_RESULT | ;<host_name>;<status_code>;<plugin_output> (3) | - PROCESS_SERVICE_CHECK_RESULT | ;<host_name>;<service_name>;<return_code>;<plugin_output> (4) | - SCHEDULE_HOST_CHECK | ;<host_name>;<check_time> (2) | - SCHEDULE_FORCED_HOST_CHECK | ;<host_name>;<check_time> (2) | - SCHEDULE_SVC_CHECK | ;<host_name>;<service_name>;<check_time> (3) | - SCHEDULE_FORCED_SVC_CHECK | ;<host_name>;<service_name>;<check_time> (3) | - ENABLE_HOST_CHECK | ;<host_name> (1) | - DISABLE_HOST_CHECK | ;<host_name> (1) | - ENABLE_SVC_CHECK | ;<host_name>;<service_name> (2) | - DISABLE_SVC_CHECK | ;<host_name>;<service_name> (2) | - SHUTDOWN_PROCESS | - | - RESTART_PROCESS | - | - SCHEDULE_FORCED_HOST_SVC_CHECKS | ;<host_name>;<check_time> (2) | - SCHEDULE_HOST_SVC_CHECKS | ;<host_name>;<check_time> (2) | - ENABLE_HOST_SVC_CHECKS | ;<host_name> (1) | - DISABLE_HOST_SVC_CHECKS | ;<host_name> (1) | - ACKNOWLEDGE_SVC_PROBLEM | ;<host_name>;<service_name>;<sticky>;<notify>;<persistent>;<author>;<comment> (7) | Note: Icinga 2 treats all comments as persistent. ACKNOWLEDGE_SVC_PROBLEM_EXPIRE | ;<host_name>;<service_name>;<sticky>;<notify>;<persistent>;<timestamp>;<author>;<comment> (8) | Note: Icinga 2 treats all comments as persistent. REMOVE_SVC_ACKNOWLEDGEMENT | ;<host_name>;<service_name> (2) | - ACKNOWLEDGE_HOST_PROBLEM | ;<host_name>;<sticky>;<notify>;<persistent>;<author>;<comment> (6) | Note: Icinga 2 treats all comments as persistent. ACKNOWLEDGE_HOST_PROBLEM_EXPIRE | ;<host_name>;<sticky>;<notify>;<persistent>;<timestamp>;<author>;<comment> (7) | Note: Icinga 2 treats all comments as persistent. REMOVE_HOST_ACKNOWLEDGEMENT | ;<host_name> (1) | - DISABLE_HOST_FLAP_DETECTION | ;<host_name> (1) | - ENABLE_HOST_FLAP_DETECTION | ;<host_name> (1) | - DISABLE_SVC_FLAP_DETECTION | ;<host_name>;<service_name> (2) | - ENABLE_SVC_FLAP_DETECTION | ;<host_name>;<service_name> (2) | - ENABLE_HOSTGROUP_SVC_CHECKS | ;<hostgroup_name> (1) | - DISABLE_HOSTGROUP_SVC_CHECKS | ;<hostgroup_name> (1) | - ENABLE_SERVICEGROUP_SVC_CHECKS | ;<servicegroup_name> (1) | - DISABLE_SERVICEGROUP_SVC_CHECKS | ;<servicegroup_name> (1) | - ENABLE_PASSIVE_HOST_CHECKS | ;<host_name> (1) | - DISABLE_PASSIVE_HOST_CHECKS | ;<host_name> (1) | - ENABLE_PASSIVE_SVC_CHECKS | ;<host_name>;<service_name> (2) | - DISABLE_PASSIVE_SVC_CHECKS | ;<host_name>;<service_name> (2) | - ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS | ;<servicegroup_name> (1) | - DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS | ;<servicegroup_name> (1) | - ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS | ;<hostgroup_name> (1) | - DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS | ;<hostgroup_name> (1) | - PROCESS_FILE | ;<file_name>;<delete> (2) | - SCHEDULE_SVC_DOWNTIME | ;<host_name>;<service_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (9) | - DEL_SVC_DOWNTIME | ;<downtime_id> (1) | - SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME | ;<host_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME | ;<host_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_HOST_DOWNTIME | ;<host_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - DEL_HOST_DOWNTIME | ;<downtime_id> (1) | - DEL_DOWNTIME_BY_HOST_NAME | ;<host_name>[;<service_name;>[;<start_time;>[;<comment_text;>]]] (1) | - SCHEDULE_HOST_SVC_DOWNTIME | ;<host_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_HOSTGROUP_HOST_DOWNTIME | ;<hostgroup_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_HOSTGROUP_SVC_DOWNTIME | ;<hostgroup_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_SERVICEGROUP_HOST_DOWNTIME | ;<servicegroup_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - SCHEDULE_SERVICEGROUP_SVC_DOWNTIME | ;<servicegroup_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment> (8) | - ADD_HOST_COMMENT | ;<host_name>;<persistent>;<author>;<comment> (4) | Note: Icinga 2 treats all comments as persistent. DEL_HOST_COMMENT | ;<comment_id> (1) | - ADD_SVC_COMMENT | ;<host_name>;<service_name>;<persistent>;<author>;<comment> (5) | Note: Icinga 2 treats all comments as persistent. DEL_SVC_COMMENT | ;<comment_id> (1) | - DEL_ALL_HOST_COMMENTS | ;<host_name> (1) | - DEL_ALL_SVC_COMMENTS | ;<host_name>;<service_name> (2) | - SEND_CUSTOM_HOST_NOTIFICATION | ;<host_name>;<options>;<author>;<comment> (4) | - SEND_CUSTOM_SVC_NOTIFICATION | ;<host_name>;<service_name>;<options>;<author>;<comment> (5) | - DELAY_HOST_NOTIFICATION | ;<host_name>;<notification_time> (2) | - DELAY_SVC_NOTIFICATION | ;<host_name>;<service_name>;<notification_time> (3) | - ENABLE_HOST_NOTIFICATIONS | ;<host_name> (1) | - DISABLE_HOST_NOTIFICATIONS | ;<host_name> (1) | - ENABLE_SVC_NOTIFICATIONS | ;<host_name>;<service_name> (2) | - DISABLE_SVC_NOTIFICATIONS | ;<host_name>;<service_name> (2) | - ENABLE_HOST_SVC_NOTIFICATIONS | ;<host_name> (1) | - DISABLE_HOST_SVC_NOTIFICATIONS | ;<host_name> (1) | - DISABLE_HOSTGROUP_HOST_CHECKS | ;<hostgroup_name> (1) | - DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS | ;<hostgroup_name> (1) | - DISABLE_SERVICEGROUP_HOST_CHECKS | ;<servicegroup_name> (1) | - DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS | ;<servicegroup_name> (1) | - ENABLE_HOSTGROUP_HOST_CHECKS | ;<hostgroup_name> (1) | - ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS | ;<hostgroup_name> (1) | - ENABLE_SERVICEGROUP_HOST_CHECKS | ;<servicegroup_name> (1) | - ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS | ;<servicegroup_name> (1) | - ENABLE_NOTIFICATIONS | - | - DISABLE_NOTIFICATIONS | - | - ENABLE_FLAP_DETECTION | - | - DISABLE_FLAP_DETECTION | - | - ENABLE_EVENT_HANDLERS | - | - DISABLE_EVENT_HANDLERS | - | - ENABLE_PERFORMANCE_DATA | - | - DISABLE_PERFORMANCE_DATA | - | - START_EXECUTING_HOST_CHECKS | - | - STOP_EXECUTING_HOST_CHECKS | - | - START_EXECUTING_SVC_CHECKS | - | - STOP_EXECUTING_SVC_CHECKS | - | - CHANGE_NORMAL_SVC_CHECK_INTERVAL | ;<host_name>;<service_name>;<check_interval> (3) | - CHANGE_NORMAL_HOST_CHECK_INTERVAL | ;<host_name>;<check_interval> (2) | - CHANGE_RETRY_SVC_CHECK_INTERVAL | ;<host_name>;<service_name>;<check_interval> (3) | - CHANGE_RETRY_HOST_CHECK_INTERVAL | ;<host_name>;<check_interval> (2) | - ENABLE_HOST_EVENT_HANDLER | ;<host_name> (1) | - DISABLE_HOST_EVENT_HANDLER | ;<host_name> (1) | - ENABLE_SVC_EVENT_HANDLER | ;<host_name>;<service_name> (2) | - DISABLE_SVC_EVENT_HANDLER | ;<host_name>;<service_name> (2) | - CHANGE_HOST_EVENT_HANDLER | ;<host_name>;<event_command_name> (2) | - CHANGE_SVC_EVENT_HANDLER | ;<host_name>;<service_name>;<event_command_name> (3) | - CHANGE_HOST_CHECK_COMMAND | ;<host_name>;<check_command_name> (2) | - CHANGE_SVC_CHECK_COMMAND | ;<host_name>;<service_name>;<check_command_name> (3) | - CHANGE_MAX_HOST_CHECK_ATTEMPTS | ;<host_name>;<check_attempts> (2) | - CHANGE_MAX_SVC_CHECK_ATTEMPTS | ;<host_name>;<service_name>;<check_attempts> (3) | - CHANGE_HOST_CHECK_TIMEPERIOD | ;<host_name>;<timeperiod_name> (2) | - CHANGE_SVC_CHECK_TIMEPERIOD | ;<host_name>;<service_name>;<timeperiod_name> | - CHANGE_CUSTOM_HOST_VAR | ;<host_name>;<var_name>;<var_value> (3) | - CHANGE_CUSTOM_SVC_VAR | ;<host_name>;<service_name>;<var_name>;<var_value> (4) | - CHANGE_CUSTOM_USER_VAR | ;<user_name>;<var_name>;<var_value> (3) | - CHANGE_CUSTOM_CHECKCOMMAND_VAR | ;<check_command_name>;<var_name>;<var_value> (3) | - CHANGE_CUSTOM_EVENTCOMMAND_VAR | ;<event_command_name>;<var_name>;<var_value> (3) | - CHANGE_CUSTOM_NOTIFICATIONCOMMAND_VAR | ;<notification_command_name>;<var_name>;<var_value> (3) | - ENABLE_HOSTGROUP_HOST_NOTIFICATIONS | ;<hostgroup_name> (1) | - ENABLE_HOSTGROUP_SVC_NOTIFICATIONS | ;<hostgroup_name> (1) | - DISABLE_HOSTGROUP_HOST_NOTIFICATIONS | ;<hostgroup_name> (1) | - DISABLE_HOSTGROUP_SVC_NOTIFICATIONS | ;<hostgroup_name> (1) | - ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS | ;<servicegroup_name> (1) | - DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS | ;<servicegroup_name> (1) | - ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS | ;<servicegroup_name> (1) | - DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS | ;<servicegroup_name> (1) | - ## Schemas By convention `CheckCommand`, `EventCommand`, and `NotificationCommand` objects are exported using a prefix. This is mandatory for unique objects in the command tables. Object | Prefix ------------------------|------------------------ CheckCommand | check\_ EventCommand | event\_ NotificationCommand | notification\_ ### DB IDO Schema There is a detailed documentation for the Icinga IDOUtils 1.x database schema available on [https://docs.icinga.com/latest/en/db_model.html] #### DB IDO Schema Extensions Icinga 2 specific extensions are shown below: New table: `endpointstatus` Table | Column | Type | Default | Description --------------------|--------------------|----------|---------|------------- endpoints | endpoint_object_id | bigint | NULL | FK: objects table endpoints | identity | TEXT | NULL | endpoint name endpoints | node | TEXT | NULL | local node name endpoints | zone_object_id | bigint | NULL | zone object where this endpoint is a member of New table: `endpointstatus` Table | Column | Type | Default | Description --------------------|--------------------|----------|---------|------------- endpointstatus | endpoint_object_id | bigint | NULL | FK: objects table endpointstatus | identity | TEXT | NULL | endpoint name endpointstatus | node | TEXT | NULL | local node name endpointstatus | is_connected | smallint | 0 | update on endpoint connect/disconnect endpointstatus | zone_object_id | bigint | NULL | zone object where this endpoint is a member of New tables: `zones` and `zonestatus`: Table | Column | Type | Default | Description --------------------|--------------------|----------|---------|------------- zones | zone_object_id | bigint | NULL | FK: objects table zones | parent_zone_object_id | bigint | NULL | FK: zones table zones | is_global | smallint | 0 | zone is global New columns: Table | Column | Type | Default | Description --------------------|-------------------------|----------|---------|------------- all status/history | endpoint_object_id | bigint | NULL | FK: objects table servicestatus | check_source | TEXT | NULL | node name where check was executed hoststatus | check_source | TEXT | NULL | node name where check was executed statehistory | check_source | TEXT | NULL | node name where check was executed servicestatus | is_reachable | integer | NULL | object reachability hoststatus | is_reachable | integer | NULL | object reachability logentries | object_id | bigint | NULL | FK: objects table (service associated with column) {host,service}group | notes | TEXT | NULL | - {host,service}group | notes_url | TEXT | NULL | - {host,service}group | action_url | TEXT | NULL | - customvariable* | is_json | integer | 0 | Defines whether `varvalue` is a json encoded string from custom attributes, or not servicestatus | original_attributes | TEXT | NULL | JSON encoded dictionary of original attributes if modified at runtime. hoststatus | original_attributes | TEXT | NULL | JSON encoded dictionary of original attributes if modified at runtime. Additional command custom variables populated from 'vars' dictionary. Additional global custom variables populated from 'Vars' constant (object_id is NULL). ### Livestatus Schema #### Livestatus Schema Extensions Icinga 2 specific extensions are shown below: New table: `endpoints`: Table | Column ----------|-------------- endpoints | name endpoints | identity endpoints | node endpoints | is_connected endpoints | zone New table: `zones`: Table | Column ----------|-------------- zone | name zone | endpoints zone | parent zone | global New columns: Table | Column ----------|-------------- hosts | is_reachable services | is_reachable hosts | cv_is_json services | cv_is_json contacts | cv_is_json hosts | check_source services | check_source downtimes | triggers downtimes | trigger_time commands | custom_variable_names commands | custom_variable_values commands | custom_variables commands | modified_attributes commands | modified_attributes_list status | custom_variable_names status | custom_variable_values status | custom_variables hosts | original_attributes services | original_attributes Command custom variables reflect the local 'vars' dictionary. Status custom variables reflect the global 'Vars' constant. #### Livestatus Hosts Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . display_name | string | . alias | string | same as display_name. address | string | . address6 | string | NEW in Icinga. check_command | string | . check_command_expanded | string | . event_handler | string | . notification_period | string | host with notifications: period. check_period | string | . notes | string | . notes_expanded | string | . notes_url | string | . notes_url_expanded | string | . action_url | string | . action_url_expanded | string | . plugin_output | string | . perf_data | string | . icon_image | string | . icon_image_expanded | string | . icon_image_alt | stirng | . statusmap_image | string | . long_plugin_output | string | . max_check_attempts | int | . flap_detection_enabled | int | . check_freshness | int | . process_performance_data | int | . accept_passive_checks | int | . event_handler_enabled | int | . acknowledgement_type | int | Only 0 or 1. check_type | int | . last_state | int | . last_hard_state | int | . current_attempt | int | . last_notification | int | host with notifications: last notification. next_notification | int | host with notifications: next notification. next_check | int | . last_hard_state_change | int | . has_been_checked | int | . current_notification_number | int | host with notifications: number. total_services | int | . checks_enabled | int | . notifications_enabled | int | . acknowledged | int | . state | int | . state_type | int | . no_more_notifications | int | notification_interval == 0 && volatile == false. last_check | int | . last_state_change | int | . last_time_up | int | . last_time_down | int | . last_time_unreachable | int | . is_flapping | int | . scheduled_downtime_depth | int | . active_checks_enabled | int | . modified_attributes | array | . modified_attributes_list | array | . check_interval | double | . retry_interval | double | . notification_interval | double | host with notifications: smallest interval. low_flap_threshold | double | flapping_threshold high_flap_threshold | double | flapping_threshold latency | double | . execution_time | double | . percent_state_change | double | flapping. in_notification_period | int | host with notifications: matching period. in_check_period | int | . contacts | array | host with notifications, users and user groups. downtimes | array | id. downtimes_with_info | array | id+author+comment. comments | array | id. comments_with_info | array | id+author+comment. comments_with_extra_info | array | id+author+comment+entry_type+entry_time. custom_variable_names | array | . custom_variable_values | array | . custom_variables | array | Array of custom variable array pair. parents | array | Direct host parents. childs | array | Direct host children (Note: `childs` is inherited from the origin MK_Livestatus protocol). num_services | int | . worst_service_state | int | All services and their worst state. num_services_ok | int | All services with Ok state. num_services_warn | int | All services with Warning state. num_services_crit | int | All services with Critical state. num_services_unknown | int | All services with Unknown state. worst_service_hard_state | int | All services and their worst hard state. num_services_hard_ok | int | All services in a hard state with Ok state. num_services_hard_warn | int | All services in a hard state with Warning state. num_services_hard_crit | int | All services in a hard state with Critical state. num_services_hard_unknown | int | All services in a hard state with Unknown state. hard_state | int | Returns OK if state is OK. Returns current state if now a hard state type. Returns last hard state otherwise. staleness | int | Indicates time since last check normalized onto the check_interval. groups | array | All hostgroups this host is a member of. contact_groups | array | All usergroups associated with this host through notifications. services | array | All services associated with this host. services_with_state | array | All services associated with this host with state and hasbeenchecked. services_with_info | array | All services associated with this host with state, hasbeenchecked and output. Not supported: `initial_state`, `pending_flex_downtime`, `check_flapping_recovery_notification`, `is_executing`, `check_options`, `obsess_over_host`, `first_notification_delay`, `x_3d`, `y_3d`, `z_3d`, `x_2d`, `y_2d`, `filename`, `pnpgraph_present`. #### Livestatus Hostgroups Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . alias | string | `display_name` attribute. notes | string | . notes_url | string | . action_url | string | . members | array | . members_with_state | array | Host name and state. worst_host_state | int | Of all group members. num_hosts | int | In this group. num_hosts_pending | int | . num_hosts_up | int | . num_hosts_down | int | . num_hosts_unreach | int | . num_services | int | Number of services associated with hosts in this hostgroup. worst_services_state | int | . num_services_pending | int | . num_services_ok | int | . num_services_warn | int | . num_services_crit | int | . num_services_unknown | int | . worst_service_hard_state | int | . num_services_hard_ok | int | . num_services_hard_warn | int | . num_services_hard_crit | int | . num_services_hard_unknown | int | . #### Livestatus Services Table Attributes Key | Type | Note ----------------------|-----------|------------------------- description | string | . display_name | string | . alias | string | same as display_name. check_command | string | . check_command_expanded | string | . event_handler | string | . notification_period | string | host with notifications: period. check_period | string | . notes | string | . notes_expanded | string | . notes_url | string | . notes_url_expanded | string | . action_url | string | . action_url_expanded | string | . plugin_output | string | . perf_data | string | . icon_image | string | . icon_image_expanded | string | . icon_image_alt | stirng | . statusmap_image | string | . long_plugin_output | string | . max_check_attempts | int | . flap_detection_enabled | int | . check_freshness | int | . process_performance_data | int | . accept_passive_checks | int | . event_handler_enabled | int | . acknowledgement_type | int | Only 0 or 1. check_type | int | . last_state | int | . last_hard_state | int | . current_attempt | int | . last_notification | int | service with notifications: last notification. next_notification | int | service with notifications: next notification. next_check | int | . last_hard_state_change | int | . has_been_checked | int | . current_notification_number | int | service with notifications: number. checks_enabled | int | . notifications_enabled | int | . acknowledged | int | . state | int | . state_type | int | . no_more_notifications | int | notification_interval == 0 && volatile == false. last_check | int | . last_state_change | int | . last_time_ok | int | . last_time_warning | int | . last_time_critical | int | . last_time_unknown | int | . is_flapping | int | . scheduled_downtime_depth | int | . active_checks_enabled | int | . modified_attributes | array | . modified_attributes_list | array | . check_interval | double | . retry_interval | double | . notification_interval | double | service with notifications: smallest interval. low_flap_threshold | double | flapping_threshold high_flap_threshold | double | flapping_threshold latency | double | . execution_time | double | . percent_state_change | double | flapping. in_notification_period | int | service with notifications: matching period. in_check_period | int | . contacts | array | service with notifications, users and user groups. downtimes | array | id. downtimes_with_info | array | id+author+comment. comments | array | id. comments_with_info | array | id+author+comment. comments_with_extra_info | array | id+author+comment+entry_type+entry_time. custom_variable_names | array | . custom_variable_values | array | . custom_variables | array | Array of custom variable array pair. hard_state | int | Returns OK if state is OK. Returns current state if now a hard state type. Returns last hard state otherwise. staleness | int | Indicates time since last check normalized onto the check_interval. groups | array | All hostgroups this host is a member of. contact_groups | array | All usergroups associated with this host through notifications. host_ | join | Prefix for attributes from implicit join with hosts table. Not supported: `initial_state`, `is_executing`, `check_options`, `obsess_over_service`, `first_notification_delay`, `pnpgraph_present`. #### Livestatus Servicegroups Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . alias | string | `display_name` attribute. notes | string | . notes_url | string | . action_url | string | . members | array | CSV format uses `host|service` syntax. members_with_state | array | Host, service, hoststate, servicestate. worst_service_state | int | . num_services | int | . num_services_pending | int | . num_services_ok | int | . num_services_warn | int | . num_services_crit | int | . num_services_unknown | int | . num_services_hard_ok | int | . num_services_hard_warn | int | . num_services_hard_crit | int | . num_services_hard_unknown | int | . #### Livestatus Contacts Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . alias | string | `display_name` attribute. email | string | . pager | string | . host_notification_period | string | . service_notification_period | string | . host_notifications_enabled | int | . service_notifications_enabled | int | . in_host_notification_period | int | . in_service_notification_period | int | . custom_variable_names | array | . custom_variable_values | array | . custom_variables | array | Array of customvariable array pairs. modified_attributes | array | . modified_attributes_list | array | . Not supported: `can_submit_commands`. #### Livestatus Contactgroups Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . alias | string | `display_name` attribute. members | array | . #### Livestatus Commands Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | 3 types of commands in Icinga 2. line | string | . #### Livestatus Status Table Attributes Key | Type | Note ----------------------|-----------|------------------------- connections | int | Since application start. connections_rate | double | . service_checks | int | Since application start. service_checks_rate | double | . host_checks | int | Since application start. host_checks_rate | double | . external_commands | int | Since application start. external_commands_rate | double | . nagios_pid | string | Application PID. enable_notifications | int | . execute_service_checks | int | . accept_passive_service_checks | int | . execute_host_checks | int | . accept_passive_host_checks | int | . enable_event_handlers | int | . check_service_freshness | int | . check_host_freshness | int | . enable_flap_detection | int | . process_performance_data | int | . check_external_commands | int | Always enabled. program_start | int | In seconds. last_command_check | int | Always. interval_length | int | Compatibility mode: 60. num_hosts | int | . num_services | int | . program_version | string | 2.0. livestatus_active_connections | string | . Not supported: `neb_callbacks`, `neb_callbacks_rate`, `requests`, `requests_rate`, `forks`, `forks_rate`, `log_messages`, `log_messages_rate`, `livechecks`, `livechecks_rate`, `livecheck_overflows`, `livecheck_overflows_rate`, `obsess_over_services`, `obsess_over_hosts`, `last_log_rotation`, `external_command_buffer_slots`, `external_command_buffer_usage`, `external_command_buffer_max`, `cached_log_messages`, `livestatus_queued_connections`, `livestatus_threads`. #### Livestatus Comments Table Attributes Key | Type | Note ----------------------|-----------|------------------------- author | string | . comment | string | . id | int | legacy_id. entry_time | string | Seconds. type | int | 1=host, 2=service. is_service | int | . persistent | int | Always. source | string | Always external (1). entry_type | int | . expires | int | . expire_time | string | Seconds. service_ | join | Prefix for attributes from implicit join with services table. host_ | join | Prefix for attributes from implicit join with hosts table. #### Livestatus Downtimes Table Attributes Key | Type | Note ----------------------|-----------|------------------------- author | string | . comment | string | . id | int | legacy_id. entry_time | string | Seconds. type | int | 1=active, 0=pending. is_service | int | . start_time | string | Seconds. end_time | string | Seconds. fixed | int | 0=flexible, 1=fixed. duration | int | . triggered_by | int | legacy_id. triggers | int | NEW in Icinga 2. trigger_time | string | NEW in Icinga 2. service_ | join | Prefix for attributes from implicit join with services table. host_ | join | Prefix for attributes from implicit join with hosts table. #### Livestatus Timeperiod Table Attributes Key | Type | Note ----------------------|-----------|------------------------- name | string | . alias | string | `display_name` attribute. in | int | Current time is in timeperiod or not. #### Livestatus Log Table Attributes Key | Type | Note ----------------------|-----------|------------------------- time | int | Time of log event (unix timestamp). lineno | int | Line number in `CompatLogger` log file. class | int | Log message class: 0=info, 1=state, 2=program, 3=notification, 4=passive, 5=command. message | string | Complete message line. type | string | Text before the colon `:`. options | string | Text after the colon `:`. comment | string | Comment if available. plugin_output | string | Check output if available. state | int | Host or service state. state_type | int | State type if available. attempt | int | Current check attempt. service_description | string | . host_name | string | . contact_name | string | . command_name | string | . current_service_ | join | Prefix for attributes from implicit join with services table. current_host_ | join | Prefix for attributes from implicit join with hosts table. current_contact_ | join | Prefix for attributes from implicit join with contacts table. current_command_ | join | Prefix for attributes from implicit join with commands table. #### Livestatus Statehist Table Attributes Key | Type | Note ----------------------|-----------|------------------------- time | int | Time of log event (unix timestamp). lineno | int | Line number in `CompatLogger` log file. from | int | Start timestamp (unix timestamp). until | int | End timestamp (unix timestamp). duration | int | until-from. duration_part | double | duration / query_part. state | int | State: 0=ok, 1=warn, 2=crit, 3=unknown, -1=notmonitored. host_down | int | Host associated with the service is down or not. in_downtime | int | Host/service is in downtime. in_host_downtime | int | Host associated with the service is in a downtime or not. is_flapping | int | Host/service is flapping. in_notification_period | int | Host/service notification periods match or not. notification_period | string | Host/service notification period. host_name | string | . service_description | string | . log_output | string | Log file output for this state. duration_ok | int | until-from for OK state. duration_part_ok | double | . duration_warning | int | until-from for Warning state. duration_part_warning | double | . duration_critical | int | until-from for Critical state. duration_part_critical | double | . duration_unknown | int | until-from for Unknown state. duration_part_unknown | double | . duration_unmonitored | int | until-from for Not-Monitored state. duration_part_unmonitored | double | . current_service_ | join | Prefix for attributes from implicit join with services table. current_host_ | join | Prefix for attributes from implicit join with hosts table. Not supported: `debug_info`. #### Livestatus Hostsbygroup Table Attributes All [hosts](24-appendix.md#schema-livestatus-hosts-table-attributes) table attributes grouped with the [hostgroups](24-appendix.md#schema-livestatus-hostgroups-table-attributes) table prefixed with `hostgroup_`. #### Livestatus Servicesbygroup Table Attributes All [services](24-appendix.md#schema-livestatus-services-table-attributes) table attributes grouped with the [servicegroups](24-appendix.md#schema-livestatus-servicegroups-table-attributes) table prefixed with `servicegroup_`. #### Livestatus Servicesbyhostgroup Table Attributes All [services](24-appendix.md#schema-livestatus-services-table-attributes) table attributes grouped with the [hostgroups](24-appendix.md#schema-livestatus-hostgroups-table-attributes) table prefixed with `hostgroup_`. icinga2-2.8.1/doc/CMakeLists.txt000066400000000000000000000020671322762156600163620ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. file(GLOB DOCSRCS "*.md") if(UNIX OR CYGWIN) install( FILES icinga2.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8 ) endif() install( FILES ${DOCSRCS} DESTINATION ${CMAKE_INSTALL_DOCDIR}/markdown ) install( DIRECTORY images DESTINATION ${CMAKE_INSTALL_DOCDIR}/markdown ) icinga2-2.8.1/doc/icinga2.8000066400000000000000000000054641322762156600152330ustar00rootroot00000000000000.TH ICINGA2 "8" "October 2015" "icinga2 - The Icinga 2 network monitoring daemon" .SH NAME icinga2 \- The Icinga 2 network monitoring daemon .SH SYNOPSIS .B icinga2 .I command [ .I command options ][ .I global options ] .I command := [ .B api | console | daemon | feature | node | object | pki | repository | troubleshoot | variable ] .B --help .SH DESCRIPTION Icinga 2 is an open source monitoring system which checks the availability of your network resources, notifies users of outages, and generates performance data for reporting. Scalable and extensible, Icinga 2 can monitor large, complex environments across multiple locations. .SH OPTIONS Details for specific command options can be viewed by invoking the command name with .B --help parameter. .SS Global options .TP .B -h,--help Show this help message. .TP .B -V,--version Show version information. .TP .B --color Use VT100 color codes even when stdout is not a terminal. .TP .BI "-D, --define" " arg" Define a constant. .TP .BI "-l, --library" " arg" Load a library. .TP .BI "-I, --include" " arg" Add include search directory. .TP .BI "-x, --log-level" " [ debug | notice | information | warning | critical ]" Specify the log level for the console log, default is .B information. .TP .BI "-X, --script-debugger" Enables the script debugger. When an exception occurs or the 'debugger' keyword is encountered in a user script Icinga 2 launches the script debugger that allows the user to debug the script. .SS daemon options The CLI command daemon provides the functionality to start/stop Icinga 2. Furthermore it provides the configuration validation. .TP .BI "-c, --config" " arg" Using this option you can specify one or more configuration files. Config files are processed in the order they are specified on the command-line. When no configuration file is specified and the .B --no-config is not used, Icinga 2 automatically falls back to using the configuration file .B SysconfDir + "/icinga2/icinga2.conf" (where SysconfDir is usually .BI "/etc" ")." .TP .B "-z, --noconfig" Start without a configuration file. .TP .B "-C, --validate" This option can be used to check if your configuration files contain errors. If any errors are found the exit status is 1, otherwise 0 is returned. .TP .BI "-e, --errorlog" " arg" Log fatal errors to the specified log file (only works in combination with .BR "--daemonize" ")." .TP .B "-d, --daemonize" Detach from the controlling terminal. .SH "REPORTING BUGS" Report bugs at .br Icinga home page: .SH COPYRIGHT Copyright \(co 2012\-2014 Icinga Development Team (https://www.icinga.com) License GPLv2+: GNU GPL version 2 or later .br This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. icinga2-2.8.1/doc/images/000077500000000000000000000000001322762156600150625ustar00rootroot00000000000000icinga2-2.8.1/doc/images/advanced-topics/000077500000000000000000000000001322762156600201265ustar00rootroot00000000000000icinga2-2.8.1/doc/images/advanced-topics/flapping-state-graph.png000066400000000000000000000177041322762156600246620ustar00rootroot00000000000000PNG  IHDR-~IDATxlWWm`IA(a1cIJ%# Hb\ nk3]Ddqn#|0*J5dhb'ݰ+رQ(:nqy>O"{{=|~m=spႎ9yiڵZhQ"b ]wu={^}>Qk.M>]SL߯.IUUUiӦVǏD~X_0g{Z[[5vX m⎎_6M0A?tE-]T[nU{{Rmhhƍ%_:( ?,X0jѺt钤E}-[8w)w}={^Qc}} ?;€ n % mۦu]5G?.}ݪR]]$0Kv>}ZЇt>_?w6nܨgϪUSL)P?,YRsz饗TSS3gHvIyX_0o|((D*p:( #2pm͋!($ F/Bϟѣ|ܹs*//7'͚1cYD.%%y>V<Ў$F|Pׯ/8q6lPگ~+UVV:VGGYD!QCX?gQhGz#kӧck__۲eK1o߮*M6M:~$ȑ#7o֮]EEsՖ-[T__jkO|IUVVj޼yz篊S(Pvlw^ϟ3(# wUyy$Iua͜9S'N$s=O~>Р7JZ[[5vvnmm_K~ӟcQ8=zTz7եŋ_B0C5ۇy>V<Ў$F:?;C &ŋjhhЮ]٩2:uJgKwG֥K(~gM:UQ=ZbE^~e(K ۇy>V<Ў$F'|Rk֬dIҮ]}N?5|IROOqu]UUU:I[n)lmmՔ)SR(x 544QH%CX?gQhGz#ٟ'}֣>o}[_?~XK/FgΜ$ܹOwPgѪUw^(K ۇy>V<Ў$FtMQsss3gwܡHiK.$>}ZZ`$?QxaM8Q:,YB|xɺaP;/~Gڑ^Hzjx㍺xbk =z$IZ`h":tH&MC=% Ȝ[oUsj̙}Mqʮ>΋~v$0z+T(я~Da܇keb}yDIu 7ѣQCC6m{B0C5ۇy>V<Ў$=M6MSNղeˮB! ¸elvY?B; MD!QCX?gQhGz($ >]}(۝gu?# HB/6Da܇keb}yDI&(Pvlw^ϟ3(# Dqʮ>΋~v$B0C5ۇy>V<Ў$`QH}(fP;/~Gڑ^l" ¸elvY?B; MD!QCX?gQhGz($ >]}(۝gu?# HB/6Da܇keb}yDI&(Pvlw^ϟ3(# Dqʮ>΋~v$B0C5ۇy>V<Ў$`QH}(fP;/~Gڑ^l" ¸elvY?B; MD!QCX?gQhGz($ >]}(۝gu?# HB/6Da܇keb}yDI&(Pvlw^ϟ3(# Dqʮ>΋~v$B0C5ۇy>V<Ў$`QH}(fP;/~Gڑ^l" ¸elvY?B; MD!QCX?gQhGz($ /~4'}(۝gu?# HB/6DaC>ϋp;(# DWmjjz~6~|o^L΋y! HB/6DkRtCl}Qhk? Ǐ>=z/^Yfi}… նm$DC9/GښG?0$Ǟ={4{{Gr>Q/|Aׯ/~QH8qDyD# KB/~<쳪.\X{Nuuu.~QH8qDyD# KB/~۷Ov[=ԧ>;V7x֮]{Bǡ# m# mQ]zɓ3fZZZ|ҥK۴sNh„ ?*+# Br^"(5(VDavI{L3fPPйst }ӟuҥ>p޽jjjӧ϶( D>DQhkQhk?|Daee$Ѹq㢈$`QH8qDyDBAJ$8LB/6 7 ;65etbYO>WPAhtm( IjSy>/P^,q^lZn]Ç>|\;v숊CzJ!>|'3f5661( Zpa1+**FT " RBHB{"{ m'5j(5JIQT(4cƌKBSL⯻pE#QrQ\+---;w6oެZ~:p>qҗTۧ}#Q]]K~- 7V]~'Ig>ٳgKΝ 7ܠzK'NESOiŊcBE #(z̙:r䈞yo.\P+(1XVVVQ>`jnnֶm4vXUVV?ƍӛoY밈(" wڥ˗lyAp'O7߬cǎI?Ċ(Pب~BIzWUSS3gjo~S 0(:\sw\:Xa,uo`C DuvX;iB=C<cǎ!۱cG[;zcXs! +%|D\ee堳*++4+6DuvX;IB}\y66/zcXs qJ.s;kܹÚ:Xa,uD!u(zmByBabCTg=cΑ(R%|D\mmUjkkiVlb\w,9@?\yזe=tDuvX;;Pr9G]";Ǽ?]/QQo}M8QRwwkժUgI[|5j('/$@KC›`ZxqgΜQyyΒ%"I΢+y_4i;t*bz?ϻ7\/QQoe}_ӧ,)K;y+q!f?OJ?ppDaHD!vgg&N[<>:%i6~Xw%o8^0$\ukZtN:|4ةST^^r%IR'Od?]/QQo4a< QQoB1ycp(d< QQoB1ycp(d< QQoB1ycpV6lYzY6lвe˘<1yY( (7Qsw:<1y̳;CQo:;;_Zwݻ+8b<1ݼ믿QD!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@D!D@lґ#LmIENDB`icinga2-2.8.1/doc/images/advanced-topics/icinga2_external_checks_freshness_icingaweb2.png000066400000000000000000000725361322762156600315610ustar00rootroot00000000000000PNG  IHDRS iCCPICC ProfileHTSY{@@J^( "28cAEˀR:ĂT>Ae,P,ag97w|{߻|XA ,@*?CNl.pc20d#c:Wr@L8TO#-f^! >2És6qs3䁰<&@GLv"C&#l/EؙeqE$5u "lO>xXˬtA +<Z sA,Ym 33?\o<=gQr< 2!,\$,3$< yNb1|L,5sT1SA͠!%LhvܽW읂 11ZpBC}%B̨ 伺vE̹z@e0Ex?B@$X ؀ R`(`*!pԂ$hgp}`<b0 ^ LA(R4 ]3@AP$ %B|HBb:W]04( jn?48.p5| n/7X 'QEB)4Q(:B% "TՈ@uĨqg4MEЦhG/:F7KZt z=`T1 IĬb05fef*bvX_l$6 [=mvb#I39q,\w ww7'5xo|ǗS.H G[QQOt"Fe#;E' Hyr U03YlD GEmN}; GqDQ2((u'ORT)3)GjTTmi]i79eҧoIddC{Ю0谺%#nDD"ۢpQaQ5Q+VY9m]=JU֪kUV>#Ê9 dU&q&WWnXS|i҄NǸ.28σW{t(cr`T|jlj;_̿F}M֚~P NsHۓ6!֤C2&Gd A4YimSYYlss~Y^^ו)wx І ]7lɫDܔfy~i; F~PPX8qˡ?~juEe_K%m zn?cpRҜґ]v.~O̞kee۱kbҽi?}`!CŇ^OUK^uaώK]JMqͷڠKuvuuQرc}=56V5)6'D'^I]OLm.jZ[&Zȶvǎ~;zFLY>s~S9~!HWLË^ZqW\v>kگӯްc|fsmo-[m}}Kv}+wwo , 7=$ǹ~72L={yTXq'տ$y{|-xFyV\y gƼ^|9Jjjo?]왈}#|3wM2'|H0_¿ 595 222 e@IDATxU߻ -!b;gwwbXX(ݝܝg{XrO̙xΜyg9#`0F@J0F#`SV0F#&5F#`)F#`m6ă6#`0F`w%`[0F|!`b*_0Z$F#`JzF#`@01/-#`0F`w%`bjw=Vn#`0F _0F#(b Κ5Km=7nsŋeƌoŊp;֭ Qϗ[_\j\~ҿ93dΜ9V#`0LH 6W_-k׮CHp ս+^{;[o۷GB|w9;:5x`2eJ9c=ۥ~N#`0AHbŊIR$ Euw]w%'O'F 7oW_}U~ꪫ'p>+B^y! 6l\yN0N4mq5JenѣenO>$+p:tlڴIyܱ&Lpe|=^xN8y""k/F|8Ṫ\r m0F.),^jl%J^yL J͚5N:N BxLؠAsub>Yv~ٍ7(~+WNj׮MAwqn<7/؆C 0 CE,~,Z =R~}7tZx|cΔN5k.3#`0;@3EG^lY7I^~eiѢ=dI! ۋʯ+VtB OS ddRJ& /`%KM쳏 ^{ &ɳܨۻ' /f>-/xzNg"Czٱ_#`0;@LtMsի%\:aDav9Rj"o|̃z駝xiذatX/6, V } 29.{NN;4'Øׅxnߙ6≡ghw5g1{{|0\2e0 70͌0FLڙ*y[t O]|Y>0F`"`bj:;$7x{;$0F]@xooY7F#`vq&vh7F#`v,S;n0Fv;v̜9sGh7F#`vg;LL^#>;f̘OZ8SϗO?].bvn"-O$9xݺu3-W*7; ~/^rVam0F݅@=͇Yl{ynwG>;Gr`;VreJ"EӦMsfrKwǛK% K/'a? aXܽ .Ba &cF#`BSx>ktҸqcԩSs-',(n{ݺus+A'Gu? D?{Ϙ8gqt}?'4h}h2L^rI|[m~_n~ΝhB!uO|u͛7??CoF 4yk|_~R]w!` 駟o #`]0/;vyM֯_:O߅ꪫ #>jpx7wqnƍ B͚5KF!>3ׯypċ ~燏SO=%CuE w|[m~_nI5i;.~(D)\)/(fi&Căݻs8~w9\<ŜoM<9*|*Uȵ^[n}\k0F`W!P(biӦnnAٳֶm[)[묿9c0@e#o ^,$6&^92Dz 'N(ڵsKF1^_SgcL;^|k0Fm.i/] HO"$iacjfǧHݮISRrz#㻨ˆ -!-C9jh TownRDZ LVgָ_(+H#`=ھU$55#T}UȶmbDڜNmDaUtȪHS5~\tV0uD-E]>8|,2BlOd,]r⪊b%ERUO,#aٸDEzF#`BTV S6:=#FbqxEl\B)%D/ :1] 舐aN oNUi rjXNHju*p;iZ1E7e d#`0 .L!v|1,!MBUP[dW:oRp˳JZ!^(Đ"2}U"kDS -uwn"j^X_f:Ƨ1F~1#`0ESFDaR'buhzZ&tHnsa7B'3dyie*Ë&ĪmCRV WK!۷lt1,Tl#`( ELRaO$hɯp BIOu:yZ77AXycb"c/Ui{NJW|ENk)ojKSq!7STE6mZ ݗOQzNgbʴRc֡8ņu#`0Fh(p15TY(, ȡϦH!ݰhM2I<4ExNޑV] 4 q=Y 2xLuC.KCVaOap&ް KÂ/~#egF#`A V-껽cl{s΋/֧' #ށ:C|sFyc@mF#`NA 0VY/4}(3#`0F'Z\F#`Έ#`إڥNe#`Έ#`إ]nŋK]zaӋqF0w칧> [f/_^B"!۷oݘSʊ+Xbҭ[7wnq1F\!v煤U!M;Uv焤)楜kFqٰAO1 "vB"s4֭ 9DG?Ca=g}^h/rE *'Fyyeʕ99#`@ g!.k|%;e@8)Žs59*swj~ce)~v"$MV ˈs`9se۶mr 7HժU{q"˗;;7b}k囧',YRJqlwY''rx .mk0G Zl|}+ ;!Mx֏YK Ir"L0}{Cټ&ctn!Y4&>~q$zBRFG~/xRe[Di|Tԏ}AփR!H|7i8cʟ͛7 COW]uUtnJv W^qW^ү_?}ܸq2|YtNS۷ޭ_~Y8 ={K0 a:(!^:tdȑRZ59Ӥ^zEIٲe\9=i1F^u2ejWL!'NA!)'O,۷C ry繡 &țo)%Jp^N:bz{'M4O>뤓Nf͚]ʱ+KvzU|_KŊ]>(KFNK>ck/8j*9ӓ ʭ8iۯ0F$'Pn>'ÇKW IŤBCnOJgHϻS"Y:ȧ_?E_"DT="URX!yO]11=JoH!)g21|S/7?AQ*8T%o.LuB v; I rٴi4nX.B7!@,o<.K7xC-[&]tqa4[T?~/{?>zhj޼O|.7qtA#~.Ry]x؇:#/ ]Q!r֯_߉*U26jK:t [v1cƸbFc=&}q×r0tW|#NQ_|EY0߉K/95jegJڵG`3j(9cdɒ%*x9$RSe#`@(TJRΕl@TkrCl ~;Q48,Ea IOf*T#q>J%NHo/NmEڟ"5k>!nxڨ)jbBR`o/.[և;MCfV$?8q7D6ִiSYN| %SO:iǍ7˃06miƉ ?B`a~^nݺ7?Ȑ!Ce˖rG/| {WJZ1̙#^xyuYծ];Ç Ҽ`v0 O/ʇ8D(ƖbԣG8p{N*W 6zL6`p;DPNǍey>z͝;y|WڲEF(^$ΧOq?s`'-Z$ 1c0F,M#a]׵;WEMsH-1+"G^JUa7)*k@u9`i#:t&c3tLg7aK&7ӱ3<<)ACl03ȬYg+p;o6[fX a'1i$9s\YX_,[ãےchMR䘏"ޅy:L7ǰ<5{"A9D=mٓ`_h !V[/?+hlcpg7Jё3K.ąa>^38bp,'p[܇ռyY2N[:=llܶn0Fv TJZ.m>aIl8y\("fڞCtCS~ށm>"Tѣ ~K ṥeߑ7&,{_-GK?҉aTF-k]%#`0v 1aitHS;} 9a9<, KCRaH|Qaa8)2|vI)* ّ.W2S׻Ӆp|!39HUoB#`0F N1̷yGoioʪ pIH9!Y~~;a#ű둽qGD$A,v7ֱλZN>\M+ʼn:E^c5#`0F`w'SxUG7aJ":WiNd1Oc^:=#&ouNVF:~{>DW0F#K)HY߬y|S;'y=7qKd!ץKeۀ.ƒذ-UwN*"*9ύ+Hd&4a,Άr騷R&)kB uOYQv%~e ؽw2yrly9 K@US=zy{[|˿R~:vRLB旕va{JH;Pzٞk_gJ]xGj.ucRņYNTWY9J̀/}q{uXO&He\ߴ}h,8]3S~=,~ rS/<~AlJ'>;roǙ!Axcgzo?{Et*roSzxZEN:Fz]#Zֺ1[ofB:Gztqu3 QxBoq~cP"툃m "f3 ǵvx-Jēz⺭$W_~XV>2MVz`3ozj"[5uu'X\/^}f_Vׁ?>7qJq*zSm89HVf=_3SIʪ\Pڅ}sH}Foh ڧ-hş&*3mi_Ŝ.b*N^H!S~Mtz6Z{>~\v hޛIP khTUn׋ԟsO*Xiz('-NqL'kz[2\ERw~:>~UhXڥt25Cc,[:Mo*%.o6)NFYʫhI2Lj u/Q==6!/jؑ!<cQ*?[ Ywɼ)(k7ȳ{ЉRQ잲w=#Qi4X`=Guus6t8pHĈrv:֝Th N΅h9Q篔t2j-c@Y ~!l5ԝ VwuTKh'0] K c~}B¹5%ꁊgS;E) laoo SwX` ek#CjyTzs>IVZڜ2D; ӎꢟ-WT@uюɯ^$O\.K:P;Z֭~&/yV_|-#=4N-yVzE5/pluP^= 9c$i?iq(1'H$YvK\V͕BoR.嵭m yzg>kn7|pNOY ,=ITٗ:`n s2>];Bkm,CVk=߭Lo |0Fۤ!*֫n'8+mG^O7M4m$9E\23TZ=O`G˖@nbbhK6hGRLԻk;Itq7Vu:pRqœ:Lr6^֥݅0Bo> 蠫_/ {I'"re88Mk5w/iW9}iɳ:v sUt:?+h?wZ*Bࡩ$sMoJR% ηX;zQ~_'q9:|Fͣz eax\wf򏇴..!<4 ~~rt?(mlc={Dʼnz'{{3b8F;b_ea~qti~аk44'+lAms6y,Oo8EϿ(wrߩmE|dvc;:,`zqdRR*1 s#Z?cǔPaR"ֺp(kyY9UZnۯҮܪ5_%(4ԋ[E;|5N:L"33vFs؝eX,IoҜܼܠFq:E״-eRTB䇥k\!Idss6oTzck1O/ѡ'kq-~fz{Z.jk2âp=QQmq#CZ$ϫ>'8&z]X?I돲*7dnd]gvd{p B;F;4i^We9^4x'h$D;$i#zb{ICjWp #Q 2:s,^Qq6Hq;U^k뵵 xP" a(zM:zQ= *Ph1wz;^ء)wa1OV~6DORyۜ66/Ig O1WVm DhݹPibK}c+{R=<ƑVI.z0VnRu=je4kQC.m|HP ;u "RYdc~ fT pߨvxvbϚK(+Mϟۚ{D&U;!{uᣱ5W<*9g$]zq8miP ݵM2ukc8rdzMejse&r3ZpUV<7 TM?:{V4YFHT}Ch!hD,I}NtAJDi}(;B*z))ہ1DԶnuжyzyD2\GV~_ڤsGhl`rL [bj>v>WN/bD7^\@ >u3lo:!\np1a?]8em?msH飯<>:rN˛TA:mZt#>M989مJ/7c&iF 7"OG:(2W :|07Z]ŭ c izjc?GP%Aw}[U|Z谆3mZ 2N^1IU}%xX/z%mq:tg]ָZI珤]Խ.ZsyS]tL}Vd_REO+ҹT.VyXtHJ66ubDH u^ז@j]҆8Lhs48Mb5>X_߷̒1炎sAuGޜn۳:G%4νUqO~>W|N.ba9]hlbOu~He꼚hydIjA;[vvm>'?p%vRk։[[o˜C꾤ћx`ܹYvbPs/3Xu3)I7 MvL}̓_=y P <(Ǽ#OanZeų}E#*fL/9'0ܝΙɶW蜧#l0GB2=Cv\/WDd@GS~.@Α8C;XZu~*0p? |׵C.F{ᩋ)DW(IDAT,RRW0n8'Hjkǿ0m\-)bD; 64<9+wǩÛ6i<.{/_n*h L+'.u<1 r2Fp\ `> qNEѮ>fow^Fѝkͥ XvFy/:I9J͏R{W[6=&~|CUXѽ u0S$-u_3<`FCzS4V*f gS/?5ujx-=e@٢z f6J:ZOf%5Kp4/̙FGs bYc!ä `zʧu}9]&.O4~nOҹI'  iK*oM͗@.g.6*t1:LǛo[b_Lru';Έ8]*>\5&rӠWz;ై֭ؐ^q-K~eik,~ /tWu7^ 53Q.Bdª!}KC3E|z p/Fa׫IqGٱE@B1UVE8Q'ީ:c酚K@βF=;%v ;a{xb ޓ7U^hvs&0`ty5c0F#01ˎ0F#k]\[#`0F S1F#`*SEZ0FB!`bP0["F#`@Q%`bY+0F#P(LL fK#`(LL3k2F#` @ =PRD0F#mݺ3#`0F@(5Ukf0F#+J0F#`@q0F#`0F<01xv0F#`LLY0F#`@<;#`0&#`0F LLj0FSV0F#&5F#`)F#`Syg#`0FĔ#`0F䁀֭[K&M*ˈÇ˟$x =x'|"塇rÁ;C,XS~! "SL{GwO< Iիd}:B<VreyG oUW]%3f̐뮻ΥI aO  w^Sww2?c,^e˖4) 7`v!^a_ȗ_~)vjm0F'pg%RF +/c9{Tqa;^O<х۷iرcm#`(\YZzǓtsq9ApO%k>న/󹼑W^t,gŌ0ۯ0F#P8LY{%/N'. ZӦM*B孷rbX :4,ߖGw!xѨ΋A:CA1=Tc9OzxKPW\vbn?Qfxy18y=ϖ0F#3B"'Gy8//I9p}$v?J)(!Exd(Q}6U)$cد0F#H8WYD400"/1bR صkW7ɲ0F#P0_vq1o ex g0FE`S;0F#`J` 5v0F#`v&v`y0F#`vY&vSg7F#`v&v`y0F#`vY&vSg7F#`v&v`y0F#`vYq߀jժL3Eb0F#PgP+0F#PLL.oK#`(bLLj1F#` m#`0E"vB8F#`@01U-5#`0F01UN#`(\& f0F1& #`0K$7mIJ.im(|۶mw}W*W,˗Ϸ ;#UTr[y}eҤI2eYt4lPBPA$<K5=?˖-JZhQd;8r~.GvusƌҨQ#)^<&ĐM'ON6mZhi&ƍzo2e2իuɒ%KTRquVm߾]`XOIIw<իW- /M_Gy(K5ҥ%Kݝtrnذ!qwѢEol”{f)[lڵkݱ=36j Lm Cllmݣ-\ձ=#QqU7oƫy?rKfͤN:aOI&Rv|"F4P?pz%Ŋ+vhk.rJ_~EaCK!78AFXxq;i37޽{Z2u]Uzuy逸r5wq_~E>s5k\s5ҵkWs2h,G> bW8駟vB},>#RB~G}4z,\pAb2rH/yi>3Fd[?C3f /0C ?vp80Cx+܄zq#E]\%N,m?Ww_Ҏ]ypf0* SV/+[oii3K/ ~akwܸq 8}zl~bs!ua,,Y.@r[NLƝ:]8R;nchrg(Q9w Nĝ_#~<(1d̰ e ֻ[o5z~„ 7gѺ@,X<ЛwM4+6n^sqSa/Q~(_\Įs,ۆZ1];uSbo2 꺿&aÆ ^\Q6ݩ*}2d|ǎjժ?d[|44h_ ͜U좊]U!t =w}ہ  6m8aEǟ)Tl\tJ\@'}4̿Sȉp7*k@>ɏ?aҠ1Tϝ/iN̹198`@zǺ҈RN ᤳk\Lc;%<.O%+]:AxƝdE`'\oa”ȟ ID00Ѐ/,@4qs[di(?ëO<봸Ix]w 78[!9o8V^=׈ުU+8&//y-x>ln޼\~w^2LJapCpaG?4ȭ[vy7Mtx1;DC W2\_5.bד s/?Kfp1#~YTOHT`7D0=GHy ߱rRr>D9J"۩EӰm6 P%16M %NJҥK._>< сS0ۻWD!< rv衇ƖJ86[dK/3g>CϏRSi$*Nn?:ZwDŤFNd79/s=\%*?`[ XƮòL&mcfl9-g2xxeks"`ܩs9ǾsyNqa\11ʼd>D wNV'\tl p"OUʀP `o/!\hxۃ'Z/켪c-hJX7^N=>ѷ!S9e(kq=8G ^xxphsh39m#^_Fυv]pL?\$ܣ!8Wa1ƐD'EAƒc4\ PI '^Pk/6.$oC|0&R c WD>aCGܮx5z.ྦRF:Յ2`Wb(wh~Iut,x4Ό+Άt`% ѧ߬#L$}3IJKLXeؑy ܏WFJIydirVLƝI\̵l0k: "s`da?w\4zE"^ha?)/NvƎ;1[ז>H'6hy}JLcx;F:\޳;4d9bYǣŚEBc5p 0<~ᇘ X \0焆';wg>C| 2S&e a sb.Q`[ʒ,9]NVdi\ n*zc^7{}~y C~٭ABLqL{47kϵn(ƹխ$/x%ξd!m?OѡӁo(;z1d͊iц3qo2r/mdA>*_:h0w?KG1u#'F_906` mc=7l~<{vw}q1|l<1t ЃN?Ip"ŗk/?#x}~sO+0_?>߱|wQr.Rr[`Z`յA84sy@]4(8`@qʷM>M* n.:7yR؆9YqrpFy?דǗ1IsR`Tq/di0MVNK=پch qnq·?t}dyQɯ|',?^d0Nʚ8 A0̹O]nO^غS{2SM3/ixf$~u2⤯Zw=LTd,En0F#P zTQc3F#`@v% c0FLL%c0F#&C#`0F S f#`0FdP0F#`H@T0#`0!`b*;,0F#`01m6F#`@v% c0FLL%c0F#&C#`0F :N6#`0F0T [5F#`@N - k0F&bت0F#`rBTNhYX#`0F01V0F#&rB#`0F  j0F01ZoU a0#T̀C9n!  @$ L%% @`D@2KHTQ @F- @$aj]רy{m[L/Uu<ϱ,Kˎݴt @>g?IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/000077500000000000000000000000001322762156600215675ustar00rootroot00000000000000icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_endpoints.png000066400000000000000000000320761322762156600303060ustar00rootroot00000000000000PNG  IHDR3sRGB3IDATxt) &17*T%ݼ>z*˩i#i5ThՄ=mx'6 E"'$ʼ&?M|!wsw&B L$@$@$@^ |k HHHTK$@$@$  Œ @$@$@$@9@$@$@>P,}b1 P,y KXL$@$@K$@$@$  Œ @$@$@$@9@$@$@>P,}b1 P,y KXL$@$@K$@$@$  Œ @$@$@$@9@$@$@>P,}b1 P,y KXL$@$@K$@$@$  Œ <E!m(V3II84u< @0zdon|'>yc G&L$@$@'@4}  @X0 !dHHMbh´O$@$`zKӇ  4e > P,MBvHH (&L$@$@'@4}  @X0 !dHHMbh´O$@$`zKӇ  4e > P,MBvHH (&L$@$@'@4}  @X0 !dHHMbh´O$@$`zKӇ  4e > D z8>NĀ=xn8-_s+$ X/f~[]1p&eXQ> x'@g-g}s_w_?=w4H$@&ʖsԮöG'=_w1` rĨXysCXBsoչHLGӰ u]9\+n?&QzD$@H#K.LS]=c!MNHӢI")ckփ]=<=,20 ON ~鈂7qD]Ȧ={ٯݸ=LH <P,#܋ԛyDyT%CKyLE1WZ aTFNf>OK»%s1Α<Ά&'~EX1~+7FCݏYu[6l¶Rb c?{D^[q؂?wc?@ʲlNJ>y8g;~,J1V;4=IĎui }z.9W (*I@"1\EDQSI.[9$1/<ԉ;l?Cߊ%#j^} lNL!2IyԳ(j耽 {j~#j"MN=Vo-n~ӗe~)O>[(!%PPG 2qqԞD;h q`{<JAHɚS]**7~^ 0͞BPsyz ==8*.l"xp P.W<Vְp+^{t!sM(e w +?+EwimއڲoS(UB|1aj_ 26g"i63p\ͽ}'u}F&No~9u-E.:s2' sCә f$ c S65!P_؄uᙲ]Z|$RO9 iZݻN!5Ä"4c~椉md[w}zp½Q]Z>6EAsDF1b^zl?*"` |bTqU8cڊYfz{V770(, `"*_9KLμܟa+ov:Qmpib6ON;g/T qtCvdC:Xَ|Z^!jX6}=6\}6jcJu:pЦ^3uWv; :bh/2qoו{e>5{6 #ȥrru' qמ][iPu\x+su ␨8rR%3 3a `O S<|"cFd4]pAGF w<7Hh8 k  X.$tHHh(F! 0BbNuf$[6wĘ!'p"O?:ۅRUca۾5iw~~o9} eEO)fֶA|L<$Z-ZzL5x`͝J/$@FbnCv51Cܨ';9qѐӬ]~? ]Nګeu  X/&!%Uz\pz >lzޠ*cz^6G!u @P,֬f(JQP/ޜr$DGbR>aD^k'GU.I(rv~ OOD㫂Tb2-:Iٱ7',.SHTHGӠH<Hš2srY, Dv&Ni$ 4lPqkg1q;]"'<2xG$@$0JQ ߳\fcm+a32m.n>ă @P,HA9BH 7Ʞ}  e, @bݸ6mi뇍H kga7SDj8<*P:vasw5aGVta{~8tD]U2j{9m `,$!wH!2m{7#ee.`u+3s#Ү<+ xvd/~cۇ6  k?2Ju=@mqΟAmr @P%pO =*ԶF'V&#Uؾ^wRSzf_*&#mf4#"-YS~fa3k^j%سuRղdmhj= ՆBdd;6ixؕ{Ӱ~VQ}Mƺb&ˑ(۾W9\{p`1ikjvbp\H[lTP˺MJ)yK; Wi^Hv&g#\uxq-Xz}wƻΌ?I J@1p–݊k+Plu\XD^n|EsYA;Fփݡ,1%Tw6d#ћmӶ-v%/ϡ4HOs"Ru( ] =۷y Xæ/TZaõw\͚Uf~_:2E߆r÷VyeV;/JEjPsJ͵]V$,NcUzXm}So?}ϘDlvd.L4issh0ѵ$0> ׇCK~`7iBU~PB%'HkpXʕQPV?v Nkm_yWkP[<=Ս#=[j:?W3_%QZ?֪55@^OB(CrVu҂MwhBi˫kR/rZ QXbezSܛ8kk*QS[U% ^bu_W տ>u+T˾փx_]ox{;IM`\,#@* <jBUR hx֋tOtJY&C.*bBy b* DZ߅MfaJa[pSP.wjB){Ϡsoj[!z:aE\3^,Y& X,Fr˥m)r)kU׸]wU}V~E Zɪ_~=8X)95bcf& {^^XZ߇XC+).;';>ڗU{߿8|%0y}֨FU)VFg q/Nq;q흫x=psV*FS3 ~^1UNtse8;% E֐ՇlFXo'>45?rcA@7NF`X#yjR/c`83x>l޾zx;^k='[,vݖyDj`c ?ه3lid|ޙ4l Xc0$@$@$@ %}M$@$` KSN 26 )P,M&:I$@$JPg$@$@ @4E$ @( w;& 8gIHFHaX-[੷?Q[񗮁u &HH84F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ k$@$@ @4F P, F$@$` Kcā^ @"Q(6k C@I:BJ#p,E$@$7~@C@4mZy1m pdi e  X7[# 0! FIHKb\lHH(& ]& .epy5  X0htHH (HHLHbi e  X7[# 0! FIHKb\lHH(& ]& .epy5  X0htHH (HHLHbi e  X7[# 0! FIHKb\lHH(& ]& .epy5  X0htHH "[3"W'1`OD==7N\1 7IH|(拙_=~d~/Ϝ2خ 7x0pw?[z-V/5w P,;GMW㮤[#_{bw4H$lflk&Dɫ/js<ۥݞǝcj @HP,C=rV\P;ta>L){C$0^ pvFޏI,r]T-^4 w̚)#b"1~8Fh~ӸEC$g`X@k. p_e9 |D'?¾(shHBKbZ!oW#oaH?hT㺐 X P,J?p7k//yd!Vf.09%O$0 P,FdߜEĦw. @ #&nz4k<~Iuqa| mD$@#&@1*VF@ބg@Ч(;[u' 4Bf<}e]/B$׊[9ϸ s %X^"p9,fSw&0A9-Z};)9&f;Նwp!ł&Ծs4)Km@ݝ{lݦOfx0 ON ~鈂7ag t㙕K:X˖Vv e3K!Z2uvVe-]c6(۾[`  eHхԛyDyT%CKyLE vՀl?r"f~NDs'BZ¼|LѦ caEfh1q|!cX3.Ajۇqiђ9~o3FLs$ akЅF<68aXp67u׉][7`WP(+r篛2Z%LOFڑrmѧ?@v, pr3~T~xO a>}|wu|+Ҏb% nȚVG>~cq"?TV|  v4IGwkWCg -HNB)ov;  m­ӱ<}JŹ+zR+WZF<8}.+ƉS{U>A>*۽yz38\"g/Ս3oAÁړPTX?&ߦn[!9{bf#Zj'?GF"9%k<M' $*v~(% W&]\KboݍDlz~G_n@ p6 9 P,7zM$@$D fS$@$@$@4g܂us$~9殗3$@DbNc_8)GgP*Vt3lע?/oV>dzS|! p#@ ?E4#},!D˴EA V/_̿|$j/$@$`Kh.j>cQ?Ovs!Y'\/~qx8blu _P,1|ijJ To‡-p\aQ~}L(4|H'$@$Gbǂ9A@>+5:r$?s^Q'cphѥ<%\N~$@$x us*UN?LÛd E['U{B$@G#i{$D$@aMb99,"Iq'4m @P p6bMZYLN>=#Ϥ3^ r­,WqxxX $msq2I;$@$2ː7NR(jƉ=!0ͻoHHBb4B$@$V,#Bܚ-msia,ޗ#U#}H] 6GBg.lw:Fb_c&}Kۊ~چg[CyװJ zܘYb [Ĕ$8X~ٶw3RV@aaHQC]X'={]=>"=9О#{_D_[5(խBf,r XN84iktbuj:KN]{ĪT^WH[Mڊd9BL͛TyQtcuHU˒=ʪL4lVʊ ؤ8aW;֯F:6&8͛Nx<NqxH[Cٳ]3fԆzqs8;:{bvǜJdW9r]'}MN&g#<; /o =_iK*yk{- n|Iƺbp}W1wνW3O$`@Vߥ";VX(͕EaW4(:cd=͢SOu`jC;yɚ]X\Bs<5HSrU~3My ^|o"f˱G=w}KV9ꟻEYjGV}Ϫvl!!%SwwPe$Zpho͊-cW-WG5k?vUQDqTDP+, TT|7~+f^28(j@#4nMSTJ-؆7?;2[/I#ȣ%Yv*"F^f`5WZ@J$_yOY^[0}H7x'=ޛ'[csD0DՠQK2ȩ,p; %&G{Vv^yaHW,&ϟg1:w|H0Qg_fguW\u2hFeI!^ B(W%TT}ل+aFii.dEY7 x~$k_kWwn\1՜ry_~ّ!2HN׌ҩ&]f%.@f7DAjkĦaiٽ%23\O;9Q{JDV߅hT~#>buy?5N$`Ta|ͲymsY{?g+V^*y뜞d>J<~U-jkjPGrOB(CrV҂MwhBi˫kR?t# ?/_,G~4uTUEy& ^˾-9<ƵT4u(#kއq x)pG[D{3ø)ѯ',roz~>}漜W̐ Y."Nl\1+vf: |MdylY\T.E_ħ;JះPdV˝ڨiSbԤUr㫻֢:ucs'jb_F1M,d9Kۛ^S-kh"Q߉W^#I[Voڨט1մ_JRgV%C\EYj_cu_AE<BL5ևN9'xO}]52$>.UN:[.o=Q Lۯ )Ǜ '0#_.}H,i_G]\%V=u5h cxF"G.*%Uؓ dV.Zev覤R B[ ۔+a:b{b$Amڻ}iY)-bMRSԷI):ܯҨg<#:~ }_ |VyNwwvKxc9}yDG#p" * Ckxmw->45?rD?x K,S{:}X?=.E r4XFWY ףok;dR0/5 Hyw&(V' 03q3 21$@$@'@4x @ P,Cz@$@$`pK 21$@$@'@4x @ w;=  8QgIHFEUOXHHD#Y  !@ X'$@$@"@ X% %{B$@$ Y  !@ X'$@$@"@ X% %{B$@$ Y  !@ X'$@$@"@ X% %{B$@$ Y  !@ X'$@$@"@ X% %{B$@$ Y  !@ X'$@$@"+IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_roles.png000066400000000000000000000463771322762156600274400ustar00rootroot00000000000000PNG  IHDR\FBsRGB@IDATx |Uյ!7#I!d ն"JkNUb[b-,WvH,t+}.]NxJ$<9ό%Wcձ<txawZar]Dm檏KVm:Um765۴gq;Vf=><klī˧nwaDI{Mۿs8[BҞXw&,::Sk]t!"бǏ@h`BDI`鱫>U~Dْ0!!ߝw]5rQ`[*~|(]vy*m<dz9+qXĎ~22$Heh-:66Qjg=$~_?|V.f=:W?=r<#!@?fKu",Ǵô*Y!DuL{x$(sߋY't m8+Ԏ-X֍K/NNy؛P!7v)X0~Ow^t$@cwKp]VRwVkYǫEAm#9 [@& 7ęKqvZGB㿮}ྭ!Ѝn(YFhn5XEƫflAm]RUpc;(m@N̆AMETꢰF'cZ7 ACHHHtPc  0(:v*b +]2#֡t] xWx бIg9s -wTѮks~~J]\K|/& :v˨ qJ,ʱ,U]:\nB7iv,lk=@!0뮶HKݺeI͓qhۆeWaWq%Ң =_`˱:Irӂ12 xzcPY9yI"<#s2q;zYzn#GtuDžytBed>àX? S"U P[sMg/QOHHHHڠ,^'pMr47y"!#5&0QGjd_+GjVv_$@$`DtF ev^{.:{MPHICǬA@nW8T6&YVI$ ؝gMO&O_i,ͫՠzYh1nWH\"@62+|- '\ow$ѣ-TiGu p+XƴmxdzcFPp [$@$@$`6tf%  ~бHHHlͦ1K$@$@co бMcHH!@"  c7(/ C8E$@$@f#@n6Q^  {?pxHHFl$@$@$:~ 4FyIHHt-  0:vi@MS3ZFϷo 5I `c.! D=v@  0V9 e =*Ŀ~rpxtF bBGNQ`ǚO#@!ůgkIQ 4N ILK=vӪw'pD} RbpDD|ԕl!6$|KdBC KwW? H]GwJ};s3"ɸ4&C|;3MMxWd{X 71w7 б[^o`Cs+>%Nx C)ڐNUÇ1LF^Ǯ|4_ Е8Y/Z=> ׏Ec,7qPo IQ%- o$`utVװwB6'% N涍 H ‚ I|\/"k9nqdH}Aԅ@AM6.ƶ2̖h'%|>WƋlj}vb- Bj,s-yR )#q}),q$ )<ILۧϣ>7( @"@n!eSSvC֪-) ҅2bjȒ +80^'pXƆښᖱ 2޼z_b%KqӘx+ih|_xH tN⣾'p,Bn~9.?t8DʼesF4Yz0{ W7J03Y I'^1(F;|oM~LݏoԦ5jȾj_}bta7wћpm}Z\v^=^ oכ3#cfMڮFX*c%PW*eWf^bT5^b\b$`tQ:IV-GnGjԨǏ/'}*;׷IMBs4FY{]\ۄ[zlY6:%i~ZTDڵmxx0M4׮2;Xu,FLGt*3e]~YVa&apFf:v먋O>=5w\^9^5cEYTlpdonanI;EV,lm -?kk:v+h6=W/G2϶hwNVIi? 8ECN1!64҇A+5kVL$hjtVk§Dt*)  x[%~4ݥUzOi5T;G7_ }A Xi\;2cb;r66!'/>~,[Z<}[͓uzw'`IE0m-݃g{XI\{ەZ5@SNa"M؇Ho^9OgO#= _eKB=9woFiv_&9vCpk2z;uI G 68ugfܳ.?2Eh8uv.V.Vͱ#>&^՝<]rbk45rԟܜPc#kp^nr\x/8vu{7F;Ap’3P{ |rr9LzT=qm/Gxmz{x]C*3aXA/C(bn:ho#hYxzMG#PGǮNX߫{='eU*/1M^PX $~v?,2RK}=keU!RV w}Up{P\"Nt:\`Q (dZ cW%=κQJ|LLo^[=%J>sZ|"bl9]Jv&@뤼^kNx!ƈPX]6N9l;W }i}u0:vcR .uJHHH؍JA$@$@c1*ɻP!H_:=sp9;:_N؄MD>$|Xu,K|B[˳PqNm*Qh!@s˒ڲI`d&q?4Bb3!IZ%q اh>ϗ@t]pꌐiQvFiHoBj\;2UM7ƙPhR!б[= =^3 GoY?0[A\WvqSGb%9=Dgt?gYНH[j$k;yvht0y;E@ͳׇGAͳ 3cw%۬@7@jc7IA#VDQڹW{Cmͪr˫Cm1V7ڟ-6>7pP^ꡤvڔ$*8Gҥ+sѓ_HgDP&?r]HFԟ;TXv(|{T,|1ⓒ |~FFl?XH k7]K54@Vs;.Ii/-G6G <[,Rag/DAm4^:p2~NWc|] xc&OW5,,wSj8 T=_{'2=΢=Yh3e%9vV=d)0=.>W Iͩ`ec3#._D85^׋O/}a,U\RxHzþ *|WQ<_ `Nh:d5&xWl:X5KhHO3N@HTtGY>3n fڟ~,Y5 б{Y*| ;Pd1¢LHI {z_>1n d#ڟ0Yб{YA?+qcj,l`$\R>a2`^hzd=V$9v/jB ;?HYe5LW.f[`^hzd=V#@%jrmvUf95z@xҢ$3 /%3]LIZ+#KHC^Ъ zFd^U:3Q@`=UvÑA |б{X[*XnϹj,W,w D/Vg]Bwӝ`:[Lי-L['%=X΀Š/- %n/3ӹ˔O7xV|8Akr^YN0pf9wQ``}l>#>"@&>=rjJú2sds fR.KtLf0dY~0hgNCp#rIV65dE ^o?жyMAc[0]U!ڟ7(F&@ǮvėirH_ʩ``YOG{|"Rt8B-y'q[i>V_SmZEr֦ߕuSr[ f忕~ kͫL??WrY,'Ih.mM M*G0d6Y(tL++^ԟOuS/,2Iز2˹glT=.VR^`:wYuP 2-XY,l``KIcK0* H#LVe tn,W,vnѥc`0KpLW/ dnj#@ӏ%k2:v7T߸dݶ p `0&I&&c}X tta}tjLAsnI P1.S29|e?ѱIб;Z I:e8\"Y`\o_`:' qwܡDzF'9v'4֊zAvjVfs]jL2ǾOy.0d[p"E tɪ E}ꨕ`%]ň3Z&Mc #);%~jĶm`hzd]F!AhBeLmmX6SU\l:Dn=\fV*eQ10Xnj!tI־R%t#d 7܀Ǣ#9~T>jxX yx~PrK3ʗ[ߞ_ oP б$,쫾K,'۰JfF3X\]7, !Z0gf:вA 1<r*+Z-2c\/5*Xt Oy0ד_ϱoê mXS1rzڗuiL!\=H *1NW̬>cWGJ^WRr&@ 2If:_m/Q N=E)WO~9˝`ESq3iWK ft-NE3ΣYy'N0xjH~%C˒r+r,gHC  qVtJZ)xpr2&DŽ#0rj$'px 6*BMS4%@jMװlNjk]4x\lέh݉{K HHHluVƥx`1V۟>zBĕ+?W?׸y_=ԽHH%Y(|HHJݬ$@$@$ :^ Y5GIHHt@%  0+:vjr @/{K$@$@$`Vtf&  ^бHHHͪ9M$@$@c / Y бUsHHz!@ ^"  c7(7 B(D$@$@f%@nVQn  腀kTgowGn~9z2+19a6~_IWh?c_Q((]zPnq֮OuR,y \3gA^!!i[(IW^=Se•IQ:7H 8{:hѥ[B3'ǬHzQ،F&R;zݫ X,ݩeI`Phćc;Ƞ@p&1?LŦt)CC:0#> x@m"oџ0ŏ7OH>u~3'a֫ Zzgzh v3+IEx{쿚9|y轎]-u{i!s'ƜyKuw1NY>/eq}RQܰ)]ס>w1HyڟC?$ c?^Y0OE jZyU&oZ0T\[UXj gԥ/%@ 07qyຽGfu}X%ޠ <NNֽn*?ͫ~Vg#阛y3Nqǎ@SNɓLDuDD _eKJY`5_? Jex헋x`ѵط1Α7]'7'6;h:r `GŔ{~Ghް?;;FaBUaWqƿ+kGr~_nk-laV>nG#`ڎZ˳)g#7򳶣,p8|% ygNj쏷_뿞FŔ}?׷sszTXul=}8f=M=bG~Zav/_(McS7NI:4]d㙜ZF _9VT}QgN;8>± ЙUَ۷c)7|+]G A =eP_O]G}_j{t(4J VCp^7Qݫ&ߓ24"anOxr:xHtܜXXV"XiMmCJu/Dd2/@hް>;Ԉ--Q~MT*sEjwt<{jov>mB̹W%K3ow|N7~X#N[vc;W#m g0Jc|=VHjD:υu+BfLT [[}o^4Izcuw?NH7y'\\ @ʴȘˆE avTUap略륨˗hΡ9kiz׵~ұ<8jio#Bz N]k~٦7ShΑ9kizו`?yݱV0>Gf$cd362@1 օ.Y 1@)HHH@t`d%$@$@$` qjK;l>T4z^-sAK!@sv'`Ι hhnQP]vV!A"JT8Oɾ럟}\w@hggT͘S.C8vXc%X0!I끫 r?tFtB7iv,lk=@!0ʾ=n#@)ϗnC87Oǵ#nϖrɐbîJEiAd c"CqNܴ`rL Q$ʳh'@:O]e{9yI"<#s2q;zYz7%H"E<>ڟ}?.Mq d>àX? S"U P[sMg/a=La_~>{,vMr47y"!#g'0QGjd_+GjVv_$.ڟY?wl_|۝y\u>aN!ٖ:CϸKu>Kֿ{}(^nW8TzY xlLc >udcitV~ 'izA5[㶱jr$;_\x;hocҐlqvGB=*K6 NqDQ'ڟtj̤-un #Sbf%@3!7z4z+>nt HHLڣ$@$@$Ѝ{7 H$@$@f&@nfQv  F~$  3c7(; t#@ ? бY{HHcIHHͬ=N$@$@бw$@$@$`ftfe'  nػG  03:v3k @7t݀# GIHH1e~$y5ԓ'^17ͭ?JO$@$@] ? {U'  {2  0-:vӪ @Ot= iUGIHH':LxHHLKݴ$@$@$Г{O&B$@$@%@nZQp  I'^!  c7(8 $@ޓ i бVuHHzcɄWHHHM: N$@$@= бd+$@$@$`ZtU'  {2  0-4}O_#IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_scenarios_ha_master_clients.png000066400000000000000000001206601322762156600340320ustar00rootroot00000000000000PNG  IHDRq#'sRGB@IDATx |Tչ@.dH !@DJOO%B ~ߑB+{SCQ mBkmA MDnAHr$C2! dr!sygy]}C%HHHHHH/tV$@$@$@$@$@$@8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D"ΏM%     8>$@$@$@$@$@$G(hT     3@$@$@$@$@$@~D ԏꕦVۮ!=^) >nzbJw=$ P!$@$@$@$@$@$pcAos"/Nܓ gr x-qޠ2IHHHHHK(Œ 7Py*$     /XK$@$@$@$@$@ @ ,HHHHHD"K`Y, xE7L     8/e$@$@$@$@$@$ qޠ2IHHHHHK(Œ 7Py*$     /XK$@$@$@$@$@ @ ,HHHHHD"K`Y, xE7L     8/e$@$@$@$@$@$ qޠ2IHHHHHK(Œ 7zPI$_lq*kaCEͱ3նk0uGP-X?"[u%   ?%@f@G \ϗe rV#%!י4$ք 1Tb,Om͠ QK$@$@$@ PĹ³$py8zf#9* #d?8ƄpMk=CBP%8Uحs]ՆeղUa߅r%L6G`>GOvHHHE\Wg$p4'vîb6!}p/L)z NF:SK"tYU]͵kЩjْ*EԙCp D)32ڒ6-,_aՇxdXwD$@$@$@$9׿uM$~#cq05ٰ6HI5N%M6SwgN5\UwUZlg-Vc?:.Zz&![e5<Ls5    y]$@>L@׿_T;dWdʤNlzB%S'deXdz:=\-2rLd"   <Z:ϐ%p*yBnܷ'>= bXD!!2 Ӓ{}GX)rBP j&""wGܨ/ZN6Je|T\ ]S8U,(6HHHE J%ቆLש-_bkd83Qϒ Pa]k"d#TYEzUzr,O? +N;OiR)L鏓Y{!   0$?FEbj8_YcXL-fKVaa-hBEw;c0;>FyXS,~MQHHH\ PĹ1 *2ҙ4F\m38{8MPU.F,ur+:5HHHH(Ϙ5Щn @0o<; !cIجX,Hr&   q2' *k.fIufHq-VĥF` DLL b$LBH /6K:ZOcނ3Y"Cڻ)F^ @[ Pĵ x@-κlH^]%H!ع8S=GPT\sy6i&7 ol3.=z&<^v{1K]HHH{(ǖ%X]Ѿ Ia0zt zh6< <8hxdfO86 ~^U)1kH5,|Sd-g2SgQ1ݺ h4KlW&d+ź: [mւ70o☚M Xz2:׿qCFHHHE\ 4d~O$.\M% ÆcXld;m7?ҍ38[r68>,"]H}t ݶy f8^[8sV&!H\ہK0_?)5,ڈoܝb>m8,sgX2c P'0s2w@~~&mٿɴѯLǾi;_cΤȕ٠gbCز/Oڳ OjEL$@$@$@N `~q^![bd8{qK|JP~7*HR[޻X&~{ǫ0%'xrAhNB'6bzuܳO?rTj #dcwa1\tс4NLO~fDO ZWۄY?Y?p?veFf)`GvL[;H4` ;joG!,_)/'Sp=D$@$@$(u!#]ⳃzw/akb;6\z;{qdhwT:Ipg#{cBB (d-AsXv`gg *>Uy.gsRj ]V&v<#Wé1 I5qfI;sӤ.LN~+"%(%;3fmفei\ YODv/ik&LHHH  P㨳AC@UBܟb #^*/ZjlCr9>_UU:DAذcc,bOyD( ovAd/p_[$W=F˯-s gп w#eJ죰-oժLhX r_++'FlU&cUu-*߷bmy#DFJ saATSL$@$@$@AN @ Bb 1q;M' b&OȎ}VW̑+%s9zα b2?8#MBaޖE|$fL,LW߃Ev+n'g}aSKJLDfP4B-4>ޑ09e^ĻS`}=`rtm_25f ?델  >]"W_?U5ձ xytp #[}(gq|xwHWr.V8 jsZ/L*R @ sF%9i`LF /W`Ip>KXBmه"dImp@X#{B%'Kp㔭nq3!sti/LC]2z{zHVc] OkcX*dEh.牖a`ŝ7sO$@$@$(||G_? [}=^Jψ%pq%]ط+!2[+S-#wI6k5\.mL|4>3nm61qQ͉"{0ͣnkv{ZRP$bD̄D{"aH nDׇf,mP*Bs05r7{=b92'[%Nទɞj9j1M5O G~ۚSRv D;Sx;+uve3gܓ .F_ '^6NDhTbU`66'5b*+\>W`뎘 EcDyʹXIQu69:ʷڙ!Nja㘾p'#yvݒ&Ev˕Ԋji ~1}|\-4[yorIyȔ9`̔9#w k%&C飍zQl234Jm _WG K,֘ kV O @Q\HmbXHܑ ~Xt:wX,vo/8/QST5xqw=}OaҌ1")k!M+Ή1X9ֵKE;"S>J:$Dӱ secu90;Q$Mw隫ߙ<҂B\8} o#4:[`A"D]xD$@$@$B%jүjDSr p>ߏ OD\D(g,WگS Ƙ04ք!1H6GAZXTx6Meb+jbDYkrj-JsvHÙ'ƴ'Jz`Zę\zݱb-Q6XJ0Iy<RiL esmdɝQnzf-WK~E to) "]͔TGKpLxt||X:j9g>'#{Da7V" 5- qm2#QlzkPE4֓;[ sCV^z:&W[o3W}KNsZf5gHHHEK$0DnPʦ*u5pUbclN fE`sZ峮S+_ $S13ֹl!t$@$@$@$iTX 1/t $kΓ 7|]l qn *8_HHHHHsHHHHHHW PȰ]$@$@$@$@$@$E(kr&#I?T_ޤZY 6_. tgS'l gI=+=6} ɿg샟3U<   JqA9t0?!a[X-ȹ[%*,E58{7jQx`@R͘`6,}j d"   (8da$»u8cs&XЊkV6@wKdqE58\RdHHHH Ph$Ng+$w$NMy; xEH]µz[$Nd"   Zq]˟lőJgV.J&    %@]˟Ve.--ָHHHHPu{L>M`ˆSOGJh 0>=bl @ f?It[j} 1$plkPZcCpJ$@$@$@%5qH 0DxMXO0mW⳽`HHHH p c˞@ X`1}'*Hee | X.7 tE\dDž8tb82ܠ^+3S&V:õqN0ܓ M&78#_$S#8ձ G_+ ]/:y{    H"&fU$T5 ~$ֵ6|3?46\xV8g{F?dmI̳}I"489)qO$@$@$@%[wc$@>D(?_sq _GLX˿7ʽ-qV}O^¥B$@$@$@MojoX{9RO>}@&1oLbe 9NXm3 @(ZD $.VK#2}85#{Fe+ذDAet~%h oNVTtV<Ƈ/܉YS30k:l] ReqHTޙoGFjLENE3[Qhv)2T\G7mݹq_[ȹ >/VeHH@H.oE6Z Gb)zbJU@*jprV9]n'VF 9Z(S+uX<>9yNSHW t3a~~=֥&bCȝNS_Hy l 3oé͛ӲPcuj|ýZiݸ q(-sNr)e-s IHSv{L)䊵esx,N: /S0Dõ(q"nYhmX9OV,#/:px?~_ڽYNQ>el5baɼL]s}l4@xS/ñRYsسb*/ۍ*&N2b$[MX!eζג(xz l8}-.ָtdo”~ =s_NAk+2,G02}-QZ֋X t.jztzd5£Zsb]Alq3Wg9YfEE5<`q?$6bMF,/FŚ3Ms*a)uSa"M=gMZnKN#" YOGljh]StfJE MIb-j)FA=h꼃zϗN!xp!e}i=2!!:Ёc__};+7Ȁ!K^9s&ɦKǔ㐠z!Ԗ}"6>39v #0Z2 8&e.THYdq.c_\|5c&LEs삮x8]NAz%k4ǑbA'V8_gUZ=Mj_O aTcΩpSDӉ 6h}{bDߖlX%Ւ%AUϗs{^3%F̼d*xU`Ĺ{ qcx S~eYXc\HKleÔʸ OoG?YWjpʅe@oZMs7cҀd̝)·!yMpy t-oc.KŦL_ҽ8TNwݲ؂c׻Wy]3b`Lxo 5ֈ^G*T7gbAx 9wҀ݄TtH_3bS'WjS/dz_#" `>AÅx`.}/9lWb4>0=:Ր-Av)OWWK r&h@yW.ZrpsSs`+df Ck=~G|cOn; ƏUUFiru7t9[Jޑ=I1pn椑{6`d> kvOUV_Ų2?r^ÊqO:]3aۉ)!H& rFYg׬{Ӝ/pG$@$s(|nHؠ)*[:p*Jkjeݲ_բ21_|xsZXTEMd5Xf|Cٯkqsn*]ז(Lus&ȩ3LݜIEn~k*7A9Uj*Υ|]{O-*Xu #?M,bEVՉ%F|<]%ϘyEhBnCΥavfrLjǻ߽ص<3m敲-%2bض}nv2leRRJ:lx1*$eS)7`8Mis˵&b|?4 O`P?*_*ݾ:ܨkԒkt b %SՅ=W{3ZnR48Z)[S@5fN3XMLݼ,c6V:6R9׾!:KD !&l8?iVM?4A6 7L'ɺ)0 5.*u8GF5x8M$b[XBq5!.asP&)[ܔS$@$@@"FmheS,*ǡKqcP9NQ|iD"tz~֩TBf1@еϙ0Si; sܰOi aEx%" $[X>^F.726ȃ4NH5I-pKn^Wuz`Y/GO΢HHHO PR3{dۦcO.1?~db"`"**Ӈ%o:zsYEcׅs h0=+ 4#@ OL-uX//3+Ռ%La]$C˪:*a ɱ;tHHH 8 PDɵg'S)5$arߞ7T#6 3ݘܷě3᠄( 1H(L$@$@$@G~كo}j*aNKlJ0:8 8"6G5Z-}8Y}$MMrL$@$@$@AG~|U~xjZdqN\׏[w!&[=2 '. ex_g MےA}K^na NݛHn~f"  N3lŏu9szaQJ2R!OOde ~| 6HHH xPXDO-HY⨁S(}bh?#aԱN F%  t p*^xWW]Sm_>AYI:1bG AWrfG$@$@$@J@Y wp>&_0xsOdkŰH,9&   '@c="kHH -Ę~3aa#@^y5&S߿TnX;l> @p:e 1K qK1V,a"< XBt$1 >.#~%ն:|qx"M:p]>,l@!N .3dx   pKXxғ ,V_Th<40^Qy/ nDx:|d) @` 푀e56)5EO 0}Q\ae ] ~#$@$@$@ p΍{.ѳ* -8#F\W/Sw lDg;N_Ə- =#  EHi]8;\\>pg\W}lD$@$@$&.G׋}_7||嵶F4i仿İ:ZZnG p)F$ !roߎqIy5(2&|o:4)dRTaduyN>>/7:pO$@$@~B"OʗY-mӿdM-Sɗɦ1y@oqϏG?Ip{<8ڴ/HI^lWH>^+·nnhp*eNp>s:S=w ~xNN9RR m; 8'jziXY&WNOsyONhjJ`6 zTh&srLv6]Dv&4s5#Dd>ݛúԽlN\g*$@$@$@7EMC͊\ XƚwΗ _|,:v'<.] b$Ϝ7\gaP.++p?[oştXO$@$@$E(|W,݆DbBBaޝC0wla6%(6c_ko=AֿX   o6-%>J5t3z"]x*▸h|J+BvVWxBȥm86B$E{[1NG0  >83X 'NsOUW?{E嘘^ȵWy},KBn˸,lno+^>rND!(^#  #@cRdZLy:gJVa[^W??MYbVlnRsZrxݳB?Zr!fXY\ @qw,ػu;g#xgic0[g[KkF=MELHHH?бϵ4,NŬ3+D>w(,@E \~>eƤ0a&txB0˵2 IGttȮj;)3*ISX ts=_e{UVcË@\C{h&/sgc   >c@|,'$ȷE|o;dXK)I/ 3@نL~%8Ug8[!^=ճg-Gcyxfqq>db-ڋta+7##^TG9 @Yz`19^VRe%pf}>څ}YYf.CFY6cߠf}} S j/G -Kڤe=zv &$4ՖcΕXx8b7UI|cW%Nr_3ޝ?&i'ΗHHZ#5q5"%TXl`*Tbu ]i]*txtK!Jܞkrp/,9SRu;}6{:w?6u_,LLΧa&ae '݂kiG"SO>$ X~P>R,z[Kxw 'l(7bӠ>lF}i'1^*XZpo8[ Dvn86 ˥Zuj:S%  y(n뀩iRR 5{$f'J+ *② ,:+BlO1Y},DҀQg.SOk0&~M/-c3_h84'@tC[Mi.=a6 Ɂ/Gt9SZf)K%-+eFjCYp c iFugCg'ҳ!޹XfX v? 8.hlXK߾ 刍/P+E\tZ,:07uaav&'/@NHI*0;ŌښP$bD9Eڡ.9A4j!DzO 8-C[kXO%fL.qrCxrno^CyߔOFYzAdÐƩ 0U@~ܻGbpTHS@7pd ui]< ?0$@$@$e/O 8P.Q-uUy}QjM'  #@|c/cǖR%|mL6BM&&B ߻s{iӣ5l ?VD<12Nt#trtvF`pH}FJ{pS'W&   !@?cŖހ;!w[x59gBNSGpGK͉8n~r$h77LwBcCW!?/{06u*i; Pe =" %86ljbjh5X"?J%'ց=e̻|_!Z,@W81y%CzԽvi{"6;vzϗap #Xb ŰH XޞѤÓ3οt<:&%c}qT17 g K1O/ S_9QYcqGş.lxɂe xEE ^( ֠9buȞ:8ӹ],g:wZܓXsP, >$ xKG 1gǐ_ˏ! Cu{v_Oϖ@-AÓHHHPuWqS,rNKN9~ .7$jĦӕ'a;\RO7.S,5KEi|EsL$@$@$@A 40^t5OЄg' j8~ pLsDQ5 N?^sp#Cp{Oyxդ| Zd p6bl?ϣǶ @sq͙ úXN9ݖ {/YD$CK7{EO(p 1Fi&   !o3V>O%b)?@cy2XrCzjPzg϶Z~hѬr/ݬ7iVh+D]kk?Z}:yk]sbHHEVqʅ ({+݉ySS KXYشq|֓;1kT[+fMȘ'Do(xc=2Rբ6+֭2b\b`q-S: :KMHOKǖX`9/ԥ\=c=]hk*+^Zڦ2[Bl_1~ajbvRmflzvf"8w?!*}=09%}JAL kZ>ޙ MǦe.]smZK;9ןmL[ύO|mh\];3>;-=|dž$@$@$pSy oGnxY2kןU"9snfs*rh>dέOOqܳQ~u6 >w܆chr:X^Ije׋ss_t?ݥ@Jܹm՗޶Ek7]hRiKE)Ϩ ieڏ延EtW}}uN>gI͓^}>GQ~mv-ͯ]{{t-uL2ѲVw(ϙTZg9-?4|<m7Z]=lnoI  x- ;L뗛,Z-kގKg8W[9IYVrVXk |n(g}ׯWٗ] (/~!s 'brˑ#ٻ볳we?i<5Y*eV߁iFS2wȮ/v4D,ݕ/Wo[/~G[Mhj%H¬ "F8g)Sk6w?Eζ}Yk.?Hmkr ƃZ'ߵ&f4}p\ٷ]kJ43$@$@$97{5,5'׍xN&Qpaᮧ^ND{ݘ#!>#p6Œ ι %ǬI,Ӗ‹_ ՘>c=؄hcno`b|ȩeV wce %-ڂH}ziyM%>e\[9cVG?G +0Ϙ8=mj[rS q)j/mI8iYhfcSkZPcLcpEZnjݨBLJ!w}?*zX\p#;Evf2 "ZN+<UvUhQ\NM>\:ͥ,?:t5AȻ R]kNgHHH46tU+ޱ>,)D`ù1njS/5]mƚGLl0s]U~{n$٭'O,OL;o|wO;N_ ǭpZGxj`Mqh/-@De/wa^Θ#\ҰMد܊RI:2[^oNկ.4ا=ɕ|(]:(ɔ/1?geV_j7}xzߵyZ0[3 @% uDFƑ%n,sE!s B Vgg!=%EYizAeyaϔ+ SEQ9Snp.84dž5:h7D-gAsJ,\(&LȐV`cX`NtmYsS].kFbjQIWV=])+.Ě@Â[oxZ9qظHڍ"3scx5kgx%HrwgȞ9wKw=3\y7:] ! }!Vۮ!= 톪'ܸ" BcMx^a3f饏4cC/kqfcM] TZ,Kc5lV *%۹Sr{ K>MݎMsF``6dAxXD\p;m<ߵjϺ۱i(Z4ϐ @PĵWuMbj4N0ɟƵ kA0]EIH drf&{d8|1Œe[>5 8҃ߵrvHHCth@5m`*I ] foIHH XбI4I$@$@$@$@$(b      `!@,#~ FvHHHHH XPH$@$@$@$@$@A".     q2' @@`80Vۮ!$kw@ *;A$@$@$@$@$h ܱeHHHHH@HD$@$@$@$@$@IVvHWXug$@$@$@A@k`E J%/S'pi;jlqV &  ^q;Asptkao6 hΎ<Nk]r 7HHSHi?]"' R춷 Mn!!ު )Ztۮg{OBNO\0<cSgSذ1Z?HHE\ yptoADncrx- 8?G%Sy}X ߕtf@KN;=>!~D,&1)G@`C5f 1a=Q?~vIo[ȵ ta)9F!1 Q@e>9{qACp?m(@ P $ąiBOIKȵ m2fƷ~U5ө[QKpV(2  pׄg}Vr*SWE> (@ P' .IЖH]JorRlw~ruT~x5oZgo=U-^*voK;,N54-ڀ Ⲕ( SFU@[GnfwweoCL{ y8/a~zU5Xja52 ~ԸF@'v?1ؐYPbboԯSG`}r>"ușy79;٘^2ڠBgp(@`ԧ'x 7g@  |pjƽI=#W!17sENbˇNcmGnl`”);3d8v!.WO%끳KTz ]WCQY*[澲mUahE=_&Е3l~YŶ:LඍX`\EQ2ݣlO5[03Y!ޔ+a̓uebwYU"<xRs۵}c}/Է[˗8ZkCk%o} |ڙzߑj6kkg>Wn{uv+9/jo廟iUu frcM}v쇴MZOzB׍'N-7%Q%kJ-3ٮS5c$/]Ke{Tm([I*/{*-n䦹ki%z9K 1RT ŪNʞedlk6-%@3ς#nגl麑G"nU}'X >CYq֧"/N?y/xZ+ippt]iy6XU5+סj zN5XU`er`l) )nmτ=ߧ*AZZr`C# kپ_S1%YM X?zG䬒 FL*-]:3#;C[qs!=MjZo_CqVj55Jg.*=]#Yedj 3PSw.J^K7Kʹdsz*k5h%yZA z0kO@嚺0J|'RC/ (@ t@s֤%%f_=@ZqȩSS!A<|qXY'54"a14$&_%K7O;15 m`Ļb쑒]#QEy s3d KNY2Ni&+SȖw R"z1cc86n&l#Hq!RvT-!OĔixvB=UIݞ |d2lZ.ɻf+CgX8c(= >~|<fܨT)sc{<7/Ԗ q| e%#7ol j(o/VV/~`0仒ƺ|0zni|qCHP:+uV0B79o\)>| WޏQv?l7=~c t`榿z`26j-I4`q&ZTukI-+6X8]_5q(lO  ?I5*MCFՕ ֖gܿf +:rc0yP_kL'ynBWMv~9$*<=Smkjv~5h(r Yj8chLhJ}?A͙[3Fg^~ST 1I֓Jϧ EM;R4T#ߙ5ی yQ!vzէ ;~eHy3QR^)u"Kƅ2Ki>q?wν+(@0^-{ d5c@NBi.5<<>sݏ ;k\%njw`U17 эfGy|&l79uv!9- I<sܵ +X o [e1'_ĸHiS#2s`΂FCm6pMZE>U]B3rpjf밳U5 UwQrkƺ ly|aM-w^Ww 9!{fX/Wפؘ3ˆ #Qs3⪓97Jr`ˮ s?KĔ#(@ tB[҉xhd 9^-SRʫ0kh~Ŭ#r.ٽxOA _kjT=0lj͝_ubjT V;( Aoy QYwVIUo? Wܪ7XaV3n`] ֤g1+`]##'7X w~̊6ґ* H5ꋿ`5M+ٺQo&Β#=z:J`WW.^79Uqsh_~ȴ?>2Y+xY;r ~phg33aEͶ{>чV^KmLK_zMUj;_HcGn^~ 0,*tbCZ^)nwS%H7 ğT$u=;2X#7?(Xo:DIU(sR+q340w1 +Jܻ#溷ۑYSd,cQo^;b_LU$Ȏ$JaA;&yO޻W/ -;`kp\#(@ P oxd'-gLL?lz_'z@^ &oʵf=,2@ `dri&J2=Mfk 2<&w OjTYbJ˶*SܘqO>k` Ӎ,mk dq/ V58ydFR5oSJ+S&OPi6}‰לg$ݯcfMij`5fl('Hs;Ԕ 21ERST=9~~d'jQ-#&>QsojOILnn{h>c!ֽ8M;IIjj9JWeJrwKӢɊy:Am4ZnbzܡQvS@ Dw"a. C|oC#۪X!q Oi6cv^H~e7%NHLL~TW02oiUNo|lu2Kz^?fU5GfɰQcWNykN}T2I.&>b Z/ш,y.[<_XQhc@v4zsކVzZYO 35S.(@ D@Ȫ.k*d>=7AEMf2~@_<^33#H ZY1SgNf/xu POA\Ӑ2G[S䣣?79čG?\Mfϛ .Q(M-k/cG\i%>p̌&+r15roTMEg(@ t.gvWЯ878L% L=B\@ą 5ًdC!^](@ 0  1lϣ2j \༙rp /_KXMf։Uh(@.`ץc2lLLf9pqh-|u 5ɢ1iP/+C P@ĵϋ{w:'e&kd6) kfA Խe =>clД(@ P{xqg>jq?FX5+n3;Ǜe'9][G ʳ(@ 84|THߕa\W|*\pn1HPB P@ 0sT5788U3!y:G,L ?W!x9S(Е Ryy ,u4żbqc C+g|zBz(@H`g?H>qK$&ArZX q>X힉8Ke#( By)̱ۘc%u3,.@3"wqߝ:'C~.Dž(@`'=ت<7@ҼbrvXn0 [O3(@ 8 ,9(]wn(@ DH>AVwrAvBXn`(@ <-[(r{Y {(@ PM ,$ D&1(@ P $ąiB2s N(@ PJ $׻M\3n`M̖(b͹B,n^w@~@-/.QCV "*]3u oϻrcU](@ P rpl 0 W<ӞON P \eWڥK^g %̤ .^,Wtae5oov^(@ t@&KBJsg= 2 62԰P(@ P`@\&M P(@ PjNi(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@qe(@ P`g(ӣ(@ P(@h+ӎJϷ29EVò^P ([W(D P]Ke`)@pXgHWUa(0NŠi#>(@ $㕆8zRݵo4Gw8s vg`/"G P~ $3oF P V&8+!~Y| PM >R(@ Pq!pXD P(@ P8S(@ PB@A\$(@ P) Δ#(@ P(@`'E(@ P(` 03%H P(@ P ąIb)@ P(@  L >R(@ Pq!pXD P(@ P8S(@ PB@A\$(@ P) Δ#(@ P(@`'E(@ P(` 03%H P(@ P ąIb)@ P(@  L >R(@ Pq!pXD P(@ P8S(@ PB@A\$(@ P) Δ#(@ P(@`'E(@ P(` D+| 7*ϓխ bKTT-@-o*;E*|J P(@ `:~巟T`u!2b`5ն[룣XvVp(@ShEM&Bjm^6Fy/Lk>R Tx/#GcR]{vQq2A fm-Ĵ1UԩDoGNrI{Sǝ7_tOøN P8PX$}{uu. چK8qYT&<K?{׍ڲJ(@YoUvߔ7C@E~{вs Pm pT915Yv}ՋNsc~'gu>L(O\/il/u %B Dlg;.]ro rtI}'q(@ P?^)e@4^_y{th$z :2@ |.;.Cwz5Dž(@+ 0QP/'N9:Uҍ޳q6Z *ƘD@UQ7swChܪt]m-cc<:ma 3L,Y a{'wА{G4yX< P@ ~> VZj89~:Zd:;.X Px,WKNkQ=x o>,z&7Ob/)(!y|\W̢zTUʋ kIN:ǠkpmdNՙ)SFqxV(~8W߈Oe*^ꮻV-Җ:{7*Yc@FzC]?jRע $?b-@bEE+ֻ | Ƹ8Ge>X^;:s%+C))p˶32lN}ZE ~,qڕfC('SP8E8V xtz9V%ų?f UZl}l~*|o<|Hd{Y=K*Zr~EbßDæ%ԕ!2hEv ˶J\<TV]ݑx\\bJ:;{%܏g_'ᙡ( Bÿ!0Ӻ}t<}-QoT/EXQPPͮ XEoSO6"/czߴ37E̐ᏧmA~ϼo¢;'PHLZ$Ϝ!2k{lxSk@rjF[5)ۧa@okC{ ><[/>mzu$f&_ZsI%6)2j 0?l(@כw{vƘ24T@@d(oP%{W)UW<pvdʱY#aosƸRPAYƑal)>;m(MٖoÄa^t%ÇPWf\ky(g<&yp.#~}$*DZES./_AfGmhё5@w$ k3#i=,ZPیptm/nwouEpjN?@D 0Ӯ*mL(f h3ʒ8FJs:hk ^J\wBB)&R*wfG<.7t_$+wn~4n(i5qԌO:(`'~qp@_ɥ#ɭXuIߐG_ (@HV"HѯiZ/KxLhщh^j)B?^ IɘrU kTff|@zՌQ_(M5 aC$I1FN{ukI7H}ّWGy͎xzD뚾VxND<( Bw A_i)A+p#\.nX^*[tK΅ķF}z`4n=XN-;/Mչw*bPIwU=5n@3 P@ f!~=DO-jS˨>эcu՘uC P }2ts&I}x|qMy2?o9@?(@0Zg)@xKFJ̩u3S멳U̱*)@ PSv;2]w J (@ P(kɾ'2f P(@ PN $͈ ۬_î<)*SԼe_uţ8MKNNto8:D JY}uRØ܏m|1q(+ E?Uߜ{>цEu4#B Ph!"k*uC}xphN"ͮlpx뙅z}M]+ڴavSO=㧍R,Gan6qMQ'c-X3|a2CVm1F̣mx5ekׯ.5;\{|Ķ_Sn6={q.YgƓ1c$h@G̉0L&,Z>a:6ɪ#pt$- h}(ؾrJR4HNe^w$?#K94=ȁޑ^9k7^̌G#IW#1 ]hPZ \wwXhLF]-֠GӪ7\;{q%\aszcͽ/TÎ~j?[*W=r+蓏d'чŗu'MwΝO-݋F~=뿮(7NeT[Q STOzo1o{|#_ztyyu<zÆ/G43S{\ZZ2Ve iJ <6ع=_SX#?pG&A1v,]$㖕`-38ƞT߷k)G~N[܏~ӣn Žd<ŋِ{ \=; TLpC2ϦM'4AfJRC2I_uf$ 3VIJXy T'b ]6zj '}ύcڕh)3Iّ[#廊)@ Pv]:qCLdRY9=-kGej2*5K-\cFJLa,FL$,gFTkJɯ5gMM2ITj*eKZ'Tjj| 75F"ԥKK:jstA: =V$c%j?|ǨcZTEvM:3%Y Õ]$}=qJJ6{>&j^fe6δYi^5RZk6T IlF9=-;Q6MV^}ج~ t$\$$稭 X\G9ҍ 5KhV(_ھߦlJ?V<aE٘(@ O JθQk }S;1o\&|*q |O>@BѾ8}xn$piCmM#bc(nWfEW1~R<"4.z ґ͐$*'>JηlE+V.t̤"qN{5 6׉BMmc򴑈/uҒ31 Ph)`- Co[p'8Y)ث1s0!>rI$F@2̹K ϑaTS*߿:דΥN化@,=ћYXsLw :-V^俗[ۥB~w(@ xDt?*(@.`GRA3 P@ Dt~5BIItXV P@ŒP(@ P^q)@ P(@ KA\3(@ P(@`׽̝(@ P@ĵ;S(@ P^q)@ P(@ K JoW!3(@+.4^I2- ?!Y P.qԥ(НA?.(@ P , p4b(@ݳFsx.)gfK PV DiXӡ(@ P(@ :L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ P ,db(@ P+ .L(@ PVŇDIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_scenarios_master_clients.png000066400000000000000000000574311322762156600333670ustar00rootroot00000000000000PNG  IHDR1sRGB@IDATx |TŹ$@ nT(Z+ [zV^Jhk%[7X} &VP5D^ KI !Y8gٳ$%/g}M>639ٙ9a0 XFehHHHHH@'@HHHH,&@m1P#    l$@$@$@$@$`1l Pd      Pd[ HHHHH" XL"b4G$@$@$@$@ټHHHHHb9    =@$@$@$@$@ȶ(͑ E6    E@iHHHH(y (-Js$@$@$@$@$@{HHHH,&n=#q\Fu@ dHH ';Γ #dc'7 4'_z3 Wך_$@$@$@$@K";` +lE$@$@$@$(8 ך_$@$@$@$@K";` +lE$@$@$@$(8 ך_$@$@$@$@K";` +lE$@$@$@$(8 ך_$@$@$@$@K";` +lE$@$@$@$(8 ך_$@$@$@$@K";` +lE$@$@$@$(8 ך_$@$@$@$@K";` +lE$@$@$@$s:N$!>kr&,q&VxH$@$@E";ꛥ%S1}pD4ٹgfջK?^O @f9IE/: ZCxlkx @`7zM"pY萍 ˨Pۃ^p HHH Pdp$?~qN7ᾷ? $@$@$@. hA7G @pHHEvU) D#Whl^P* $q Pe돴OJ7ұC ^,>`Be tdwdfAF@ӵr+\ƅn :!FTM=J!Q GOIHJɶ&m@xDt}G\u_!A7!p̗۪-B$@L";k@; LUEeXtK2R\|c;c@#(ă3@?2М$@$پJ$^]7?a~3W:ʧ>ZNkd_nOWVfǪ">=,KZ" >'HKCq^ll6`h$)徽ws{;rۡn=uQp%`m ,ᭂ]V!J| 8iqݞXWZޞZ?6\mxⶾX?/.RQ^1nK$@L; t!u8*keNYY"#@DU#Y)g ,KJn]tT઄d$%JCa8c߻z\߃_;Gaժ4d. #o®LjGr$߆N(u51V?VWwuXKG= l_HEv$A]@a2Dz )2 1jmvfC8px#qߏ_g~<aʖXoc^b;8p'݄b,2?Lkcc^ ϯ-Nx~*y&鶁u @d1H #z8uJ:4AۤhgYp҈A9pI)3^8-Im,aM0 or80kv$@$(? }#}L;R^9G`L?`+'` l7F(CE "n@ћR·5QyF`݈S["7`iX@&&$j)>_:DP  e.ʵϲ,& />:n][q8u]lYp  P(y@x즑9?C*zƵ*%HHH Pdr!K@=ZWL`cwRUyQJ^'{HڪS^U>ʻs4͕$@$@Nc_ D w݊׫;b=w kKVbD9LwAej!%;o֨˕8k Y%^GnU(f%YM,6fZ}y 3 -^$Iyߴ^3ݦ{9֟\HH=:j.c N"ѐOQvT_sR~<{s^Txf [R&v>{7;'%_mR؉_;3碯 oA@FHnPTJgxhrp'9!c)&Ŗ<ԡ?hijlCaJL]\<}G4n: sYb%etCgNC췿onPD qCV8؏-yKlˈOGyU+"\F\۽Y5ʛGܰؐ @޺e0~vLb<-*T1ǏןTak!bS#A$"q9XKawY v6i{roh՘36}#zۈF~#c"&/O aI6mZy*C 0ʺl!ʹR3^UaNE:-=o϶C ЖXsҬn*zu2ܨ^ope㸛^pK ruu^z$RzKV)9x;t~ JYUXdҞy>[~^47!3-ʕ5ϋu7}p^rV!KQL5膈-hp=3T=m6FJKu³!O3=ꥧ] F~Ɓzm9LM[ۙ @`h5X[h5I%qr|J,Ӈ0Y*+~u9o3i-cfHG_Hϭ);s1@AsxLhu4C)-ü @Lk7ȰiZ4Htʷ¸'T*ߣAa#cVC__ X3[AԼDgo2|mn~[OkkdcCdE-!(nKWR:' ]ݺ΢F#'܏)sV8vRz>&D=^9 é`ݯ)`Α4l"a  &vӒy3_lˬI% ƮD(OR'3Ͷ}{4(n"yr~ՈdLF{0u<†̧0Ez5s LQ-JtmCjKT󍼌h;Fcũ+,< !% .ZC-nTgQQ$Dve*_( pJ$@$l`/$8jm iZTW9tq_&ȷĨ+`ۭ _!cc1ݭ2ڡH󫭮FP^u Gm5j$m[;P]]&{ܳQeuD"*讐[O&:pƤ$@$@ Pd7.&"v4SL5{ixr -uxS$@x*?v}u5&yĻHHHA @nj#[HHHB'>f$@$@$@$@>$@C4M$@$@$@$(CYj    !\&   M١Y,5  Pd.M &ЬwHHHHNt 'ۅS @`Ovg$@$@$@$@I LEcHHHHHk'k3W %pi{ʂt, @k pLvkI1^@(:sۏ# ry&=k7\?i;LHH|F"ghi_(=8USKFk# lUQhQ%($@$.Xxo>>x~M]`O/-,LڿU׾9  `OoҪpwon\=hA% M߿=7;{Y hPc'T`ѳ{7(녠$@$`5?`Q#$ВV>MQ=3 qu;@ xfn* #-* fHEv0n͛6qPh$m/l6I[ -١UA]lI۶h6mSh$% !@:u%m6APh$m-l6I[  ١QA]lI+6mSh$% '@u%6Ph$m۴MmHEvpoP m6Ip۔۴MmHEvmPJm6Ipk6mSh$% $@ԥ6Qh$6Rh$% #@|u%6Qh$BwEMn}mW|wt_U$ 'Э]$:!MO~0q~sXOK܆=0shWI ϜwbG==}xt Cծ_dC$@$@H"a3L?<;J$@$4 A]B.P`\×{N *;ríC*~Q)#4?' {H+P{qw?c2zvm>- 6U=ko5.F$\|^K "#EXS`wtff]!+.q6 @W*̷S`!{"n@{?L T&Ư_Ӎ@_HH l/pxs }z"a u9Ds5s,L/]tp>2o,H hPdMUfA@6o\1>z v`'굯;egqIf[tU"$2\3XsB_$@$(2=h(?v Ubl?{)^ }%ղO?qbT6zhg</X" 9`X[ln*?#DbRlo^dS`}Bh kEzO4uǗB{kYF;.;zG$@~K"o'uB'ɂ#X>u^dS`Ͻ̞X)k/]%xF=q/D` *cHH(}7xaIKz lL_[#b/.F󿰰#cz?8}E{0iok],#0# 3߿.ݒV+&,7iD:;sĵcˇ MjFeAO<p q;_{}7|oH|wߐ1d?P{ZP7R Dk9i)(eN٦X_/[^۟W^:Y76ҐprMlr'sCw/$@AKc'5C~u_}ZV9љ4Z"b^ aǟ~v` h6T.?4TaC; c #9/Q{3e{Oe`I|S/Am\,Ysu#o;plT؆cl@w܁T;fۊmqK͟gt+bܞ|#Pk>2g`NYR:r@$bo{ wLޏ5gՏO=n1Ѩ>us z)6"~x_{OWa{T|PAIu4cQ ~'̕9wA=TZ?5Տִs_F_'WcUx`gHTŽ,?o*"u15|)w+u{+5yllʾ8=2"d͌'m2nhx7;'K՟!W-enuoWLٸ_ކ2qS^ۘA\ı>Wy+a2Ō'_%ϿĢLT\ f̙2o_S.ق.{Qx@if3H"T-͆{Vc{I5{8LfGjQsԖaObe~-i6 kkO!?Fp{+'7{f :1c cƠdFܳY&sxM_|lQXcG$΂,B:b$[J+0m`_3|7B`}N}_qu%(FA3bk0G %JPرkñMV^ %"(s y_3ĭbUU6Yz\tA1GE‘g0-.(VcFq7pCPKCb|aHE?i"(.{e&+l.("~tc]P,QŽ^_iW.䮛B[:ruWo} E*d j~ #dzE5h7IOߙbjՇ\&_W=m=@B{y%p0cD Gp[ܵ+#uX Zi\I$,T v6Lj͏H[CEJt,fڠ_= Jh֓3ÇId@TqKLy;2 bh:*C~5c8?y;_=ƋI:?KD[lX~Ďq"{=""0dlK݇33H hs&>z2>*"oc4>jv;I[&w}=ZI{_&D6YED&#%C]Ji/BK˹ D*-#AbB6K&D0PXYiϖP_j`cDP.ce4c5۪|Yҫ|LIZsuwFjbUcdE#jݓmӞWLRAMjX͡Jy8]L Dk"BAaR_O Ku֜ijJZL\Kh(*'WRKk&CZGMT_uNvti_MLLy#jW1&>;iIUU3U X^4=-kni*}LfbpVWFWH׊F'oa=f #9OWqgOh4D[OĖ6j/.o+D1&djQQj֫V[-?m٨(g! 1p> ە!gᑮjFb̩Qw>DrU҃|?r3#]+qނ{&C6-\x jVsSXYʐ{B喵o`i" !2fA}C@ I6GĆ_w}k}/UvQiAGm#mx"݃JU|Wݢj7v= q_uuPO^5'@$@$KxgJɎ?8l'N&` mORz"id+/> @kCzP_E#IHNAɴ=-SOPVeDxSƟ6ml33nI\IhV_`p2O| z7^i\g$@$@Pd{S]K@cɎjyj(Z{'&O\@i|Ɏg/:ȝ  h'vc20~7ƞ>&`xӲhIh],O4&;HEvm,VQxM&;not Jm"ThF!jQ׿w12 @| U"GwL 7nUb^17K惧]7wxwd' #@`UvI׵.K8qcLu(&&J:pãzbk-/p;,wIH N|'X/m/;'c{g/:, p5]pU-Ɏyu49Jm t.dw.oFX㸬pP|uhk_J'H@4 iܫ_ٶOФ!AXZH T PdXͫcZ&DGBz<,HVO$@^ zV`bLo!p)F+zMË$@$h(Ts{7\{߁<_|\ &%rjHGGst:)5d䛣_#!@`ӇxAqDSUx%L<'@ZwQyǴAV- ](nZndWJ#&A$jK}'0*jfU؞[A*hH:B"# ;eg즑8wXnI@u )7YPxf "S! ]wVq<Ҏ"zG!HMY7w\`cM@|:zז͍Ekg"p,a=Ö~6?6CP+Io=q)>'?^kBVt?j?pnx*aDD%EؽL~uaۀ16 x&%Tae#눤j$_N">5ϧDs*L7l/F?mc[ WK"mǘ0;ЍH| E{Ϟ6jG*̈Ao Pdm1c‘Zi$war30mtلAJM E?u;$~bCz7L[L0R ~Bm钣UሉXQOUo7eD VsHskf- @7yZ(Li"="m0)F59 6j_Jd6lo+^ܱXg(|̟\VCE}UWfL^>|G@g:#y8ZuߎEltl&#ox[nc&c̴5|۵%ȸcܶ!?}i`L ӗGhUk&"ZFņrVM~bBNVaFC_>7 }[_$"mj~5ng6Vy-rfȺm;X&@YY"b kc %@5ӂ_e*C> Z.$iGr[sv澀x]vU:fߒq<_/FòlF93 |R0`,uԤۑ,s%yEh=Fч&9j ;ZYUD-Q:F5E9FD'N `[Ǧw (J V@(}y00*zɚk !1D 5C3&n7" $pΡ`[->4A4śP!o ݑvGҲ7 .ALN$@$@$@$@M Pd7%c     gλi'22u1 XE"*]lGWҽ\Oi1BqZ&M'zo>>H pgK.┬B:_ϡ#UƊ*J@$@H";Hj5mO)Mf^ϯS/=Km MHԯb+wuD~)3~*[/~Q\2UK4! `"@,&ڎG jى4ZTHTyU/3 ҳ$@@Gпg8gX3_TbgR|&Mo|&)v$@$qgإ}i <0a?-CDG ȃkTP=F?tG]<3' gZ WA0?/ewHgRP@`!HH &@cD;O')Vҷ{ qكzEkۖKϑt@$@V$#)O}i>"VL)9/Cebw߿gGYu|NV6HH*|U$Ȏ5D~U* ꉟ4RW_vy ctS_V95~ !F/)5Mg %@ub|3 'W )վ)~ʴkF?:HXFR苠* $@$@$@$@#ɤG}*ĥϹ~. ~?$UN:}!%@`ld"Q4>V!kZQY0_m )5a[b,je(qz%K[$@$(zTBbH]DF7o2yR"7FIH PPdJMO Jh/wxC7HH? X7?GHHHHH Ȯ-ڈ0yU;jm~N,P*:#Xɺ3e$@$@$@K D6Drb"\;nՊk1c  {̛uxM袣8V+Y峣K]yU5LtF4b́W[Yyb296Zc:?6;JO>  FΜ8su(YqzOrܬظYx`,,|r-\0Kaµ8Է*Aɖzgɵk,,}Hb嘥_,=2=򳑈##-8fW(/-iPͳ%7: ,y 2Uc󣋑-^y7Z<:jV*r\xũyX]2ȼu9vwkn&X}o|[W׍;:jng#@kho^d&j }$@ YnUij:->@Js4~ViH!!Q9ӤmI}m)Ʊ-AKIIt摢6)X}i&[&j5M.zge8]KJJ0Z\kLZF͙-1C)V%kKc|VEuhٖ;61`߽s#o3Oh\wK>pw%&;78T#t>Y.E|黵cE9%k)Byah7s6{툞{YZݮ%j) vGmZ|bHnɮMygm[Zf?l](TMZF2TǫϠx-%?z߻lR:-i[.S(ؤəǭ\-YxxmUV!x.S˼o|f?g-_S)LHKӒi9ZnF|OS-l({zX#m@0p,L3UR~YZrJVPZH0ilItMA`~dvהjZIOҿ| LbXrss6ԯM:"8X&Jǧ/hPS`VtC'̆-U;)g\̚Ӄ-2}Vk<U:!g)t R 9GyV /w[cMRyb틯z|%"5W_8{hJ:$襡k=n%K^"&K Ə7OTu=~g䟜a|HCYO܆+1uI6srS4n: s|VB^\~s= $ cU%Xp96<}σT#Ǐ+_`ˏ;1I(Η2!Srw/XJ&Cªԟ`6[ĵG{Y(//EAN2C;hLF&ߘ Zg|%xO l/ǼjLz( F~ 1ZDog&$C!!7מWX!'רØ2Գz4qv4A2yzJ0d8d?- 93gι/O1%qC?,,ZʼHoQs<4=im Rx.ӌzH\釴?Խmi_1<]NsH @ Ȟt]:sdxp"lڰսDh+*sXk+"}l0_"=ڎYfJj㐹w& qJ~F'z^lHDETqWȿQ/{NjK/uRi@K0Yx=6U~'K!jL ]$mǸ$E0cP-òE9y1.3\rL[Եu˃v섋cZKͻWȿU%j?2H$@G exHL=2* 6Y h@H얱 gHH"] @{PdӐ ^ Ev{1 x!@/ @{PdӐ >Y||yH|Fj}fI  \{">.AIꟁHH"[[dr0_ @+x+7aa. E4 ٢     !.$@$@$@$@$`1l oiw=5p @ȞA @>@ @`39 @" @"{5G @@d @Y@dϠ @l @ 0  @ @f=#@ } @, gPs @D @gu7{IENDB`icinga2_distributed_scenarios_master_satellite_client.png000066400000000000000000001667301322762156600351760ustar00rootroot00000000000000icinga2-2.8.1/doc/images/distributed-monitoringPNG  IHDRtx-%tsRGB@IDATx |՝?O L $w䦉 JEn[m [hĶ\vײ[Z) 5-l-l[m UADB!I2$̄I2 dnk23Fz"|2FꚮC%p/_%>(@ P՟ջs|L@{wȵm_a:|mh^Y-0;I] Sm 2r d(@ Pp{(SyN9W[>q =j!1* 3Rn܌:ez9"5(6H&a/D(9P@ ny|TQfOyj w8ƧpX P( Y \Kˣ4mJcw Ć"Ptʡ2.?AZthoY@6mY$*-$svY\kI\i W:kӶ/(@ P[йPGժqA;,hړvoVh7ZP u;b17!٘fL Œ5q(@ P#tp;T@g2ґt X@-I -#,.Vz8y7(@ PzV]zlI~O&Gћ\)ed(@ P 7&B P(@ P/E3KffY(@ `lu֙$`)Y|A4ŌsBds[݅ lKX !j #$mTzp-|'AdJy7\+γ(@ PF݈(ЄNYɒ8RT#GoL$l,ص4¦#(N^)gkEN'uP3Qut xI S(3 zƙgWd]of\_GbܨQ7.w=4o l_4r\l:sCb|<E?/Ú=\ֵ`Z=KPRd NVm9'a]hk8m}:FKX0Kǘ}R.5{(@ `@*^" ?s\}U^X?>QqQq& F g>|K?l{݊w7 ext>&mqtYa:G嵝۲ K6[w'wB:󋐷6,5;JLY89S`Hdhfbߌ(.+Gk0olȈт 1s!lW$َC gbGyDL(@ P]# .÷cxQ*%Eq 7'DCu麛N/WI WנmPS$ȸO{ßVA9]&pؖ3zoVل IKn}߹wB=fJLjc"މ:ȄLkmFF헺 9?Yf>p?v3j`oG Q|6X; Hv!}M2nK@!NǴD哩r(@ }M@@]4! ZƮW ӞQc9OJ>w wr}SAxx sS\mRN39}l.y<S2fUӤu- w4(AadTa3w9s΄9[w}j9Mz5eٍ"W:,Xf5d<.H(@ {Y9KqJ<6I/m=&ɨsե8ZU޵F+j/Fy|G^[/#FX Cc#,n Fe(@ Ph eP"$u_y>;$w'ABd(&5n T_OU֡Q]dw;=MhC2N?(TGF!Yca=w mUo]u>C&7-[j¿KY #1T QwdܩYHϜDJ&uD]z ڈShzw#r߂751 \dA+-X 4 Vƻ5H|G"Ǹ342\QRa((@ P 5*0Sz%vqjt#"e3I/޽a|uMWvfzT^jZ >>i@ $FꝋmYIXR:O>L!7Y՚RVbߚ18Ly=qreŴ)1Ͼ?A(,غD&.I<5 KR`޼O͗+gasG=W1,jsjLя0}斞FKV;2sYpn(@ P `lӲb*pMWEzYT)l\򐟷7.w_( bYX7e+cGn4ވ-~a):u6y.`}iXV4d%.VUw3Ԋ=[jZniyޙY|@ P@PpOP43+dFJ|~X?7/I#kK,WZ=g璋ƺv+'py#l_MFo~Ȣ\5OYr6iĀ:,O zgduN kVǢk[%=2r P@ y`l=zO#gK֟K %bz? 8 I=lO.7oh7y;ar"jļɎlKa|ºVKk1RLjO1 Gy&&堇˾=/4x%o6zMJ<6˲eഥC.u.呍\i [g$ϲT`U}V}b"vG96tlb8(@ jLV}0x)},>'=t+pl]4 Ev23w/Dr .ɭ.|nh?dG7_7 /&JAE&T[+DXTzwǤ&z=YZ2~!14ӣ&i(gK'P!LZrp(}fKM=s˚0CP+ A{Jy"ӱ{n9X_b{ƝD.FjR;3s{ PC׈2kI .8 "mbɸ9M{j.FjmN뭗a ވ EJ'侏Q#1GMTpU\?Sxl.Y,ju}^]Oaߦ2k<$dbedS+Za^%@ۅwFN) Set#0TUȟqXsEq)cN0C89(@ P B%CE;cbt'uS/F'!>"*SK-uaCc#12.#bb@?Yg-F>1A^Zz*/9nMRYZե&T6ΑqQD,4C;랰MnR3*x9l54HWMYa Rs-?ݧVNAqbrQDL&KWW?WS;\|Cpg̋۩ό +,%`dfȷH}(71}1V7AnC$@Դb#4H34Wum(LutC,-wammsX=e"Gly8jQ0{v ?;P( Xv ܀퍓۬a -Gk?usuzkZi/Iz%xssN{!E Cg>(@ PA/.tA1CZ\xێoA醘"0o4nrClXoJg{^aMV6^YP7+.JWT݀c8ZՀҺKЁQaxb |c|2&:3G P"+<)z^`bb,{Faoi5Qoux MWlH"z- GZ MF`v2Q(@ xLh1|S W/L7nZ%;#=ke M7qFoWoJ2Nj {Dc2vsh(@ (ړ6,6Ҹ9RdYh8o@2S(@ xY/ $Dˬ/2̸ΗʲQ(@`:t3(PlnWC2u& P(@`@[PW[+|l, (@ P PCu$w$t#_(@ P:.Js3MͲ,d(@ Pt, |J҄#Uu.OZ 8-K0Q(@ g`I(Sנb "wt㤗n,oD P( |X Ƅ(~1x.Vb(@ Pvt`)B@VrH4&E j.ъ7Q(@5t=NRvR LńhX${Uz~XjQ| YB PC]p3kI. d(ۊΣQ-MacYr]Ey]gd(@ PMy X ^;Wpь 11/eˈ^DLNDQ^ B|, (@ P>_P| /ڌĀpȺF̀8 C1Ǔql0@ P(3 zƙg '?.šr1 C9u:!~zktS(@/ pȥyj !گ>9';()7FEA/{ P(@/ 0$P).o+7.YcȫH)OawEյr^o]s P(@p佲'r}d"OM[qq2eD^x9t};19S8Ko68w KML5!L P pj#P&A\aU +}(\Ι$;+, K<H9NSO] @̮,FIgL0(Ak>6B_ 4(.,wGH?}p{$+r6* 9q&'xu6r %dNТhrLx0Er|LĜm3H!iӱvW ؀̴4gjB/c&kwثlEBk;w1܂E_v7,s1`c;`Ǝg`ذak?BeQO 4Kpaqy'y: tM2N/ւb NXqkcar\9^4YNVd\v=Kt47Ѫv12R,ܝ4f<)ul0Q W(7 KtӒʑP.'YMTdd݊[^OAśi -Iӳw IӖVie<;52cpK٨_xM|H P!!,J&hiBLY"s$#e>x,)X.`L:0Lz {̗CLde1#fBDń*/rߜ U>[d rkGk||+SNsm:PiX-QZs[53WAMM=` cd,X"KJzWMM8vb?_9i7jrK͘6( [88f|(}mZ? ZFffd 1fr P`@w5tFI̎+kt:umB{V#+$Ps挠NJ#%tɁ(4zKu%͑ȵvЙBW#כy ᘛO .Of<^Pq&0ZEƩnL/ڃ(Q4ĩ?_tX>RWJƌKWfP&&\ R ]g3e_ٶkM{/&܎D|\jϭoBkYjй85蚬:L''M?L/=npٲt~j/4nzm&}ߠ.AqZvD/fl9vK*ceXzk[=|ɶ9`~WJcMd^ӧ}PV>+Ƈrdc9Ik썕adHZfO&L. =Ѷ郮S{%q, u Xr9rWnv"OC42ܸzrqa'&*m{`ҁ̟%B5 wNt·(; |-X h`V4Q7ɩ^1#{ $rtW{Z93{z[{sy|d(F,5ezJ(hgٞk8hvHIXD`wjhDwOx T{t ګkIXFJ9]J Ii@s'&[EHg2WC74xAqcAME%0B Ι(Щ@Mh=#5kXe{t0F,|;1z^ 3cMTu/tyu|< D-o;yd^͖\xO P>!'piړRlL r u^PFc|ᯰX $ʐX7"e"6msE'qQr+_c%Xө5ttЫK#K0M^ݑgQ29L\ooWw c 5`ஷҋ/u<E[d*=PjoՙFx"~+_iC~^&1}Fb{:0%kWXǶ8*V1lxǾ&ߤC:=0-!2)ʚ'[=k0N-YfœM34|ZO7 6S@tKjlkl=^e^{Z&'ق"LbӦpiϛ\uGL=*%PT97G!zs$ Hs(N[PiN޶ %VO?9]_M?Cz f6p{XO!.y1hUS{L)frxKat/v¬[e\#%Ynl}>;k6b RRjnDT1M,O9/"&n 4/3>\8Ӳ(@ Pl-7eW =%:~|A/׀NOgkʹE=k4/$dcXNP+ǕZ:K$-p0Q]Pd7Pz#sY.=' ĭ2S{+]vhͬJ@) &cvXeZ鱓9WXf9^Z$O9$,,&dhg @zA#6 ԎHx|$BVJ32n\4Rz=82Qf4t dJ{[(n޺C&Vie•a^3u[+p1G7sw_` ;_: 4?U5)yv|\|MN@}-^VCЙ!m#e2WnJa:R'qL^9RLe̖kt-=]rfs5)C7?'tU't& P(p-t^%ޒ5rejwCt-6Pt:áN_(12S'kq$"A䭲o$|-&Y?1s(@W \pWOOQ +uouH:mLz1V9`xXn赝CLFĂ^̺5t )2/8%(@ P `stq?KCf5te ]^^'3p,+fBg\6}rU2SfйR6 PT>#pLf|X^):YG.]X&uLS uZvgi6 :y\_1=,)@ P~,Ώ/P,ɓk6rX[!v^1Q teen7{21TE 5v`])@ P 0딇/zZI:Y >޳"5sdYYWz̟>*jѣNzt)+X=Ρ:L(@ 0{kodevipK]1u`_۪څ'-Æ~6#E,QЈ;c"0Q(=kמm2E?,IY{kc& }r95 OKK-g2aC%'KyX(@`]P7w*_A_/¹F<.kq-JKALΎ9 efqm(@ 0{8edd,5`8g L,aȨDgN7e2!]#_ 9(@ P'!^q ?ib_KRS0Wۄ'/Q"SrK0M`,_ƤCCMd(@ P HC$ jVX"=e9onyA}2Q e,,^o1Q( 肣VzYL\:5輱X~ўǼԙ.cr)|Xnx֒(@0)2k>Iِh9=.WsD P@`ii7׳Nz6~|5MV9 tAFVaU=~x x}469gh ؝`;zctSP6 t.Kپ8Ųm*mI~@@g{_AHb0w#j<ǐ{^=[j67l1_jU7!'j-sqsrkC(@?`@' K|\5Tϧyd{>+Ee[\wbM!xKwԽ$=wF\3G*eg(@ Px KVP\C+7hd:Ʃ)QYuQLm9BDsP+)YbtFY:$Dm5zo ޽`utu$<(@0 ;OZbs>0`1px`{A]w/kq=]o-(@ P@#cRQk}?a Q0!6!_ no0ud\:LzHR(Г zR;u"Wh䡗1嬡 k`ED1b]H 満]z\A]w?o22_1l|edcˮ}z'(@ P  HܥҫVy [2Y;ӹKxW&]̖5ANҝ/ɻ!!{ҵx\b:}۾(@ :?i(_*sul;vn-ڙK9>/ Brt_GeoLåHwk9 dr'ouܪ(@ P=+gl-;'.Hө3~$+$As, t7uޝÍEïW&%zY<;iΠ(@ Ppj>Px5[zܝGSxe@w\twĜIY+bb|\e1ET4ן{@b\N>],֝UkL5ϛD/O˙(@ P?Nm%$ ׬mlLceX+פofb]o0gd N#qr+Ŕ+0ifW]"9"yVQLC'@ڪj8:wS[|.窺ъer].DS/0wws1(@ P=+gy6@|,dAq,(R씡e`l&0rP :C6*uk8.ݿ 2;6g- *KL,4L_%[NkX+>¦}fg=V!͞Hl;xA6c<ړpR|pj>z˩L/؂K5_5^9ء䭠H>gr}j,t~??.OJ(@ PW{Li}qGR,{cgoӷ qY?sr PXPݵ  7zլ%;0xl$J^>Y\B?5@IDATS9و??3Gӆ=6RlYW =s!ڍ}EYf@F9S`ߠ&s"'[~ɖfo.؀aIz2LJZmT]Vc{p>ۂG{Ǘz#M֡&eN?A\Η',(@ PRܯE Jִ6,`n ]_齦2s#] e*uM㋰[JyZU;cvy:!.,}l}[8m6>3ٞs1J/lwKCιI $fO>$(cđ؝{X;&7Tْ7+ބ'g@W|a{8_7Η}?~Dei-{߾% z6&EIϛcL\P;(@ xGwS`D\$$kҹ3l>USeƒ/`شH2lkKtFuU]V1Ʊ_h8tOKVO8k# f`(y`-E 6Sz)=j)fJWꬴ`?7AP<mmO?X_p?:t ܻl;竍}(@ :m:\f?/ċc){q\ h?`F/;_K FUkg;C9l`sb29~ K|aj`o[ANCn!ez//;B -!$9ò9%\xΘ v7H^("-?I3(@pﷃaaE:8YkA)3Az"a'k31 1{g{m(oh8z 6-Y+ dn)5?$ٞ# }lj7G}'Y8m¢cޖ\Re ,i.>*!4e3㥣g3q˙+**811qn{9sjPl`A`N R49(@ P)"}D >Sy/5OLVR~ :)tQqQ P$)|2/߹%h9͍|!n98X̨MƵke'J3"e{ĶsL,+"]`j%5uN7wp,]u>uo.+/5aՁb<3qdxsCxq+ e}V|B P^pK%iS~Ζ[+Vru=2_?uHz= ]F9fKVD x0 P|KC.}=46V[0Y֤Jru~˧vaG)ws]ʉyZQNiF|(@`5h <-Q!%ѝ _łu#jO]G='/R#oAڍ],Rv{ :lpqacN(@ :j )MdF'b'%ZZWvR&g/ wC7f܁npG0ř;6X}EHqoޅ<)?/3+ PzH]Ai4:)Ƹw˗qD&o^kfPH9MqW[P8 (@ P _wdH55+kWi%Yn ]*+.1qpg0EC7T ޝ^̲_|1Z"a(@ Pub=,P!Ӟ'E=b :žu8QJGi!6oG;D80墜(@`@RpԹ؍(1$=›q&II3c P A]@Tu`07łRB]@4#+,9oc xZ?(@ Pmеn T^┬QVf;Qc1묕ǪǍ2IaUrs3>Y-ݝԹ[]K'9tQOV'9M%P-cj*kDTPD P@0 􉚬? 4|tl_QxVdڂ;OAܫ,PĠӕ7X}21,({ϿV2Vjy?Tz-3^ P^7ThU1_ J 5 e+Pp3S^jY8|?_ģ=V GP0c 7&@y ##w/[qSX(FE(@ P tԘޮHS 63yM ɛ_:r_l,OO+7 @UA<)ﱚSZL#w_ʱ2 $k=n_K[>`(@ س{0./qQk0oqݜYMz NKI>5=!kŠQS/)żqF~-?<&\0]z>?. }CӕО$&a(@ 0}`%'`|\hÉ򖞺?vG.Al\`6P&z!S1;\YM0p^VaiJ|Mz(@ P<k Org' kymCZ>S7̓\ P:Dy=3ޛZ]mn}}fH~( F*1VbE@iIփ(^]{n)7*d]+T_>Sw r(B{ZrQ!Kf(@ P??ͫLRF_[Ld:]#m3oE+:':pVZc┑\̌(Г zR;@*rTջV2C/n-$3@ Gfg ]qw&Cl3_E P@ 09:r̠Pce(Cd9I|,(@ P^5t^i)@ P(@ tW]wy<(@ P(@/ 0R!!!\i&|тVaG2}vV^(O`>6*DZT둹fX :wqh6u h{m 3g]5~ݫ]|ֺVN? ݃44~ ,(@ P x ]g>C||$^@Wk]Gn8:4~L(@ ܰ{:ksPhY`LO3zҦ%g9 sOǂUjt7 =>J؀4iUKӱt[b `Z(5QQ lƢE+ |UNK;6lRixfkxCzҴGL^ۼߖgg烵;V-#u׾43v<ўf#8w>!.u-w9U#uJ[ fEaSB3g_|F<uXV\MǞN[ ιhQy_}haj[~u{j-VdS]7{c?mϚÇ(@hTt/vrA347ݜ*y;45;Wo;FCT17m7/XQ<5ysl>ӦdMgr%}77~NRϰ\!uv/nޔ^RS|˗7/Ye{n߹,Z廛,\tf_s!#GrlEszUmͯ~][y\x:&Ym(Y'wQ39sCgg:?kNoZ]>.F P<*b_tslВEFvf7/_|LCpqLMgÁl#0,|vw3r56/1}`N˭G*4mmޝ{=L_g@wiis24dNZټS޹3^ 4oŒm%6,@fl2Ȇ ݑM@1+g`Gpݬj1m6~ijۊ}kZYg?N?H}e=d ;G]?k7پ:?km嚛;G(J:25;ExNM拶{#ƎZ7c[>l3R$.bl,hޒC~I-9}nq\v^8.1Ƹ ohR<"Ҿ&Z[@PROD؆4'V#۟Z̰&!^7G~JtPӥvmAieybڦkur>{$*1}?طޭNh{ށSp]5ftNZgr|(=^CEcϒ3 {7`΂g9دkb=:{xx>9M_F0745!;lSق2SfdgĈm&p0H^ImL\j鳌M"7=-t~ ڷ'`Ϛz?k1?kb)@ P 0CI:$7Gv`=[iEyPǠF{J)AFjsFX &7![gbl[fT/D9>DWTG99 kA(_%|fd8kd\ebҤL)E*Vn>&JLɘrޝx=g> vL#KEv/16(C#rlU0{zuUǣAnu*ŋnr'~.߿DVmfJ}6-`s5YZ9I6ux99Hr!΁׹;jO~֮f gV^mY #kC P%W[D^bڵ3Z`"4k+{eً^sG`* +梉_)׺śkiv| 墾"mV q^`+Z>Lm3vw64Z5&SG8sf>zy:"X^pٞ]HV?FYpLx6șo  jSKQ;4~(1 g))\W{(@`(3(@ P( Y P(@ P c(@ P@@0 fd%(@ P(@``@:S(@ P!. (@ PQ]0:L P(@ ס7c BrD(@ P@p.8ڙ(@ PP YR֋U(@ P( &f)@ P(@@`@-zQ(@ P/.(@ PU],E P(@ obV(@ PTtڲ(@ P( YA P(@ P PBb(57TaƮC]:>/ȸ:(@ P+(@ P|D=t>,-5Oyۇ(@ P(:_l(@ P@uP(@ PEt*,(@ P(@.0w<%`lbu ,}`( J P:' >zJ/@HHbccK7ҝci49$ ɰǚwf:陖: #$m=zv]Dn(@ xIyZ $ sq=+BEmŘu0lT((~kJn.Lٻ{]|;5HjRMi M6[sNjۣilDlM%bb *((_{ fgozl3Y{;ٳ DgۨNT'y嶿ܓ(@`@m˚Q-,l7X;,3aKB(wݎH<*"4`%ϟlo!dVd߳a+7c]^8ִw:Iw[۱sb–oFvw]j' (@ P 0ϪSfTIƽgSVatܲ"13y]ol?$xN<="+i 屹{PLHHۅF_CfnTY%f hZN%ROJUw1˲ٍM .>MIJImn" Vǫ|aAjB|1=p5Fħ KOG-(QWGMx$9s-~j7Z㎹;abU K lx<-{BOC9O P^Ј-IゥލW=,׮c//M[|,ʩ##%Hݔ ixt(k*^NĸQu]=wކu 3 l{}OḌsǨETbϘQkI>{I>MB8 \{MtלU Bק^DR\͖޹JiST6+8}Qo㏉-ԩa x! E3c P>E Gy$:(@ P$ΓZe>,}1E^$h >n َ^JY:\#`~rʗ֦eL:*}nS­~tM+X!^sX_/ȼjU4nXկ_sdl Ģzd;VZWeZs1^?6rK ii$ZH۾sIԖ~>JF}Y,Bz633^ƪ@9K P 8|@W>UGxz 'J._EtɛܫGWr*Л>8Pzz!eouך-떂_ӂ`>tc}@說䨬D{,p=f0#l#maO ҁ|,"/$e!mQ}s ǔz7T됯, Q7(mDR^\2Q(qaI.>. RWNAiGHy1 ?0I2\(@ PsxKN H}1:/H۹+HN %rw~y .IvU,!Ca˜ x8QYl|'~ }_6*ʐ""X&G=#T"& HE,Se6S¾^gSQrl?~VorQϧПX ^4Uujg:o ]^ux}8a`[\"yΞ ̏eH<0q8r\|<=:7DKJdЙY; =ȚR(M~Sv߂dkTp_:n /ѷ7ư~л7r-(K,KkjQ&ٝwJ.g%,-MXL1cPJMnyTDq<"o E7S?rIU3ժ@ b^Hm]%qը%1\;_&{iNY5N G\jD3.5Gm,e*X<.W.˻/xȈ?AQOڎr}qquIdӂM;5 4v4G#/lAjL*ϵ/I(@ P\M&->KN tU@E,H9+S$3kqF3R\:_*)]R%}d? $<.sAUғ@hd^'S lt]Z]>[Cܓ$E)+e &jGuE|IjR|Y-o&zK(@HXhwqq+(@ Ph닫e {& _./  ӸYw`gBLBLl۝l!kڻl6L(}Z@q+E}'+-(QϢv A 0O&z*U{:2ʀph\g]|}m(Ě5;GzZ s`xzA@~=+1mNT~P1.c۩e;o +#:*ߥvP&0OD,s(@ PC2P ԃ_;QR 1n)=! F0'X)Ju[*s0/ p`rJ0R܍my<`}B~ſ8Q(":N@B \-yhwH3C69vWGWSk?|3Glx_AmG^;^ fPkyIKHҊK>ܲis14 S1m1ZToCtEAM26 jYW i4sxq~LUUn0YׅkQZAGm-YˬҴc)Re,N5!NK7U$Sf?Q2EQbpOJK 9*^2$u( :QfUcVEg")(Ta\ y參y`ٴ ,3f寑sȒ_mk1ԂWcO)e_ C0,rZȈ/uu }dlyl1.x %wtdu2OgܙV\_lBL拢:'K@rm\`̘y?O5݄q~r}mm P(bCb`&O G}`P`F^FװdaDOQYxnD!,?: $ jk\QyUZM?be")1 1շxY4)~;L~J RU6֦ˌn}ܥuߜ"SYlRY(K-2E݇R撜OŹ_$\u_ {)Yq:c#1?wvPB)[NF2`ܶ)@ Pp:2q PUK0zsc)^:X )Xn4fvn+G?ߋ+eqCkW`]1IBzH, )Y XMx|~y,]Sˠ-&M E?ځ83չ;U¶=g~F7cc.<6i< _ OJ8L eϽ R)#)翉|8>%p@枿qTc9:i}&[NCQ6-8bwg?BJJ.oi%mS-@Ε`OP(z_)@7C*|V~ѽpԵw|MMk:oNC9Ӭ}2le%ZUi0RЙbUZ :aT,:pGAjqu}xL܉0 J\Zr\6ϫ+Ԣѩ4Q ~&SXvmlK0#T%b1ʥҊD b-G oD9-&1K'/:^EYA]LZ2S5z ixvZ~Cck mH̱o(@ tLpzXrsp@zcx@o+%ҕji(Ź:9YVϯ{%@d/SjTI]P`ɒ+9 vwB }zI}iZ+PېQo jRxԋo 8fH eY lk̍*B=-l(ԵB* a]Ks=(@ P.`@V&Jt*p{ABK]\V>XQG%G>.BұR[q@(@ P5`)@oA %=tA˧-בWq8Uk`@ P(it. |rZzpʂ T\?yg\jW]Cq@&)ߡ[HޥP(@`@^P HG\~˱MnUr]e]=sA{^ܣ%zfD P(zt7fh[d[`}G׆(@ P%wukC P(@ Pysn(@ PW 0e(~7'M"1 P( 輲YY) t\OWeL9.#,.oxug1(@ Pm pPzA}Nì|[d`? Pw|@^`yyK͗ըZ94_eTKఒ(@ T~㺩̜%0[&^7 L[ލW=,׮cC$k}ӟSw"~\^ci(@ P 0҆e( yXzMs(@ PpOCRQ(@ PhS]D܁(@ P{ 0sva(@ P(@ )M"@ P(@ P=йgT(@ P`@&w(@ P( ܳ]X* P(@ Pm 0k;P(@ PpOt.,(@ P(@6еI(@ P(@ :l(@ P@ $(@ PS=RQy=:y8p*zt: H P]=t¬  z2de(@ Pp& g@7 8yZ@ee6(@ PY5•<[O]޾9|7-<sYc)@ Ppt, ,iA.79(@ P 0V<%c0}=ֈ(@`@̑.p?̀(@"445c0>1(@ P`@:[L.nA`(@ P2t^֠ KP`ip(@ t]] ^fu #R( #@ P^)6z ʺR(sva(@ P(@ )f k3(\E P- i\,:3y P(@ P`@*YK P(@ P \ )@ P(@ Jd.(@ P(@ 0s10(@ P(*te(@ P\,L(@ PйJR(@ Pp:3y P(@ P`@*YK P(@ P \ )@ P(@ Jd.(@ P(@ 0s10(@ P(*te(@ P\,L(@ PйJR(@ Pp:3y P(@ P`@*YK P(@ P \ )@ P(@ Jd.(@ P(@ 0s10w/:*KU֣Uube(@ Ppot>,˪yNLIQ?cPטK(@ P q` ADW zA+6(@ P|-q8]}>?kZK|IǧKu~']T07KOplA+O-Osr}%WܐX\kqHeIp(@O`@ ew}&9X42ɏJpNߺ'@IDAT̩,G [B!z傤gAݳ{# wGғ?ƀL(Zu{LL݃e~]*-re国{^`1ք`K8QBo܁A}|A3F&#ht|4[/^|eCMzrxz|e+֝GzNqa!~6 J|/`XŤ1((ݒΚ(;,BmBdj~XO@ ?HC~WtTչ;0N%eRi-=öyU"%e ֞YyK׼&qś7b F"y;G P&CMyN\_u^zҟdWA~e`W1'<& OC̹ƺG"kC3z3vŭD`b|&^==EԻ.M_Z$ S>$' 5-_]0h 8l]"^8`OW$ĭZO؛gFWad4qXRk?'؂нYm>@ ɮNnџ8,hr󙓗 W ;c\F0f5!2?.9˶/ jxG PlV{\Y`Τax:[؂Wbྸs )8)ey2bI0nZvR>0m6v梺aLe5 Jz/AWo &s1WoՔzhZbO ּ_$km&!z(|Wϡ{ +g$ XJ̲P8 n .dVobµ820߉zI' ^dByNgKjH܃&k~=!~@ȗg\TªP{dPg~YIcN!q\>lq_2mTr/rd4{Ԛ>6P{\Қmu_m4 C{dyVքV?ӷ \ˠ&͙yK-&$V7|ؔ?b^o+OAeOBWD`<^X#\֒',^[2HkPfcUDxlsx )a`jnk:/ K:Rэ-n?k@F|TZcO["؎-z{G9pRF.!yAP3~!k%NH9se`lߵ Wo`NEsj0tܴ ۙK'SF +ʹis.ضv1K{۪]l۽NSR2\zږS t;k|(@N 0rz]VY5(jutVAl`IPi-:@Nf~f 66IgނFtT2KҐDF3{Ȉ_Qd2ǦJӯ( {l)^$?t` 2BqFq)UUwtH.IѪLbʱ])@ PY>YL3_Cd=msi =um]~sjvySOjK$և5`Nȸ#U$DG5V6[^t{J)M+/յq̟~'}\v|i&5;N_v@2ug.g6C@L8YR%Ú@#}@- |op&(@ P 蜈ɤ:'5;-//:u$\a_6ty/[Ufs c<@KA}{ƻQO+̠9kP1_a~}c.vnY+4dã6`Õ7eܼ5M!f٥?"g`v|Z$*VO-Q2Fm\%U=$݉bXY9V$֦uQ=;#8 o 9gNo^h\sf~Lݷ W-y4ߎIcR_(b3\oS#Yz7LD KknX23n\mo{+G̫#TrnGj\%p(@`@^㒉3}8#Q:w& ǘ>m&ّĸ,`NCa?ĆCsw336NM[-iL&g=$LZk{S]~qe{2ɣJ$Ғ)eu(|RQo{|Gzvb~H8­io8bla֯κWj IEZK3G)?82.ҶmFb2J婒(@ PKnk$O&n'dCI2`P5ogstg_G냾Z྽n9kNM*`Z ɕ?Az 6Y` Gx1xijy6)jC2Dwŭ, @pf%eHITH$e;f+ZCd5TΜl۲a٢'#gWS:Np抪*I^8RϫI}rԻR|\rn.5s%Ӧ(@ P \ SۉOU`@ +;{ ce6~~`T-tVuX0q [@y3@yb|h2j(}3i#p<w&,RPo&ݸܑ(6'Fz^?yL5ɟ8>B ߼#g_B:ʺG!pJpwf. OFF.]@9-/U[p߈Be5?U L(@n`@׍=%?=oK0[zㆠ oi+`޸a`:WzclPBzRiGnGy3޹z^ҟ{4sTi`B(@ 4t7{3νPEcTw\£rɗޒnک kg| W(.OeӐ@ Ua=r}n\&RrQ~N(@ xGvtZfd{yy}{'cL3^9 (.AԤ'fݪϫKvm|?^:8pN;(@ P-:n>(&ol(@ P$5 ԥbj(yp jTyA2*-' P>8{,a+_Q١~JoKdaԡ=5ʬ֩E@u Ƃc^lVӷdc,XHe{ֹu śϷխkѭ Lzkņ(m@k{ݯTZZqh;.v "yu/b3Z>&-De\VR::IeGvg˪~_sMm(ƛj~z*;Kvly/:w.x޺z>tvh|1(Ц{Z%ŅgYhu^)X-ǮE֣K0ܼɾ!XǬq:hD0l޾] ú=ł;6"L0==7#1>k{jY\tHW߱{7Dޓ'iDþcү' EHi"6{ȊaR|[2zF9\XzkW&U57z7^אlMEAͷWKZg z@XlޱK6ڇj+CF6KמՍ55|:5F ǧϻmۋ͇(@ hOWhx*+^x-<.KӊS5̫ȨH|rq_UqQZzLBfMAeWyf˦H-&&ʚGVl/1SWI<'Fi957$i㴄hk4ZNJK2bJf-::Ҙ7iM$k[}rvW_nH 3HUxq%ǼL4sxC{D%-^Qfwl&m `Ң­i-QϞfs+LMU礵Kl9\o'¿=|kfR\*仇N~ MCN*sK&?1Oa?$d?3WM_G=:Y _=2dއ`nʓv"7#I(( ޴uV[[ Q= /a7o`ּ{0JZZL?%╝!@|W#BOgCxz`܇OtKx*}}}۝#| O>-Եp '?og⏫%2z1vƼ_,-פ_ytNDi=ZC4L $?53*6R2w 4|^ZhSuy9δrc+7?M-1ie7n(@ tv+~pktwCZ/ یtF ;?. 5!wڮ=4S/`nYmސ=:UbXh϶!ؽ{"ԎjDGjƥ}| -a>g9ZOfۗ^~ItG:glfYðQ!Jm^غc{vcS@5Zǯ۔R &g_C. USuE}j.}h"/:z|?d쟂7~7̑ @,w'{b-X㠶(?i4 sw (d5>$58岐mI{'ҬAC.yL߆#[ÍmiAxvi<-y|C+L9[)֋XwyXMoj /4ȔlDZtBV'1MOD`)j%=5@MA}-2$!LK2W1e5=JlD gr*b-.ܚ)N%2mQĥ6JԱ~MO/ 0(cꐂTf4bKjXjܨ봬۠2>`&vm-`{N1L|rtH-KiMv&[~S|sV%m8y[~\N PpU@E,H9?|V[P]Uߠ@wZVlk`9 s3-@X3[+>A=xjHa l=}uVoFU#_Nƚף lAm P#0n#ZoyZL[74~,Ϸ7Jyo]k(@ P]`@@-A.;aeؒSRA LL8.Q<08Jn++)@ PcZv }B|g(-ް񥹘8Mmz7k3(@ 0sv4suNbLhU[(@ P(sܶg)@ P(@`@ S(@ P=W]m{֜(@ Pptހ,>(@ P(sܶg)@ P(@`@ S(@ P=Wϡk_O|z3[(@ P}ڂ%(@ P(!M)@ P(@ P-CBP(@ P P(@ Pn!-(@ P(qt7(@ PB[4 A P(@ P :n#(@ P(@ :h(@ P@u܌GPh@Óޟ;R(@0*< +* K9NpBT(@ xG@'T0w럠j=._óND*< ؂W?RvV P(uzc0j' p`ud,(@ Py|m 4qCԵh-%&w P%YL-Z lfPg{gfPg;(@ P`@ E lgPg{G:fPg;(@ P]`@UA l`Pg{{:fPg;(@ P]`@= laPg{[] li3I(@ 0sKs 1I%gs$N P@guFǸ39[$T-mu6 S(Qtn)`VAu6 \fPg;(@ P`@-lePg+9.:)@ Ph&S{w~p7Wsu}S^uwNry/`ìp^硟_/SH=˵.ˋ S(ѥ`N!]p'%GCju>ԹBiRSwת;9ysu 9˽c9;)^;qޥ2 \)@ P^#kTfsJ+Y5OgMuvP(pD|fqs7`P\OF P@u͏GwnfV 0k)@ PFt݈ͬ:/`v<5 \T)@ P[1/}tfn W <<~h̎4xTFL$c(@ PyICzk5T0?Az|kB0^:|勳&5%@qw{3zps/(@ P] ĝngsz ̳ԥ\¨~}[~xH1vw(@ x:omY-S=s1cp?yxz{+˿xs=mP_8~vm(rn$/ɠ}Xa P@ ιc06zncn<9W4]ԥ\&kXiGzupu*kzv(@7`@熍E*K̩P ',:s.iF&*4I'2;]}UنA?N??ew PD4+xNsNq}B'*1OA]scH oGWuo^@DX\c2KN P n~x\ W7>qZP4۽p6gbq ˙=t <#vVPgv[Ĭ[sBZ7s+:3~Ĺ*eȓY8Q(^ ܫ=<4䔞zKygAO8SS sPdpFP-4N `_=듭Z;3S7g6M{Z9Q(^ ܫ=<4+_6]xy ^pƣy˫ ە/~+go׺]A%}|k{v5l^ LI^9XtuXe%)@ PU \%xFus岲/ lDT!&KBx}LeV}y_^{uID-©3zZ'; 3P<+''#=s*͗'M[>>tmQ%QHթ`PԢ nAaJݵVSRwDvݾwT ZU\ڬ|6h35OҦk>׿GTS;NiSl*f|!\3Ekr-1ʬ7$k5\C%/SdSnK\K׫miZlK"rl;Qm7*)OWii lt)HMFe(TʖUZ2GFkQf㘨d-35ΚYK-~ZM Fʐ*[EXͤo3i25d[o֢"MCzO2ߎte-=WK>Qf?ύWj/h'+kª|-9pF3r;z?8jWvb$-))I5 ~z[^OЦ0X/-.\>XTR͌36gS}V6kYq&e) -R1E'h9UZNZAVfm -[RLmE&i9FQR6>Ƭ>1ym -&)SLDiYZB|6S}iQ*(--Pʚ[UY@c?Ǔ ,| ~s֬|(@N *4S Z >8W{-/Kr^je5yy9~UK$@|%{؃9 @'$/_/I9zVWS_^UeRU/g ҋ+ ֖#z@}CPgQuB +g F]"ę1Xe ?{y/U.T)d9q_?z&bo\ZV[)xj(ǘ_``X~m{W?~GX2s& JkuRdBl)uȿ#|6䟯˜w_A若 ]k?Ϩ/ xxxP}<.ܻJ\Ao3ҴS' <ڋY5PV&&{2K5M\Co=(mkZc0m6}۟s\UdO>+.=w/QUHHD@C`M-4jCZ{KSP崱J8Rs!mѤ*6D<H2~L&$d~==3{W-1SR'(Dbk܃9W+5'1}61[vk>`8T 32eN*0_([/*? f3ǘo 0k-; { (@ntnM{y(`/'1\X2(?Z3&a ^1 J+yPTwsƪ Ik R0L9^^s$`L>^Ґ ˁ L;s/>}2*,,5dT[y랺?|z SIg润zU Nn | ;Qϙ̩LB7^|O9ZKTR9CK(ی&d vU?54L ᶕF8$4۰O~eh?2"ޕl_]~>'f߿y >]ļFlݺ{jyJ~ 1DŽ!  &ߏ93Q+畧~|N4f^@!MptXgd"WWinV44YO-IQgs-4*qon>_=r>YY762ې>25[fOޏNW:֢iTNErPK(Ez.n()`u*y wek`tr`A=59.9yw\@0Ww$P,-M]`Ղr)D竮Ga3ܯ1G.TYX/Y^uu s)&^Go _\/ƥXc:x~:G^s>)er t1W-_㌃E+kA;= oErzܕO[ޗmJ?x͙.[^,|{JyZԚ1\_g=hxQj2Z1DX:maˌ%ґZ[܅3q0u/ Yr鱾F*nxXhnq9*&bRd-Bşs۝KQQ2ⲃbX\t3]Pm%&rBMRjxuAh';^/1/2znŢ\V9$'c|l.܋pN5W P@:yWqox#q(s4K@'2g˨Ꟛ~Oh wjm@YUR*umZ^,(y Zq*Z!d9x5`gge[T8b'_I9U}0FVdi[^!Wis{9x*Q*ݍԠ m #Toڵf~VY2Jj`Q*HZdzF蔃WM^+% ͼ5}Q!Z䶶O#ןJq߮xQM=mPșyR~v &ܧ`Cjt[5(+ٍAQ'3e@FkSk RW=gb.֤;;LfܷU8|s~urcl@:YN P)G5 7A7jZ%ne+Rg_hsߍ,!򌭒P}g?^zj%;ހ3|1]P}V)~v 7w-PԀ';T!g2eСw95Y3/ P)~\ͬ9 /f +% ع'5S_<*41>D ڧ8$ʨ^RsImvRiuSV dWvjGyN!qeD P@\;MeKY}]MxIJOlFH̹J'mҏ=952A]3(@ P :E~Z7a#-nIDATBT<`.?uz@LH R,,:wu(@ `@׎3"MCnD[!4_а]^{" IA\ ǟ(Lh~Lc\t>ֲZnCBiߘ0%qs PQ]4:1᱊8p2@7[PwNKd 5JI(@`@=Zm]ZBysQX` xuqX5m28J(@ P E. h#%!Oșq)y\챲Q(sselU(@ P X|]$OHδ8fQyDA.\԰ԜR 4*;zk?9 ƿ.4̕(4 Tlo(@ PtV0>JF|玩r1eT5@ 62?n,r[ B,)@ P!.:SL=SϙTLSl,P_^7$N ԙr&(@`@[;*Z@Sl2*+;Tٌ*=pH\+(@ P%.wTi90|Û?y1*JR *ƏpE`( >.,() "eO.+MMGqU \:ddK#kf0Ǐ(@ P G 2E~az^\ր(I "io.mԵ ?(@ `@׎3"IA]$ ֥'xf'Y6(@ P rEaLu(ĺX(@ |pI 0U\XY(@ P E. 3}-g0{(@ .\=/`uY%;\4xk6$űokLj+ʺPH=ŲL P`@Wi/FMnxi[as|ظzNmWⵯe0 = ufν͵r(@ }4I@*~Aۅz٣R3uVfxxfE A qvHr r P$.Lн3-N=mL!Y7V(@ P`@ UI P(@ P I" ,(@ P@(ЅByR(@ P0  P(@ P`@ UI P(@ P  €"(@ P(@ B](T'(@ P(@00 2(@ P( tPe(@ P . ,(@ P@(ЅByR(@ P0  P(@ P`@ UI P(@ P q,7_o[@ P(#}4I*6/zDRObg>DB(f5!%oiB P BzT? ˃P/ij;fOxKx1֞@ %;uߗy"?dlwc*kK8t>*JS@[tm; Pz;y;:vkI PoÅ(@ P"W]֌(@ P_t~y(@ P@ 0}ÚQ(@ P+/R(@ P\toX3 P(@ P~B P(@ P+.r kF P(@ P:<\H P(@ P rEa(@ P(@ `@症 )@ P(@ D7(@ P(@ p!(@ P(@`@5(@ P(W_.(@ P( "w߰f(@ P 0Å(@ P"W]֌(@ P_t~y(@ P@ 0}ÚQ(@ P+/R(@ P\toX3 P(@ P~.¨ذ6מڧO*AۙiU#%S'p |Ճ)@ P*.eD1r\{02rp+@.$,TĄ trOo*.MU/(@ P E.|X#(JPq ~3;wZ2a`YWE P)t=%AG4ɳuۤTCVTm'xW1k`KFtAe([{UoQv|~J T9u f2"S:5}8"Qf^(@PP cCd8 ܣ8\xwfWO05{ܐL,G59$D@/lkV5{ĒC?â?ʠ(:>:%A̬':>sUg[]PY(+ |O/^{&ÏHJZ>OcA-)~l=`CVXIn9QJLBS$ o,c Wȶr.-o9eTBo‹Kov DzR)!+O,oyrO_#{!p'A^>(.}0sҹ̤H߷gYC ܝJx r-x(_{6룢M P 0}9v֝*NY Ðtd N@\:KU4*9pQvS\-V3jY7aN>]UָSɓ֣:TF8P<ߙI,gO`@hʄ[-S;seyx9S DPsLǹ,he&G1/|Yv쩕 ЧR=( {?RnlƮszu69W. "U1؇|;b}\JʶɁ`-ݯok!:rg86Aټxo+ƍ&AuHOKubXcQ@sW߭`Nu*_sIݏR;760s7F}tա W݋^~Njѩm^!;݇MթWyFqңSiG܊uoUo`Us*ef0!9t17X].er*Pꞕn>w@{e9>RQ`!׃S.RHZ2K9c,Ylޓglqw%zK}q0%'t nS-3-PgԿ;ޑrL=/J.g j}F5ҵbI@b]`D0 O%\ėhi-iM:hlCjr__5J@L_LťC<pkZ֖|@Rq}(K nW%hשS ir]>NTj?T٩^۩ԼOfOrg1ɺ}U8@(߽WKOD)y$&IL='0f4ҝ/Q_OCZJ<لON fCU1Y`SI~7N%[ѩ]S}׫mR fUU/Lyn\W;<,UZ9ZLP4@ 0=^UwVL&<~cg[KyLZ+Eqm2}VWY\ ^@Sth!s>sP,n4J0g_ 3TTքMpҦx\7#_Q1(G$ .˵ݚbG+#Fw1aqV-X9;5 SDZқQ:K!Yqwtwɶ3P,@ 0Qtaa6 ߖg;#X1:Y3N$Vjx^1%558IA<'Oc%x6)%o}2N#q*ɀ+&J7I)Hnuˇ1#pZ1+g箕{oN rp|;5xSDXҎ`O-_8@d "zUG 2:;i(3E@r]MVCj]4EULyP|JJau*; :ף( bb7B#pyeP$!8`R(|;gw:v-;:>(k%8K P(@ tfW!(@ P@ 0{<8r>}<1}݁5{jp]#1QzqQ@C3=Oߡjyұs-2J]kv#y (@ P 0 *\%CGuטV(@j([~6})Ou-:5GJjh|NP(9Wĭ54x(7U.d(@ P"SG둹_d?v{႕/Bݏ⦉ʒPP`Hb<>u9/\~թfɳTL(@ x`@%j~{0\'|o=+3~/CO0Q%pK{ո]2R?_ui~ p>RK܈bB]/N(@p v~k)J;%'bA3N̙(@ P0%;͠(S"[MD P@{C)@ P(@ Ĭ@TtUkGrz~3pa3I̒:Jw {ڎ`ֹi&-^܏GT=BS%;xYY~oގjC8R0Q_A P(@O 0h,0g|7J'o]yKQ|dܫ~=3q:[%XuvVa9lœwN 55DY7~׫ՠ‘e3 ׸hT ~;}o7v*AYP@3C N=3-FR_Ufeg2f-5czK1,#z'Tߏ V1z}o3;jZ^NV`~*K,;gl>羞}_jYi9y>ߊeEoSVPX(yRk,w˦ee@6jҩV9597(GUOun^̒:6ݦFm"FMڙA`=oW勗;oіTJ+[6̿r-KE*߾{gH[{fVV\ i۳ #ud^(б:^kȕE +) mGmkۢ }[~aەOO]Er{L۶v\.UL|Ż5GnlcVVVm,ۦO'YQ$FVrPV3& TpSݒ}^cEFVPj+Ԏ;eYsmͶgl붭oT5kEn_VʪWO #Buڦ^J*5^:>J:SG·=;ܰLH.(@]yer,Sɨtxu;+>[|F 3N{GXO8k xu1ߕCVOz$4os+JNkW\OZOcf|a>,{=m>{QR6 jKXٮbl>2oZfNT_WrU4m' Z&= F^c%|'G?s]ŻV" S ݕMw&`8m=k 0sd$] E}DIg22R|71Ԇ1RZ݆ը5rd3gQsKsU=T^ Z0){B775 7a'^!G{s]=ψkNP8Z75G[VaK+Oy pxu+4f`.o68(W1\NF[`"nH&,RcyO0b'瞈'OЧK*QWw6`0yeJk%|Xu:~0AS VG+c~Zü+Q^c=Gc-_ki)8ASLhӱă:{bu8Щta&PCIJeST:`Μ9Ȟs/\=USN>}R$SWJ*{t*_Sz{27p>\ۏd*cuS4'(@ Pm>;-˞'[Ӧߌq`% a3[{i-5?fl*ϟ*_()cJթTk\6N%OS:!\Yu Rר݇?sդJMF[TA2-d#w1 t{VךS@SƮ 4H>ZM{56[DVTIPԚGOf}6}N%}0_S|Vg3j>ҤS5P;24TҧT6Y_sm^F nu6u_5(Sa96 ^gu~n>Wxf.u4omj%mФSt}k d#[OUHU*Fs\mhḰQ x #uc(@j'Nwaw^ĹDR\ <͔sEmӆ}vܕ^k:'Uߏ5-b;CxKx1MNĥ$#ѸS5Uż|4Ob\RHZ0Ue._nlnBH;$f'岄${ڦTۚHN:(~L(ߏ֜Q{Cgux$__Dz*bVRqȥ]MP^*6˿mWo+.3NDrVa8]5D[~p)p/6Zx}ʎ+QLF+nԱqX9(&v* Pz޵? P ة;U(@ @C*,(@ P@0*R(@ P&Λ Q(@ PtQXE P(@ PyS< P(@ PQ Q.O6;?,;U]v (@ P a Ʈ{X (@KPyL@(! .MBDǃu@(< (@ 6tg6/"0&_՘U@RPH PAI Zn̈(@ P&Q.F͂(@ P(@ W]p=(@ P(@ 0 5 (@ P(\tdn(@ P&.l,(@ P@pדQ(@ PQ P(@ P`@\OF P(@ P l F͂(@ P(@ W]p=(@ P(@ 0 5 (@ P(\tdn(@ P&.l,(@ P@pדQ(@ PQ P(@ P`@\OF P(@ P l F͂(@ P(@ WjJQIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_top_down_command_endpoint.png000066400000000000000000000400731322762156600335260ustar00rootroot00000000000000PNG  IHDRTK2sRGB?IDATx xTչHDEc%?N8c<9Z#ա[j9m`k I@njMD b"&@AH22#d9=_ϓֻ{PD tw (<HHH@M$@$@K$@$@$ &  %  @bw Œ x @IHHbcHH<Xz$@$@$@1@$@$@P,=n  X   (q7 P,y KHH(<HHH@M$@$@K$@$@$ &  %  @bw Œ x @IHHbcHH<Xz$@$@$@1@$@$@Dzퟝ(f#II84t< ?Ro: @μ G&L$@$@'@4|  P,}MIH Obi2  _X0 )d$@$@&@5a' 0<SHH|Mbk´O$@$`xKç ׄiHH(O!  5 > P, B@$@$kK_}  X> HH(&L$@$@'@4|  P,}MIH Obi2  _X0 )d$@$@&@5a' 0[""nnq_ej,wM+\% X/g^ZS|u֔v߶[f?}~[4n  #X)[>wO[sn]X 𜥿YWĸpZLԘy.;U6ǗhХ.K+}ǝcꊍIH (Zn yvA=W݄Gߪ/4 H @4lfދq*.r^Q-[<ξS&"b"0~8X'JݧqEpm0LHH`D(#z([݁l1Zc,X{GTwBq4 K*(8wl\EG%1pԴ,df桾SA ٮj]XFs;ǦJxb8(YaAyS|rSM(Ew Zʲ[~_ETPL( CMP+c#yT_&Mji#<̴iszGހJ_7QEZZZ-݂e0)49n4a,:j֮NGTF_ގ͛7ㅢ.UDdA$,5M7?ւ&q&~,3&c\&": 09RW5SbRbzKףpSLޖ!s5j܄OBTUU὎9Z`IK_݆z@XI"F~v'} 1<l@Z*`k<46 uWebJ 9xwuQjquXi֪dСC({a̙s'֬`^3xkMJ' gaX˜q=.$j7N`vT;!o~-\~3G-s0-ȭpQزM̫nŇyHl+( Qek[  |rHĨr۪kq"3'ss+f }eo$8 ˭VqOWb*u$oMxaW%p"\Cs¥QڴgTk2t8Q-MmB(!5,.{QcUޒMB8MUvUBXs,~ELzeTkm ]Bi)Ϣ3+|'`"S6\uM3{O x%^Mp~:2ZNN[;:Q%h;HS$D{ ITTbc9͒ #im_8$"O!a1^'{ۯ}d9x^BFӰC$@$t(A:D$@$l(C$@$t(AqngAE殛HB2X8Y'P(l oU?;Z_O|! P#@ z)[xjmħCe٩nV]a+-.r[0SiH P,C-^`y,FoTECNwCNګe4S;M @X_NS<[iMZa]0[ڨRN>Z']Ѐ:IHG(>kTyϽQP#޼l$DGKR>aD&GM.A8aQC$@$QxUpJSO'ryN|ﶹr "\HTHBGSG$B$@!MbnmHq4m _ p֯';T5ϧ/`8}wOyaYbMHH`(#jտcwψ['Wzgd>w|5})z! ?X t0w#o$@&y@GIHHG(>K$@$@C ,^6m;jp iN;)SD:mWl;AƑ ؏MiHyQ}ӷW @x2YV+f^ޥí7̴فef+3!u!Px IΆo\Z<6ڛY\ٶc`N]_`HQ[>_~8~ $@~!#K2Ν> *RKIVGv)kp vO={c)֤`غ&EMFht}w!5YSua3^{8k3R}HQkv>EyX>jN㼛]~tvak26=bT,Grb#͡ڈRR7@ڰ(K{V#u>')"֣[FĔ5Ĩy˰EeʑfSa{iu ӭ+';Ttwmƻ ?I;)o:_&BU+JKbr=ֽ͚\Pujmd=Yզ^uX![3˲3ں)MζVZh)WVVN-n~&j)mP5k3󔂼LY—NjrC\f%33M[6k}V*PZ4%_X_**WP̖b`?}ɉvd|}8Okd[1^Y“9lo}Z6_5<%+;_np6b!jvUꇾXSi֢V+ g3 J*]MUJ!E^)/+W˕jKٕyYeg7JEfs̪ߦlD.))W\bmɯ'IT3&%B`)PŹKqjM!Wi/.8 eDq~6+/ qrW&ړCJjւTEOOKSg4f5Oi 1$7/?fܻ1؝шlC]?76'P#b9L=w)nC޽q- P,9o?ߴ{f[y#i#X|2$IIH`hdϐ{#b銹CN   |&F@$@$H@g$@$@ @4D$ @ P,I} i$@$@$@ $}M$@$`KCN !~gߩ$7 @2|sIHI ;XHH|J#Kq  P @ ,2  X/ e(d1 ҧxiHH P,C!HH(>K$@$@@w 9lF$@&Q" @2\3?@ j:D$@~!_0  #X9{HH/(~NHHLbiw  X3;! 02GIHBbHH(F}'  _0  #X9{HH/(~NHHLbiw  X3;! 02GIHBbHH(F}'  _0  #X9{HH/(~NHHLbiw  X3;! 02GIHBbHH(FΞ}| 5sHObƃ竛?6tHEb-!nԥanltGHH?q% `!ERwΦܵZ9gK~mw;}ALihRD=+ZVܞmۑm(UJUI`UʪLXQچ]ϡYmR^$|-QY.E)U%;(%MZO aW:N$<`'.}M( wt(^G,= ܟUҤD'SoTߙ"}qSoVНڒ!gXޥ )y9RjS:;J)VRRݦߙ^qh J$0NÊOd'1NLɟl˧+C6]Wmg,T-X-9ES.&!AMO^hۧxW̴4dy ۧu Qp+N>Fh_i9b詯5TW3щ+vuݴ*{;"cġ5%Nw< 0I;"'DzV4l/DF)gCؘ20.u_M7m;YHMb9lT_{G>~ԁhn C!]5I&&8BdgPU^x xZO4sB+zC!%v.U~gK-*݆mut6{ОOROn^V3pfd߸Mۅb1|\Kq)z+?ӡ}US$@CX'v-:7L"#k²a4@kPSS#G?h}H^[qg*QDuhMWofGXu[\^_mUv,cP0vY]T _[u ,^E6iBx4ދ ]1W֯MWGZan>:'0 hAìjM V(*Xq:&2I#EOQ]}KnI|+ifN<#] ƒҊyl1-Ei[qГ*8eB|ԋbB^y}x#od%"5i˱dfTxH_f݀ZčX>oLT62viWŠp)?(ށ$l"9pj}^uEX:W4dm؞4&w QQvO*akVcN$0p*NȯPSC%FנɘyX/t;"-~koi 'fv8qv,;B"oZ\|>mNSb{o,nm?Za7Z؎BzмA &*L9:avgiW^%B~AfH/YlB^d[-CVWg|풀\e$gk }-7򢞩q=  G`Cnr\u޲2. P pda>fBϯՋz¬a\3NXH2.\'4oE=ozHB2XΚ=گx5 # XYضh]V\E=DG̋zX`$nxOe| ʑ逼olΈN_]ԣg4-NC')bz! o9KoP )&RTd eP.m ;jA}i41Ax(% Pa})dԬ`/`#(!tM0)!t1qKQBb!'@ `R(CcH$(!`L ep B2lI Ⴭ@XxE0)!~1<qO /ЂI !@Xx%J=|'027B-&I2hS%JVICbׂI hz9 P,}&}%J#d> rBBBC!Eb GxK0)w0b'p U0)f !@ T- &rlٚH(ȓ_`R(vB$(A`raI  _X{L JID BeL8d $2ؔaE,NC[,F$@ŒS8e(CbN #@ "w)L$@Lb "t.q5CWHBb̡щLYЈQ gKόXHH #a~0|  ( @XIH<Xzf$@$@aNb' Lbk 9e HH3gFA$@$(a~0|  ( @XIH<Xzf$@$@aNb' Lbk 9e HH3gFA$@$"9`v@PPA P&e(g x@P,Y'w!\"_ׄiHH(O!  5 > P, B@$@$kK_}  X> HH(&L$@$@'@4|  P,}MIH Obi2  _X0 )d$@$@&@5a' 0<SHH|Mbk´O$@$`xKç ׄiHH(O!  5 > P, B@$@$kK_}  X> HH(&L$@$@'i hn_tgKDD-@-Lc$@$`<K̫Q+6U}Κ߮ wOހuf $@$`$K#e @Xt\,uO,5{. #&Leh~[Q%'gԋ{atHMb9lT8y_ϱ[Bs; a sXWy HruU|# %,G .TŌ]13Nqڡ)sjvי7E,+*[P Rوgs$JD[ ř&Q/65[SBďj;k 4 u-9ں) eC4}UԾCjJKӰy& q8ů`AokX=]]Ȏ:=t:*Ɠxgpx> ns_Y yrՓ:aFgw#}$(A;̚sy3&C =~t?مN[$c=kR t{Ub4+4-G{O\"P 1@(dq 1$NAg`ao:i%pq\=؎H@B\bX)ZEF铬d~HAI 3GR|+et$X7xjlo;7ޅD nN߸{ O`"2"9fƥm!pONI1sLb\בg2*Jt4#|,5`u;H}V[}7TGVQ5gd׌{DE_C&h*ХMe߻$~"Q7DW)`u~ݱŽ]Ws*wG ]||Q)$,A VhXڊ[zv$={,iHH D P,C4 HH{(cIK$@$@!JbFX.vmynb\ %PʦcgU\BU/U]/>hQ;.?.HB22x?lA٪BeZuyׇXhSxlLxm @ P, `y,FoTECNwY(~iKše4S0D$@c'@;Ð* 6jjvb)Hw]9z:O-DhKy-NWHH >M/>*X,IWOT ms"&DGwWB$@J#Pͬ8" aXTVӭ-_i7n8_M +Nwux癪FN#/,K  rBwLqxx|[E>#z0 @P,=غFQ  `"y`  P,HHB@Xn/"mRw ҈ǝvym+R?ҧu(={QWo|CڏR/a--s @ˑ%pNƅ5uXS`fWzK&%5)n2R@Kd惻,G)غc Չ=v޵)d}hj; ق<_HKqͮ"~j͇@kH8xL6{f=J=ylbve"72̋\t,Gɩ^ZfA}8y5U{1Yko?O0I]A}26=bכK ]._JfflSľcV&W;(&kUd( -UJђtqQ6UmUx-=lj}ݾ;>U׆_nyLjqq,܏#;FT/HS$29'CDSW9,nJD+9q0eY1K2qIɛ%Ž%?yd1enj 4F];h#ٱ.GԵ+\Z,:bd3^Fܱ!tPI~usVٯ *ù{pIph^~;ȯEɷ Q6>/sX%ɯ«^ F򵫰;㇒pz7&7yc]H`Pg +Q{PK2JUV.81H/-Ƕup}?Oqe cO#mnDzl{ivfMOP7ͽ 8  jK+߫ % o>A9ursaZ 'dԢe%(^ 1i U{Z cI lƛV`Q7[=zj u]\ 2:=u/ ɳH D GHW)ZUx'c:urBU\ +/])"5 8wqCFܮdHz9FTT,CuK(b?*>Ɵ3oZ,LbԵb͌ʶCz}]Sg=67a$[.%CDQJQM}@}]3Tl'a?jd ^=ցR4h)6-& _צP{"S`6Hrdŧ`tc/PfT!-)"9'>yH;MLB(O"GLQ}[ŒT\-lᄍ[VJ]J--6x[PoE]BiB^pO/GX?C.xs#Xz+gg#er1]PHw{`(v>{P8քwgh,v߽ Dg|$@O^qd\,]1׋iHH >> 8$@$@"@ xvK$@$`K䊞 2@- qP,+zJ$@$ g$@$@!`Yw*1VzJ$@$J8 l2  {$b%  rXHH P,/猘HH`(#$@$@Gb~9g$@$@#$@!0V' ?9#& !: @X_1  P,GIH2rΈIHFHb9B`N$@$~(sFL$@$0Bcu  #@ 3b  X e rXHH P,/猘HH`?O bIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_top_down_config_sync.png000066400000000000000000000461711322762156600325160ustar00rootroot00000000000000PNG  IHDRTK2sRGB@IDATx |Tչ}EL DT@NG^=ڣ o`9#ЖӆVlQ6ԆSM>TiI1Idt?{&|L&!3k~3?ֺ}\YkY+B&   z'HHHtK^$@$@$ &  %  AbO Œ @IHHbkHH|X$@$@$@5@$@$@>P,}i  X   (>4 P,y KxHH(HHH@P,}i  X   "}9Z?+'3Ҭfp> gi$@$@#A {nM$M#/,E&e > P,M߄ HH (&L$@$@'@4}2  @X0 MHHMbh´O$@$`zK7!  4e > P,M߄ HH (&L$@$@'@4}2  @X0 MHHMbh´O$@$`zK7!  4e > P,M߄ HH (&L$@$@'@4}2  @X0 MHHMbh´O$@$`z VT;DD>>}^VK$@#@4_oq}jZc}읏ӛ.Ś+ 0Z+>xqI~z?c H=ˑ&d}))1Qŗ8y֩۰w~e~簪ba QZh>)<~Rр{^gZ2 p%apmy?}{÷D $@$0(k$b$ <+nVkӷ\11 .p UZ3p{d/mBn|S$@NbW_?kgaaxx` l{viHF:2ăީl>}VvApyb=OMHH`(FŌIN KcLwV'ɷ I WzSҬ}O_;faє84R!3llᔛ<sOa܉Ei1%w2v$N:P<6SՎ_R<5o'uUݵ`겍jG,kN8ydj-=qFqQz$=LrQnXwKVCCR@I֌Bt%VSHDZd ==5:Z.ddPl\3{K`sPЊ!U[ Mřz?3ՁI 5(7 NoDbLaj_ dl$kIK&v5)̅_c=2$ !@ -7NAG'RN@g 烽OخgM!*Yҫܺ"|#۷O̦=A[~@`2Hfj9]+d(uxX&;`=Q[1Xqil1 +ř"nPNAkYP\˃Qߵy6nؐ_TU eobs=Ϡ,(Jkjm=Swf?}~@0OG5FT`i~=_f)$޼sm 0+' Q!h]d:viJO|#2=n8226OhH!`#a`kC$@$t(A$tHH P,E @X]CU'Nw93w[Os.b %PjM?Ƣ-~pydJGٚf}xI>u <}o$@$j(֢~'&-LЭ=%,S5c͕3j?s;HB2Zk WƏ4vsv\40G-),j>}u\0 eɨz䔵}S=~3R{x*W_vmC^:IH @(kVj=[gMFlTKOĤH~vFQF}˩1QtB4Zw.ƛ5dM$@> p+PbU/_0N홱?61HhkDHH gzm:zL$@$(!ݼSíMN 7vL L& (Î(yxzv$ƎNgdőǗ  rB-[.ʑ6tʓJj̟8* !(As 7 &qю @P,fIHB@Xz7"d` hI>I)"i j| T{>.=wzWq$+Z hQժTwoG]+IF@xܳ8 ~Ko-vp XS}dn+5OcH.[SUbjk<_lWeOo0N)~d֩'~$@#B ,zY8z'vP۪&)Q%&.EX5[v`$ɛ5;PWDr!&aˎb3 럯3ع ID$uZ~ Նl]oٔî:#eN}MĦ{Oz''v4lTسeQFbHJ^hǞGעHJ]M{Ps`+$IۗM۶`Ĕyإv%ج 4ȇ^UOvtǰNÂxQT&Ob隷1w5 )-گpS{EMfˮдb"j?%5kS^eQ,25;u u>5=k[Ri[RTWZS@:J4JɛUumVmUMfm3ef1P[;\=*txc$@H LYv<{Jil2>؉k6aOL[vK>9Ҫj[Ro ejn:d[îflJ[f1^~V]"/\,dgg!+?0|W^w=oqT3f>֗ 9PnFe_K+dV Ņ((.̋Ew_[OZ f7UͲbE̼mgwt=cם{sr;Xuyl -n ]Qqad+kwHEغrbWu\V'T֠/ SSm(}=ұdzHzRF,|u.AE yWhC}{շ!y f?j} F>9{ 7b<|pu?3޽-I4(-j)ۅxqzW g&yin]7_|ց+V7.&sy@=z[9'07YF*EMaZ)62=)/=R"sɕ,#ȒaW:!۾|KƊUb[RZu8zY˝KE(ru9alTc]c+'xϫ%cE¢E?uғCtPϾ~''E2\ %RcUa[{xAXOV=މbũ[׭R %_{n[|xifQ.JNT N }ԯwͧʂ$w}>!#3I@ Bݟ VG#rJu״4]t:`ow"2.-AeV}._G3-r3қڿ:!b|~sPFiv;:O NOv[vnoGlz~f=~)Krk|}J,v޸s|IIH``fπg#gÓ$@$@' hX&}M$@$` KS4$ MѤϺIHLAbif$@$@Ib9Y7 )P,MLtHH`4 wJF& _Yo3r  Aa @@ gP4N$@$ (ЊHH (K$@$@@b HHJbP4N$@$ (ЊHH (K$@$@@3`!P3$ii` g9hTH$@$س ז'nSe" !`f%$@$@f&@4sw  !@̬HH(fn=N$@$0"(# ̭GIHFrD0  3X; XfVB$@$`fK3}' JHHLbi֣$@$@#Bb9"Y P,zHH`DP,G3+! 03[ `f%$@$@f&@4sw  !9"w~Nz9qN܉ ΏąQ+)^kh:L$0(Aa L ;pq? bH] ΋x]c*aLo\:%<`1J "@ 8E.ϖM&d~ M}瘈|b .;Dn'HvhDGrtc\S`: Ӵ"E,n1#"xgBbpxaO*h)kgbG?= 6X(!FsFcB>Nڱg}"b ,1Q-dǁwVUeD_)<V@$׻xlƞwi.åq1.C5UDlZخ}%mgҋy݃ز>Y痘aSQ_=v:7H`4'kwpKZJ2e6]kAeZ$U/jr5Z5B_شŠ*$']6kuh%ZSzV"Gϓ_Uv/o״lfɪ'E Q.#_kj T :\"Ti]WhuuZU5ImU96OeZUY_凱'&#vçuw׍\XK߬r CV3 aid |>1k(\&sS䚏_cv8z^*l7l`maKێ㝰-Y+&#+!]֏|ds_%ܕPYkJ=6,)CWmb-P /Z'cW,~ךç?C9 `O*Ϟ=KU5؝S{3}-sS$XQ^XbmŮM1Ll]ƍUF& 8 OpPZýe``%}vjb*z.@Ŋ`x] D:}+_U[=JaY1_J ={zr#Ø11(.xuɪz-n99N(O-3{-*Hweӧ 1q g.ѥJHKTl8jw#1y#*@K{'d8Xm$-ɳO=*Y]Q+i=*ei2\>O&&@f[j:^;[ (x0 .@yKst`رWzmPo7nYY0_~V1v؛rRu)z}wǯHw(Ds>|w:5A{x𷸯FϣT` ^|%Ķcs*)__$ e9GRM@P(k "v@{I%&P/ByZ3P]z!u\EloIuןo}}gAgcf'K13˱=5xHBC8rփ]8iJ*AN3YmMQ>g.8?JOhkW:6ZlhAkhmR\7W~D$@$@$p˦oҫdt=I7#'Q#aG =+6?q @ f~^dՉ7$9~ʞYG!6\z f_aO%?=nYcM@d$%ƾf5y {WP++س&J`ޝHZS7%*%ԥKn ORM:eeb`渄qI5 } N;`ۮW'+}I? { yvǒ mA\ޢH^[_U^빲ILPl9SV!پ!ȬWlIiUsS嫮yʚ{%q*:  -=OiO\g"#0֙+ UGٯOځ'XuڿvKoiW'B>վ:_T>UVS}EMS+/JʺW-[kѤlZ#E+iFU;2Z4NI}ܲ*8KZ9LmC,F*L,ӫ/ɐ\E+βez,ѩ+RgUImYd=5+vdUHTݎ*-E4Ti6ٶhr\&вڵ,j 4[V8Rf(oS:Y5%Ug(:G,IlR|i=UNuhҩHR.E+UYZ%N϶؅j[ uUbK-X:ZS†NUBD) (Tvsok>NԒ]-gjGOj>}Z3Xj9Jhd.%`upt}vjr"T˩/gIuIJE˒/h ujZMlUuᰤ0)j KݎpK: !Oz-%"R:^D,Us/MeZ,ծ|jղE-%F,ˎ4XjmZb ː|hJdIŢCk2ZG/N,VU4}٪P*k:;;բm˭cP(i?gj-Wj5|=sL?o &=X LLSiJLbe@۫I Ԍ>j趽Sfstwtw_>?*7OBZM"C0 w,P+Y!z,ߐt? NƙE/1.^?U= _[KyHȓ(!oqv\īwmhɃmJZ9`ُ%⒂+Ŀ琔[U_ۛF]?x+"҆xAw}V\)&M1 ՚ |UUsGL?G:"_v[?C ?0_fj)R!,YpÑ}RzG/Qt;~޽$B(0WJ'˄xZs}۰(-O'9#j7bgN]7ĠEVm[M gJܙew.D?EZ#8aPVkUcݨn.w^Rq/VӜLȪϗDGѼiC pJ qEڻ} ɻ| p}5*K`Y>]qل(w-g"P$`1dݯ ASOZUsJ-lZak,kofdWjUʻ36ZnqQkѲ{^ܰlȖ:,~xGDkͩjrlrH%ީZ3P!["[fM!kv˒U"yGBuReSÎ=~97dhMR>xwgyejU.c2{,ZI}0'N.0`V.&*ktg컆3RQ+8d.eGѦ4|?QAn@[e_%>؍F̲:J oCbvLqB¦ yP"Mʎw)R:]#C0!whA_)W""CKWFIj*څjK&aW:ػJwm &fws-BDD=pjm/׳-!9w*?CUO -}z 4|pYDce9ޖK,! '&ߚ7]޶&Y-{$@f Z)>{Z&-JO88!Z(9YֱTO*1U/%귘*g07HHس4aJ8ޛ ެH iޑ P,HHBaM$YA8px]?\t.YHI=K[js%*J\B%Q(C% > "m4ؘ| YdӞ=L5$f{P{ ? EbBׁBBC!'@ 6`R(Cc8$(!. 8e6p &2D/8E!Nb lI ው@Xx`R(CBcx$(!*L e\d B2h &$03[o`R(@N$(A4qlBU !@ZkB9I@bf0(P# P P,J,[0)!tq0 (=pߎB~#&p"@ pB, e49WP;K 4"^U0)#,H P,Ʌ &2Z 2ЄMhߗ`R(MبtH`X"4Iò!K?QT&ZOcoF=d!00 K^LTIP'IB24x O e$f`n -%Q !@̡QLñ  (1 @OG`$@$@ P,}3b  0'@ &@͈9HHœ2/O$@$7#  s0> oKߌHH P,`$@$@ P,}3b  0'@ &@͈9HHœ2/O$@$7#  s0> oKߌHH Ds9}# Y:AL=Pn]F$@$AݳtG$I8͂[$hY0 MHHMbh´O$@$`zK7!  4e > P,M߄ HH (&L$@$@'@4}2  @X0 MHHMbh´O$@$`zK7!  4e > P,M߄ HH (&L$@$@'@4}2  @X0 MHHMbh´O$@$`zK7!  4e > P,M߄ HH (&L$@$@'i mlZNHDD#@#W_gOe$@$`>K_=~fl,7Ϙ׮9?R2  3Xo}GΚw?X, 4޳iAVߗ/5,_|g {;١o+_w*& Q!@Urϳ]' |!)!W זcȃ</uk& 0|^Z~DLS$@LhPpJ=q/zF`y6B$@$0$! ̪{͈N)?c}9|K@$@Kb9GG/F"l~jv<}#  X?Q1{\9g.O&&79%O$(a~3lvƏ;nIH` ##M<gQmmg_'ݳatHMb9hT荀@t8vz_x$@$`:5]j^Y_B$7yr3.jL9JHH gyBX̘189pƈH?Ƹ"E1/6SvER47m8osw޷E*ay{$tس &YҮJvGϜtDï}pچDqOXb`FkZDo(6Ъm@y {z+=qSl?y2Hbܸ2~> OAGWZa8_i'V猅p 30jR9j +\ĸw4cDZ2mp' e5:1B|olW#CYo5d/;؝=<5հr;6~Q:ߣ^ U #mػ#mL:س) |BOr o@۔Ώ?]})dJoXg%l+eM:됡-ۇQK߮'Q e[$G.sS-OVQm{UaU|:A4eLԵz/iy7z^̝4$8 mc2l ;zm nHPsсh]=.;6Cҟs?y'8tU5w8/_䌺9 F9S0-֨:mb np3xƍ&@n?vvX/trٺ:%Kp/GzE@}Pha0wb >:1 ދ}#pU}6<ϓ0). wЭRQAV2dž䅘{Gt3d2:`l|kl/ނD .5AD7F|]E7]H+"ڸ4-N3$̿ V`]iMJFz:}{?ekǷNmk[I(i))oǹCBb,-1J~4˜ 2fg+dLH ڂgJ0UJ+KMa] k.5`jXMl,*4ȯ@RxvLpwĻc5~;{א!m~l=t7?@&)H}CDNf VM{*Lv]uE *_f)$޼sLҎ}иxS>7ec=das!v} $0|ُSc~މ2O BbE$5 ʟ,G#|ǒHHB2Da ,iHH D P,CaVՉ]fniNsE$@DbJX8cNv OlUs<[Ӭowt6ۧ~'9oHB2ZOׄ DEUzJ?~fr\'wtm hXv a>Õ1M&*x] 5:FfY ? m)qh>}B 'IDATu\01K$@$0|3 ) NY[+Q7>37#uٌ2zja׶m>ꅆ C$@.K^ =(o5QcPyKO$u3zR0[N¥*Ku-4 @( >Ԛ~s(U J/Rt~$~x7 UYjˎ`\~}gU$@$0HA ljI DRvƎ i$ %a|=  ɛ.[f/fuPA>zW&&c[Q5(o`T.yQG$cΝX}"6ދ}wFۯ'k<{{} Ђ8z;WHh Mk*,SRS :5|UF)*[QWPSSU-eƾ%ELuՑ5 DZUGM鳲QŪlUyBOAkUZVFVT(m9Z{/ծۦζ4mj_F<sݵwѯv,ZjU[-P~tH d rOC)EuS]K/ÓwEm7wbxs;\Ep/FL/; 1i:XUAUbR[k.TWF%ĺ,{s)뱠Jg3V/@ܡt?zA_['f?a\ߘ{®D ʿ6<&2Q[K#rUHh%ve?s>za^KuUyt1wݎ ]9?#_JfKQ+BFqpõGcVT/qʮ<74<&0md ͛7M?:׶IN% }μyPQƗm9ΌCq!1@4N87w0R]D(WOZ<9l(3Mچ+_~^h~58[WV^܎宅B>(:XoZqI\B"RQ/"4eOLmض}^]θ4LuFm TgNb@kؚ55F;͌g?>O 3{My'565Xw&ϭ~Cr}~rUV_XNo ejn:d[,flJ[f1^~V:%Bvvӿh\X$ M(.De^\^b22vĖ'- ]gsxq\rz2kgW.n @,\EغrbWu Us5/ SSK{3=XW==? _ݷKP46;9jk9b|%$%'{Vїvӥ?ϮzFlp+#ƽ%^qiO궳૫'.lGNjt93 n]7nIj}ѹw]&:XE\|5͐^ق+7*k~ ys@aG{#$rP.8R1 ]97R9шp>vt3ѿzNc$`>KٱHL8=SA];yY{$'k uShiX4,q q7=#}&cGMg"M |'  X) (XxVK$@$`K=% %QjIHCbi$@$@Db9JY- ywJ̃ ,C5 @@ܰFIHH`س"0f' ?ksFL$@$0D!cv  #@ 6g$@$@C$@"0f' ?ksFL$@$0D!cv  #@ 6g$@$@C$@"0f' ?ksFL$@$0D!cv  #@ 6g$@$@C$@"0f' ?ksFL$@$0D!cv  #@ 6g$@$@C$@"0f' ?ksFL$@$0DJݘ¬IENDB`icinga2_distributed_windows_client_disk_icingaweb2.png000066400000000000000000003726561322762156600343730ustar00rootroot00000000000000icinga2-2.8.1/doc/images/distributed-monitoringPNG  IHDRFDQK iCCPICC ProfileHWXS[R -)7Az`#$B !T袂k VtD({ *o+;79sΙ@ў%dJd󄑁>D&I EJ,v;""@}]݄PYJb28΂8&[ bU!$,2%2l-2 g8 {XOʆX iwqR3y,&:eHdߒ)C6j0(R3[EFvCH#?9,b/8R{ & gša@ k2D1#ؖ%B{4=ّ#|~fXHiQ5j 4xAZt'ڒϋ X܌߇ia6BQ!oS2L=+w4/̊͒W^ZtƇrpe03 'rķH1bfF͏ʃ LVQ:kr?N- ?D%lxu'.ьzI{ qA ˘V)|Gxq{nx(|zf;.~LQD?b1h6ƃ Yg& o.N…?÷x'N# pĂ(#Vx3 FK1Fmpc!gx07h۷Z8FX$͌ՏQ|C~V`ǰV,v k;cm) [ +atH) 7jc]egF s$7[0WKMcz/2g[M`Z8 >o6¸MK1T~ӱ 8o:p{T[$̗pɃ(Ch`LaN/&p LX4YPJZ l^P4: p^ w`ABC!-x H($ IH*GD|d)RG!{JW$rt"wny|B1ڨ1:uF49h ]nACh-z@ t<0K±D,b b+Ǫ801֏}ĉ8gp}18mx^n|JWB0!JM("NýKxG$Dܛ t<*b I!H$ ɝNbHEC3.R/YK%|r!||E~JS3s ͕[#OA\EbBqDS)K([(Ք7.Sy(-B5RSE&fL%his t+`"2Z.rFފ3 K)^UWS2VUb)-T*S:tKiPlJ%g*$c2*Tz݀Kgӗ{U&%UUTb樕R301#X8ʸ4N{8u{>^K^^~CS_#CcFM\\sl͝5ǫw_g1-怞^Ho^ސ~~~AFfC]) 9m6j5zolbgܸIII}Siiu3Ys<ͼjha90eB[TKo|*n+UUUˉ':񫵃u>{6*6m ml^ۚ۲ml۽﴿@wܡዣбڱ)i-gUU].>.\]>:u-۳I&Mqwgq{0=MqOY,=uCj_gZiZ?ϗ*=(}WÙq5Y䬤|~%['{NvBP$l"3rTQMd*Iԝ_avcs5rӂ__2{= ,Zwq%%K~/.\_vi҆e/)""aѭnwWV[ubNҒϫث.l󖟇Wn_fZZڛ|''kڹuiuΓO675zeN9M93Mg{g5;zԖ!/^pջE\/|6;~ݱI<^vz+7ntތy[ۜdyu7н (=(}?jĎS~maxs''OuV>}|CE*y6?Jj7o<1]ֻ4>T|t)ӡٟI|15aKȒ0Д^GQݿRѤO.Y @(<b*|K^k#bg+E‡7"1N pHYs%%IR$iTXtXML:com.adobe.xmp 838 1092 iDOT"(""ޚK@IDATx MU"s!E%Q$RAJ4s5kԤYYI EhA!2Vywsq=qk]޻~VwUb@ @@Q%}n @pF< @@'0*#J\&M|;9 @H 4p2r: @(R ¨@s (G@¨@0*/0 C "%0*! : r @H 4p2r: @(R ¨@s (G@¨@0*/0 C "%0*! : r @H 4p2r: @(R ¨@s (G@¨@0*/0 C "%0*! : r @H 4p2r: @(R ¨@s (G@¨@0*/0 C "%0*! : r @H 4p2r: 6Xm֨mf=kl7g9/7׾=?Y O`Zo ?ڛi=0 +MQy_%@"(\Sk۳E@^7;eOrR6@8vr?qMyZ͞g l? ձI_~賋uߕe3ߛh#+~hGE}֬Y6egYj޼0 S }wY˖-f͚6sLkժU!}ָqckԨk_hԩn-Zڜ1c5l6tRLpha$^U&kԵ `!kޚ|koO>yU |M[`Jpg_ߑ!mduiB`eR|@,T-%xQt{eUN3m{yQH/ߑ>N\D5W+sU:d\ c?}ڭj_g$$ay b/z;V*vƻmȄ׶l~;S(t(U'2E:w #=5]8knBoH/q ajXv֪A[Mi䮉b6~+ԾF'O[&MK]Tmɒ%ε Ģ-r;SmWOvcǎ6x`_H~ڎ;8ڵk6y#߆nc=sD/?4h`{mѿ>5H6V0wmm-ߵ{'4A՗-]6+\$T} LPO 2-\64D'};5mh7ﺉ,_O+p?ݮLg_﫼>GōG:~~s1;c ;?|/3w{\{Kc{DNǣ?1F<*mvޗ뵽ۭ_c%"; Fe*6 ϰ/ccv(c ӂ{?a7Φo;qr-XV${̺>~gy5&bomB&ZvfM]Z>^OfYoCI\tE6qD'd5Z4==3~g/s$L|0y9kϟ?v\ve+m̘1NZH֦~ym.sSO=}lԉ<|YOd|vb62<<ܜW66vmZZ=bUؙAp&Sax3'Kl$i"#Do'V> ~5 BN 5<ZR De#t }F߂>6Y|l6l> PhVZUGZϊ?_H7:wq9͚5C9:u`3g;E&*h9Zwm9q$~g;O:4h }P{vvW\qv ;z-5[zJxխ[ײX[HrM{P O&\3خψ/{sIOJ/Nul`""W[с&*d(Z"w.MlM_3X>0*FK;2yH\x@+eأwnQ!^ֽW.&f-2GD^*☴ *2pV(Bݓ^dRYWYu*&E˘s7-T?w~(ƽUKG?v01j(榸]vGwW{キ?}> /8S2eEk2I/q(AjQڸM_G ߽be/l=d"w}2HXq2L,4mY3UN|ˤ ngdqR1˲Z!@H'hamP-v GEK&h .¶#sx}o`jV.M&k*z|i18~;W砍׶[\_y#GLq.ҿ={ڡjsu[nI)J|e  _kڴ[H""Uz0뮻7ߴc9ƺu/F>})ux}M4)qkسxrAz\Q$9" %(ق,Զ \Xvߩ)'=חuluz?|M_3X>%2wd㞇Ȫ)7Me)p@׋QӉ]1;}P/`mb"}=}wF->|m@")"ZV g[I2')PaSE]jKuv6ٳ.A[51FΘ(<{n/O7#f"ʲk|g`kB*F\sK YuUm„ 6b[s5kM :Ԇ Č0h#֢[ss(Kލ7h}Nx'~Wg5:EZۨE?`Æ 3!M_ yoE #a27*\Pa1ZREJ7eoF-DJiԙv2VmIDRʥ*\Y޿W C醵ؑXRL5ӟpV|Lcq{CqrSZYZ38qZbRRb,gِ]:%jg ݢ[s5;8XI)RPX)֗(đ,MyV7a_|JR PR+P[kȤ(^̎ͭQh oN,TM"[qIU&a*#өIoA*jMJ+0E$l_kℶv[2'q.o[5b~vyg0|A.r)1i"],P Jv$n V$@]XЫJ&}g5wˮ45q5- ~xd/L~]u*?>ϻT[iwI= ~N*(Z7x9yv-M.E9,KN.@HG@geE\$(,#CL7ahL۫*_"zի9_^C"Loǧ[ZmOA]u n_tnߑ>~(RkMXqpD-XRffz&ȭR k1_O@Q-g9ҹgou DWa4G8_`b֫(# ^-A05piIZzĕ KaT'aT 9^a#@N@bLXk5w:i| ¨@FeF9t(n;ڈso@FQ@xQ9 )QaT 9^a#@N @EJaTCtA!@@@hFeF9t@ PF8Q@xQ9 )QaT 9^a#@N @EJaTCtA!@@@hFeF9t@ PF8Q@xQ9 )QaT 9^a#@N @EJaTCtA!@@@hFeF9t@ PF8Q@xQ9 )QaT 9^a#@N @EJaTCtA!@@@hFeF9t@ PFE:pt @*%A_s@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @ o1 @ g<9@ @Euv~VwWeU @ʓ¨<6 @ PFE1Lt @(OK @@Q@0I@ @< ʓ.mC @EAaTD'!@ $0*O @ QQ  @ʓ¨<6 @ PFE1Lt @(OK @@Q@0I@ @< ʓn{m׶.]mɶ;z뭗T?'ըQׯo͚5֭['Q63gҥKm*rŋu]תW:R16տj׮]n:mv7'< OݽvarYvMf۟K/ԍπ ]KC@ ;|)S9co]|C;~mWSN2d :4iҼys;쳭q~),YĎ:(2 LkzavXk= 7|ӆ fSN'%dutOvUυg&˦N>X >h{\\f_e<@'ߍV'F{ P VKiB;ڢE~_FeM41%S 5\c]xVJ;>zh{ǭgϞ6d|^yV|tÍ7YdyhN;- #5Xd+D:P_O #!+SD PF+h%?xc=w! e]fƍSO=B$:F,%a IL.oz6 dkF'x }֠A$w> ղO1 É  r0R$י.o+yӦM3lYf̘a 6M74O`oE ˜m4(觟~rudp mUVċb+իg#V,DM8fϞ,$n"G"C]r%ֶmR}H#8aY˧>Ptl…6agjٲ_Oqz)FN?twH㔎K6,  ӧZjJTvueӽL7]9R;3th޼yRϝ[Z]r5(S׭[Ցu̘1qד0މtjʪVt͸'܇tDRC| dIa%|U/Oa /x8?|uym'nr/o7M}esϵ6&~,4OnڿdR4WM%4y oMo ?GaݻwR~r)N]{0IJ_ı'){.5eSpFپk7tID~O:@XnÜoWͿ/4`A%Pʻ N0)UGuǞ`RV|g%A.* &ԥcGi$cI:Lb:[}WW_MJIbb. #}ȝ$ HF0vW/{=C}QPw/8i/./p+9CKLFK=Cઘ8AY>mI%b7*5_~֪H%5&_~;:DC̙3'+{'4?Nrb!]@(._A\k'HfߏG~V="9qc}~tCD @(Zr.و"եKi$M᝞@D3p/J$5n?OD Y]wn/K}+t~KDF`* b[‡36XN&qKY>~;A&Dߢm`eg:²/X>Ͱ0 b jJ4pt$NƸԉ1;7?$.nZd(ty'+N}ËL.  us` ISS]#L -\֖ۉ &>묳J݄[U|Kع(\:FJE]庥o+98fe-))skкU?ɕIEnGrqS|l@Xs5ME(vD4rR<\ʥw%ؐY(1\TR_y啦#t.Qܿ΋c瓁V펞Q7*+?ϲX놷u! AV\\xFOE.{"#x=#jQwqRCqQ(hܚX ]*{߾ڕ|@DI(rئ eLʩ O@@6Fc]M5Uf뮻.eC5U(;!v%i"G(?UGıgT$3 T쮘iũ(WڵVk #u8"pas\c/c.[a&7eSLצ`%P/e LXq)6Qh}d# ^]L.g3q  e0 WlOUFY1K*#aX\=JdQ(LD dkb+])"^L JUV|Gc]KˎĹG!qIuv+&C_] 7H]d+ ;8נ %r6kR))HIܫʵ<%Wq {fRsn%W: ƕ\YčlĹ:}L}xxwEF\>?o\,k((J%hk``1, ^$J5>)JC HhG.i}@&틻^>Hj/ c!XBh RcU0Ų\;&]饗 (VE%n7FwM|Aj ׹>?!x #୿({Yfrj4]t&pT`M"- Z)'"n<K 2'_؈޻xg3qAK )Ū~)#w#a@ ?߁ O^>ML -\2O%V|br/?ti|嫯5sW(* [E.6l[&b6]w8YԕNBrzrS*eȽnεNi^YnA/f1qiZs-M&>^ -q 8vq?6m?xYWָ%|njQ)r[{ϐge!E-ws] Q֦M/5Lm}\(K.:`W_Y`qKڙo\2ܳ*0 رcݳ$W5Ÿi#$?RoĂźT㑍+~)HZgJ;.%>tDž @XF+.`{S%Dk- t`Q _'Ƿ q%_(SN.GDO%H8Sui&jMƒtnb>%5?~K Ad*ZGq [6%JP|8̋wR$JO)U7]>Z5`DbN$v|IuFD&s*e - I|I*JԵcx֘4n؉Y.:WiT\#r{L7UCY)fL}W#R BD3z˖.iСKD.j<$ԾT8˘1c\K_A%\_t /zqNgB( l %VNYk1OM^ˆt9 PjիWߦFyMfk֬3٧4A(\l-$..IHDժUR?5!׳ *h+H^*?]ܾp$SpY%-ViWW`Y6Әjr/~H`-@M^yS&뗬6uQNHG]jt==O/zq|R] )Q<۷K7aܹ4 8|U @#0>zũ(Co"#mݶ= @# rE.'94r2(X@ Pp* @@&0C @ @3W @*0Q@ ¨0  @ P *5@ @0FU @ LaTA @!0* g@ T` <8t  @( Qa8s@ @@Uk @@a BG{뭷lΜ9֡CnBGل @VVe#;{l;餓f͚F*bsNAgoZnmo^>u>VF wm4h߱}R}Ѷjg' @hوUW]eZ*8;.2'ZliW\qE^CڦnjM4qlԩ&~HHwypR}?lv7[ӦMKg @h٨=C /?lj*X.Ymhڷom ,#G:kxʪ[D&%{.^>g_@ H/^{5=z{n*6/d%Sϵ^Y4 O?Ԛ7oΑxijժjIb?\z饱ȷ۰aC7$YS7ojݦMkԨQ52OJتTEnɎ=Xs=E"@a 6۬Dno񆳒թS>~ gx㍝ezwHu~m{m5tc:cƌ^zFEI&KwͶj+ߍ{ƌ뭷uSW_}=#LzFC~YݻV&5",ˡ1\ݧ^0#gC=zW-=gR/W:@*J/f͚ew\袋]vې!C܄Sb诿r~Y۶my?8Y4AT;} tAv5oՌ߯_OH]p dʯ_~ wܑVXtow}w"IJrD$Lyv@BvkgUFsj慂{ꩧl.][UEEZwuQi?{ָqc(J+bZ$xG&{ &Hݻ?vm9{_~კsr T.^i-ZdHOY{[.ST-Ioֵoʔ)L] /TdIPΉ'Ċܕ!r-6qDVzH.k\$@t= d%⋝5K֧tENY”޳;,[} /t!4OvOBR1 >%ϟ[Q>eꫯY9H.br5[X8A^V4X* I93g|sst]=}s"An9+_z%7b2F%¡i:|fzϙ֋fe @h8-锜@BEEcM뮤 [oYvFrduY^d(]N\Y!RY6'E믿&4/W_}si{G뮻ιVr҄65j ZT;cDie90F~.mȢ(7Y$Vʛoir5Mnhp #YO$ҨإTE_MֲzʺD#rg#k#Sa$WL 9=ӹ<9ܿLs?O@*Ѳq #I,H(AB '&b$W*OWԮ&r5%0\sn E) $Ğ&ŲI,Qq%5D,%@qEr E%q+b;0T|Wb>8=r:묳t>*ͻ+KRu1ʦ1&wA \V\R"aUL] .zQ %-wD=_J 7=fZsL F8*4vYJjr,; l6)cuM*b.+)e%QL0o{'fuQkS^t;yѢgI~\ɲ`y+}_lV9_* 2&L 0ų5OqU\{OeJueيs>s~t_m@V~ecF[laJ:.viv!ln/-w>`HV,݋ r M% R1d]vr1tHCȂ$ !z&J0K(◔#z׋L7W"Q8֤b#>q*n\" Q6%_πҽ+,jŔg~@IDATS<%~%*J>cg%+Uab딜Db)\'ZF9n&s ؆ @`'0Z6qH.8W^yPl>"q(VH%YtF"Yh,KO?2) &s_Z;t!J kRy+Dq8)^1|f*jgYdK&eq˶cq$FR$Wh9F˦xQ~"nJPM<7*K8>z FX;-)kPX\4SQ+g 0GDZv(j;U>&H.~;vLA1Fo6Yoh&Gqs ח˕&e0|Lۚ|*Q_U4QVS%[adZVB۪(HdER̘DcȒ-&b/FrItso{$!AQ&nHI0Rd9D,r5[*}J&6ن @r@-M+EGCn9 .LLǴ-H7Z7s}Jn_'UX_{9{lLIzjOT}=!=Y+OY34EETn[V6>MA;Jư^{:'iPZn%%'h߾l|^jᮾDEOt$6N9''OeAS"MYeE}+ίc$M;>}sؘ1cl„ .CEBK@)9vXwe\9S6} ˆ8;S韊ҒKH(&rK '0@+ފO1\r? ;T'u1r8S 1%dbN :nBiڶmha O?Ou.E N"ßx/"q$׹s \9S6 ˆYP% \2iVB$c&竎Rj˪-Y|dSߕ(!ZFy{T,h#NXv|= @"0Iځ @¨hC @"0Iځ @¨hC @"0Iځ @¨hC @"0Iځ @¨hC @"0Iځ @¨hC @"0Iځ @¨hC @"0Iځ @@^Q= @ @@ @@^Qagݯʪ>!@ 'Qyҥm@ @( b$ @ PFI!@ 0*a @@y@']چ @¨(NB @IaTti @( &: @ 'Qyҥm@ @( b$ @ PFI!@ 0*a @@y@' 5jM0;[xhZlimUZ5?Əo[oj*NII=6w\r-M6I@ $@%(跿N1bn:uZj6guvꩧښkY_C Co{GK/dڵ;ϵT/ @@Q}Uol}uYǪTb3g4 mf5kL\*a /C=,Ng5jH:/ @@iL g6p@'`.RV o>C;蠃ܿp|lڴͺuOa @HAaLyׯM>ݹu!r:.W:Y}$OT7ήJkذ]q3QvB @ J!)-?Sb&Md_5oH (k޼yVn b̙΢Zk\Cϟﬔ+O?nfӧԘA/( @ Q::<?_}.Q/_/R|,l:t0k6JqQG| 8Ў=Xs=kf#Gt/$ׯo;v8 @FQ"|TB .ꫛxT~+4 %/ aJ`D.OsFgr=V[m5gq?h'Nڵk}gժUKw; @@UAGs"/Or[Tr 5kJI N@;4-vN?tS_$x~az~7 @@ Tjӧ sx \ĦMl`uI.-w)5ʪV\נA?g|]#ZTWǕe˖֤IhwnY}-uR;t&Mrs[6qF#ɺ# 70qTHc4k,VYeD\QO' ~t؆ @,q|&pWnmN{}tMNHI(E.xZd7nO8 {]}5xX@Rq}5-;x`7ؐZp/[ ˴>Ih6>墦 ,p%;0&W8H:&|bSمc$,e[c5nppr?q{饗\l9Zb^q-[` @+4KƌcW\qwc`E;9:*qBy%y&#F0 )v&:b.2tM+n-exSDeNT,-S^D5\dzK#q]ӳHqAX*] }W]u}geއ9G]@ CaTyƚ;MA@Iɂh"~եK'4E^x79oӦjZSOu^BwĔDRR>v%JTXon ?%оlmY~dKUdzW\$|8]<6D:]NH".rD҂3fp5j|>特2*c MaTǟ_F`sٰaÜ@RzgmFƹk?s=I.prmӚ;k]]?W廓ҁk/72Y/#N8}4(~TXHȥL&n_?՟ɧx(vJR_rxT t5<;q{LD߻wo3g:u @ˆg!H?!rRgiM!*뮻[G޻Eϑu7poޥVJ}]׏ މtfWL>u?*tђ09ou$=%g}ųO QYr$$$*rEK҄{A[9 @ȓ,]N;44AV M9s9' >OS #HɝLneEMq͛7OF>&&+NΦenE\çd*t2I \(g'⅔#*G°:,> @bNiFC )3 ܧFk$Y_x$KT={ l>:˥SE.,׶,pJ r_ n\&? KB;v;FLL:@DasPi Z_o4~Y3DQ2Yl2I+u\RF;)np@Rը$ 5v[M_uoƭԩS$I tؽzr'|Oi%_Prpu_Ue)Od{OUdSte֭sK yq}kUBO?MT hW*J$ 8-Қ+Hkn(a&J-t+ &lAN㺢ɻėjH D3EQr%h֬sAJlUmyN$(uV+h# 斠S‰>Ǝ,0뮻_~qz8uT{Go-c/;K)k_XD;_')%bPu!0 -Ym EaTƛ $YW_}M! ?RJK,iR]NEt YZhI,hϤ*ִkYE$$rY,0*|^}U}͜9ӥ^gu|[/2_xNdNđ/w-۸qc+;-+WBOHʥ/tBWu%brK]NEiu/ZW@@&0/#ɴ 6tքt`$Nة1vk(]nfncQ? @+Ѳ̕WekKTkz+VheR66ͣ`l]veX D2NPIX)}# @+ Ѳz5/=VVr_-hdl6nB >][}$tY B~q;3sΎ(]2IDQ @ HٴfXGm{UV͹yɓ6kKͦ5R7oDć2) pժUK=+ZSeҤI;K/Mi1*[ڄ lڴiNMEknj9YZ8./yyxTEZw'K>(˘cܹnm6,ayJ:/ @*0R;]LkT~]_E}Rd .t׌M;L` W^y~ T7bO?9x`4!@ P TzaQ<&HOY{A"Gc]v޽{}SLq.gJL !!1⅊,Mт+rWSt%a5Vj+Mo .bg͒*]Qdݑ%L.;0ѣ;M1Gguz&Q.ɩj;찃|NIH:&Qv@ b!0Z6R{sSrHg&wu!~P%$R&KS׮]H֡o1L$vz{:ꫝKۣ>w~^wu˟DwÓkHsuWsJqW&\TG1G^x!sI@ PLFF+*:'ЩS' <3gδN8 o1ҥ[v&(ڮ⎮pz4h 6.q0!Μ9shĉ/Dң}:a+?]qX`AR *h}-a @ P4Fˆ**$>[>}tvQG9;}ThagTQa$+Ie x Q;=l#8")}sϙEjڴ뭷^y| @@E&0Z6:Qa$# ?i p8C\O #Yt/rSܔ_^\ p"[k@n6Sk6q @ Tte#FڭJjz%rȐ!n+e+&a$M5E^\npZ_IEɥNyOYk\8pHe9ŝ>@ (eㄑO4M@ĝs9l)NHIx=eSzp%~qCŕ#tvׯ洘2)ꩌ5Y}s4ҧX$Du,gw ݌3\R 5 @(e4ݯ[g!=ouԱv%&Pl >#ŭ*So/Bݦ|G\T u1ф%.x饗_N܏vK)Hn2|pG&2|u׵?܉B[`K]_:ڧ8%j @hI,^8;:pͳ &RZGLbD"%U:ըQ#ReCٳ],kQp=mĢDa\ѺH#ZM/> @ P *ڈ@ @FG!@ FaTF@ @'0*8r.@ T46" @(8QsA@ @@U? @@ B @¨ @ NaTp\ @hFmD @ Pp# @@E#0h#B @ ȋ0*x  @ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <@&MA @IaTF!@ <x⒠XҥKz:N @ 2d'tsaq~$OO@ @`e!P%F9/g @ @XTRŜ0Rb'v @ 0 FNw,Z @@"+>B @A !#D@ R /@ @Q(C @¨ 97 @ D D@ T:J70 @ %0; @ P *ݐs @@(J @@#0tC C @Q(C @¨ 97 @ D D@ T:J70 @ %0; @ P *ݐs @@(J @@#0tC C @Q(C @¨ 97 @ D D@ T:J70 @ %0; @ P *ݐs @@(J @@#0tC C @Q(C @¨ 97 @ D D@ T:J70 @ %PaQII[*U}; @ r%P!m&Q>QGU7ŋѣmڴi֢E رWs8@ 7 7|Ӊ0UZ͚5I&־}{h‡o|ܹy晥jǨQl]}ֲeޘ9s}߻ӧOV[Ygo7߼A @T&og%]0:ӭqƉjI C%&&V{}gO{vzeK[/ۃ?M0ָͲm\W8 @@ț07og[Mof[}]$dMp]pVNLn+:rڐmҥ7jXFRǖwǵ^k|;m۶v%,oSr^E_4B @ nݺYϞ=M$=#{aZ&J&"sfmfM6_~&NhW:KqC.r%T¨/G@  0ѣva[5k'aPm控Fr8jժ%?c3fp=VZIEt$v^{$+ЪjO믿:"VÆ &Rv+9SLqO"fʊd;3JR<օ^h[N\oH`^tE q$% 4UL  WmΜ94*-r d_|תU+;ܶnݺn3mrtرc] 6VYew,_y/z=C @ FYgeSNuy'U&0h P޽{)w˔AEb+p7x]Gb UX(ꫯ/vU[ou#Cu\ED㎄P~)&le%Z馛sO;cߣ+}]w}9r]wun[})$t$W9Y ɑ"6@3d$G֡C ѿ  @(0:suE}]7 ~9+*vՎ;8wOwu_kL_#3ņbd/O#eKT mT^ %'t8i~:OFMɓrWtE<9SlXWe )ʯIrETLJ!. @Ȓ@ #%п $Doʶ d;_H֋K/Եxۗf_ STt}{ 7MA*SJvYKw\tB%WUEH>|K#m N:B] @ %rFqPlN`qpd;_H@SN9][Bǻф h?՘g}W]rSb_~ɅNtyKQdm(II I$(*1u_]F̸b΂ T$Hܿނ6o2;st~g:NEV|"@Bu` .޸)beQ?  0"aՌT]t-[Ut1 QgRy3(d!m5G^?(at=؇~_|MbŚ7!]08,GkE%?x;ʬ~@'" " " " 9(5a{NxB`{キuYKO#F>|@ 1>(5ue-y/y2&XMZlpX\|7Ol*+] 1Fɼfq޽?DY/^E@D@D@D@D ^EESǎxpx~E0a_MM&3iICxHآdZŏ9\I`-#aȼAs Eq"u95j/;|0" 7V%^#Y]9 F}deQp\@.ʽ0"ԍA1"AÆ mvw&ֱ>*~i{Yl:u麙;)*/$%^{1O|F "/شiM3g 3ΰ}7w%$>>S F3-[,ñEH6 c!2!5D SR^^zɨ e#7ׄ d~m.aO(O?\Ht.rITQ]I!4uzO_WJoE@D@D@D@D k%&8"^RLb/0%پa:uyBT^7sSez#-oCx3<KCPG]c2Փ\.#eӧ{Ҹq˃gH@2ay/m!" " " " @^ #uY[u .S[lEVo~?#:c3gδٶn;V]{6;l-[TgVqj_R# aTjhUpIx}óF{ ~7xD`]XtyFJw'zN>dkܸqt@kcƌ1::# 70,Nd}CsϵvamLbwyo#!?x֭[Xxklƌ޴iƋdy'|wqm۶.j׮8GyĆBtI&Ņ^1\.Aug[vx_kA?Q@V[me{>c!{|hz/" 낀#M`]\("oqeQx3Xkc^d^{' %Iu]`3Cc[oac~v7[.]uVzuOl?܎=.I/:wv{׺vۧ~jƍc0BE .B*,}#8?XoÆ ]v_Fu?wfm6̳F(|7c(BW^FǏw}*WuObn*T.ȑ#n+$z7N.sUWYz:-uE#~oBhA^^F-_/k=Ge/CJ*ٳgr {Z9]I8]wC.BYftuӻOĉ} |3g'4 X`!^{6m];OC !x6mjZLVM<ٚ5kVAJO agqFGO$YCϰD^qQI}Slej'@#<1%AB%#Jު`aP>=`Gq% E7ZjȾ/0i6ԱcǰE{qi(LC7޸TFxE&M&MBf9"itp<|_虧ZGӑBc5q؇~qp oQr:N8̈́Ea?xi]#y+$yjᅠ30; !'o ߁l TaQ{0rD)߫\,tqݟe`M@⋸mBG#WD ׎*B !v<3uㄱjܧ:>`8^E@D 'z Kw ף_zk&5z'g˖q۸T\g+\CꫯURgi|"}uqIp  ۸A~I]v))p. -i9}!lυsb&,y sSƒ \vk8׹ }\/w r)p2 >ܸ(xr(a"G}/Ӎ(TYh9w5d \#sֻN<,i' Hۻ^Bۇ{;ol+]é%;H,/*D 7c<&}cQ{"52ȵwb4%'ٖ}swIwǵ אmaRG'݇q/;2u>'u'㫊ى"_G'./{3gN0p5~^/)sCNe]$\wl^CV sn_5>x~~愚-rp?3"2,`^D@Xo.i^Tu#k4cw<|31rU;K|DQ.YccdX̍wyܸ>#ߑ`!̎]o$/+J-vRͳ*pE:@*0 p/؉e+h^@X@hXTz!Q=|l=aEd ~!<\xp "<'P(ils-d" " WˆaDs2V}А  _,#dYY蕦=SZ0 mzC@%ETW $GU\*^hpcaw'`pby'k๰<.xkd1zO-[T!|^MR1l ʎ6`AjdWsx#%F@]3l(Sn9k1)4pD|+^FF)cr zy2Txp1> Q%Fϗ߹hƷv|I$JFxN<+t F[:awAB8!(Ö4%+b !/e>7oKxsa/~y9xx߹:sIel˦s&UZ." %I`FLG0 ؟t,ސ ˆ?64!̢ 1:U= FG0< Kb^p>_X{ķsi #$:rÃB]L"2N/7x7uGB QBxe~$=QgC#p|4f 'F`0OqdVɴ,|oCҀLۗzB Bw4,$k!44x63/?>$ p^pnýBgsd}DH|<H^#xFMs" "PF+a~UEyo\t4 I l}4J +QT̬#!2!$r=C[ײܿQq1DNRYwNC2 0PPy0'Hxh낇,0 㕲FYXQ3CqYn5h,%i! ı/F< dǑAC8!ɶmOHۡA.+k\2~F;5@TbtF8G-)!tpߔDd2ȉ{8Գґ=:drފueK'gqB_ұye|܃,G%a.'U/@- gcƶ.nCl{8 +V69.$.)F._ue΋o*DҹB~?1H Y\),!zâkXGftMQG= ̅%2=:lXq᳠QFf7~gIKw'utb8f׹_Nt 2N%+XBVPuŸK]xs" fI(u"H5[ds 儑_۹v!^F'1\JbToLU@vŶF;R@JdR#z7aăŅ'M_JXqqL=aNzҔ'j6Vs L1q QxV~gSY]}H͵If.7U p\kD\%2w!X pBZf9Tb]hX< pјL"zy 鑩u}Hߐd"o sn iMYȻ!Y};&ٰATAd ]I[\Q>ƽ0!}5u-(I}Fw鱳1tp>Qd =1+!\jQ_/GhbW%aMmC‹PvQ^C7'!xZ0TMٌ!4u$ `-,Rk}d̉IzuO}4~\>CR.{Dn;>LutCY L B|]'1 1'> jY1WX\wq| us>;HG4axP^xy," KaDEf&+y`j0it;2esQ5RpXDEWM:a069W44:x0  ⸩_N/ { ei}F!x!418sM6mt~XD@0 4iӰHcy<&ʡØ ƒE-*(FFG c {{>j-7x ='44HKFXy(7[aܸ[C86ogL6$eogc*-~پx4&5a>'{l eFQf0 jlFg#f$Q8 #yD^Pvx5AD@WƧ"֢F\CEL؆Ę{u>gqJ e!0t$wg${YSOeLQ@RF%])/< #EFRy2 bzxyFT婞Txd/Bz䓝/LuxLJZ"ר0C{ -@}Ż,^rz#^eږr<]R\9گ89xI\X4Wߋ|!ޅSIsGh9::t}?~'}oakt!K%-Oۉ@I¨$A,(o VNJVE4.bV4v|x7 ՞{@vڬk~xCQ¤tD@D<0*OWCu$ aT0K(1QC%thJ5SS$7+u͏-UD@*& yuQȄV>kZWbBc M6ƩX)/ t6" " " "  TaԿ QԳgO۷oj*57V:/ K6p@[jnvU\W\i_~ּysԩ';@$P( 76h#b-C[GW+Ҿ;]w.䒬]}>Hl/P}GW7xcXe/n)YVFD@D@D@Db(1a{/ =E]d 4HYKP@7j|9(hРAO"@F(D@D@D@D@*6F-~eEVZvw&l%QqDAq-TrGQnه]uUVFP^E@D@D@D@*(RF|~'駟~zʿ~cGgR?/N((Kb$UD@D@D@D 0_b}IК?q~< sD[d͚5˪W;vM6͚6mjmڴE1~̙6uT[ni52Q,(Xt=.\ ƯTZ'w܂ٳg۔)S~ƍ[&Ml7Nis?T~}n g_˭YfV[Z@cŊ6i$ÓB]Z^.[qΜ9Ffm%Yk˵P昈ĉ=6\Ta/,XR18,XƍYspmlHVvm_VTթSǪT(ce&8K/ ޓ\sox;^xg3 gy*WGoڀFzܺtbvm馅VE;ǚ@!)71D4DZԨ{^cI?3 |o`ճ/܋^{s@CxoKɰ?h}vZ+axdA~ 7xI:L5kǢ @EH,݌;,o<n~o}1E$~Vz;dKf 6,Hˢ;7' aޟ[n<9& oJ0<;C0|]w~Ν"r`Gȑ =%cvm=Bq>Eb;0B>C9rLƤ{aWϏk [Fl-d`q/rb/==v^x1'K}e" " " " @ #4 cL0”<@1xF $3@ٙgИ'$* 8z 6,‡A1V#GOsFm_n]?f*,F'+`h,z ݖzhbR &$D%|2Y$ +s9$HW0D[|| H8裏#<2l0nOqE?cs!`!1˅Ʉs 9׎q_2.g7Se"U<8;찃n #m1ae#,taxgƢ>^8t$u}e]G0 ^FܣѐJ Fc0x] ㋏;:%Pj(Y'̪(!p hC )$,Cre8x߳gO91f̘aw^b_}i$X/jx;8^$>X$8î#ޞL阏U;餓xew~a{뭷{!qËs'V" " " " @ #JjnlrxfBe 2ϼuQG%E2PSO=5/Y;09վl,3^țhzr*3G /LlJJ=2 #ꂇ1k/;d:TǤ z0B7T HABMFpD@D@D@D@RFyҝz3>SZ('(.nhP2#&7[ni+ sdOyFp  !cWjU^VRˆsOgyF~Sm$*ސ{P&" " " "P7(: K `Q!B믿7Xöwoݺ_7Gfaxdk 'a4tP?Ѱ& !\C %RCޢBFr04E8f:aBI}r1_0Zp9d2N<`qa`?10qBݻw@hR6Bp(ycW,oT=6h 4qx B=֧*3[Q4H"{"+)aD &؈ULs\Oo&p ӧZcXsCo=̘,w#'ƲL|xa|qD^-R3AjLe66j(9iYH1c~AɄL,"%CC%T &E9Y#eN(xh‡WrOl^DLTĵK1THne2x̥EY\0ތqJwQWt~-ʕ{%&8 4s1 Bq=K3V%ۗq hN47lid!M(o֬Y6{l<) OTfqGg*tӌ^zzϝ;ׇլYӚ4i C±kqI9M"&ssNu\ɽkKc"ǣUz?1ܧLKGmGy" " " " @ qJ-`sT΍$!lS&" " " "PHڬ4l0O831 Q}ҵGCSUE@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeIB@(ZVD@D@D@D@D / HeI.ɿ.,XeWzիZmՊRX0*((+WZ*U@E$ze/vϨmEiWzo'ol5TJmI৹vZYd,WG+#:gV&P1_mƌl2Ynںufu{(nGh?.\S}n\ssۮQVrF-\u L;qvCm)_w-phISn" " "  0ZtwY5lg϶~ɪUf]vUTv=O|7n}ֳgOkڴij'9[l\8qFNlivQ~ZU+ۘF7LOtQFx@~hGT b(Qa4h 9rjʎ8/B {wcʕ+z6l[vGڶnY" %I1O+"Ig0翝iGž0w۬BBFDymkƟ 9Kj"" "P,%&>]pYL3gδ_6l3kРA!AGX^&M|f7|s,3gM6͇5jh:pDYݺu}SL?Zhao/1Q'Nc(#UQakA[nimQכM>ݟ',3f!{ok޼mz6l_)pժU6uT7o?Vf.t`}HI`Ĭ_/ [l{7(-[?7\ֶmߦuɃOۘ9V6׶Af [JBՅub "P+ѳ).ԯK0ѵVRacHH8,ֵ٬ؤZ͜EՍ-[z4cV[=ޔ4ϖю7~c\}:5S:5$lf\}F՚;8lf-ݗ+w5m:5,֛$X`KݵmI1srh1ks1՝X$زs$e" "(1aog}f쳏K b?>7>ڷoѣm֧O1b +۵kS?>b[l~|S;M6ve{饗;jժ{ Ɂh;s(¿"6};6ԛK0aBba{6 .n-.B SOy!zf϶M74ދ!p;ث~IEmYLR5tw;lkǴz<|una]81 kLĶ״ZԳпwcg;J.-qW'c4x<7&55pY;p{D P;g\,9~m{!ea_DYÚ7ݹpN*U\N}{MY3 ay}VvRdT=uiޏsCvcq&_pzƕ_=J'nO8`=of.iq+;ӝ+" ~oouxa4#޻]|>GJL=I' 2Zliᄏy7mŅ f=ի۫ޗ^{5 :ԋ.]xah vU؞]^y[b]tE ݻ}'^O?/zתUzax>rb}HFDX1kر6|pϣ!P/p -QFy!@v:k"Oxc!>jEw|9nta9.[!,ߖ"dc'4ypaG٨JFae3üXGkyanuc7̮p"k޲ӟcϮl&|o~v3[:|G.]aK {l? Xe_5!j0ڤZeϥZl֋ukԯ}N).[ݶI>k[y~jǝ XV ;'/6SY;Ѷ ^ 'X 0뮻lܹ^DdjӨ߿wɓ7A~ 0x≉1D̀|qٚ>|C =P>Cٶn;_i^O^ԍ: u~},ֻo߾^̱[n{9yK7N^E@r'!ڋ2Zts{Սp2uqBơ./쥿['5V*o: qo|mæ/~c+u^m7cP~<4m]O;ho6(9<&];t5|r bۓp\{`͉Hu0"C; CЄs=;07h>c~>?n@xvzjLꂘEb7Nh0>h:ED^01 $*" CĄBOYHȾq[mvWUA`ֹrmƇE˹{lvUW%#(:F-$Ø`xp^xw}(B.#nv_q,JxYG]H_~9Fo6d" 5RoO7슏[+AGY mh]t_yU E _S{xQt٤fNr.h9X7i=|XYt=!{ N86c+,ʂ77Rt<a7ݝ9ܱp7vom3%:><~hoKmi{2; JJxG 9R;uQFP@~(1av vƘ Bт'&#< J!,n&K&0$[kEF}> .*=o'nH{Cbs=/MUoV>> ꫯNNe{g=c޽-L7"  DA.ܩmņ3{Tg6@P9../~|>l[5?RhGQ>q3ƥ[R2*CfOLXMgǼsiotxX*qp=<\qa@#7.,_am80 igxhTE79*5Q W%&GW^Ԓ ˆ 8=QǨJ*)=/B|~LGԼP JRq0"!֘@ys:S^?C`VJ E@F(0u!YwE OLâzO6󷏿ㅢ)0"t/L⚍0B4{#/zFuȏunaQ5s`z+(ka]ug_JTܽCe&d1U9r~g0 @B" "?JLd>3 q5oBIMX^/دK%0օ0z衇x$B2ǔޜT:s@1)1_!:uC9$ݦZ'"#1mW!e-wǹ :6tΩ^S;0bO%UZ." "(1a;w#6jD2a 'Ci2#+oTc]#Bxƛw,U'0ꫯw{Ev#}642 =ಫ)H Ȩ_ AOvkek]v:ZFX.5nlGr_9~5z<(kaD bma/tީe\{ұW鎣u" " @ #NGb k֬F(I Hup:&I%e5JLJ` aDJo2𑶛5k NNA07 #$fxH1{>LG4i׶t+Ȟvv&,uksKH }s2cC$,f߈ۻu5\1v B89ۦ-t~x^OF]=pOwm^4d|<$_$HMn -RT39L|S]bWDm,(kaD}$k&t%qM KO"ޞTN%;ͫV,&: ,*" "~(Qaĩ$୷޲)S,ѪU+MP`xHCX ,vi'A B6m@HpoH1k֬BYTAE-LN֏qdw{:BewpID@D@DLH fDD`}%EÑlawn}=[D@D@D  `XDXjUpĉE6uj^U@~0*u,((_~6dhPv(oM_`g??`{k_(Z~3~]6V6`"!!t)EWGBW﷏\)sͻ[mQ2r٩Xm+|EְF)cl? 0Z|=C+{#6|s_NVZ?4i=ֲeK;3QE@ Kp_ےٳf$Z)\o`Mko>̉`#g-4Q5T}ֵʭSeya4_P|rN?h|v{v}}KYࣩ׾=lfc{i3(1a4w\뮻vּys[ͳٳgr!6ec=f5j԰#<1̙cmZEk0*PD@K=nsk2eثկ^8|IxoUn̫2b֯#mʕ6[jEwnp)IDXQ\!(~e|h q҂%vԢ]бYu " "PzJ\nڎ=D ;7ޟ~R@1xVV-;sQv(Yz?t=Ɍ/gES_:*g+u.[nX7sriYIJlHe ֏իixdfBD@*.RFQW^&M'C:^.]j3gδ_6l3kРAл%KجYx!+?U^֭-җjJ*+WË?ʕ+q^7O<=F~xXUzr\lٲe6c ~PB9ަiӦY:uQFƶɌ:?I΍ĸk0kذa|}HAHljUCwuk%zXȸPh0⩻[MBɖFм).5Y׆ZJ& E.e+WyQ>pެnʄyxj71~i/ X[lb[2 -ڮnBڭc9ܰttԭЁ|ȶaW9Eˬ&խ5 ]yV8NJkgkn篚ʚNVpƕQ /5hik8h1&jsWlY&dE|ӟR>i-Xm$ē˟2d" "oLZw=!wg}wLH}G>.&l۷Əo=뮶|{6tS y2e]ve;]ڋ/h:Cmv4FYd:udbGu}#Fw}إ]vvG{g39f?pO?lB!-Z0}>B;StAa!pۗSf7(y-"!CRQf]>nnѿmco_]i `=v5n ܫ"F[hcG.37;ݱ^ѥ¯Nu'nڧg`$m\X%{rekGawD ݷ[}aY|Q.u+t5r//9nb淗bԫBOy{Vvm׭2!*xskƄa36n^pH@$X]0~__v|⊰M({!H],\ꗓn5/t?W7e&kypQGbC 2'2}X$<*o-^N:$kڴ17|{~_oτիWϿ#tM7yoe`#;n<B2_6cω.M'ؖscQ( Z__7K:7u'ܥ+¶~<,٧8_O e$(i( ĸFyNmq hg[9^x;֍M=.Z>gsGE"ln.re,YʾtF#W\z|$P^'-Xh{L;<02ɓf͚Y~~yosb lamx0xE)2Fxp.ظq<,q[+uÂ2Bʇ!J0<5_~e!0buQ &E׹sP-\n6!.j}ꪫ _5D1"!'^z/"|crX(Iֻ\(SNtOg^~]bXР F_ijѐ]Cy:}}b7S dt|Skׄ,z47'gЋ3(ERל#NR-ێLp=p%)[;B?b<v 5\eE%Bh@<㤇?CSCz|$P(iwމ=QȏN\/)at=~qa<s/ܩ)2F<ϴFڂ0"aiqc{*UVgALʆb(_~>vG0;Ï wa4|p{7| Bq#ԐLv$F:=ٳgXW4+;=9䕋6wGfxl%<dzxlsȇz8~up25v5¨?6![ٶ}(K2k*aTe^7x2%_ȥnK}0"B8W@>(3a:ddQ;v &U_X)#9D-ېFLva#2E=PV1FP\'m9cd"  <4o[`!R_22}4mvJ=f ] Xvked 9Ჩa4w#"U8ȼϮ<>oqxǢp >q =e[35Ȁyw5 BtbaإRiigXimV3m#`)rARDH܍n5d cfg.,.=h _hgf!x.F2D`r,^@E`cfw1Ke9`m4VߚecGcx~uktf/lƖЫ|8C,KgjfX60Ct-fXiٛ(Ĭ/`z@e47e#?g_׮_`;=0;I&3B]h/H/agtk>2PQ}ѡ;L,v57k֌q%0J۱cǺ-^8tqo 2oL&N 0EH>57xc;4qDgOxwjӦMdۨgŹxpmxc޴ǻge;u/>߶rJ3f{4imsS ]sz*" " &6a+?~{キm6 M^sB ,}6|ȱ ;:2ܣ38#k"(&s= \y֢E wX_^|E'0lrKOvm9pwpXDx2w^ʼ&@駟n={,P"箻r aeW{@6dM&~? Qvȑ#han0㜴C^E@D@A m6:2!՚5k&2&AϤa}nN?޳#Ng͏?;cu֑cc9;/Z{?rnM;zJ[{79S ,}Exтxѣ <1H_~Ðc&Dp#ɹ~{ҥk'/B0_~ew_>h7xb'":2#̅^h<#?lxt :3f$¢뮻]{ M7dCue"dvpmyGݶ~y奣rgGa?#O?c;l]c36GyHF{ F ao:oq.SX9FL+JQ+E#&2yG` юM7uInfZ9z#e? A0LXq  =$D ˆ sׅQN~<#\\3r#?xQևR?x8F.b55b-'Ynp]T:p@w]#D!#ha~iS)E#x{X+[a9:7t %ƨ1(eL ddd ;lD 'ڼ0b@o0dDx.sxjp 'X޽fBXZgWYL.`J|y@#*Q̆_(8?ekbD} #%$G0It3FEqż0"$QF{b k!{)-%Q`Y*m>El1"K'.!$St{C q!aO^t #꧳c4s."8&L̷W"PZ $#hHhO;~ ׇg0V})0E k$!Dr#Jb$'΍Gg,c<+0!k2gq'“8? c;s0Lr@2ˆBXȼx)D$Y;xIl2]IQWNsyNq̟v\s{d aNX52$42 #.ʯoDЄm)+"!g.(aď+F*ɜh!۫F*-^b K/%angQi dPyIj7Kx-M.|uu#˰Y|Ƴ@#̏/)xFI]0 | Ԓ lBPF Gs2dʨ+F׋k0db 訑I/'wh߾DBvQ72&O߷ ~pdMXP(8^%uUr@"a, wnB'ه%, K*^)la VB 䍿KA!΢[,aDRz_}XO3_>$9̇+%C=q|D*9^&" " "aĤ\:,\~T2wأHBMU8vv_)aN>kDσ%D$N%lI~0a'&Շo_8?V{q>]7.u3LdžEBHF d,)*QE, :C:%thtE=_UD xaD-!\t|8t˗eL8o"L|99 2>vxV#_THKIygbs%jOmp$NG ;F'- #FfGk?'Q^wR#egF%^8^Wۋ0<xn-^(CS3AkH:yf!xg;_/k$|zދd@څQ.$eKXE#[^\IQIO\! a;ŜBD!\<53?eGpꔪ0J G$t 9cn kCG>!mi:eGhI':@D@D@D@D@2 |wum" " " " " I0J eFeD@  #t=?6%#=痉@I0*I:@ ;4L%UD@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D k$^'(-$J˝P;D@D@D@D@D@F@(kubB@¨ CD@D@D@D@D kKarJ[xթS*T5:@ ^  dӦM5kXժU3ϴ=zVkfիWooguVVE" " " " e@Zѐ!C_~)@|N4iĶrKdM /Çng; m׆&p.܀rzH0"$M4ɞ}Y۷{)?fuɒ%vF΁NJy'K [n~A0*]I c(+3o<;SdxP3k͚5&L`-6Ț7onժU.>/]f̘aիW?X˖-Cy/ԁ #rVnv0Y6ydMچnhxbY2mXVZecƌqjԨmf!~Wjժ JEo宾ٳg;δ?j?n8'b*U:63I4_pnU2(Y^x,X`<{9|j֬Yi] }F\^DIK/Yrs=N$ kao~UX1^{W쫯re8,bs,gy*UʼhfmO.$j /.G}رyN\l]r%*Aq "K/@sa^hûq':ݦ'ڃ>h2o4uo ׻[1v[;3 Zo8ro$U@zuQ6~x/ >X$E~uǫSE@D@D@D@J@ /y#D>~뮄tP^mڵkxc CtMo@x=^©‰#j<\0o&\u=#5^GYfN\xAɁ#Es >zEjs"OQEϭ&٦nj#F0B1_#Axq ^52!hFx_^p߼e3;ok0JK?#SVx!x:ꈚ1_Fbv7R$M$ \oeT2PÓN:)rȥ. 3<^/hq0D"Dpak/꫼u-.IuUD@D@D@D ;2&x_"IHuLeP#2³6=FB o0B捹bxYqq:Ϗ72: ^QYօWh]u&" " " "Pr2&g#m2d"asPڴiS + \Bk?#0~KQFm9FF$| {؊Sw(yYF z]9H@h#Y|8%6|… ">AJ$CR^oߟl*(F"|V?2ˑ5t #x$çQoʆ8O<" vs]Q2H2 ~ex.my-,Ë #}Cnd@օGg}^jժ>c-ZpT3ORR4&(%Fa!RJ{cqORM6SL @`xK E[WaDdxի 6m؟P:zG:o8bxFH}ץ _{~%Cx\B:tiLLXa/օurN5b8uG*Ⱥ0`37 /źY9cD;lqE __QU+3W ׏SQ'S_C={t 鼋z/|]z #:xttLIX00B֢!ZxpHœk$Zۇ3F֡ [~~[>)O6~ŜGl*G(ذa\vLJBFᶅeFj ,"DLp_&IeTa۸׏=[ȇ"{Ĺ8r/s4qw`Ik.] Ch^*9,H ŠS@d@ڄMgy7'R:،Ϛ5AoJ,C0D(?] u }tYS:?(VY%ۆw9s5kZ#AW^%uNB ,˹㕥B5L0-qa=‹[|Gp>Xk@H0*&," " " " " "^FD@D@D@D@D@rQ45YD@D@D@D@D $S  ij@z HjAF9xd0J/O&" " " " "$r" " " " " % a^MD@D@D@D@D  HMSE@D@D@D@D@K@(蠃W^1j  ^}U{ݧs=vau9&%uG.@oroa>>}ر[~'[:8Bebm0EED@R!0x`{ 3gQ͘1É5kDvmVvG>ZF*F`̙vgf5nxBMdRK$2" wի<7ʕ+p(Ǜl2Ϸ-ҮAD@C@h-:Ljj'Ov|:tVZ^: kԩk׮@y>06j(?~ZмystMvFם0'҇'p饗;p*V^m'x-Zȅy-#GsPR ̓'&M便|gx#dUV0պu]I#@ g}wuտ|#o駟ng϶=Ӿ [bE!amVF ֭[ӧO?=vB,RPoD@4 7'H1ջwo;#e]wO?47 ɏ1w+\1bv;"'ћ2A୷2#ء}Ѷ^{u]:e4k 7m'nf7W^;uUWGRG*2A { 7{ȅ1؏Q/$}oH àDwM2 r~nXHtqȇ0E›t},;Kʕ+6bt^{ao&aA7Ip|tM6vXѣggcĖq$B\deq>,V~]EGDza^[mw7wٮj:F3o*QeĀ%̠eŊ]z ]2E@h ?caދMFeD@D@D@D@D@R a,($}U@@(X**" " " " "P6 HHQ TTD@D@D@D@Dl0*UW%" " " " " `@$ aT6﫮JD@D@D@D@D F)RQI@¨lW]@ $R" " " " " eQټ*HKEE@D@D@D@D@& y_uU" " " " " )0JMFeD@D@D@D@D@R a,($}U@@(X**" " " " "P6 HHQ TTD@D@D@D@DlȘ0Zf_e+-e-ϳyն&_bVRTURɪTⶕMܺ*H #ᓷ2V!VE^ϫVUY aT>b *YjK+ʻrʕ+&2B h5rJ[p{k~7n-]֭kݺu<7n rCYÆ ()9~C ?&LwW=~mSO-}磏>S:aԤIw={F|^ ؾ;9/uvgdM|Q,j?pmb)&m2I mh渙n"EdK!B Fkd{_~ڵk[ǎ+ˣGv#t+V;;#t"*f!m$oO?m-ZۻSh{H+^m_ O6 0.|A3ۋ{>xWȡcu8{[`kn$e˖~sW/s^xad?teA'|2]oD@OdR)e#yl)BoD`"6a4׉E(:-B-i\%a*'Ov+g輭:-z뭶}HIOPS:x^8'.R#D-Yaı>y晶.h.<57tMŠ{ӧ 0=FM2F֭[G'7F|@*b'Z0*PϧxwAEtH0?lW0bְl隕lJ[^.U_ժmm6lnL(pQGaQ9rui '+t?~ $ ڇ~hW\qm{v z>Bj{֧OK᫯{N>d7=y6hРaΧ}"  "vR)lf:|&"P6 M:nEp 6.Ybm7צkKV-OH ׶֫ewkSYHСCs努_{6l3k"H1bb {G#Dz#Y&0k,;A~a@IDATӭVZN37'xW|O<{U2ψ#8)sTD撵d\1h"H/vHEժU]#qgR6^ F jhkّ(ץ'W(&&o+#MZ&Cl-&LS^ܑ@p>Uy#Y Y۔HB`dIm&HBؙmŒh=Jl䠨7$G"LtDz>ESg(&&>)[ B[ey3W/٤Umf|[j-_gkU DQJm@b;kW{Fc!JOXUH,m$Fhڴˠh.]bO/ !Vjc&;z>b7,HK=^q~2]B`b·>G)SXf͜KquM&"t` 7MFKr R6YhQ2ϒ,Æ :g#ϮXS,*&e@ڄW[~Q|C-^YlWͱ1Smz<[V(U5vn dKTٺ P`͓D$G֯;8Lsy OjGWڨQl̙V~}Dd2AJK|dcm&R#\b{%+9oost;yMD` v=\RD5R6V=' Ϩ+sQϧXM SZ~^X–ga65bj0h[%]Kja.6Zׅu6Wx1DTN$t&㞏h\*#$$vԩR$'JۭUV1z>]]w5fFTcqxJ6@Z <3Y*eY#AOaz/e@ڄђyKlYঞZ6ߦog_0V "T(U*_Zldn6ʚh>zJ6)Ƀ8;= aI l`s~ cm&W)I j/_>fTG\C~/T\٥.>>gE]Tƫku9yn1X|EEDH0[g-ۘem e|@J`nQ֡Nsۥ>x^UR9 WB1+`3B'ts΅  /&2Qd${d6R!ONp1!]&%M)ad̕a哵DO&|Y\58am;wxEܠTM[nYgY֟$w!$R񡈾~;ZN8ݻ;A*ec=So:sƳw~Y0.y.~Sދ@nH0r!L?Oe,7J>tOQ^Z[ԩnKfQ΃$(UF C“p#tdn"Nq<@`Ds&~\/2D j o 1|`zwgkY|7P0NC uamݻa*aOl*s'!#^_Fd >%h/,(sg9L#Fpdeh6!'.]Xz\$c۱cGÓ=̩|2dn +omHAϧ87MEH0ZXl-licc W.M:!еԺ6hxZX`^QJIYQy#N%D_|wzFWF] ާ"Pes!~UK{Qx`0aD LbFggګHm*zCO?y|cPV.C[#dNwmg4xؼ!i?dSF:OF"o[oK~Mlsx~,1Y6=4^iF$VX%t:g]4f,%&?gd ^}:EUp!ra$\h-lb"S&FGN"Xu:SRGCyXX;xTbü&D0L^?"lxt|6`պD['3y"Ye="Xƍc':qTz:VJ@ZS:s4"lMZ:Ӧ/xټm~^ѪnsjkZ*iA]KTWe*V/κ%xg^N>UE@D@D@D@D@2B ȷ$ ,[jSαYhn (GHwsksjZʵIzKTRs|ʤMFXu[&" " " " "PdDq !//[,J(3¡t*H]23hLD@D@D@D@D`}'1a ܹWj@HeFsR 0XU+" " " " ";$r^" " " " " " a!VD@D@D@D@D wHνRKE@D@D@D@D@2D@(C`U@0ʝ{dQZ! a;J- U" " " " " C@(wZ*" " " " "!FjE@D@D@D@D@rQ+TD@D@D@D@D C$2VՊ ܹWj@HeFsR 0XU+" " " " ";$r^" " " " " " a!VD@D@D@D@D wHνRKE@D@D@D@D@2D@(C`U@0ʝ{dQZ! a;J- U" " " " " C@(wZ*" " " " "!FjE@D@D@D@D@rQ+TD@D@D@D@D C$2VՊ ܹWj@HeFsR 0XU+" " " " ";$WK, ZÆ RJEn\$^ S/b*TnݺYF ݻo dsq*Wl -ZW_}e&L {Q*S~~Ɖ'Z֭u+WujYZ_|a?^ݻwv!&!Cw}g˗>}X.]b / b-+,pD7\`.S]~}'p;򹴼駟[n4禛nvE>&V\i{W{.m٦6>\믿r~ʬˆ)SبQl͚5־}{ c9Ɩ-[67op'FeAh6mZѷo_; VrtѢEVF ǷbŊNoO?vX="FD@D@D@D@D?iF/;׾kҤs=.l-3S[ousuٮi{>#:m*P#+Vm{キx≑+ǫ]m&%0>^nС^iߝwiEBh3"J&" " " " "P@ƅ<䓭W^Ξ)aDadXlָqBς G1sύ3 g׏l7o͚5SN9ŅE ԪU˪U[mҤIjڴ %/_ncƌٳgIh65ΝG1goV̋ |0 Kvr^-QfƌVzuw|ƍs׺FY˖-㞏|/8 78N&" " " " "1aļ^z)r]:((aD15r1 v‰~a#CFhꤓNrd` h;V^=w? ABX +@E/ӋDB-UC=Bn=06ڈQ*rO~#݃>hXo1BX0~'o-w"pUD@D@D@D@2E c@G<t͚5Dhذavw찻F5}_w'~;yN? bΖ[nDf>#9._E!nvûżs9'/7'WDqk&"b2(iFt7{#״~pl'jwg0+ʑ"k$@ ,Ǽ/ψsѩS'W6 #^|y2ۅ ܼafgu[UVu6`;v[b0«BiͷzkF(g}@NFV 6۬Pޙ-,>C8p1i~9o#lrM7#FDHlqGb ^ve=υ'|"e" " " " "P2&0OkDo ^x7ްg}6ЭG$ /R> }t?:\-:x׆5H獽?ߘlq@ٳ+{[xWCa% Y`pb{ך5kviaa+b:! {BHd`%YÓp>SA=^$^엉@IȨ0" 2!c;S 0|pwunƈGIߎ6B`ZrfL6²8,Ɯp߾d_dw7Č.R_{߭[giB,y⋝Gvk D bxM70!Zh7UD@D@D@D@F 2kD(СCݶph$%H"ژ{d5{g"E)¢LQo"7#\zZJ?GnC=dD ,}qˆca#t0a}#]ԭgT^D@D@D@D d\qAY0`@Xӈ5PXEs"o^|E{W&±C)?p'h`GukceB %]w8HLt2 6B=ȦG(aSO; #6 Eg !6s7&&P"ˆb.i1m6 ,#cD?ؕ!eS vN17ʧ:vyg!+>S/X#ƵxC8GG}C~s8bٲeƢxˆHVolPb(o$}@y KE!7V[$b@n1@I(Qaő?/p`c=(?3fpk'yU=csNaD$ D,ZQ>i ܠ+0b!<3>S`{ֈ"[]*護޲Aj …'4 #:t'tD0: 2дcF9C~' _쨃mN?(|D(w;Oup_%y^D@D@D@D@2E (ST" " " " " "IFE@D@D@D@D@rQN&5RD@D@D@D@D $2IWu Mj@& He F9qHL0$]-" " " " "$r6" " " " " $ aI[D@D@D@D@D 'HmR#E@D@D@D@D@2I@(tU@N0ʉۤFdQ&n aI$ LU" " " " " 9A@('n)" " " " "IFE@D@D@D@D@rQN&5RD@D@D@D@D $2IWu Mj@& He F9qHL0$]-" " " " "$r6" " " " " $ aI[D@D@D@D@D 'HmR#E@D@D@D@D@2I@(tU@N0ʉۤFdQ&n aI(i Ny-K:@HeN)"P L[¶|aGooMkV) VD@D@D@M@¨U@Y!׼%66kJwYTl{nh'unn(+" UVY 0N`vmY(U`n$~m,YyX\ɞVg(ʔ0Zl-Z6`+W|lĈb ֭6|㘦M-^f͜9ԩcUV-" a|;M1ߕ+omݤN6ȷ:U*ud>4l]}[nNsFYljVuW}=ըT>8]͆\hmUU*+lΣ["@$6arJ{"cw,lԨQoہhm۶-qyp۹y}{q-"^ں?-\oGujf/qmhMk~1l}Hz_ 읃ZƩj#" "P4 9s}ΈSN)_0:@)yK9>SӧlY0[Ԑ!ClvaYڵ#?6qD; lWv#LW)7O=ըQ[ٳgcǎKD(" #0uroS? t P֡1Wi޸Yv-쒭7N,\Zсo{nVޠ3a7UȾo̳fGvlfw!@"a {gL9w`6[7|?h:+QG2 " E ӭuva߻8Ʀ&72x=K/@{JÀVZvgt 8ǎzהz{^>aeow4#=} ub""?5^ž<<9+M?BO_T@J7o 7cӦ:֢D@D@J3 #Bׯk.r ͌3\rFocNԩSw\זɮ.67O_$7.Hx崏pB iCgz n٩m_xHpk 0 <7wtݟyIQ8;"REDQ{W콢?{]{],(BEUz`7~pwg2I晹L}yЦ%DV0{ĝMͯGN3]Op‹Y0?vp}u^ץ] K'wM65мXd1#-3\E պ0˸Y })&fϞmx 7cq%HpqˆhqDcάL\0vXӹsw5h?0(vz<Df|w^,X\l ~tY}!Tz)ӶmLT,0¯NKa::ۄHEqNC_E I؁G-wM1fڙLpE&)3ƚym,q3̩_Mzr߭v/Ty$LZۚUN@mWF6>ijժe8<c]J Bh7{YbeV{ݙ9t qk^#Nɛ7:ߜ kJ*6-P,0ab`,Ű3ww1Üb;t5 /'LF;?U֔*;[Msgiim ՌЌv٤OFNu&p!lўV؍w}v5kyǬ_;4_LL2S Uaܛ1kypݘ}K/x֦0ݻoQGen<X$$zoBti~uLQaX'}YM7XvC,T_D`&9lhCN t]Hu9ig'|+g^vqBe?+iΞ.+MtfX&_N8>_&aGǬ9`?_gpݒ3fkS5}'{*ONOf޲8_Y:Ψe#jOٳ_O[_ {)0?4krE*=kUl*8A 0b]wfnCHʬMak!1Q\"8&~$'*U"qFԕ-lu-;r$w\81g+ t38P!PAp0 QKa9dqL eo ˆlsc 0n"3Ev}osoF췍9YݰcƔ8I;v] EQHHE@Dxuaiy p.BAj<3S jժn><„k*㏻2*!"M>pBTYU0ʖE6ˆX)L>e]|}.3އ|̷3kX3狣ڙ"] 3͑vMT:ؾ;?v?` -#¯g*Mۛv&4F|;np~fST|qCPK6 =f>|>fʂypr!><4c&\ vV7n# D#4OaO)Q1q-k="J|to~s&{㴪_0)" GH#=Fs!FL 5iĉ!/# !G6{Mmϝ!d@^x-JP d#01zBn޼ 0Ѻuk7SJ-l]?0Ae)%(-͟]\30b:F8"a 7 7Nrq}{ΰFcl7vև5o|l #&b'o2󔍔i|,ˆ|n0=FVguf'L~\f:j~\2?)ˆ߄^aT& 6J;چaXf1b}Յ\?߆> LkFo5,K=B|F;nka%a$" K gˆ]tI`(3$=~@ԙa1Z@,֫|2c? !pB0_ 6 k# &[ˈYBbOk:XG$f{" fu :-K^"=1`[l k%(M{ϹH<)'_s3 G7YɅF wCݚv&SƧ\k v SA7·#W:F(hdOҥlyX31 U"o6um"هb-䍄P@0EhmD<4 t C̐X-o`* ${/݂aH8f|][ٮ ,wYЗKوlpǵ`p3{0kv][*LI FTx@΄AHp(b!.!de˖DwDMŊcTfͤe#&cl#E%?hs4VfX8aMAR9s8.קtOChxꍞ̘QF}@i"ui$L7#{Ƶ h~{6K3ӊf%YcXptEnA6BredcM @(hb&tը4[dÁWzu 1lՁȘhcsq.)"ҵ̴ŬqVVZqk )!z]{=G$jp/nc?#Qޤ1e1Sє߹E@ T:RD@Ji!,\bzNX5˚C_Ya$" " "0ZLD$vWX1ZfD@D@D@_FՙO痲FBqZ,\HF%Q" " " " " EI@¨(i.I@¨D^5JD@D@D@D@D( H%m%" " " " "P" HˢF% D@D@D@D@D@J$ yY($ aTU@$ aT"/%" " " " "P$($JeQD@D@D@D@D@QQV]" " " " " %Q,j@Q0*JڪKD@D@D@D@DD0*E(JFEI[uHF%Q" " " " " EI@¨(i.I@¨D^5JD@D@D@D@D( H%m%" " " " "P" HˢF% D@D@D@D@D@J$ yY($ aTU@$ aT"/%" " " " "P$($JeQD@D@D@D@D@QQV]" " " " " %Q,j@Q0*JڪKD@D@D@D@DD0*E(JFEI[uHF%Q" " " " " EI@¨(i.I@¨D^5JD@D@D@D@D( H%m%" " " " "P" HˢF%#; 6ؠ(?օ6fuB," " " " "aԥKӳgO(ԩ9JYXA&M27e˖5ڵ3lIKWQ" " " " ZF3gtbgرQi֬رap fZ.+,qe]hc]uU>tM9,]EvkE^X137Un]2F9{/lmXwLƟ7>5os=gQѱz |bf -[M+Vw}|GAm 6mnv2oBy\(6}fH _{5S|y_\ORA|7'p+}}k̅^_~<7uKɶgSO@eС't,܎;묳Ln/U&5kA$3C͞= Hx,y*l=ߕO0fK)rޮ];}F%rwi'/{^TXL!.وFvK/;>?aq'1׃X DD&ft)b8g*.s%gaoPhՄ \ L!÷孷 wٜpFuK. Qfd|q)0 #>h@ ~zr;u~5{/Yr&0޽{ 3(q/ Nr矻#Ba駟W_}5() =CKa!4XL[P~B[cj&|r9a=UzBrK)ג`Q0>㒧5NzA g>HY?LRafH `*޷~megt68؀vHP v\[lE,&o/l=\7%EÂϨ04JM-}XSܵ\{{キ;$,WSԧ>9FY fOZΜ=@F*4Z'fu ||>"1(/ExW8%OpLg66WLpBHCÙllIDd&*4tf͚.8}Pi (`#Z62 ˕0)" " " @΄X`>_>b;Saw3(i0]&V&M@>EI Z<,p!ŵr!pna A񢉠#Q$&Mr}paCkO<ݺusGEQgmtD)4$!kQĐ(!#ax̨>UaFSD@D@D@J #0gBD] &upg N b0'| B{ s/L|"?3 zFatm| a}" a~1Cʕ+C9-oې!C 31-$\ ?+Ť/PIa>}km։1c!mIĉ]ζF9Qh&XsQ }>!Caľ5`0紛6-yD),WSѧ>9FCTFu~z.rodp Ds80ވ!C'ůՓH0L '"!XK2y.Y{$kB0KoƇ&`C.]LS}oy>9?O ~;E2FSN53oX #"EyK;vtKJGOD@D@D@D`&sa. ޘA0:t0Gyd(\769 s5|RČ60~?&TD y_xۛbߧ>؅fls1|XMdֈ|D(r̼BFìYBKӞp}/,CF|ϦZFϋ>&>~p?L!]̼!p0x||c)\ }b="FQ?.uR7a>QBN# -̽ѧM` كhA*hb0? &Zq 7fT{?1Lg0|wҕ!3~;3g4EamiuƑe(cքY6f4aݙwfNԪU͒@|O’ \c|E8p Y{xf7gAfzeE` u Z+" " " " "P HƫsH! aC?D@D@D@D@D@J# xu" " " " " )$Rp@i$ aTYD@D@D@D@D Q ($JU90J" " " " " Qi:gF)8CD@D@D@D@D40*W]," " " " "B@(~FFE@D@D@D@D@RHH@¨4^u@  !" " " " "P HƫsH! aC?D@D@D@D@D@J# xu" " " " " )$Rp@i$ aTYD@D@D@D@D Q ($JU90J" " " " " Qi:gF)8CD@D@D@D@D40*W]," " " " "B@(~FFE@D@D@D@D@RHH@¨4^umsCѽ[m6&"" " Q)t" "P :ǜf}1G5[1E@D@F }X 0ZPD@2!VQ"0˗/7˗Ϥ-ʓȑ#l<@ۦɥ"  p /Y܌3ʕ+&lVЗ~G}Ԝ{cǎe´9F1\s翛yK'"aDQba3^'/6wk㤻a/s[o6P"ȹ0B ofȐ!ffŦZjf2p yhE}lvi^@"pE ]^b9KW_}TX1#={4]t1g}92:&W L27#6m4RfJF*ڕʛh&6eʕ s__sy|reʘ*7c:oT)_6O_;Nչ_*Ъ?=`sw{;ne:o۠HX T-Z|Gfjժqsfn@qWe`枒0ʆ{fٲe榛n2lP0´2Iq298EfrV44WĔb']G#Z1UYly3cṘ55*KwGIq׿6ntO+W0/]e[r*>S3`Ӽyss1ǤY6m֭9Lrz(dsHeCKyE`j_h(t_Kthi֚Azfm̖V- oѴڸ˳̚afKnfnhEڸ@q 5}K'z[b- U9 #3=|RF悴s;y6lhD"FM&Mγ^z3gG>Ηrׯo/O!|FLZh6ƍKa5f-X=M'fϞm/y }a:tQ>e˖ܸ6S&>mOc=fj֬ivyg8M ̻kx8l:0 QF l߿{c,xIAv(kذa>;:ݻwQo!1P/ }؇XB Kt ~ & uYn00y衇L*U+-_~q:udN?NL ⩧Jn xBk3x1taGy$y?)efÈy1E0kΕOK&N|Ϯ{@1z衦sή;]}K^pяSwO gyT5r-4SL:a4Bۼ,uY~mFmf2`y1"?##!0\uTJAۙ6p1Ϝ_.B)vj|'~> V!M\Y[v3/ch64tOVkykdrb=[m^<k8gɪ`1>dr@EL8Ӓ+ϓ5wܜ]#M[Z%fyBAi[3^NvJ{n{-δׄy+~j2)8~c':vm@ g7po^8 Ûӂ?`zް0 (կ Jr`V+L}{>}81վ}{'l|[F n AT! *mС'8/<)~'N ֕ǿmۺ/l7iww" `I)6l0w\ӫW/7 /xR5#l_^hbA6>5EE+41^x+v}/SHQa\I7X} y|/~"꘩&w!0c;ܶh6%K>~s0_dˈY.X0N[Znm_`[]=o{DJ_LBXr>񔃨Dd|ͮ³.1м+G∷C 0ZigX/(x$?PſsNM] k;qkqsS߾o_Ohk׫BϦ q9ٙVh=oؠ}S3{2ǭ 76RcP;kߌYo0tjmvjBAm_!MGjie aĿ qװ]o:x-9u#S֊GOA+ƙg|.vG#Bk{ 1N`d 2D0B`67Wk_Xܿyvvp>ӶfwM,Yoهe¾K{BR=ڕc% r۞~6V\w}wIndɍ*ܜxg]9^J{mSGpsO'H>8;@J1d¹7Mj }(<_|1qG'KB;v&e'PIn/,}Xa3( .qy%nCRGFkV6;7VԹmJr[`LXd>+x'=[FV2d0nr )>'kq~JX͊ڄ ܟ͗.&>}ʿzHt;j#$^kBLɀDHpIv})މzg'?|I' D~LzIJv.&H&rg݇m_L$\xyg~;;7)YF֐I3wQ3?$yӑ9L8폱c)mIN{DSm͔]{{+Z^so焔[S[_@яRKt9Iϟ?x8jETtPLx믿&%rlUv~ RD0&ǚvA; !Fzlnq;ɚ;Qj]^u̙w(xFye+(Eç{r]_T`PFف.g'4>?P}bؔl4wi_ٛfuwB(1e۞fϯ+'D@~tN!~Z}~ar K /L|gs^p>_=rTcSbiDв/ӶfWJ";93{If)0Î#tѼM3@؟{4|vqdvMXq-t !8r-͘`BBa|3s9'š3;L80 'چ=tv?&|&rf͓Lz_t!}~@[фY&>FDٴ"Dp!WoJGh pקT f$|Y4 L0l _01&ΔsW?~ #Hr>:G}(˾q&~3Dh_;pbȱv;es첋;Z&GuTft]52mtW|U^kDat;ڀ &P@ӚM-6q&Ja^oJ}>}' ? X5y7j ?bLߓV1 ߷| G? ĝi _as^wrO5{ߺ3>}3q}wД-,EJO_7*l+NG3">ݲ\-龧k;ik&|Ĕη_Q< }/0?M6m- #ˉ&nE& $?cǾ;(GVa/o0)-#pg>M4e*8@; Zs9WFvf-c0p@'8šA܄gOgBhgI\;K^'; #Xۗ-#WDM^xQ6uxdM]DA&N .p_"U  ׏2{;D?7l}l2%$ݶ4kQ~f"Fp JMl9{OSF@fwF"Nq-t:Q=[+DnC#>?jPD6n敿':SocU_Ng9EpWt 0?ayq>p!hetIJ؝~M) L)/ˆ/CȓЧX\$v}[&jDvbr7%aBAqtᜰ2Δ/t`&d.$7cOJn C8k7s:I%6׵DP}2o(|V0b&OdJ=BL0ﲁnoGʤsr~[0G'Lqfsq8ƾqePO2<.ΜڷZ 63 ꪫ'yJ1N|\_6>/٤L0OxS(],,A~|hhZbE5f޻Z 삲3[<շ7!/o=ѵcxgt - 7ef*l+Nq60?hvgt|wyobI͙S$"`~ ZbMRPKEك3HǾ LA 2B_t8O۶&>_@~ ~aDCD` 7O ;|!#R 0"/ZoOtmLD5JfIwɚٹ 8QC[saFl"p ><8.~iG)LQv_ϵ7 8  Jٙ3(\:(0E\8_ E&[韙y?Ƿ;X؋_S"?Ins Bq(ʄm /OGxl5SG \P㟄_| q4|e`~N gtL{úcjFk`u,,gM<6vWcNGnLF0;kjx oJVL9\0s#7K,HXXS:pݘP}0`ZH`+m_8 *柅|ͧYaYu1cǎ5[waޔ|kHbRP^]YZ!\5~|$mf_6{SД.[F}1,;6I ~XabB͝sŒ vΙ' %"aY B矉kˆ_^jݞ&\Q͂& {ݏk\pyu[ynV[$s5Ycf }fm1s7ؙb 7DŽA^eꧡ.3p \y]mתuR?iy՚޵ lEl ׆vҙřez^4!NOm'XΘ^rӥaLۚ)wlKq/~3vm"|$4uQ6|ɾٹ+S&֯-<}@NP`@$k^Qݺu6gCAJbU) O>h} ;찃XA0ToLn~'1/N vt6xг_vÚUYHt&clc ?&(E$OD@'B]O .@h ]v[̯|i8'$!-D>GzeHݻ[dTCQ`6p/bL72mN?<%FGpҮ? @>XP@3fb;B_L/쌚{v k.rk=6fgK~ۼ;lE~sV c 'yX`M0}¡a-0ٰ;HbĤVqy78&0i%ڞL¬+ݶr6uk;wk70|?|:j[Lue&ɅM{d>{le6,{/Dhk.{]HryVsaLsm5Ϝ |x 0ж q)0_& Sֻm+׳pc/+Y߆5XfMw(5r.Br#\x|0bƅGD8E+}䣜ammfFvnkQvvk ǰϚ}mD@ OAgpMAdM\?nc %!?#wlOua_D6mVʉkS&|9|H <=6ѷRmB! G~2qnbټ5KlvL҂e+@,:or':K`vYB*.!N[dkldiN0TPk41ȟc ΐMX;/oEӶ 1aFƘL˷1?NgvAۼ|g&m͔2{=Q8Lwb VkUV:o3$&v&`D@D0*^g." " " " " # " " " " " Q@D@D@D@D@D@H@' aTo0= " " " " "P H[@D@D@D@D@D@$tzF #" " " " " Q@D@D@D@D@D@H@' aTo0= " " " " "P H[@D@D@D@D@D@$tzF #" " " " " Q@D@D@D@D@D@H@' aTo0= " " " " "P H[@D@D@D@D@D@$tzF(~+̜ L UM ԂRG@¨]r cM6 9X2$ +0m6jfkټڦ%jzO@h:A(YXj#ӔA6lzۛ[i*-_`^e5!V|7/h/^l.5iUK,qo6*TP@%@4aӠA)]k {\r-]TR%E'˻… ͣ>6c rJ&$²ׯ;s=tرOd۞o]۞iJiەpfڙt5O͸ͫ3צ]z(dK 1o!Cɓ';SZ5V[vlᆮ=AT\}ٶ9'פ~ݫW/3p@3|מ:uꘝw9i X{>Co:ʜtIWT2$}oرcJZ̞{i=XSbB. _z%iŊNs/^}՜ח%yEϞ=M.]gm8lY`ڵkpՕpgP4Gq=[l?09S uV.7{ 3!SiQ٦|rYD 9F-2}>|Ziܸ>}?~C-[֬0 S~o6liҤiڴx#F0ӦM3r)SLAk@1߿;>裳hy}yW\ (f>yue0{,[tMn=F?[fMsWlHJl۳ #ݺu3vtu?q/9w_sy.{w{g{9Sve쟾i,hGFZt*(@T}fycIy h:LrYa4uTO7ܜ~ItG6[lEr&3%;S*^`FϚ6(oM 5-3{>(#,"ٶ=ٶg]F2$?~fQO(Xq 7,_"Um"Z]׎W[\" #3c.~>/&cb3K/?9sf_~+;]&?E&7pqQN-QuvLI<_~!9|[汪6wOc>m2c_s{Ӛș0oSo09# S<4I ";0Ӻu"9|HP !'/O>̝;7Yfx|ljN^sּA?@ؠW\9YG m?:a#hw8XMn`kن) ؓFgu lB?XOl4<?Uf&ZӬY3?e1Cv>1X뒃I3g|~>~a7ƇYv&r)C~^|N7m`GAO8a.Ǯ0OKGy$<|?|{}An._\lX1Bd6aj׮kcx>\~!k{lkfGى 7r܃q>Fٴ_Sݍ7^H>9gO,XaB ޸Ƿ{",;ZU۶m/'x&³=[mڴ1{ALBbV[9/GK_#Gt"L ę?./Bg:)Fe b͛,} % pƈc06<} 뎚 ^G0`戂u-;| ș0z7ܛ380;SPb`[PRH`&/po}d%X?#<ތ"}]k\IHDǾN'1q,=z7KIW_WȪ0ˆΈ"WQ&/sk5Bs=?QME~lY #ԅHܹ{Ƕڽ`f'oOכ./x^dz}sQF_~q#Ha_ȶupFx}\z];?HXV0h>蠃܀van?ܟ>2'|pϳkYcx1/'g%/U=O z}|gf'R$ʿ _ ҷyzWpGEwq'}$/aʵ }D%o_p'x;%?e2s!Mo\c5{>so-m|kgLf&v Nn~&X!ܟ.a]=sD> J؎/a2<&k;fm^rB[mU} uv~)d <h w6;Ln 7=$ar.?>agG$ /-%6_6'ϊ|;39V¾ ͳp%0%?(wM|reZA)/qkpM9(ßW, ;xvUi_YђC4ٗVM)o\{׵{)[>X)۳i?=_fs 0)FwSѺlk5qQ_'!a}|KA@MX" aź;ܾHXɱI"׎^3l̄-qh#ww'Kؗ ;ks.BSCO":a_}i! +l%_D[yS'qp= JW$!2x`oӚrr*۬p⮻J!x7@ l.ё HK~:$ڝ( dC8d$-ӡqN>FAڷ`g& a,X_D`=!7ؼ+(#m>>1c@pt D \gw&dŐ3(ݹgD)|{0wetn۝1Wn{lQ2%3aD kkD6ˆN?Fk[$,liÃ[t/?kй|L?y8b?#FM&'Tls%2e)h[&7=|qQaUW]^"`> AAv&B&'(u܆_Nф0Ds\܀5 ?J^_;չGP=сfA(g hmd<3iUqsz 0b_6'둍0h-3f@ mF0;Lq};SE lҥ2K=gte(Y`c$-ݹ@^ue S22qFȜsRx:Fm@Nv3F5jBa6 N`r3yۈ7.og u moz?9㽳*,|x<NVmч`I|U3l#0"l2`@rLB;.n?>*BA_Hq~ |>_ A SqfyaS&Oq6?kt`,˖V<+)zڙǝ&- }`|!)k„ lOyG6ˆ@ o;cEW_6ږ`_ }"k.+k#;mt8 V0b;B{ȏ|^OR8a{T"[0>/HquTQћ/?On7$N[褀j[ E gtLOaKo;74+a1kcBV)a1bp3LFϔ5a"I#`  bYOIp<+0&s,J;9 x~m# 0c*L/_rb*mf a.8$LMl~u9qm󌢦t9 _|>L0ˡ>:Lh0u ]hДul.g&1qfVq0s1&ܰ}lBfjvИr6JcA9c]![0f)z M 5681H@yY}z7f`^e1fmLo\{0w_ƾt򬵳PΜ{̽|ʶG6t{/ L<1? W_6'=F5lvrm†1D\aa}2`,@a_p}o1+j91޽{5ht/3v^gD=Ƿ8) Ï9`+#jJ(}yl8g_oW7c[nōpG1ֈbC{ J/ |4WA?ʓAD` T:dklN=MǀFmt8?hĄ9cӋa=(W?κtZd}D0ME;v[7xkcX5x(O/|^:MD'I7}|f a.::`B>̋H " 8㎋cˀg|pT [8O7./d6@W~J V/uXCE?-)ɋ&/>mcO^'= :b @xg0[vF '+.׊gׄb6|V# Ӑ/Os'ez}ӵZWiBK/hL{)KaF9 ƽG=s<cB !\f.EL•($$θQ0@$€>YwwX c9 `gp\Q8zs_"1(!ٙ"ncEo ^Jn2DOYhQ}R0oY&.Os9>愦{ J"\ ?0Co  *$f]ȗ.!)a)]lʥDNw:;:1WqD{J͆?F"oFυW fy⎋Fs< N.!LQ ~~$zNi}wGm O'};/m%}L3 υ]OqM#:=.Fh3!1zN}?|x>G]Nwxs?!йV!?)tظ:N% d=jOf}H9^FղVcsֵWˣm"+kU媑*GD@D5oÁ'̹XTu" "1Q&~3fYKk746lQ~() 5%E@D C(] tF":tai&" " "KFD@D  0 #|%Y_ID@D@DxHw*" " " " "PH ZE@D@D@D@D@J t1! aT#̳IIԨFe^fSID@D@# a/ŋ /0h~wEsEJ%K * qvarʦL2&o#.\j./*-chXۼt`+S̪Y4O<*zjm~I،K4~]8}4_qןӓQa" "PL͙3<Ӧe˖/A]S{1 ꫯ.st*FJ<+V7x 8L0TR4k̜~qEI&> vʕ+g6mjN;4ӢE6d73EG~22_:u#sM\xzwy(yʦqcō~"`=9}?T`ofY]չcxx}/DU1 3glVO,xMժUͱ[w9DX|yLMV?~TT~k]%`@kӦhСCѣ@m&o ^=?#(zyزyyb8Sb9kj00lܲK9K |7naƕ+a_ ay7;;U0)Cn." uZ{ヲz95{+naRO7EٳҥkRcǎK/Mwxζ3cթS'SF W&~ >??YW6y_]dxؚkgn_^=9.o69fĉڵk($; 4f_SfM曻٬Kǎ:u꘲e˺l0e'qƹSELҋN07nVdz&cC Mۺ5 {-x73x|s W_ì_ Qy)R4O;&DᶃwӪìV&̐ "~V2C?)9L][^RzU+L%x7լV࿶/*Bm?]-jW5MkVIbഹ"tʂ%f=vMkfձѲR (BE*x0~fƌ)馛O>9Extݙ̀ev2|ÒRvmg:<3|;w< ^q H<;0Ӻuk>o'N܇rH}ePxfwUSDK?x&'x"O )>~7ݺus9 /rg~}M417tUϚov0ԙ_J;tS]A=#ӕK/s SN9z~;ϧznLԾ}&[ԋ( Sv܌+ti!条-.{/YnG1c}6Xamݴ"KTP䱽v!0#afО-q[m]E.IT HA@rFD T(b@EE|>LDQə# 9毷zݻ]W=====vUǨB#JRu!A̵ L4@{MV{jry>]W(`&zE۳eCH=C ;p5LZnku1&2k7e%眭wf\.aG-xE@hΜ9rj+V+WPMr 9ƌ*nh o<>#Gi#CV|qj%Ø"VJa# & J2#'>b RkʳY F3FVoׯ/a?rb(!#?O#Q? 'N>@7 @>#" UO37o\6Xi۶m*eQu>dī_}-^XL2t!ɟjРʕ˫+!O:uƍ S̻}!?㉅'|R EO,Rc>>hzɓ' ڽ{wB\4 Ec>ڣ5E@P x/EI78kĈA+g}f1iۭ\Rb]Ϋ)sڵH^q~&8vXd]7SLVMYll]7L.{`+δp}(?[~kgȳ_U3K.6#{S7obI)J+{-`[gg;`@u_yC' !\'/`MXb իWK=&b$e3f̰&r Yš?̰ذ;P5chܥ+);>֭;| F{;ex3u>iڥcZ)yO/ZNp2#i{fx7{9*QWƺ`!9x_~z&_dlĠ9ֹ ~0Q}P("p$E,TbJ_`^8~.w q؇š%>7rw bd8 ىo(cWݙh*)!7@ o@-+ 1b/Ouy z)nr@o}Κ5+@MJ.N3tP9{]vBx쥇uK='1b6$ %Jqƙ"קY&ར6yT8Azy/;xwDeNb<]{[dpȚuo/+V#>n!fY B̜|%EӴu5xlځm"V# oCݨ$jIL(DEm6Gnh|hGB0VV- k+`TᅲeF;wvv129>BרQ#SgYyp0G3P?)@ ڎ;7`2A sL(]%̌ür~m C=z2`|,&^z/Μ 9(C .$ȗ# s0hEWH T!ӧKn&I!B>vq [f&Z.xBf읹i}=a\a\6]BKɬ^W1!],!r-'n}`%EȞGzAǢ"?!E6鬒=οr>D= ;vA8G=x<9u|9ޚ~Y&<^E(罧rS/! g.'w(%F"'9WXQTpCIn H܄%͞!Fi 1Br6F΁qYf42pHu-S#>`3nC~Ndd(A=J# qp?Kn];|rC@o< PC.Oa!Nb^4ɯ3g,3ȹtK# s{]u?g^j?uA`ܣm7S8V;":~Fd1~Fk菘ԇf,)rq@ {S5? !ܑ=20[V d?7.OO 팦켦5 !uα8[\֢f@znb4~W!\ ¹򊼧jfը-}M眮m ;7"\m"P:!1NC9 E>Q%aj 0!_(M 1ʧ,#;qRB >E@hŞDb j8/sP:8[o衟nݺIXWSL]ɑs8{9D{|ry%/\Jc;e7oRY؟)f.Ы#"on&Em64luL9ڄ!-93p)yC1 nqu'SׇΛ"Wʆ08Єy6J(tu{ݑQ wtbKgk,a,fl/2sD[r;OE@&7#E,98%B|1V2'1"/FՕLS%`8ްķ ^ 9#Ѷ˂!FӦM>yGvG7dbݙ%s:~TwoԚ?<.OMbĪB8.\`?ޘ|@ IFd} `e[Dƍ\|^777 W`@y}`h@Y` x h`vK26gf!Fn~yG>'w|2;^|a@tԲv(u8"rb`puċ `XgU(ͪlv 0uVq(@:N[%}+}{E@P)JEmeTTIbl@Fۄ!rCؠ4йQDʺt҄ gȌ1vժU {'A& &'!ݐ%9IEA=,CA{+VL?":{B l]eS+{TD&nݺr"4"/@&M$ s䵑ӃI3'$GMvӦMSow{{d&g Og+I(4ʖ-+eϱG;sqj3f]|_\4 =kjn4pv|䤔+>cW1YBr=Y.{GUm6l GC(_Q6(8%v?a?ym庙KPkM`!a"of#!j3w[Sτ9C ]kdm7/}l4ǃqU:μBEaR# ¢[Ց@E@FH1b] wPFMGR0nA)MY5JP1-?c+dԫYOrg^!|9nx@< 4|6ЀcA*s 7 E=1.#PΧ劀"xC0u͂8 s wka(cƌr}-3T@f0?ͬsQ`Ĺ՚L0,naQ,w1.G؛3cX#&1/dPH I{52 qvr> N@%Kgbw씴Ǣ %noh3L ߥ^"("("f"("(">(1 RDPE@PE@PBD@Qi3E@PE@PE@wW("("(!"(Dങ"("("J+QE@PE@PPb"pLPE@PE@P%F]("("(@(1 8m("("(Ⴠ.JE@PE@PE D6SE@PE@PA@Q|z%"("(""JBN)"("(@ (|KE@PE@PE@%F!E@PE@PE |Pb>ߥ^"("("f"("(">(1 RDPE@PE@PBD@Qi3E@PE@PE@wW("("(!"(Dങ"("("J+QE@PE@PPb"pLPE']y;ќgNq>=CZʖ!eKp}\("( JoBǡ(uEˢ  vtlHiO1?z}eDgHUMPE@VPbobЃ>H*THf6h :}4K)ש?E}vʗ/O>UP0={2f̘*sל9s='Ri>{`ҦsiB-H?F͙9=JT&g6z}t+v MYFGϜ)OV S;]$=Q֐F"+)FO?љ3gJ*TnD]zǨx≎_+Vc<@UvC۷`[o]N7VPGA?85o#h{/۳٧Qe[馌8΢S/PwЇ5y7#l.{.^h34w{wEJM'UE Hqbt뭷ݻp²2"Fx0S4L"+B %_|ϟ_ k׮'G#~.{n:ܹsxzNHSQ-= ]~{OT;slQBhhK,hJˡz-k-R'H7JE@Hqb0 )BTJN]p#!ٳgoSLlHw%wqO8ʩS͛Ǒ#Ghذa1j0 _R2xA؉171Bh Ƅ:xI6z1CF t~P:sǎrmα @?(@"0o{xa{ۼy3,YRBn-7n:߰a{t=Ћ/huʔ)4p@z'-[ysZJØ-[| ~˗/yB{U)x(,hr٘Tt|r;uߘ?S2rn?P!p"zHPcbQ+ŃM|_JgFӪH3ä;ܣ;2lR:iaM0˔.-E!p3qYi}R)I[0ߵUEzC Ոn 2XD;<@^hԩB !,QNoAz`N:Hcta!fxq'FE 8# |CD\4v޽ !Nrnb?J?#͘1#Q?V^^{MBbȗ| OT@@,2 s4kAzr!{o9O'92Mx%M*yn-}(9ǢE@7R,aXD1ruĘz/pc=@H HLz)s~ !hڴih@Ĩ"j1QBx`aa>E#,5uyp86y < ts F>&@f<"ܑ?xGX {gzjxRQg9Us]λɛ5}e@YG{g/\59=_E~C')#FDԍ%_I/1(BW,4,` :7x2r[j`~VE HUbʉ{!^a`Nb?HAnIKCik!F#B5V`cς!FHƃ rrVjdx\*5E@ FoHnsD۷o'xrgB`Ez! wWs ysAab0+ |s?Ӹe~q,pDϜtu|Cm a?#EPyC}~^ޛAAyobQ8vjt9zC8"0r31Z30mkR}&F/'҃,Lvh`!s%Gi&QF=^JJ|!y]E@"p[`Ƕ[a$îát-PI7wɤ/& ʽ xCFc d'$J'upe$b1nLI fq\P h,&v 2s0Km&+}bNs{؄ Ccil 4Hr)WTrV)w`pB!:IDAT%:YsZ ì%VfXGDZ."[M mLU6:r& ro;nqgօoRW/f~8q%8#GpMʹN;神m 2#O.8\M}AL#uXyBӧCr$F C,L!Xp莻K(I EL7!F'䉅,V4Mea/^"FX"x7 *baG,,0q)? esc}Qa; u-=m|-.~w'?9EAE@PT35^}|=XjժT XxH[C vaؿb P{|ԛ ex~l54t?~bʕ+?L(G: Oaƍ>yS9 C ! 9>,+VL"$@jP;v,ao3(!o b.MP:t"' "5PIP Edh `7JD`.~qg1^cW8 b 7"f#(AR/&w[nT0'z|Sߥ[MTEp(a_Ż̸vΛs։`*kY*\? jVMlu_`%XU Í=dIR/P:EY MoQ,1+ o.{Q]iBLEL^FƉ(Z|E٬%aSdRYr"c=lN Tȫ2L}UE H1b`@*ҥK#=l*7j0axo%'7c86|EchUTkCXHBmx@[\Sf's t~@9psbW?+@bӼp<فd0]7ܿ]kܢ2Ƈr\rګ?ùClR Ap1\ۀ.Gس%6c<;P~F3.@8W\:_굸m6svs#Rcl{}֫5Q@@__#|=z㕺klf{og`;!@@OkJoLԣ3fs>8niH'Z}[nۙ]s@J-&)C}COt  !vFsCSkSFQ jW@/"~&JO=s j#@@ J{|;;Jcw_Yϛ}:MH@Hx |%JeOz!ִUǛ\# @ (qT5_7ڙfs'|Dr'ű ]C@PB1mZ|XM^<{_Of 1WRfl LuL?t ͼ;ojr;k;-^Ve5Rޒ~2Gh?^O3K,*wؽfߜ)[o||f<ǖWVK[ʝj4 ?cyTg*-7yr cMmY:O?z2w[~:osh߶'4֑ (InEkgJʝDkc]Kjc5uxzRi财N n y(GK:OW}zK&{@n6 Ym˔$,-|S]̎6Nq~vK1}}{Vy0O׼2P=_~Ent1]s=_?t&3QN3_*ni-gVIwطjj:e&B[uY-\X}nUR76w8i7KK_ڭ+Kygp8)P^|:{pSY֭#ۊ˾^DŽh>UlRG_ @b &x(މ̷*,:Hu|&q߿){c: MH;L?jRioԤ Oڲe6.S㾤֘npSXj%vIfRwtӫtR=i eRrM;If @ hj(.y`]ôqΚDZ a]3l(e?ja/]ƭuh&-NW,0lUjoQߛRUTTզ1*,,P^:oZחW@ (M.AաegRkvS7UA/ojoԏI`NŷvJe[-ξ6MR3rqy^:ܨ6s} 'BU$  @ 58<E:@@׆u   1t@nJ]5d4]C>\=MIsU•Nm,hG:tSk~]d P廪4ǎ{t ć@b\SzX-),W쁦 bѴˤBs^XB}mOi@F{f_3CMz}j۫iZm6u_@{AxVR'8j Sx?@D !fJzQ8 [cMf;3ٹsqOw8;ӹiNn._srMl]f۹Nv3W׬1ej5[\l:u;u4|+qbuiknܮf5L6[}jזs=yLri;٢-W+fnѾ=IR~ԧ-KW-ӧϫB1nMvfvaUY=%8=:gmNPߴ18mL ߡ=  +MkwO[se]ȝW\v2}AaA#mnt՞<6 yY<9ia?/\Xرo8>]TT譣}KGڎpԤ-tWy~픲܅y &[on-ga{CBo;47fy}?.,xoo֒mnwk{ #ۇS⹛/cP9y==O~-O{/L Ӳ^c_7gB2շ#o@ co~:kJd2nw\Ͼ6Xc|_:_U{^5EC.PS)磷^|y]Ք7A߽o2-p_UWܦYְyjj^Vy-q4z3SYi&r39^{oޮ)MLKw릣C4lh{opNAwBnnR/ޤϖJ}C?)ǦLݦ4k3S6Yy԰ qd= ͌ig}:^o%zJ=zF߹w06Lon=(]خo)z&o`iQNO!4# 5ʞ^{stB|=a+kErx<J;Q&DsTmxܶxG & 9MpΒmzI&[3}TGLÆu^S{;by߮TÚsTr.Sl9 7g?_幜IA3iYwzSaHKn􆒣U`׼&iѪսxvT112|L'v>u6X*;]j!  rMiඝ߳Ns.Ֆ㝉ס)ި GXo8iJ8IUUwxҼmz񉻜3iZYR+k7yt|o/A!h6ح%EM)_ ;/Cuޒjh8m[~΄=Xt&8ߞc3wv:N53=͓O<֋ggj33v;+/wy7/A]@Gⱇ]tݧ1Gʴbl ),vN)XdLv۫na>(YNC%?tX"3Qi6,ށ-63DeWS;Sy4U6?izRη뫍|3շ^[Yn0)m'7v+fJn_Vsn%'Nnu lӳ\GMY&jyS1}C2H=ͷ~)u.M̵˴x?+u}Ӄ?Voԫg{q@] !fJ}Ӛ&zKm-2*Z HnPTK F|YR[Ρ%2a4sf/(ϼ.׌٦ls `W^4o)7P:lz&jMpi蹾}Z+9ų4ujiE6G7I]?%)34K;~=v Eg2ڟpjYX@˥|s}z{l9kҲR内r-0iS|cxm`͖`6_}y@@*Z)Jʝ儾.4+9=%b=]}=rL9fvpMFsgFsMj@\--j53CLvW[M:nuA5jiiWZSݎM՞N~z==a#ȶ@ $nPWQfNmsmpx<?⯧b!_t4]) @@ 䌱αA@V@@+7:1  -@PC@@ (Ma  @t F:@@ !Jb$  =>@H҄f: D@LS{rMtS:@@ 0S_9! L mFA  C~@@ 4@@~,   ( '! ChdA@Aih=) @@@#   @hbN2urV{@@[fJe   @ 0S:Q^Wf65|4@`4<" F44  AixdE@Aih)@@  Ȋ  8R   @A@@ 4q@@ J#+  @hJCH)  AGV@@ƑR@@ (    ( #  !@PY@@B#@PGJA@B4<" F44  AixdE@Aih)@@  Ȋ  8R   @A@@ 4qLRN9-'D_$  AztmOT߾}  9.QתwOOƦF]h ľ@rw ?ԽW_M:@@ )MOwpROirP]sA@@W^y  @ &W{S{WnIGn  OQ@@ `8^}Gn.pC.Mŝ*IJRR7?kZLjS7`ESE-5kFM- *5:2lQsμ:ZM 尲g%R6sߥuʦҼJV jNGah @" 0SȣC߿into46ꎭ~f\oO+ ^iۥʺu&LIޟIʞNN!z~nr._y{gXRMF1hNgpƹƗH\~K4]0Us7;-ڹn9;2عNٞ\6~m:"Y sM Jv՞࿲n۱~x2@ pD>l7j9koÏI9lu?:~Q+J'e-tJ]i۴Z3ӕi~FdvRmbȺάwߎ9m/phmyC;Lӕ>$S难\?XĞ3&ʷ(V;@Ǖ}oWB=mf?M5Y0*Cu{6jVO;|_yi_le~u17:xEyĨi 31wm7;z_̞ M2ΗՇI#uE)c=8cjgf^NKYR&-s9H iCul#pPfN ̖t{ /U({ ' 7gNPF} Lv5G9o5[nyP7[ymwqOP?+8g4foܽB82W.9sr&Yr㛧LNlnnӥNM 5uv6 K_ZDR/rNIۗhw>m @t$KZ)"RI%Ny96̆N{Jօ~Elrot#-zբViHF9Atiikyf%g()݄ɩ[ͻ{ېnkn7ԕo=| # AD1dM!hX S<􃿟awHMSF1c ݒqas$O{hC=,\E@_7#p>uѣ6c%  @̔H |w1}^ʻC@`4`*jӥv4yFpsz  @oYGN~QC}fmLssKG>,{/=  Aip~ #/ܔPt@ (MqWvNۛ.MMQ77ˑL  p7:k‘L]go!@@ ,asؠtAQC=# @HJC9omSn٫zd+?f:zdvsNi̡ؔe>nC@ )q걕6h ½-4}hyh87pR6 )6[t6VE4ւXn{_ƈ  г3='3T=ohH}h #@P:0RK@bB4&)FJ`J@@D (Q4tt @ JF7v! Yh L H: @L H @" &G:0% M/]D@ H c%{SXN@"+@PY}S^*C@ Jcz L H>6@@ Jp&.# Ai=\)i~#h7  (Dku`J@r@bZ4/Ƈ*0% ~,(@D (M=/ +@P`o`J@'_ @J#<T}_Sh=ڂ @l !@@Z4Ο/0% ލ  $,]i[^o8)C+F @F4O{4." 0U:@ (ޱS(NG@B4.q`:aSNLԂ  @PL@@(`I(  $Ai"2}D@\4!  @PL@@( (y  @"&(G@@ J|h  0@r(  $Ai"2}D@\4!  @PL@@( (y  @"&(G@@ J|h  0@rP/ zЛFE?~ǙzY)m6wG!wRT5mi׵HcyѶf(0*h/ hMc5%ch{իu!/7 4"5L+G>@ [KΏ֟<֏>҄aCSz@ >F3}8֛Gl(ĵ$vqԷ֦ j ؏H` ʑ3oyygf1Bs}jYv'=/'q]iݷYձs3&8!Y0G=6Ȝp+b ,5鎝ɳ峅NČi,E_i0@`tG᠎ Pn,PmtxZj(}\=_i!hopΘZ0@ (XmrE7qRI|خǏب+ʹ& :O La-kW| p~/=/ӊO\mY?>t? H\W~RY><<*w4z>{٩'vS~IoY%ŵrsj"oES+lYnmʪ:ޑzvU=\uNڭYy]$@G4z"- ١pl2Y<ew-Iee+mWJ5kO೮bvѾ%Z`V5u`1OW:!*[Ïܺ*Bh^:ܨorT/fsqu)NN5M:QMdG U.ze;4KLO6? ҄ -=ύh7l>n~jlP=_Vhs4mZO~اs[u˧JRj׎ 'e5ݕw@7Ho.~g`[￞3ZEݢt/٤ٳ6n^kfMzs|CkTjuu_ѽc{ߚ5FT!qv{T%u @ 3Џ  6қ9kx.vB6֟m_ܭT{n([WMh5WvzZtu]/Mg4W޷OUkߡ9ěƹ/펲|ylS=;v.+V}Hmn5W޷^6o1}{}i_gImm:XڙA>i@[͇ՌӇM_6cn;utl WVU9{wX k_wgE瓞RČ|4Tٵ6oS`f~rn7זf굜9Y&7[wTzR&-s>x6,ӬخO]ki-㴬#Qyy] [u}G=;굺lܦelW٢;#כר9^/Uy̏ SLo=a*j,TMsR\5 Oi=K+ $BR)$)GIJ昛m+̵ J]s$.@[Y̐.բFsbzF͂_47({<>LgM!9RKiUzR_8Ҏv=\̬~6s36]Fӿk~v[9./ƪ5ʜjg+ ȏtCZrV#% *Hҳ͟T9%jefM4}tYF7G[ڲ2AjZ=uژMPUA}l44穢yƾJ?HT;_:8-.7M>#̾eC(0AxwGkY&Շ 奚@-5MM ε&˖l)CztJ1C; `.x!gݟI7]7 [N̻5/kPKOyqY BE*J-3V:Z}C}QTww3d|hMU9Rj~E,.7mp]hkTO@7 A G]md͖QtXLls kE(| R_ZL`Zjkѻ/e68{ԸU-H;VkzUie@&IDATژn((4եuo޹Ϥ־zHL@[ݟ?Xz@޲}{;!,e R_kZGN~]G>Zicu,4/oTbίRYiZL-(7n0\sS|@[hkѶif]Q3mڗkSf͛gKWʰL -}i*i@ ..CW |z;lN9P}loWhنvmts}' g5Iw8&)|-2͞@<}sI6Tmgg3cj|n/mھY]45KOڡ>3Ck5V8Ǭ85-{ijnYGw~r\Yʴ{Mf5ۇ-d^?z6̹4OˮLN #{# @> PҽZrXM5URٗz df& WWT`]WG: ({#f0e4@ J`B ]'G@U RWF%e毩u<Mk!Х/WimSR\o͝e‚G隫=yl:y6sZ)~^cqlw}V[GH#;&&5i խ]>쭝޶ٺlKhݷۖ…bw>U7fyɝUל+ӱmGNoy˿|.Ns{W=w)]X=_?CvW K\yz"dO|,l~Op)+\V?wq=`y~|ZYU?WUS4d55r>zׅ[M9y(sX_Pumj+Mm ׫eՙQKg8ir~,73u%Jvg_Ol+S5Z=;t&t}TR_4aoά^<)s_U37νtk&7u{^a^;̽c |qG_-h~vUMieZmqJMGh^2_70~\Ow?   ? J2˝ 3]i=_{,+t~)gLP؉rz_6kz{Bs(zs2|d\U4c/78mx堳b8t~o֝C=҆&%NnW9K]n􆒣U`P׼&kju/^5yẋ O6܃2SCvbm;F?_{v~ _ ή)h;伩;y=g]-U;i~SQ̻Xo8iJ8IUUwxҼmz񉻜(iZYR+kL锞wlVCUn۪f6צw6>y^ogg!y1Z;;-uy {zǗ_mޫTOyLsW^M([Kz{:zH C ngJ=L+f֐zybExda@\W:ä+Ygok[m3sIWy>1OSeSz̜Vm&\Jy)2_Vsw9ݰKa_ ]^q^3ȵX^Bxpҳ\GML1mC(IfZ:K&eZ<>yGճ󵧧28 dߴ6R'=}[Ty҅*T0)U}'tgٖshGL@zX+ٮ 3 5c)%e$6B=;p;f3kvl4K;~3d.CNvק+46ڴiugOW۬CV,XRAV|l=ZTa)\ L@T`l6_SM:lo&ؾ3Yo=249'OG}yz  $;+3wRI=/`]jinWrzR1/b=]}=rL9fpMLZŌ4~wlwUb5bJIgjii6QpҺO{پSΆx{z)PTqAbH `厘n6׶ } ;/Oz/$Zk~^l8_5Ŵ54!h2څ '@d%gխw %I@@#W7:<   (@@ J+  yȏ-@@^4   (@@ J+  yȏ-@@^4   (@@ J+  yȏ-@@^ 9I%(2@@T8X Ē@l`ڊ  ̔ߘ#@@ Jcnh0  7@9Ҙ2 ğAi)=B@bN4憌# '@PcJ@@ (!  @ ߘ#@@ Jcnh0  7@9Ҙ2 ğAi)=B@bN4憌# '@PcJ@@ (!  @ ߘ#@@ Jcnh0  >d3IENDB`icinga2_distributed_windows_nscp_api_drivesize_icingaweb2.png000066400000000000000000001140431322762156600357430ustar00rootroot00000000000000icinga2-2.8.1/doc/images/distributed-monitoringPNG  IHDRh^ƅe iCCPICC ProfileHTSY{@@J^( "28cAEˀR:ĂT>Ae,P,ag97w|{߻|XA ,@*?CNl.pc20d#c:Wr@L8TO#-f^! >2És6qs3䁰<&@GLv"C&#l/EؙeqE$5u "lO>xXˬtA +<Z sA,Ym 33?\o<=gQr< 2!,\$,3$< yNb1|L,5sT1SA͠!%LhvܽW읂 11ZpBC}%B̨ 伺vE̹z@e0Ex?B@$X ؀ R`(`*!pԂ$hgp}`<b0 ^ LA(R4 ]3@AP$ %B|HBb:W]04( jn?48.p5| n/7X 'QEB)4Q(:B% "TՈ@uĨqg4MEЦhG/:F7KZt z=`T1 IĬb05fef*bvX_l$6 [=mvb#I39q,\w ww7'5xo|ǗS.H G[QQOt"Fe#;E' Hyr U03YlD GEmN}; GqDQ2((u'ORT)3)GjTTmi]i79eҧoIddC{Ю0谺%#nDD"ۢpQaQ5Q+VY9m]=JU֪kUV>#Ê9 dU&q&WWnXS|i҄NǸ.28σW{t(cr`T|jlj;_̿F}M֚~P NsHۓ6!֤C2&Gd A4YimSYYlss~Y^^ו)wx І ]7lɫDܔfy~i; F~PPX8qˡ?~juEe_K%m zn?cpRҜґ]v.~O̞kee۱kbҽi?}`!CŇ^OUK^uaώK]JMqͷڠKuvuuQرc}=56V5)6'D'^I]OLm.jZ[&Zȶvǎ~;zFLY>s~S9~!HWLË^ZqW\v>kگӯްc|fsmo-[m}}Kv}+wwo , 7=$ǹ~72L={yTXq'տ$y{|-xFyV\y gƼ^|9Jjjo?]왈}#|3wM2'|H0_¿ 360 350 ^*F@IDATxǏtwwwb b *؊b.LEADD1@N)޽ɽsgyy&33gf"g-N!9!`R/*0 C 58& Y\!`IC G,f∅3 C m0Gk!l 4 C m0N[|-vC0t!`-Fin@#ٱ۶m3gʎ;zRrPnMΒ%KL2'Ou_|߿?P1 C"pTi\wukɐ!C7|S%w)>L6M!n7oK0 5ի'O=s1˫*gyԩSGg.9sܹs֭[W\!~zdt0 #QA\RIoTrVZI%?H^=!Q8jzժURpa)W\[hcĹ믿.哻+D@vc@A!͛7G$[s'h+Ae0"#ptjՄؼysɖ`Qٱѭ[7˺uw!83<#6m}N?S8޽[.rUDt! & Xz]6=iQCؖٱw^ڵ\ve矫\F ?ȑ#C}Qɛ76~PQW?Co[Yb3Ac?F]`vLP/eq̘1ҽ{w|֭+? :T^~eZa0*T8jpK¬_^1)^xJ>}SNChĉ_jb$ft,miӦrYgiР٣hyQdɒrUWIŊQt,7prWJ"E4,䏙m۶2]v,_Z'q#,[ SN9E?|%0f͚$?i$5`*:u{:`o:7|#tҚJ*iZ!-/\rmygG?=zըQ#rI f&/O  \sb'~ o߾r_RL 8jL40= 4HItEj׮E{>SO=U;?YF!={bŊi<ƍp|^YǰaÔԹ;dرJ..ϐ![iDW_}%sCJ8p~jXO~+!钟s=W;5[Q.޽ϝ <,2C:s9RJ] 3kg˖-4`ɓ>eüN۷2ܹsu}x"mnY3ICNl%Į[W_-Z2'n7t㏺["bGsCCR˖-ӝ/!^M2T<餓4]4d4W[h ЀY HYު̙Jz 4?^5We4k"~ H~j$;Hw7oY{ #UkVD h"ABf!xmPB;"|80^X61A:2;fhL (S{{,AN#p mhLw̞=[ϟ_AF0YtZ}"D¢{!΅ jO?-\r/B!k~dCq30!(ċI?#/LC,3:/J21PSڿVg+E] HAGB%Al#GT ;+Z#d7k,i֬jp//_^ .IX_\fM]h駟;9Tq4`84pᇕ!8x2h䊩_{qmbB0-[Vá%{!O,109EU+:tP2[2y "]tTB>}0zY` ~ىgWC 1B=!D4N{44ﰩ2F$Sy &l 7 }vqh_ڸ3R%UO?U 8 nE@ ұOCĘ@x-[K8M(lд ïL`ѣbe >rѢEu3IgvBgÂ*d#Aa :ƓX~B[$_)9aVCR.Xq;M EtE)cwH6mE_콘/Ck%f;@\13`}g/W/,A&tI"ߔu\Ɛ%B[3e`Hww$]F0;x&{W2(v3/3MpPyC Gt4t@R"t :1{Oтh# `kt0vg̘!OOvd(lr1/R7S%t^zIf"Lɯz_t*NQ!N֓;?]f% i)U?؃fAH=Gg|^b!2hY ;:#a$#Bt'|RgH_믿`wB f!md:{u Z^ f&ElLюѸ|f`~ *,c2Cy?&1H5hNR;ȓőH#zr~\g,1!H䌖^^Vǽ%Y BzO9Ն"@`:.yENm&)Rf@<q|z$ӛ,;B?`~$\21mQJN~&~u~Wl6f_!2 A7iD rDn-8|j#dm_7~m6 h lǂYC>5|pZ#!`)Aؠ}+*?e%W^Qb6LxVvL+wAxa'͚wqbA6n+}!D>HyEE *v٦wrL4ϨyOo,=CHGTu4[pvìgC0@A'%0 tVe+!`dJ3eY C + `jh#LYmiC f2!Q0 :֌0<FY !Q0Ψ5c2 ,to!`dT3jX C #`囀`#Z3/CAg&`@FE:֌+X#R=r0Q6W8?qdm2tYu1$nndlŎ|ظC'\[~[E '/{+[<s2sSG.(\I~]Y*:^u~FV̼vL,˸~sJyt¢ڰx~mmyfɗ#٨aI>u߸r2ZVGZTѾaYmp~%ǁX|jҵ^DayZ][2oNiZ,OqɟWlN#fSjI٣ɐn6:޾w݅[wIye]RP^yA 92}Ci^`,;'E %Trn2]Cfzp]ydkkɑt 7|Fi7t|zZ]vG!)s;)<0Frr"bd?dί)ȋWs?-l)g*瓔MJk7@|o)7+'s6N/Ԇ1;vo6[X$w^:R瓚u<*l׹2M[Řq`ʕ]+]H/*:@k8Ҧh(]~LCk_˕,k~dr{'GX8U_sSHR4wp >^耋ߤd^2(nq #nNNhvJG77__ZY*|M>G0WFLV'rS7#bPaڰ}zt+&3uA.OTVoj_,)?N3!_ |,… G)-e½D"T>s@Yۙr9sfR35Rۆ1QMg:`ǵ94L}2mLhJPeTP[paVސ336o_^p-<{#9[7ةηH#)LôeS+T;RߧO<`ݤFHX)piTlu6hB#t}S9m$~Y%b1,k{ /*$ TiyͻEyrJCt+udIf.1 [A~t3N5bs(.o D>I 8\?5-/&:r%ld 8 yxS?(šnA <PɸQHވ!q'8\#p3I)7@cn$'he ,OgmXcmIK4nf]mkc=Y$."mfIs0av|Vbr 0>_YOntkg晁Xh}X(DZm?Xxcw+9+ݻubg:m/QD>47,k;Q.%C @jSy,~Ӯ.V?mI-CDk:yiLˢ#`+ڳFES*Wl#YNe`&A J T\jE?{ЙlcqJ0:-ڸi~g8w6l+0c` *yyӐ_tGeBؖ;^)%v7rsЮGuh郧6h>G1N-_TgL#! {4rHS먽͊6cKgWGmEb:vue_I> ͙NS0ץ#ڃZk"{L#O^Э@ x^z|A/mxp[4|p$Q >`!E 4(abX{#ͿŵhNr#YXW/X79;X\̚8~j\7\wAa/O$J뿹r_ d˰+ Dn  'b܆:)GօOs:s < 搟I[}ت7E"\h~Wn۰ ?lfH 7P:_N+Ȯ̐5S"!s3[nC>خ0ra)L0b'p./4|3ue}y<:y<Aw >>(>UnvԒ/|#;8)? ,05.9[rҠ)Q`!\)\>?> [K]A=Ĕ$L ߺ2ֶ`G 8f@H8f}N{FQ֞(>+PDIaF l+zh)گoÔ9b>hL |3Ro{P<>uk\9ˉ D8Vm:.?TvV.[D}n_Qzς`,a4bu#V81MgɎ q1HDzXGtmz 2:?s[ ?q?dV}[i C !~Le0 tF˃!`09!0`y0 C F@1'C02F,!`D@:(d@F@:#Ԃ0 ؽ#ki"1'C0 #1A-IC0b!#[2i3 CH9`f)Ϩ`@VC Z[y C `i2jY #VV^C4Ag@VC:ո02 FЙ,!0j5n5 Lt*˨!`d5Z[y C `i2jY #VV^C4Ag@VC:ո02 FЙ,!0j5n5 L@Udɒ%NhIo۶M;={vo!+C+V?X (?HBsΑU;⋲|ryᇥYf!u3b߿dϞ]>C)X`&#G8!Nɝ;\|rysrR|:r;t!- #@L޵kL:5b~g V9K(TRE˗!GyD/^gsNӧ|/KC㹙3g[tiy7u0'\RرCn&ٻwC-(̿!`dbt0wu*UJ֭['{͛7K^y3? #j۶|QI۷oyJ3hHΜ9cjoL:^kp?llАH&MvrI'v Iuz o;_|z{n}ʔ)!C_.]t.Lky?\zOO x2dڵ\uU_F=fԨQv6mlٲ:xҾ}{}7i$` y'4ӧ' Vǻu1\r%Z<~ 8Pz5~ lZF3gC8n C@pU5B 6i?HkfHB?C|}ʕ+… S4j(ٲet;\p`Ф˗/z.>H,+a{=wq!0<ׇt{CĥAST|JIׯVa=F"`dHC0'-[eJ,r7ҽ;Ү]; MfҹsP^+V 7֨QCMKqdA;gCĥAM>cjEED ',ٳGc]t-!HH r)C6̱D֭[Ã|fVD+xg(1 ?8p&@B n yB&'"B܉3d0xNK0} ێD0 ,%VY"Bxa`Kxv5 4hW҄ ~Vx9sN=6Ub 5Zu6.}#CE7n8h;;B kxפ:hCf@3<f>.0 {CĭAWTI̸K@ï 9!5Ϙ+ƭQY۸qt=D2??pƌ"Ms^;$yYr6lzjٴia0 >\cNX!z" &!pt"Mz0-}0ݿ[s+7߬9|+4na_7D`гgOF f wygׄ[Yf=bUSf~H6@=|rj`F8Ȝr l;^5!`=~?E*=ባr¾tA4hN~!^zJM6jRҩ[n0hޓ A>C7AA2e =9CvoVg=3x!]vc`' _~0[Ō3tϾ}:v5 cwpCrm+vOAzź 4k4\lY$-'7>'6`PM`6yt6SH,э@&€q@hZ4~G aFӤJ3G;HbŃ5XAiks,̼я@tbbuߘ'Ffş3;|hL2!CX#bGȅ:L Cdʕ`e7 C 1wqD `n!`郀tl!d 0 C }0N-C0t!!`F郳b@CH-_%9'0 C A' C8Ag!#p؃!`#SC0 `{0 C `qrb@a!`d3N]XN CHt80 @ӭSZug}&)=z߾}_N'_3f0)M;#O;'|"~O~'=Lt9TwС_u3!SR_SNc e,ӦM;LxG)ZX g}rgf 4% 6S9"qF?SœygΜ)LqڑHI;v숖Tu(QB ¾}>B 顾uƝ:_.rǙ+O81`]%|۶mr?TĄƌ#\sL>=1}j ]K#){ڐr/?.ǛXs%ĕԩ 0 w4&JΝK.z}uCs{'T%h~{Ѳ};dAY/^zG8]vr '衺^|s0]((7~%.RH9m̠[{3r-%w}RBH;:swt={?n:+xwޭnW^y\xᅡ=É69sȓO>)L{O?t%!x䪫wyG\r+S HʕuѨc=z( .驧ڵkիW q{Ҫ_!D-M~wһwoɛ7˗O#eʔ +Vp/J*ɣ>* Rx4Oh{Q)#t~ypez~7 &WR"HL7Tlٲ:Sz-)Ub ` 3F uIy睡6L C/>|>mk׮9TW_ 4HIg3<J7?y.(f3+fRH? i{AzwC椋.H.擔>OܙURAStb*_ֲeWCKj֬|JLDz״~!?~rI'ieA@A#`妛nJ|hheo,YD#'K/T ו+Wj\p_*UdٲeHaӉ=`7oTZUЉ~miӦNrGI`#h+ fУIh2ٳC'3@Lxg K.5kW\!KE9)B7n8D@_}Lek )7Hi*JC|'Z&B'Dp#,ZM5azN'hkҨ%4QFZ~+h_&:!>!K#hh7)M?Abi6%B5qbGgftwhGgemα¦;!p }Ph|B}2%c惨iߴ_ȉ M/t{Zzuu>EL;`1`&}H9 $A .LIfbO'o=u :8+Or2Pg ecFH p H$aYfpgP8I=/BA < X fXB~#B k9` ʞ{8D'h~W|}B{`vH2 <=zhp)#mחp,b2\D?x}#<3c]4}$8 [9&m{fv48P%',Y{J (Sc Ȣ#>v8/tdNfƖ*4O*9 @3ZJH4Xq0͛7J*)'|/ع1, מ$,"AE;ZAM[H:AcA/;m;V43$8͛hI~#oŷGf7X+y`2zZ~AV^#H*ޝ+ў1w<;0зhǠHfBa!lv4xa4A/P|e#'LXw )m{䗶: (|OxGˈkc\gĝ3 i8h!XFhdǾXF ّ~EFI,8R +^J3x{BɊ&=J o yu]j"AM#(#8U񔉾6A ,9Zߧ*A Y )0X3Ha-c `1raax0 C U0N-C0R#b4 C U0N-C0R#b4 C U0N-C0R#b4 C U0N-C0R#b4 C U0N-C0R#b4 C U8R%0 C Y,,!`itcl)!,2 C 0N{-C0t`@!`=Fi`@0Nl0 G:1 CHFɂ!A=Ɩ!`B:YY C0#R0 C Yd޳g,\P6l ,]TVX! ټyuG"iZJcuq2zh7n+A0F G,, yPBr9HժUC)Yh<#Rpa$[cΝ;H=hѢ)M:߿bp'9|j`zeȱ+8Ο?_~mMFV!`11 z׮]2uԈYn>;:fϞ],X09r1dR\4#~ h4 AyΟ?rdb,]w%JuI޽i~^yRdɠWaZ7oqG{LLsέH~}v%$>n۶M`>3f Xa} G)e!_H4?>N; qRB۷b)oٺuH H~Ӿ}$1L0RhҤvڵkKoV"^xwU//B~ai֬`yweر(QBx_R75h %+ /?veIZ~+}N;M_~Q˫?'yxJ*kӦM+Cz)#|}2d} o֭[駟$:rHu/-Zgwh LvO>̘1Ct"`A `L& [o8S"Eԯ}@#DCgMOwa!O3~zu_z>/h|A :%OBa7?(?xrƝn9F9^~ex&cƌ 3~1 !˓sٲe%gΜgV}Q>9O< 3SAFĨeAhhAa}ruȬWmz{7BfM yὉ!`-q4Y@{;{Нh_o@M6 &ʕ+u|}օBB,\  Pr_~ >|a !#F$2BꫯSNqeK(;'(%5isϢC=(,X j>L}Y%M-\AX" 4ff6^QQW[l5kքvɗ_~yEƤ n~ !AC= .]Z,Yv !x nժzEرϝ;7e^|;7ިF"L?2 "SL Mnݺ܆C<ԫW/Q |Rzuue˖i1!tMh,2,Y$qVF ]Ν;ؗ^ziH~rAS d@c Í:Ŭbbjq"y ltI#\p*a\ }˔)`QO3|VIy<@]"Ip$7q$ ' _bEg)VN*` ^T( um}] |)M@l"h:${hYŋ󡷞IěHxgbFc$?8f<꫺B^=٨C/G^EJ#Bu"hƋ93E@ <ݹgƍma}/[>i?tȚ?C e zv[`/9m^ڵkC6M_Ќ@IDAT"!*ŏV"-q C(sQ iI䥗^={&t})z#o:tPSe󦊤`iBI )믿&#L7=\<͏!`qiФK[k`>owڤY|BÅl yaG L|6;CH؃}ꩧ c+Ҿ}{5 Mp 0`mu=^|~ջG2;M;"O:#O |`̙3u[e4ni@L  " m`Nmmgxē31P"%\tRrDLD#rfN8AñmA5Н{o~ b>’Σ>|!-[ Xܶm[N !~M_+~_~VA_L2U5uȬė?kWCH:ǸNnZ!g7z,mh~;&xIäDA* w䙭Ï{'O{I[L C mđ{+ "h~1+)ojϣאsZ] 矺}ҦM}_[6l9x Cmg.0`byP kJ9{C8D`_;44!"S6 C #풵 C0C:1!`G##%k@bA'7 C!`}d CH #!`!!`!`B0 #ޒ5 C 1C!p0>B[!`$tb{C0FGxK6"~^ٺ';ufY37;:=c9#2pP-pэ{dʺm2o.Y84-YP˕h;_.?X" Ut4*_kx'Z%ۺ"qXL0q6_,ˑ=:f5ݻw7w]v@RIz-}fʲ5_U$8K~ZYr4; _VlwFrf#w<9 Qv; N!7ːeyo'hs=BW./L6Mdݹs :TVX!Ŋ;Ou!99a{Æ 2zh=.g믿t@WHEC%&FҫMn ql?p c7@ԡXkԨ"gRLx@=X%7|SS{e˖-yȑ#jժGɰat5k衤)ܿiH?ZjTIoɒ%ҢE N~g̘!Ç͛s߾}ŋ4{N=TgϞꮙL'_.h) {HAl┥rSrJT\"a}:i+dݒM wᬕJɼ;4sE0mO ψFd#'G7&^~w7XDIr}ݲ2i> 6I5r߸ZaK6S4cttN.W80ܚ]{|jwظs| .z]2A 81٤HF  _ccF2ٹWɡ4A *ACnf1Sm/cǪ.M<1G{˽tJhФQC Ͻϋ?ֽ|rGu&ǮnJ_PLckS+zMO,[Xj;.mC2l><_LIʵl V:lU oٳhFɅ8tTc34wL:lhzўAǒĉr~q3ٸ1͕ ;­$߳`bL8ޟ]S6haqs@^TٳgKѢEC\,±ڲe03F9&FKf7 =gyFL"+WV;;ლx]B _ pPH.[?-tz!O-,̽QitQm[s|=<~.ѦФ ŹK!F:-4B͖{@'ăݷɗԴr80uZ#ڃW>h6yM)$gS03vz}}\N{w8׶{ Q5hc'EΝVohh`1n_ɓʹJ*!Mk2 ü$xdsǎECvj [|}ǧѤI\Xf >cg7$H2,Z6kc<3ij; "azТRɅY$oy ]bJ,:\vq2ϪTL -wT&nٟRx:ee~ 7n1oٜ'=/6>qy< K.;:wWڥ];3Bwx: 0&@?T!)}h]nUXi> g4]v_joz/`s˯T3 Y_rJRgh>[N ?! c)]`J,%@Z tˌ!`!s?ovg!A7▞!`q"`'P0 F: C#82o!`7F鍸g@A y3 C 0No-=C0D:N̛!`鍀tz#n!'Fqe2/+PC !`;;0#_Wnʟ;~8]w /xֻx{-T3rF=k1ά$I&믿𿔧N=x>YzByE8bOO[4frnt= Q ;wGs!X?oa ݃0J(qᏳS"g$r.v֐ioڸgu1 H8ES9s9Q_~ȟ\R8 |׮]Ljn ew&F`;j z N{;EDoO)&_%?zڷSXPow'1II|'N]i5p q#U("1[W,3hƜi&Kh(N+,9?zhoB '?(kqXĂf̹Y]S#FГ8`ܹz+q5JTZ_y?d!ի~RT)!.t+9r,[LgL#mAsNPTw6ZhByA?Ҕ;8w5q>!'\R&.9S^kOOp7.s˫-/t۸HH{B(NNA(ne{Npؕ;i$X, ]Sp7'8ə&.YZq*ʅgȳB9}* r=m>=M;(Г.MN5{T([f$nt~9D0bPȝ C8|?r_ȸ;7;a+,4 /s8R6ҍr;扉ݱ`sܑ\^K4,<[mԨ*9gz267 "ӦM;v޽{Hq)]VIXdmNHA3&^?x&ga1o@ڐ3thڴ?831`OhVGSO=U,Y"={ T4}ez:gA B ;80R;iې 5cqGO'GCqEJ/p$8JIW)D #YUJ*Z)8HouAXGCi@6\0˴0Y8 g^F 6Ź;hp#0 }TH!ݢ4mN˥ AiL3/OY鏴EFf H0/ ѓƥs:2x|u@ā`Gr2gƓvFP݌KL, 6ZvsԩSG5cl Pe1o„ Mjժb r$M Q>>Wop4kVz۶m3eʕFErӊ[qFN:ݑ}h[ϲӵ*n1Nf8Kyt-Z-,.x*ɀ&EB6d9/}=v&-`Z[ 闓xv7NQ(aW3^ӺNYݩAiXSߖ9rz`!g7PTC_UשutFOGYevlg4UKsUn{||9%G[c.Ts=ww[,O=HT;[X8f3fp7|vtrZ d̢YU4-s,ќjNh#'E00ŏE.𴈟_ BG ;o, l A䅶}SZj h~6g|rZ9Gk@fB:3Ֆ0T!`d|3~Y C "`E+ފm#_GCCȢAgъb@G:ב0(FY؆!0ud94 ,tx+!`d|3~Y C "`E+ފm#_GCCȢAgъb@G:ב0(FY؆!0ud94 ,tx+!`d|3~Y C "0{ʦM`עE!)|ժUk.)]ϟ?1YPC8<9/_^_^}Q5ٽ!`dSTڻIyUK/iӦڱG_h\ Gs߿.r4GC10eB}i#| Y]Rnw=8 iPVdQwio<f86f2e茀\ꂴ)o0@\&H C3׮])} aAk^Қ5kT3vʔ)$}FG MqJ@4Ii|8mV7nCW$etfϞ‚zMTP!57 "AF҉-x]# aE Рx {oz ~P\@zAEۍ$>GGŊugsTg'_&ȎB+&~vx//k^R_ђ_}Unb@\ `dcx2GG'vJOd'&>n9"A O='E@ϴ?H>Xe3ɕx-+W*^/+W_}!ZO‘vLƍR Yp.8 `ҁ ycј{> @*#   k?&BsQM)? c/.%HVK?C |ZeA(W. {ARd!}? 9bˆ7]' ESRȚQbir0@tb! C04q=ڽ!`@"`x[j!`čtPGC0#R3 C n<!A/ޖ!`q#`7T0 E:} C#踡2!`/F鋷f@A y4 C }0N_-5C0F:ṇ!`鋀tmw'@wTU Pb2@b2J(qPE XID)eQ(E FYBYǒR aBe~7s>:/qO}u]=s@ cV儙cˁ^A;OX|ݲn8yk4C{ S@` 7,\Evm(63=U7A N^paqGS{'L햆ۺC7u. b駟ިx)~)mx]tC*>%xh+۸ϛ7>tʘ\sMK_J=c'Lh }:'X\z\^dI07 9/fΜj9K+n871k ~7gJSO-ַ[WJoNk'?Im׎$~%|' d}ӟN<NJ|&D}Gvec~뭷 fsav)%~\z |GrJ;^$W<z(v-ͩګ={v\]``xUW]U|k_K/{< .JS9P׾i[`rΘ1#-t_~y+}jg }cA7ꫯNʉКbǓda-ܒrzJܟs;#ML֢I |\6klhXD[hQֹs/ :?[ 7ܐύ~a73JaAS`oq묳N  Vq{@0'ǜ2eJOq+c2D^~[l1(X6nřļ5%)4??0aBōJ:+$Jcw/~aΜ9~&d{F;/]zWݏ,,}xsNnYBԮ?"kd1]>)mfפ]8\wu-vZZY,^y% Z[Xdvut)MlG[Y@&M4geYqo~IIR%}gP?pZYA^qdס !L/N |WhgPl?˶r(bAxIM<9n䛫mq2<,EDuY}qOP_WR:N[oկƜ+,cd GG{Ǡb{NcLS=!&ṚClr;V7YcEkW =viGy+vk3X:uZVNAZqE(Yu\8B@qOgyft1lpwXBo}Dbd_YG,,n)KB Sƭ'i3 [FK)ܢ`I*~DVvG?QZL~$;1p/5yM Uh3_=W锪>Ciޱzp;T[-n1WˆH ^,fJގ6ϬI^69Ò#vu4V=  4&cy㎅ ?⩧*կF־˟^ 1-W?AeH( qӧ'߫L_|q~[J[4*+ƙi͚5kWGy{V#a8 B+dqeBf.1E~ۘXȰ{@M}z \2mSJ]u+c9m@q{ބ(7P0M3x]BBmJ덮,Ò2R;&nr322j8t ć́́^s +^@?s s sYA0&5322j8t ć́́^s +^@?s s sYA0&5322j8P}UE>hq7-]\ſbϵv(\wbz|QEV@@@@:RW>xKq.+SO_v/|<]8wir+o5NsvwriїԾl;;d,mxlQq^\9擟~eg⍗Tfhs G#ȟ6Gd}n@$vc"G:P߁vd*̎EDP7o^:pb ;O J o鮣Zw% 8sm3fΘi@8>ݬQsIj?#K1y|K s+)8ޡGyd:2,<eGuTo|##E9ǰ U{Sgw ? TxÊYo+ESZcjtL5(G@ @Vx*;qcy}oVk)Ps@94̓_:`VRΌ9O BE,sCYLVr!=ܑ]G;IHB(-l5OfΜ be`2eiE]TMoJ, !L0; W0_\֩riuig!"'>7 ,KV6Bq-+Q,fDm?J_xN[0Y!SNMַ9[eBjS{km',Sd [o(xgJ(gw^&T׭dNvͽgQ|#Ifqu䮲w{W*  ?E֦BDZN A~i и Sn[nr$>_~ylYBBHQV"([Un]Z9 7zxeR$PYYbAB4 :q`|FIDue}/MREi]K˨C, Ξ={9,<,2Q0< ? F@3ɢRrYnY`my[sjVzﵦF# 8u 0$VC>(&:vf<iZX[ouY8T8*3;S:H1VR/Gz֤8"w5eq-\b{"EqSb&Ʀ~\r%+x&ViSE-badi~+:]w5y><6 X{k(wӸ;Yd-rE'eE~;>-eĄy.,E(SH 2"# +eLbS i{7y(w1N46 7}Qw(am.uZt37Mր@ ۽npo+[ oUb^|OCpodF`J`v0O&bR(DPF B=ߐ=㶡W)LƢp2-2A5./SmwrխЎnF&.l…6~r!os.񛼐3yiƨ*lTcU7Ŏ;y^7\.*IK\sO}˄1\7jJ[>zU=YI# iQc5Qq0Yb !`Y\|hWVS;Y?]51Ȓ*]w]zˆP<ظ;,fynm&iD}=39'^94=*m9_C>mo\? V+ aw Νe輍;fy*Nm岂8}qO ?eCQ6u٬>j"xזeb(_\ڳL"V}q8;Θ$(cm(rsc—r7eY(|Gv@qԎ([`ԣnRۑ bEg9R5ԥ-i =oUO96Zl`"ϴ-q/Orx sIDATu>++-=w?bny.@ewmOӠqC›\F{U3$BeA¤2aH i*ln G֊fbk5A@UL+5M3$EZk"xM;G7 @¥n*ŇxHr +g:I_WN<u,XF<OMMںr{EmآVމ4ab1CLU?r)h FwűZS*^4>s222F+Q?9999PÁƷ8jۙcǀɹ́́́p +p-d=LUddd YAk9O@@p +1`r"s s s`( z(\y222ƀYAsC@VCZΓ9990h<ͮ\_|⁛..~?^aKYk<&:RN;pϮVpȜ#\CUlYR 1tevk9zяΚ ̛7/:uG[w8u޷Db:nIG^A;ѬLQ#e*?O}/F]PYk,Ï+?|'=T~8.@M_Jo%8i($lv;D +>W.!L;Qx}>ܺڕ> @K!80b]{7@{` 9bwN?s}@gAs߻FxѺ37[mJe=K6`'j|#n%8`XH9{i"7 3"X'tRI|3-B|v7H:Ypa| &r 8$P>`,V8`ií]sDx3x{t(j+#.Ҥɺş!9([/!~^{$6-h*-]嫺o@` 8q`5P]SZ`]2؅^b,ZV ,8-ŋ(us[BILYf%1}JPL,h#,\ljt=ӦMK&M!\<RNtMF/{z07AyR˨vUMfA\ىQ0=Zēt x>S5nU볓g3O=z*A)bitxQgiC"Ĭ]v%H¼.OV*bg}`!U-BkFB T}Z`xd9yw{E^uz UkW' ܠuKYh9nbB(? /p$a~(jp %͂R[dQ&JDamTU{PʹA\yN!O g mV++g[yq0,wߴÂFGqDBN}砃J!:`hv;=p4*-֞Vˀ;-t3:M:SaRPWHJϽ`e!{,(ҳ~Y ǽea &U=skR\Ql-ʩ+ChE/bu~(rpBhu׵iC`bl|7 ^ߞy}yυI6BNY@ƛn=^dsOvr!i'}&@)nJi_:qݮ ʈ7!`kV(*_xIf h`)Hȭޚ3y%\vMVƆ&+{ U]Sa sbeiMMֽFWE}O1My cPرznN48{SH.и[l"&w2cG}taT?ϧ}fL1 ށ`V1Ŕ!ҫvL\o^Jʉ۶\`ARHo|i%+3,A2zRG6lWE<Mz K.~~QGUxk&!cc˛B3ځXXHԝ z2 w -xф5:.'+N 2222FoqĹ́́́p +p-d=LUddd YAk9O@@p +1`r"s s s`( z(\y222ƀYAsC@VCZΓ9990 z   ŕ́́1@Vc\E@@P8v.‡yIENDB`icinga2_distributed_windows_nscp_counter_icingaweb2.png000066400000000000000000000672041322762156600345730ustar00rootroot00000000000000icinga2-2.8.1/doc/images/distributed-monitoringPNG  IHDRH iCCPICC ProfileHTSY{; `#$@B!TDEepGPtX b(` l{vw@e  iLa-:&C;CdD_aYٌ׿_%I`1d>@ jOgM`" "|xm{vMx'bdKiӲI#a6A8aӴ3\a?$3^b%Ix]feRYJK 2WRșե0?>8dyE3;3v9,yD3K,/>ա~jp?! yN095YyH XX) E>wLXZ+CNΏdzH<̅S}%0ɳlY|+` d&͜is`ͤ#%MiVvܽݽ;)j\쐽U 53ː-]j Y j i T 87 A1`%`.HB bT ΂* zx` Q *iBz d! B(JʁBP TUCЯ"tC`2,bp8Nl8 5Q߄`1 D B(OT*6 PeTՅQX4MC~4ވށ@ס[Зw w 18bhLf &SŜ\ `F1X"k`;lv;Tp&8g\.qOx^o-2|<?E! !apNM%LeDgb81XNl"^!>"#H$RK*'']# >dOr|AO~GP)nXJ&e'rI*e.ŐHmjz-M֓v^)-]&}R AF_S%QR̤̐,UR6D6Mvlur89}9o9\!Kr#TUIeSRSPG dBc= r 6 k*)Q T"_ԕܕ+5)+}T^즜\ܬ>I>>};0~~ 61or9 ,"iq0=(X/B!C3 ߖb2V.}jF [!#(aa(3R:ryd}((q 7cTcx1me,]n< kW\_2uUҫXNa⾲BX5xF|Uۓ)%8'$\srZu붯{zz97To6oܤ)ohonfͷXl)~k<ܼ|h̗msvG{[o߷{FEaY7~靉;{cŃ\wՕȖdRJ+-(}g՞e6e+[1PQ\V~n,754ȫ?2:V/Ύ\rxdV?있}#|3v;wGۼdN>ac'Ou韻D}y>+k7o?N(B#Pb@Ƴ,syVHr㑹0;@0Dfidf`kk2HH4)~dB߆Z">\&-X$ s ۞%iTXtXML:com.adobe.xmp 415 328 kJ@IDATxE9s$ "g:s3SOs;g"Jss{ݝYvw.S]=f:I/#`0g@Hj9?!Otx4F#@Pg0F 5 &]+#`B0 "0F 5 &]+#`B0 "0F 5 d a7mرc6Fdhu2LWF%_})RDv)͚5nAr̩|EҾ}{}J.KW#`@\ϲe?gyF*T ~Z R\y)W\stѭ/F&naÆ\ܹsu]'Z[n >e0F Z|֮]+5kLZj~ٵkW ~I&ɽ+Y5@#z=z>|8_gɒ%6$۷OΝ 1F!SlY={vrϗٳKb{Z=o[.oF#:Z|?|1clڴI9rD~W֭Z?~ 4K/T[΂0F토\yZ7o\.D/BYbk裏OHJ/rqɟ?Lb(+,<'>R5۷K…/ $[lryIS55) :T7Ic]^Le8#n7w`PxUVI׮]M6ξ mSZ叞w!{쉾i2vekU3ׯ_/%J8m+9;~'|ڵsκEG!ݻw׭^{ֽw^nG۸qc?~̙3G%W\qFMYǎ~vΛ7O=ߙ •+Wʆ Xg?jQ/!˗;mҥyfСԭ[_E3gʴi$GҥKT[f >\N8 Xd dɒ!teTXQl٢LذaCi۶&r֭[eZo8.C ݻw?e̤~2z$?_T\Y:u䚧 \&Mh9_~E#׳PBz٩>[}7wjo@ d 'Eq5A_~ vc7\^dԩO2E/ڵE.@0yd!-D AV^1{9iժnZWj>?XgouY(X]R|y>L2ҲeKy饗|?_; Pc-N:tQF /^(+ҥK+Pe9'Zj=zfcΊ᧝h|sAx~六ݻɓG^y@~3*Uh7xC'bJ]~n7|SYt#Im©T~|_VxK.}̼3+KW_}ur@&N1$? HWq%ܗn7 ?#1zAU0P1(PNaz%1cEftYCDQ}q"r[H\Ƹq]#B P kwX:}V#7e%D^,ڌ XUV4lc6iX0iE kZUl@޼yu3z\5 ~rrAYD-Y8V GH nbf}&)!ru3GOPźk8~h#k!|u/cKGXGX8tQ2q 9. @uOY\D5 =@?KLLwh#krɂ8ҽr`޴i㯃33>?Oj3Sguf~ ,n%^|]ۈ_(Xt~u}uPeWbZȳ>+_|+:PL"ycv>3b0-ys.PH~ɂG. 6rx\V?ZnLcunIk'Hgtm0ر# ċV\,|qf365-C#[E|ČY/ θbڀ/@Oñ'a  .?8yYҮPq 6z:F\L ;\,Ȯ}|R#u9\6SH=ZRKf)_UW]f i>}T4BPC\@0`mQ w)AH(@@h=zSO=f<-BVdB %)/J0H⃛eg`~wYYߎ /$yg͚uV ߙ`6,8ބO+;ӈ,Mp/2l{8PF9l8l,` ՚b=.` >rk -Ʈ(,HX/ k Ϩ V|ijG2`z`0 kMv?  aS]d}ƭѰ`ͷyPc]66Σn,/܀XJ6|:\v!MaMa \W#`_Vkl,VYX%'4:6gȕ,%[ӳc#`2Z ;vӇ;viy K2㱰/׎0@YɬmG&>xUOFtN'_ k0F  U>#`9t~yFx$`WdH"O:5#`2|2ȅf#`≀O<]M0F 0 ʚi'&>t5/F B'\(k0F մ#`2 rFx"`OWb L|2ȅf#`≀O<]M0F 0 ʚi'&>t5/F B ɓ'ĉ sL#`@xs:qϒ%{kF#`RL _X8Fl,#`HM!cȭl#`  u⌀0FvK =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2F0I =k0Q0 e2FX|9"۷o׿]vɉ'_w!˗/OYfIeǎwqYv,YDh#`H!dXSyYfM I\ur 7H;h\r8pL:UqiԨQr$+ d~X0L bq0;<)[ԫWO~i>};uĉ*ݻw… ɓ'e:S$Ç˺uf\ލ7;?u;wx^Cȝ;?[0F m$[yM7F\e XEnWUW]%˗WQy뭷^sܫ<ǀ @ s9u ֖إ09YYdQ )9y,0F Z|.YEX*ԬYS7?^X턘&K,0Hpiq$8k.͛7 CR BqmT޼y5w],eȔ:*pAk"g=\qjI#!D%q# `֭\mɂ?ET[IÚh;;Ǯ@SI>+50,X>;6FQOr;PB2e.ϛ7Ow2~W!- Oq&Mt7_,e |y/b9++R7H`…  Gtiժ جϪUv:+ED /mF"v1P]o[ٍVeO3|y/b vʥ [ uuMץKZa6iιT[Iǖn˅N<8ǖi֬FmbR%\ {UvoS b#`@ c'8D?7 I!^jM?b@//Tz 'Z֧Q.=!lRc7;:t蠿9m!e _؅C ; I:cFF bbb"iŹ8w ~ZD0cEEMP)?vI.=s ҷҥK ^֜8J3 1F'}5,źE: 4܇X0F DvKHKa0F qo8H8;k0F i&>I3F#c&>1j#`@L|fd)0F L|b Ԋ3F $R#`@ g0I0I0Fcm-#`Y>вF#&>1h#`@$L|"ei0F &L|b 1FHDB#`@Lb00񉄖5F0 F+#`"!` -Kk01!/ĤT(d…Rzuɕ+W*EرCf* Nw\bl߾]E4ihm:(P 6l Yd2eʸ$_?g!u 9͛7TR%u+3T|Pݻ@X` >ԕ+YzG $GIVwNVDGcǎG's{YNz!&ݸP_|dEݻw?OSVs饗ʛo)e˖us=aɒ%ی۷OyyW%gΜ'~޼y:b*W_ŋ6#t=ȿoVZ:uT Kҥ+H,YsX@?`Μ9[o%ٳeKҥKiܸq,>-ߵkW!-cժU t/䥾Mʵ^+ٲe _y$Xx}Q)T+-[o9 vgϖk|VڡC͗T{}PO?LNZj%C>@{}YjTPANTg„ rg4ܹM|b;n7>|(U2s@阡6h 6n([nuozA?TXQV?PogyFpoT }{o ‡ \gw !)'|Rۄ8 r0!ÁÀl2awy͟?_>l sϸ0a`B \|0Yw!GRreٴiZcm$`:H2p M-Z$H@ɌA>}V\ǎM>]-_\g ( H1$W|/xnb@ƹup&'\3X4\Z󷇁21'` BN7лg ˄A2[=.?>\d5}t.Oc' X,r(ub W9 ܻ#m\ w%WOgŧ++7dbD[o T!.O r[ 's >B` 6jAfX,:ur%\}ŻA`Pw2Ӧ=Ƃ?('be/ „fUrmaNNzD+9qB.G$똾J&xps1eOڝ_ \WBeM^D לplP{{:#vP w%՞Pe L&֮'\wt0C \_>WLGr+%$s&7g] 1x6>l LavnVIuL4I G3p@aJ_fptK.U66mD2 YC`g`fPt ufnfNȟX -A" iS<9a 3,D&Bi@/~SQK[nG\XE;+_{.uJM\<.Q\~V+z+ז{#;Nƕ.?ܘI6|bωtRy|dbnp383hP1d7yy, 78':TX-) mٸp"|va01;b e6`-F‡KuW_ʕ+u' †aY!fpc.A`6p1a2(&76Cn&}EP؂gј닅XW`&k!aY$w#n;2nW8뇭XA "UƠ͖;.Tbn`3 l~q13X7k˟^^`cձI,}3Rk쮳?>9#fbҼyދei'T-G{ryŗ[/(rDZ&n,*3PC#H. 0 !B#NŋU0>V8ku$ v1]bR{x.$+c:]&Q[kL}y.Z WCݗI_I'8 Kxp'&r+j@ّ¿@mJ/õp}Iw%yR bkC n' #`@0}:)0F01P+#`&`4#Ka01&`cV0F$M'iF#`bL'@8#`HOҌ,0FĘOZqF#4Y #`1⌀0F i&>I3F#c[⌀0F 0'^x0F - %}#I d o6F%ou#`2)LzF$`ⓖn#`@&%`I/u#L|ҒmȤL|2酷n#`ҒOZҷ0O&m#`@Z0IKV0F 0ɤ޺mHK&>iI6FdRϑ#Gdk.9qDL}rwCwIG y>5"ϟmRe_^Yz f3k,!͎;–a'0@H#Ț5kr%[nA`ӦM޽{CfE|7w!ϧFݻM7oNÖ~zYvٳG4h,ZH*U$m۶ [0FWϾ}/=z9sرcerQk?]UiӦq/0@МwyRlYW<2}t=5ydwY  ʕ /P-YDpm۶MJ*%{.]^W^]v*ٲeKfܹZ&U&:uXJ_reP9RΎ;JZT0,X眐 >9sL6M ( \p-ZTPeҥrq)SPBoCŊeԨQ~iժ4h PΝ;_~Q7Zfl"6lв]?Kjܸq5GaJk#p D-> O5a:uL81 B޼yu'ڵkkL*ab)} 8Ǡ[|yy7Uԩ#sQ+ĥ߸qZC~ǎSA۷ꫯd^Ko k7n)A_TZU-[kB5RW qM o.2)VX /lQ`E`IO]j!4nXa``zB@6Ts9"eG"4iDۀH:4Y4o6hт@~ڔ?~iӦ)ҐX8.W!\si5#QXmúnsµqn \p0+5ŋiC ]֎BŹI:bU\~g#_|Iׁ 2DB ^z醑$FT!t-`$2C{+Z' X( .˯űc'aɶg\q`}+/, ,Xo>|Z9X6(3,#`Ҋ@Iqo/^\p>`ZDŦDj֭:Pu`1E|RF M?o<ݠvC8nҌ3t'" ͛7 XOΊ*¥eQ˲EK.z ⍀HUau.9{Ĕ<\&m ;7:'V R*a;$3Es=q0FLX|d㬮`"N; k =ⱺ,#`43M< c.=j׮l2 ZcU#`DL|.0F3N gV0F!#`@'`#wL|Z0韀OFB#`@0Kj2F&>Y 0qG'.u# kd-4F!#`@'`#wL|Z0韀OFB#`@0Kj2F&>Y 0qG {:dl;tTl+vYH~|q^NI<9.>A"{c29gɒ%|r9yԯ__T1Z#H+% ///&&/ve KJuoo#NY!c.j5\|Ddr?u@=zL0Ajժ%5k֔I&ɉ ?؉d?|Mٿ*L[[?Β?MxhQjy}Zi YiYJ,"ON_yڹQ@j -|Ϟ=2h 曥tRxq9묳$K,rq2eL>]l"eʔٳ˪Ud`={+VL6m$cǎCiÇkرc;wn9r^Zʗ/eN.oݺuچ9rXhQ@)XLxDzsYR Ҿv /tSXb7qCDr}rvjݰS݄_/,Qj+>%kC«sH)/~ҢT!-￞W!n)/[r܄=,X';l+ę[jv7i\ %Bx7SpҾlϲvy} m۶V49sJ6 A!럻yt޻"Ż4ԃx2Õֽ{@.=qryO^'˝!p7p'7 M2}it2Yx" @.^f!۟e+XR4p\f<^f*!Ow*'y֙ LNޟ .~.SH:xCߎ[/{OJt9sfsj~z d5‚QFj$VhİJ۹35ʶs9kזgg͚Vn8֡,/Gή$.Z/ ﹕XAya``z.,\n.zk yZүuu6tT)P@.ޕ2G{zȞRs1֩fgˠ:8揠yNE..H<7Zn; :S市ϲXfOoRW}W/=2YA$@xة+ 0'@sx1Fyrx6zi7;m$#6~]0i:x0n.k*|܀Q5^ kƹŻ2x%#= /q#Mlp!z ?6s+oY%=i{\`bE jU#1Ijie#|&>ge)0F F"p:#`L|2 `7Fnu#`29L~X0iA'-[FLN'}#`@Z0I V0F 07u#L|҂iL|2 `7Fnu9m#`v4 8_|)Yp4F&>v=%{sҽRq)=W'%aȁF],8p#:S~z-6gĈ2tP5j̟??h6+?>|] ]~-y?sP&lܕ+',+F,oHp%kQ?5c|˘:S~zjBYES<"I&I:utҲ|rV9rL>=PYg%~Q(۰Rze9%<lϫPT݁\-϶*]#IAdϪ՞mn>x"7"cs|{ ;pM kixb_cn!s Rn]YnF#D{֭[ˑ#GoU;v>!B-[g̘=zZRĉeR7xe˖?Z>yV\)7aÆ?ih"DXxZNm۶U10`>D:vxڣ5 ۾OG:8; <ߜW_.R"AFO{|7XTg'^Olе#狆kHCeJJoݾòQYU==aC(Om8pXzp(o[DŽCb_7jlD9Wbʜ5Z<8GܐCO]!uڅJO/^J0wx o2;7׻g}3U޾lsp`'=_ !͖-[K`RHjltM%*UHÆ 5?͛'˗۷am?~\K@loof;=}|pnmӬϖÞ'wz3vϛꔕNY8nq<{c2̳*x.oCA^?#޽ qVZUKg<j.|xϹWU!'8.w!:zW{ԺL!aY\MyN)L…=GN}y))-|ړ:y=n<0^S]k;UغW*hN?&W \D-uy}]l:pDkWk_@r;K}ƍerUWBqɓ'\b|8   nhVh֬(e>HXk*UA\V.'5pښ }GIO/ϚB6ֳz3xL…u>rgIJ<ɛv{/y%[k2 hHS=˫W~鼧6mӷ"rhX{~޺RZ+I,bAFmZ%іj2 kw]g{VA={oF]eXzRX8 νUfM U&_]{΅\6m<ذpA7ok@D:.=3왍3Uu{ȳ{ď5w-uhSp\iA$Tח@I8}Aoܹs'(YNpaոy6sMriqӅ;L9z9 z}_G"O]V}Wqa!qșMd-%Jyܗn`K9H`]i>xjcW2浭Fq9f8cιpLuwkk^ϭ ./&2T̃z^  F?&>X0qO%#`wMEF'`:hHL|5#`➀O_b0F 0IZd{&>qFG']k0F %#`wMEF'`:hHL|5#`➀O_b0F 0IZd{&>qFG']k0F %#`wMEF'`:hHL|5#`@H{xٻwf˖-,XPfM;vL>9sʕKz))\p͋W.sTT).h2F sX|yYfMBѺuk$O?|RdIiӦ,oխuV8VWZ'M&ҧOYx Bu5by饗T&L3'zҽ{wAZ.1Buʽ4D h1_}*;L bD9 XF.0sY3bS^uYh۷o)S1bq7ks]w5@\pO?_Zl{ob%Ťf͚x}EuC=~ipKCIrJ'xBE amذϟ_rgK,Yk7cƌuIP1F"ŇpEtM`;mΚ r`…z ȹ:tև\kFׯoD_Ǎ7VA 4ܒ%KTxn~ʼ5-T|(5HΝeI "ڊh£4iJ,s̵p_@͆hѢje":r}ue۫0FLZ|pC1aݚݻ]1.?Nl\\ k1p4f.P!TxYT)&⃃??" <n?D\?b ]jzI傸37aRa}g] o獀0$k6;6F)Y#w|Pi꣏>ҭ|e+nu}7vбTX1ҺW"]qؽcrB&kI*ZcrDdXaB\bB[v2d.$?ֲh7 u%_Eb@\XrXaÆ SK_1FAYd$: t n$[wO3ri|z#`@f$`#L|XFH'3^u0F ꍀ0Ofg#`@0I `#`2#xխF4&`7FdF&>[0iL'/UoȌL|2U>#`Ҙ@ρdǎu>x ֟x.#`'p&Ʈl}x3:{nϤhѢRHN8OңGgCG~*> 6 c;YtԮ];Њ)Sѣ%\{sÇӧK wRD )\}}_bZdˊ+}ر駟*:].)X*4 ͍дiSa\V-~DoݺUg A&`Rr9Ȟ={o߾n4su{kduG\eX*e˖ {r ^{(bs1n8͇`maE#8+80a&LͫLΝ(ɓ'Kjtܤ.Wwjaù|r)W`K(T]wիW׵]TR`[L䂶hBf:uJ_/7`8W2}@: &k KA2&l!a1d/Pƌ?f `SY.7eϋ/X}s˱'ˋֽ{w%?WN)98-݇{XceM45?v 32&x 7$xbܺ(J.p?uT\xH|p~Nρ5nN>rL<cWϦ gܹOo]潻FI5@3]# ;ԍ,w}kfBL;7=7ع[c2ָ ɽS{L'5feFWs=E`u>&>B[737겵qͬ0񉎛2FHLSPe5FLJ'^x0F - %}#I d o6F%ou#`2)LzF$`ⓖn#`@&%`I/u#L|ҒmȤL|2酷n#`ҒOZҷ0@b 0F ar_> aWG]v UmӸqi#`2&,ؼys}$6N:a{~wȞ={žOĠAe˖“&{=}db0FdY>< 0}t)[4lPϜ9SMҥTTI O~ĂuH#\{ɑZP?q5k>~K=b}v2e<=zTio.\(9sh:utZ0F UԩSery>G N9aٿp# ̙S= 2y'O0g,#`R@nfB`gf͚>{j7_4%'` ?_…-3U (۷qPz1F3N *'k֬K._~Yϟ[=\q'<3B~6m?T+VYd+?8Ƿv_X1;Sz'58\u{#`-,'i._4( 028.0qǑk28UyO8qZY˗/V_] u#`9' nذAx#m۶pişVEqla&VBp.\|2,DB1X pWVD{0\iaD|Ұgj,;תUKڷo[׮] ҄Oޤ wyG.P!ܵ  33qD9דּ:p` Hl}mO4I?k\%J2m/º.ݻʰ3KZvMOCbg_u1'8d{,+=BߥWT)2O.Mx^;N_H,v+HdW_}%ׯ?-k{0\iqO2/Çl`9?K.ޟ׎'p.\|셵*;?seE{Loߞp 27&>ɼ,ݻ7B s.MM$څOFeH|__ڵ~}eҥ   s:xc̋weZ*z ,ZH¥ ̪-YkЭ6 p5_C{3/e~ћ_'|hVkn}G}$Ҁ)TL/vkcٺu<re5M,S4lɒ%駟bsd</xwaoI{˚ m4 ʱCi%xYo<9v_AI 7F#b1rJߵ1L e5:`dqW^41{9A0x[~N6rH-9S/>DwM<=uٲeFbi#`bB &Qk/Ja\~ٚrdC"{apGfS,!n-[C 1bRrB'LKc0'-ź*#=e8Fc)"t5h ,&'R:[+8 z#`@$$7ZΝUB Dpk?/Vk:|ƌE7C#sPMnF#5Y7tWwŹO%`SA@]t.m+kCQF#-hY>#`O,0FDK'Zr#`&`5:h00񉖜3F ?lzIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_distributed_zones.png000066400000000000000000000355411322762156600274410ustar00rootroot00000000000000PNG  IHDR ==sRGB;IDATx |Tյ$$$W6T z Uՠ|@{TVUb+!ՀU|Tj)*T(  B^$kI&dL33s~[Ü9}gXk&  $n A  )PLLHHP B ̄HH )PLLHHP B ̄HH )PLLHHP B ̄HH )PLLHHP B ̄HH )BMɅX@Ȫ\K2Uaז= U' 3 b&M7D &ȋr CCHHO x T(p @ P  @ " h?*3$@$@Px]$@$@'@~fHH*PHHPόW x @ w J   P<@.  Bi?3^A$@$(E$@$~T(g+HH<`-Pe^_~|g i7YSúRq>mIζ}@W %¿O|v3FODX\cT8NoϹcGin{g' ~=Ûml'iO]PG~ɮUEwKgv+ 9x1C? -yjgӨqڳX<\trnkPUWs:Q(gJd.r6'skf3L&#eLSpzh19 ĺe"˲**&yIquJk{"g?YPSn]V?GEJt^r0:bfRcP t@޺z*,P^FA*ؠJPwZU1zvW+KC^7oe$޽rv2(~ z$pB8RzvJt3K?5U9Vx%F!^Ob{"g?Y*[@zl:|GjT5grT@Ɋ'g+J%!%k(bݻa~Q%ȅ"@^` %0eWWG )s0W$Fwct$ZA[9*o*vy(<_5ܳ7)%Y6\_y(Q^1U㣂J-aBz LykPaN^, ɯ$Nv!@>_U(j09'G/mRٍO\牋6k[=뱘y I8׎}cٸeӛq~2aYƫlB &6;gte[PT:Ү$.\[(kE`KhC=ve~;p9Gb͵le97$МJs& 'pMr,F$rVMeŗZ_c9olEc"XIKч˥\e7b/”ݨG~x!'?8~H+?'+|fE}v f}!=ald.وQpv$ @']4JcxٴdH]2<>)0 t_egdJ#_,c[r,pX1fr< YY؟i8J7ߎMkܜ``M>$EvÑ|*V߀R-*='`8*OW 3<%W_Z=}%!dV>3m͓4̸wHl\,Zuw7aw3g`ѯW⽂-Xl/8}{232I޽7^{ʡL2([֡1^\5z ;3H7r6bΤm8,Jo"g1&ȟ*Km1 5q}uG値[=*g$8֞AT]wGJK\L׷M+&3 "0QPqR#;tL u`!]:! 3 2].}\H{RTU8W"̘PzaɒCg(ز 2]}|^z?& 5MNuӼOQd͝,$_VvI+M =6%j-@Dlx CغtÐy6yG_U }8GnDzb 3e~kF5464ݻ s<^P%NV3!9#УS=M2ckwr ֽP1DGP[AYa^2tv.yCK:ĸœs"9'3y٢fa\{ղL/Ķ;4o9{S c7T(vx'Y:~z_&zOV{=>e1b-R\aחΉ edc( s1wJ.){`CO1m(źKRZ&֮^t#Q, hZhr&cg!'gCAea+ߑJcfFxؖBKemPUF-0>UZbiygݷƼ~_lW.,qb1kr( qQ\WT y5=&ה5x;/?B|_PY.' cr脽qZ銋kAȕQQ\5 -_  MkoLY aV$@$PY a0KyMuO1_[ uM/\r8Դ . #@?A}gj#Iqu>:V8U[w#Ȟ ׾.Q{6-A ʑ@PLi~#y؈_~Ǩ&˷}wOB|^MK3yOg3Õ;NT"R٣; a[(5JbHeD^70g{7t,|Y!r%]m*3(KXKaq(K&*+Hfe8QS,Z:-3& /9LHa] Q]^_eL}(  N㽢X'+U"S޸u+%:$nH@{&xgqPoWaݞb.:*_p/y%PQwyG euy5&D *F.G>,`naL3V]/V=Mi&*3i2 /?-vx1\Ԟ%q5iX»w3) +dIGnRck6 P.vP_sŷ,7D#B~:F@{"psS;c**Nm\dxk leF. ϋ3qd8bY#U+#b{zO!<b|\DX0WFr,Xj4| NyQih`5*QP;X/Fx&1Ml81|aQQ F +h&<`*P2#w$bt,i\:5mpԎ71spo|d_cR^ȂA mvbQ uK&[o^T&~w s o,Ԙ|M ׄmI1\,FvĥJ|.&!%x7{>NW6#DȆ|I ŗtm.~ tyqI28ğ"n,׉hLg$bTZ%ZHWWdmdgijt*KW]CX+;Dj~)qQ#8j.&0DmYViL>*.}]q].v*%jplznȈ&@b6Q'{.s'EP-XC2u-a(Cd~gX7P GkwJ ՟U: u5e2 s%a8(Tc;&k bLˉFbFA' I L6˫P eY+W-ߵgr8GPXQPcGlQ*b/C4|8H Spfw#tLU`L$ *o( K= .}aESF&xP6}&H-T(mR1t{l"cX1b3a(rWkG 7y&y`"PFf}Y? 2p10 [W֐3$ԔxU1 ?rX fk8|8*аvs ׈#1\ >ρj8Bd3fILk|$'Hӝ; nwXK )v d iZ.vc'֦4{NTᣆecŸU{2L$N ŝ n0rX?Bt`T;Mo(&p'_ w6_C$gi[( (}M CF ]ܮFg"wT(4l}H^ hkihjDbb$Kɖ9D.T(.6,%bU'9;(&D GO עϏg ZixV?j[$@H5jdц&}!ˁ(ckls 6vTT,sH".pE̚a.&pfAg7qD}\/RyG4# PH=Y.UWM{&Ĉ%! 7ʳV) opZ3ٗ Dpqjc](l YP1|gvJDcҿ ^ Υ+t^~Pl s5\#0~Kc͔#Ph&-vKwʳT!çyNGU*WƮg* wx L ep(2a|CU`FÇq=g* p]4i( }c :'#RjQ(:FKc 1ه:Xmo.y eeښLbDfPI ~|,%~A~ii&B RY{:SAZeV hhhuw?G / Gv*4|bT(c;e˃5267h7Fi!S_\tGcig) POᢎa2QI^ 0?˭bMKeD3@JW spSމzf"3]^dnLjGV\fW9x;ZnT: g"Pǡv!ʻ^늰bkPڗab/K+1AhdT\Ohf" =x*vPv(5R=P|׉NQ"/ʐh;|O }N7h>골*݌e2*x> x4Ttk|RaUcу.[gJz):4LO %dx\ 7+xRg|j.>4KiV&d5TeU.5| bI?%]* 뜔SjXl8};ፓxj,D@@qEthwFH>kaqїsYpb 6sX&1@0[*uˉSz y: ut8P,*B1唯:X19m&F_'^QU^]c łR#K>GV_ָ4\X$S "qP̖ίDᣩ}v0ߒ:cKjϝ3  ;H0rqzYqu &kB|pqpT oE$ʘ2 ؉@*m:7i'ihǀ " YDΡLMm̛ a^H'nboBSRqhFt)=5 dVBV嚕!8?/B_ee`[)<  V d /5`A[GS z )1h>Q(." d1Yսґ @B Q$@$`mT(֖KG$@C %`Dł PX[>,  * J$@&@bmt$@$0PFT,( Xґ @B Q$@$`mT(֖KG$@C %`Dł PX[>,  * J$@&@bmt$@$0,EGz{~ Z!=58:%:;0)7~ [!@y}px 8Ӥ$@ӽM9.w6'/z8» ؽ}X^O|v3FOD.1,5ܱwM@ͮ(Lf>K;h_NMhݨTspV8|k2ؽ}X^:Y]zGD3;GA^+;au k1[zHSDI}QV鋬*O+^YjFO}{4j?Z^{K>9ÕAX&nSeU8V]kcxDCn!`Ki†?ڇ`y҂ڵ[W' ,>=QSX5ۺ0M{OUac@ y!(fzF] ̃ 8_oc8Ur3} +2tuDG8ܓX\]Қ:=Ie@Qy ""b0tlNKҦנ>4m¯/ tBwWߴT^}<*MN&MVFpۊhf:vUߘVe[b߫V壃 elgOl?})-%?{Y L[, cٸeӛqu[Ə'NF.2'Gx>Ұɯ7M;!i3. KPVc3mf:YSOWɩ-dc@s(!šz <~aS}r-m%YƩ+f<^lg=q(F7#/> ˞\A_{oVBy6<6b@P><8ss[IU(ܹzFN^Ydrnmyx(w%ë(^ĨN yrxV?>ahS>},bTLܲB9!s2&K*uuWdhw9+0qQ,G\g9iX0vtJ}?aRRE _g}Q.m5?99YȟvWNJb [ uj sEr5~ZAᖋ@ٙzc3'9#ݻ䌬.m'T%OЗHCadhZ8ʥK7>U3l9rCSmωp\X<GȘ±-E@&쮈ܷ7!ؓMx*qCd,aQtKjaus5.w5M.ʴNô0#wjSbUnX۲?h)>9R\ UW;>d/c&l~Z(E4Srg *e4ULDkF54ɛe` ?}X[n a@gۇJC}ؽ}X^dAQ0 E ŸY6pTLc6QM,rcgGQC&Ƈ%OmYW&ȴjc+Ngwysn} h^:[{%}#^8rB nx3OG8 PCFRWRؕtB> y׉4P|T.||u:u,?v%w7..JZ'`ayrWj{Z޺X;]x Nwj*#.i 년!tFYva_KbN1WK/%E9vJiaq2MڛN׿. ·fDboN'*Ǥ'RnN'pm`QTkGm~v$ K C ĬtBL?a֜@˯r$2c-Y櫆f64tf5<l\;ٳq= GaQdٽ}Z24H%{B޾=eN {y!Ijx,cE}&p_:XqR>+qc|*KJ 9b<^ټbl؆!D-~XG-і|L ͵}N;ϕJ>|ٮ`@w?vnk\; Æ èQ ߡ4)Sߤdz2-DcƉN/?tb Ne([4-kr0qqQqN[=OD:6#)]I"í5^dE##nY&J;E`2ulv,.ဥR~ԑ3CK79'Yd}Iupoᎏ0F(N6~FB1xB{O2q1S4UuTūHM>=dl he0gDzCėӭ#`AYj#IX9R{,q|P2J,_1NBeg˲GiLjX`p-~~#x}&~L) bެߣ*,Qc ٘<(!0VsܥS1׸C6&&aڤ16m'st >UAU.ȋ׿9Coٸ/aÃsrvck˱ ȑvDk6Ն]G*m74 _ sxU{-7G v0tb<^=q|i7ɔ]M\X:ˋaIV K~풆4;D79iXVU+*qmKF2 kjkj:=5W'[4ɽLt؍D"un鵋7 rw Jײ] " ,w#;VYzqys;>SVQ1IE4k.|-Vlaص#$&cv`IP:EljO%y&*YuI7Ӥymm<*tyZ!PxYyrzZ^4£&ю7xx^\{SiihhdzP`#{m `l?-u%kKu-PEM*,Q+V,nHx-lxkhPq(<]֗GW{yqc奫OD mRKHKWTXw =2%B}(`^'S(u$X12Db;]00bիI= 'b^HCD7ή'j3eβG ty,P;7j?/2Vp،Ke23`΋tC `'M-dBd! [Z'`"vMɆ5h:u%g@$BuBX  &@IH HP Y  jT(]-ޟHJ  &@IH HP Y  jT(]-ޟHJ  &@IH HP Y  jT(]-ޟHJ  &@IH HP Y  j> ՕI>( 졘Ay ԈI$@$`_W9 J ŤHK žgIHTT(df$@$`_T(=kN$@B1'3# BYs 08 ؗ}eϚ PLHHP+{֜HL%@b*NfF$@%@b_ٳ$@$`**Sq23 /*ʞ5' S P } PW9 J ŤHKNLT/~IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_cmd_admin_net_start_stop.png000066400000000000000000000270601322762156600325130ustar00rootroot00000000000000PNG  IHDR#E sRGBgAMA a pHYsod-IDATx^ˑ#f[CjpdgU6 *0"pgf3Pu۽^͈p5 I2gUx9#ɪ`NX) B<^V BP&BP(aP( ebAX) BXV BP&BP(aP( ebAX) BXv  B|r?w'JP([~!^MU]nw w1"Z6_U۟ ~7?o.w޹X'|}P޷H."]^ݽ.aݒ>LaAVSX{?n -{Yi=t v䇈g"uEUFt?Zפ讣*aHce"rκ:ܾl-aŞcwm">oqZBu~m1GB^j6m$~OX%An 1$-&2G%wI4MRz}C ڣ+ōe+cjE#+]i+O{ҵ}[{o 9sViEUL>Z=VINy[OHݤ[&hNL%,o߽vOX>ªݗRe}@yFф(q[XSx?{SX&KR䵉V].W\{}2YKqz[W.1q,c 1GzG]OZ{rhZ{Ew 4H.=[ֽU"Z}q5f Kkw+AK̛~(6{ξr,Pꋯt״G.;*%g!m;:GzO1{r(u)ʏR=PiojEl ʹ%By6B4]BJR(R( 2  BL,+BP( JP(ĂR( 2  BL,+BP( JP(ĂR( 2ª۾? )׿a y~|P߀!p=aNۇuk7Kػ[)LRO#_v;];~·Srk^gxvFqNJG{l|#eUL՗Ek7Ď{)\au! pւqoz=-Aiݟ {!| Z[wΣO}v|Jᓤx@X(| B\_''QXAOghP$NG8kp!/45[[`brqk)}j\r[Y˾d9hIX"pJX?Ce9017g|m5ńL?WzX\$6usW +k\q m<}e;':i?sῬ톌Wk1Je:ޚ;Eogş?øsRWyϭMϟʣSO;;_npe?n/HlF&rp\Y|yr\> y`wPÜ/`m6>-o#uo1ZYKZo_C[߯1A\+7aG|$6c2?$d,gGeO>( oؾ>K|OE#Q5UK\sa A~0ib_ ~=fvxC8paN#iª֛ٝ%{) A{\ϚK6c{FW1gz9[Xqujlwuײ'11)vq:K  ..u^{s3gү_}hYhm{bNL p=aEVam%--[mfO\\. wW>`w I!I\/V+qsI+]~.o 2n^/[R&`o^{Z{?;p>cW^}ﯭϛSÿ6 `-a-pPܡL(q4[slC2uzVtM ssqZl~wk]{h[̿U0(6$cǶ/7?% յW4~Cg1FǷ+&{YU`/< GˁWQ r8a(`?G+ 0`"R pʯ DB!X|-e}# jVW~wd^ ,{ZBϾknZ8x -mk|m6{yU\wӪc6š uyw<-6*t>OR{] ^Št~_VzkFĆ ;ٟL6So u>!J{g4Wͫs:E|#82hQ$R,ݦͫ@as_Z=\?:O%gSe_\_nO{ #bmk{r:)XlG1No]WZ_n}m?Կ9}>^ 2kq\ܔMJMrԹVX=A>_Zץ'+kG݋;_AI#QôOY2#v׮ڟ`շ>~퟼ݘzŰA}Z?ؿ߼5R?9>Ä5ON^Nl*~&>x1!>?1ƒC:`=o&u79||)Ƽ[XM}Oksy׳??kqw>-yl?pF<`_qի7QNLp$m'H[e=r3L \)qϷ7_m1":2W1$tIgk#1 <}f&.74~[ksšڞx|kإ?5U__79U_,Cu(:xD!<ݨD[MvbnN+(eN?N=Uou~k,ӷeUG_±iUÖFߣus,Gg㗱׏o39v?2Pp_Oϯa]8c0 ?'qbp>uFໂh\)Q6@uArG> ֟NQ0s0V "+@a 0`"+DV AX&La 0`"+DV AX&rz|ޮ'_|}^Ϸߛct}~./K(>ηkD|}^NktnGsc׎y?zJH*kF}:*ryd?zsǷyga}~|XLV'"Q$Kv˩_M^N8pº e@u2;d^Wu't2z+yh;8a}_x& k(uJ*h$ϞpJM^Q8񷺞{޽ +w]&^?RI|֥vݗ:[>hE۪mB܋8>wyԿeAZ_ֺ̆\sWGHD?>GXxsU&p!SI.q,<(-9 {OƏv&so%%s F_\_hMپߣ.Kg!!:e &ufuh&~ޮɽ-ocs׷$iC=R{7o׾'Vw(GF=2;dˁG+D.qa͓:ר}AxW۞m_P}P?Y2f<yvZah!ڬO[]#g1II&2[i/I(rdH٘KBr2ILjbۄLF;܍;SeOe~gSKx 2f1[ԭD{5ݲ?iںIYTa_)o>GOI #s*CrX˟i9SW쟴? OW_uSb?I>Oy$gKJLQ|:46Vb!>6Jo߯=l e;Lxp+8$T*O:ozU&!,"t\h".I$5Uvlrj wCq?>ƴ &dk_eod=][۟8LVNI~:j&-4t bYp" >(dzv7?Qƈ}(|Y!9~vbd[~[(co/FlWh_;گu˹9-gf?/!:n"ܵ~%75|mz$V; qo?aF aUAXl|4=yO"ꏂU~ AX&L䋅]~FK|\aվ0x~~J>wV#+z8^X#O^ ZWޒy'fU ]6|&_we_t[cia"[C_sKҵ}N/:&Ž{~?}S2;֎?kaM;wIs=>%u.O}jOkGr>Ij6,L͙p״˾QZ[/6iq~7t;c^`I(KZɫrzm]߇Kr;:{gs}z__3/>Zc3ҿFu-5@|@^KX]bO9ub}'Ϸ֘ >5Nȃ8tDoؿ)㣷7U}J}+u ń7H"x(ĤZ%Ve~5{=udm=g^|^zl."pf}cpp'V򢤿Eܗx$ Ɩ%2$quZ K8̊u,kw=ƭ[ڶVG;֪xo^NXc{]"I*]RI7;N*/k"<7iRhRWK#c iaWF_/8o(+lح|KI$KVw߮!@XgFģ&#{xC ?*#,, 7 0`"+DXXjoCu_~}^#v5&^ZFu{69aEAX N޲d *9@ֵ:|K7ǝ y7U ]6<侏͑OKӵm:~}I|_#~Zׄo?½JFe_v7)e>_*Xi_/i OϾo~aM QܡMhֿoo!ӃJL)?r׵am]˾.$&c#eN5vM6p{x.ǷcO٨";}v43SX"šh>o/n %}=Mw9>y@/y0>mMmtHԵ>ֲR3~W+Ʒc7c^_l<#0^KX]@O{BqcgvhkT?"atO^!4<ѶeveΤ47տ)jN}/򯶟 a^b.0s5?9m9:ծ/s^KX$դU}0CWe *};yWaҾzuk}96m_a(R =p-$!i+1|KNN"6.m^c.o程u{߿?Cw9}q3Uob?@[aWOZV{}捸qQ⺛^NXc[_i_?|[f2/k"<;1iφ_El}E d-ߌh@c`Or]#c7`8) =HhWݏ GsHܡ)|gb p>cͪl֙BXU8& _:c?胰dGa 0`"+DV AX&La 0`"+DV AX&La 0`"+DV AX&La 0`"+DV AX&La 0`"/'zP~?} ||P-#s9X]Bq]%:rZۤs;B;vnk}WBX\nP7b_ݿYWqS#ѫ?#/,ϏD$ U|ɮCy9u@ uԾRX7DNrsz>߿*N> k_YC a0YXDS VA#yL$jr¹5 MOжo?] OB7TbM۵.S쾜/'A+/Vmo}^y[d댱3lV?wٟBzfzh &L*4#K#גvoOƏv&so% %٬s B_\_hIپߣ.Kg!:e &ufuh&~ޮɽ-DDxzpzHsnL={iVwFF=2;Dˁ,%I2osȡ')xAfwES%so1_'iE!q[_mBf?IGl[oO#^gQ'ŌxYaUE."[i/I(rú&l%!C7.faGn~#SmOe~gSKZXSd.oc[k4e\ wWlLpk/Q}ſ ǃ;"Cps5JP-bF7|Z_}'m{B~$IּþtN> ,H'UUgKJrLQ|:6V6~e_̰_˄^x3ư#Lx0+8$@T&'|=jr)S/F{ nE\hAI%jh[%@b6n/8HǓ1~dm7|ikL-=>+akw_}Yool?#p4ӅUONZ qnAi6XNnSO~Ľª-k~# ޓ`D`"+DV AX&La 0`"+DV AX&La 0`"+DV|~սco>j|o%ޮ|]|^N5+E0m\oxa=]w+'풬mk#u?9'es+=^X#G'g!ZdC |7ǝ 7O޺ja杇<$vZ[cia"[Cϵ/I:=dO tG7>Zɨ&g_o_o>ަM.&F|<?SX׷ЊՈZ?pkxX ( فv}jOk+1I_׆_J9;zw%c,4co,Y9]?[nO[? <}0~կ";}v4_g8k;D(C|߾_ ܶu؍5K ;:{gs}z__`|H`i(?1R3~ΗGڟoƤ7xFla,0 0<=pϷ֨, E}oxBRi&My8>myx;v ᵄU{ͤ}0CW_3S7XTaWڴ}GbjVp}i֐ޕd))iwWƥ.~5?ŇuyS ?\.oSGi7bO{|˿>sbl~'P:a˟j}SXE7]DCnGx9amo}}\}m߶;گuC0(= '12v1ޟ=>>?g=F۹?2ou~{ ?_I6x$~,g>e|g_V h;4[L +9y 3qob p ]{/aL1̟r>`"+DV AX&La 0`"+DV AX&La 0`"+DV AX&La 0`"+DV AX&La 0`"+DV.C ;r\%z}(u-8_o&t|^o珤^q;_6)ԍW/tU)~^D$ U|ɮxṜ\Uqpy]+M(W\.\'sCm#5NjhV{Ŏ<=daN)XRº2Vx/Ի7>B۾At#. ]!;+ŚNr^ǿz{[5+0š]z%nS1ՒsWXNCXu(XXBO-De~껤.]6NYI]/^nxs%aQ@wb$|Yx|UqHDž:ר}A k W5;"ϒ77>Ώa) Э72^DGR8` Nu6/EtJ6KWvlr-VEeY cta\RA IuPXC 8/$bt b⮄w!Orq<hW M62F7Fەd6!:HZv(aFlGgLa 0`"+DV AX&La 0`"+DV AX&La 0`"+DV ф?#"݋ F!-KV&B*=QV@KXQV@OXKT ` +@a 0`"Sfl8enIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_running_service.png000066400000000000000000002162001322762156600306440ustar00rootroot00000000000000PNG  IHDR;sRGBgAMA a pHYsodIDATx^{pg *bq؍89잳Uw};˴c[n3ss؈.HFȲX $. 6 F\-͍'3|**T*$2{f2ÓUUh"0 /QUUx@w< ĬYҥKj*Y֭Cee%6l؀jԨظqZ#gDB!BQB!B!9Ef)B!BrQ!B! QB!B!9"J!B!$ȷ6Gww ]qT-߾{Z&B!B$? @Y%nl_9% !B!d֯_}Ftouzn{q=vJB!B!Ɉoo}>{Gowug;V5tbY}'vΡ 6; GNMB!BV\*F2g-?p"l=;0{rzⳮX\ۊ 8xekZb(L]م̧^Vn—WuB!Bad-B-D4?WFSeʺu?7p3XCܻҢo`[)4S%|Z_^B!B(e'!P"u_%?p嵍e''gN 6TnksrM_B!hQAPaٲeD:sf9$h=r{na뱋(ۍur8]A -5ٕk&+m6mZ] j\lrfKݖVǷB!qt) qt$Tx?{8`hT?&~3\Cht뻾BdQ'!~ 3DL[V qL. ~aI!By0Cb$f<#m&p"zXhnGlَ`_yхQwJU ޹?3;3S0g:e]-?櫕Sm| RPN,-!B!@"a<(\ W}9ۄћ`Cl$zŖӷPD[X؃Z4N,i޳N+&M}QL#ڄQ>lX7'G !B!a"'%EEfF?ܹ{Qu^ׂ9ukg6|(J7qjpKM*GhE$CƁ c(ٰCݾbM}з2(B><"Q3KxQ>3SB!B1IDiȘResܑETz;u~CtƝiZ>El4j>}i,~!B!!# ĩbK+jq ,҆UM: B!dUD=G>W+!B!"d]D !B!TPD !B!(!B!B%B!S(B!Br EB!BHNB!B)QB!B!9"J!B!$PD !B!(!B!B%B!S(B!Br EB!BHN@DPTP-ƕW0hq"kEMZD<~0>i*i&蘆9ֹ}?B!BF6qE((EtjfC~aB!BȈgԋh85辦gJ,F"cGAmd!B!#,nQ>ʛMG;fFKOK!BNr$ٛ9L }ң+_sǚ3u1..g U6.V9)ik(mouvdQB!B|FTs8jdRc/'k?yq)UzA&K5;l<[TǠ7R WB!BX|YY !KoKۯ,uH5V};6׳l34572rQ-E!B 2QBBB!B(1QB!B%-rV n(B!;JDB!BH.B!B)QB!B!9"J!B!$EO>a0 `0 c#.7o`0 `0auV B!QB!BƘ;K^r!A}`>{B!`(C"E~ȱi!=ywS#=~"JBXaѓ-=ߩ`B!LF"kYV\vg-<#]DE*߸׿7pu\?|s__s￾_]ĩ7pU?~4yBss3o:R#mU;hxM[qm a߽x(\y +90w_w +bA5k~txq(B!YD?o_8) /,ADE("ڊ￿({[k.|N`͸(m6oq03W|}x mߢ:~99(!B!D-콝N "cǎ2VDK/R EDo޼9hKK ݻRFwܩ,Cڼ2z5rBXaN7]= ;n/zA= f,D*-~6J17oC7ضm.-7U^J5 m=JDW3>|MNPMW-pӧ "HDΝ;yzBDDgn}^19-gF_b4<j^Vq-ЯpF7_Ğ?D֠͗?qA #OnW1*yU|wtž>-xw_]L>pܹs={n˿ːDTPQWBEƏ?,"*B=Ti<"7זп$ԛB!2R,n#wgOM ]~׋38 ھ3o6fϞnZfV  (Q1cz\Q>QDxO Is?IdSDӑc̷:혈7cEq%Nqג5-+pL O7TtH%w.ُ뷫Grg}'?W3CPQ? ώ7UDσʲPEy#2#w{;9Ÿ́RB !BF'WH-=x?}7Nf8=S97|3eEB'\d}˖-N`9#*i"rMs#"LD7\_aϟ!v ܺ_#~DU>R,%[-;Wc|۟X2(^m+eק+A=gD xj hќ{籤27So |3/=xp/<"- \oΕqGq'NW^yEb6DTfpM.X0ID)B!3.2:&wP9xd&T̈́DxᮟIdKDÆ"WƠ%"_uW g~7xCv*)wgգ׏ƭ y%+0÷1cT?W9- OXaGmx9fsr%/|<1|8~[<|o1\"*- ""焃6mNyuK|\$TL(%B!dZDWo)}k9Q"BT5gDuaQ36\b7wq5<}&ED oܰdQyLW~Sw7q7c[Q!eYzSfx8<7X_kHDD_x+Yg lWm׎ȩ$mz > "%B!u"1b8*BTt jKr67DD5mGT/wu޴$R>RM[B 0z]$t7-OC)6g>| ᭓~ի-U $ї1~QB!B:ETl: k׮,BJd*}J*[oEtIa+l2gb C (B!dŠh"/cu@!BH0cNDa B!˗"zI`0 `0=3ׯ_g0 `0 c؃"`0 `0E`0 `09 (`0 `0rQ`0 `4( `0 iEKyg0 `0cSD !B!$hoo/cEX(o3gTd8DE>Sr ؁ǒID=_^y>~ G%PD "O+WW^#>Q+Q+IiET)6v`μ8zX";_5Tw!HfCB7zBfCQ+dXao~E %!c'̘0aoBZz+>-8=ڦϰyG Ʋ}X}u/t^-^{gsm%KymJPcd01K0']Ms K"j]C{Cy+~%wʈ:y%e.n;#72:~#k܀26qnQT$s7a Hzog\rG }ӛ~}mtݞ0| ߶Tm{EˏI/Rz]Kuv<}XhyJKPeG[?ߚVOE(!c'$s"z0v+6ڶ4":=4-o*6ݷPIksK;A4RKO2nFjgDpҲYƺк`7 Zw/F{V^*B彚thK~DަP7z>z!$ճt3=W! e:1-hm8 /ÿA!պ]і/ET&tf"j99>n>mH,燐k ~A@%dlDp˗~4WB~e'{Peۏ`] ju-So_'~uC=Im$–5_=T"fI-uIx0<?~PD >IET@aq~CUb6|yvDZ k?+>C0+9~%EaZ \Tt~B.}BLh7.q#}io\>}k׋3IOJ}b#y5=^y>rQ z/am!u5UF0: H׆ڿ>4?`I<"J:>Q+)E`0 F!d7%hUDWJ:{nۯ7תcȎk׮1 ~׎0AG "gu{d8v^zGjT;ckUGz}xSF`0l52vE4+"k[qm :{z}q:{Aq$؄ I3)zǣ,Ǧ (({|ˌ9W]Ծ8z<:ʯ pN!_@os{=>‡zv{ ~9܇QBj}Fd:Z~n6"j_VҜ/Fߵ$(DQCaET<8ٜzZo>sMN]\$! Kx˸r#~7fPqʕLtK*5CN:OV}]^qp=gz{SH̱_GZ$,"o5y~<&1pppsۈy4fۇ=9.5ocG0ż5IQ )!c (!PD"*lUr~֞ɱ%zQV]DLSD+DHv-V߬ޞψ~7ťK46yw]f{w [ﺴn|~gqq{~_`}#[/=G67םz)?8/p;K:Ak%ƫ5ԎgHן~i=)7v%GnWuR>s۷eNRreR8ߗmmÜ{ICZ'я=j(yFXIeK7-U}%zFU_DLYHSDu֥ǷJZ JT*a y \|7xbza/U<o9z[yeUYN*>zVE =ᝇ ;|Ƹ=۝b\}Þ},Fy>"}ʦ[}~i᳝j_nf??ow&x;&sƩ ;fZr>cK(y]Я~SHUPD {ݣF "gQ7~^we=8nnV.Is>r$>9?JB 5SpBݎNGaů[}"V=}XjYxT!+l1'΂ ?k~0TƘ2*(e}j(yFXu^en1u]7u-uuɦVZyCЏh<+*)N)#7H{#)x7ϟ_Q ¬=uY.C8y~!eCZރY7LsvޞYYu'9<4 {ΞYxӆRJoͱD nw;ԸL5t*ЏE 1mӶ^w,2`~M0ԕRSH)RD ;ݫF "gDQAr;g.R낼nz<^~>-EBv%TTyYH Q܇ F`OJK'͎~)e2zWE4DDl Sg&/1\~ѱ~)rS a .r!qOVq)Z?y>yp}`z^\QTRWF]!ueTDԕQWD) W@3)O^_}B>Q4[}d/oUl+~**!7 rʧ+rqIOEoo'N0xě?Oco9Fpp2{=prpՕRSFQ&ݻwQW@3-A}0~"φ*7,ȧ.l?~ǎѣGq>|XE,c0 F{=k\#Z \G\!kL*{RD ݯF "gPDGg"JBݙPWBNC_~n8p@ ^ VuCT%2K*)טT2.Eэj(yFDd_\/;w۸un޼7n(Qo `0Y ONPQo188Ar-k\8+JDLBhYC,< W_] N̩̒ʿPM! "Q's#ad"JGLBQEtnOcXCQs >1CpKh*Wij BrMGs Q\GOyǕQwfTIrm Q]F !'2 "gDQ1^Cmr7uTÜϜRdET.ຈ͆qǦ$(B\S{ YQPQ5gEuue"JELBaEt~i9;8ulǪN,9t_DUGmۏ׊785I1E4lv\QBrM/obnYQWF}D7ݬ(Eы@3Šmg&dL=-ŋ3aV^+k&M(*(._XE+yo@%gs 4cʔT}Cf:?Ш4*/{<E_.c-9(!l!uyI<# ێCƎLYMZWĦ}}h>s ]0uqcbWBD J޲I~KPXX(c1LՇBXz%YDcG=NJqȒP_n@BrMuϕgEϥ2}"(yFX]$snϼ^$(oAAl=zum8}/^J<-G%r쾆l3U4C_ODW"z},cL,x s"*||5EBHkx߬㹺2J}>I<#V3W}>o/^$ha-l=v3+NxKzl},5.ZNG"e3^yTS3jku+J^E2ڃ9$ߣ"J!$k5GEܠYQ\WDeV"JGLBaETًZLYUzQ^]_aҌN)^$%3g[']ڜnM">,5#{ |jR|Xc\k\'pgE%dD&!PD":mEJ?ދop}t@uc 귣 7;| [ޓ.V |K&x,%uͺzڙJ YW>R fY$oLK9Xi ٝ EBV8!yR&,rMٿ"sxhs)-t$hVD_[o,%tG{h<[NBUleoksK;1aJ<9iӊ`#dYBA#n}ҬQI +TyY6dEq;j~\o˕)}{X5plGX@)Cif qx㔛q"tpoc>Q:NJ= y[h B)_|:~OT]|{~[+xOR_&1DC,xts= O"׉\l_PLGBGC77=r7g*5e޽s/,2?'EQBOdE4ψ*«Ta;g.³S'Ö/OrvSXX#@Z.r񖋸^ Qy\*s>i߫7riB=9:3hvzGnK9.S>VT4éG"ѭSIvxvOB5lͷ c ѦN >T~@#â-mxf-d<#d ]Hqß[:tpG)y)1)I1íFMH;'t3pm ::)VR΋_> u,yJjV@CbM +榛[޶c]. n/ }oN!j !cH%'eB%OdE4DD%`Amuy5mL܉0_<>r2RWu>3!$ QBD&!PD"|{7w`է1iӨ9pt`~!Et8 "fFP`Py3ccޗ %$2QBD&!PD"*4ƾBkW]\cSS SDG?UPadh~cAh"Jt$hVDCq<߸SW`vjIJN쌝CATuaѶxxSd)B*QBD&!PD":k[b;(ٸSgiKuXmpʠ%1fZr$0!&*?-T[K%ࡈB'2 "gQaq;i3I`شg.vrLŠ˒dQBm^u/М%2B'2 "gѵ1K2&k%NN]֣P\׆ӗ:9:y"2ZX/䡈BIPD !@3ŠhejEeMQTTO^WяD^Q_?Θ Tw,:vݎBC*x4?U[yx)mPD !d (!D}"(yFX6t%gS489{խsa}W4cc"¥˗%JqTz,qƺUVV_Ա2\~d< ګAc1Io/<"z , }|qcFt3&<9Ό8Y<"J!$kPD !@3ŠM(x/ZqzՍ-ߎXܰ/%n݋K6zOX& #Fg %jf"qrN4sj X}gCФ1 *z;xe4}<NYQB!ق"Jt$hVD_[o,%tG{h<[NBUleoksK;1aJ<9iӊ`VJ ŠH:ya%j}u F+ =Ë3B(!D}"(yFXu7rw/ʶX6Z0n_}gdS+6t+b$//ģ2ꙹt2x4W6 PdEBƢTr;?[Gt~ 4(<7D "gD%u*L^T75`ƺfxs \\'P\M]ЎxiVZ #֚CcJ,M}iM|.@I~۬.cBr^/+چ y4W>#j-SD B5hUDW?w>TN]g,POO-_F<ݧsG{-|~ 4(<7D "gd"At[Sфڮ>â-mxf-dPD 1"JsC(yF6ETsU'fW( IA%!j<#"J(`0FRPD !ynE4Ϡ.( IA%!j<":nsᷝ NPD !ynE4DD%`Amuy5mL\X"`0QB`@3(уUư9/N|PӁ՟cև" wVk`<B5hUDW:{ q=޸Q~ s*?sJ"xÞ/A<#)(<7D "gu{v;7;غ:;c}yU}Xm?^+$ل" T}IA%!j<#ΫږznJ60~R8cnlE[2h k ֩i҄"~+%утG1{D(Ծ/Aa~)#7(Sc$E"熨!PD"*l;5}{;bg0mf1~6iL_5TwNIXr(ɉK"}VZimKpfDOr-Q̃1"JsC(yFX]$snϼ^$(oAAl=zum8}3DԞ HAhIaI"=GG>4A)~ )%C#6u;6eAeB5hVD+ێ`+~7o/vrTưgxq 'GGQGKz*ˑt&Ե@gfNQTTF@_.|qKkD?a۶x9+&n.1A4w;xH+3M+q;*iV(|vZZx]͔cș* Md4c&mghoڣ2FRPD !ynE4+†^DVVbʒ'x{= f,wrLDtµcMXmzH+2FRPD !ynE4+.ScvTE#Xu0{] ,lj1ntp#TjC0 ӆGF-5n3瑫tc:h/tyǚx4g__S^%l3"jA'\nz6&hLIǭDqŗ5Y پHOGWӍon| fE"熨!PD":[ɋƲX׌Vo.а+QV/*W6X%xefQݜDŽasSۆO_&f=Syaǒ8*Hy=Կ䤥 MD2fϣZ$ʶ+B"*g@NDԜrPm$" _)l.YawƳi>"via1ю__{Z{1v"IA%!j<# ~P|NY<[<]Py[Oaa*d.rQgDwDGETY#=+! G:Am8Yr/}DԙyKfmĬ\@Ic-JѶS;8c;_|ңhnv/e"IA%!j<# œ&vfomio3mQ%C"@gX%3κ)zY=O%n9M8FDQ]h 4I7I7Uy3T_RFcGB$h/mElo'"H(!D0 QCQ'MSW^(^IvF#7c~yY/"WɠvB8"IA%!j<#"Jh4~g+Fd8fC%(E1"JsC(yEttAhaɠLewQB`@3( h4(#7(Sc$E"熨!PDLDYv`A]ZWӆ٫?QdxFC`0ߵB(!D0 QCQEtnOcXCQs >1CpB%+(熨!PD"*4ƾBkW]\cSS QB!"J ynE4+`M!8vowug;V5tbY}'vΡ :h~VI EBHBb@3Šmg&dL=-ŋ3aV^+k&M(*(?Z?Q/Y͐p"ɑs ]0uqcVD#nHWƑk}s9#J!$s(熨!PD"9fIDym#yIP܃z0qR'G":(BrE5hVD+ێ`+~7o/vrTưgxq 'GGQGJ⏐*StRYӽm:iAm:$W=@Pk꫰Ju6%Hm].=Ƙ6╂ˏ[i/"J!$PD !a1 QCaETًZLYUzQ^]_aҌN.\&BXmzqڋޖ,nUFIH]\\> ֘9"Z<>BE5hVDhB{ ܼnlAUv}X}u/t^^Q{5U4DR!hI$7y6S/Tpo9w̍'h.!"J ynE4+-؈7~M]u:=4-o*6ݷPxh90}%4iETDf A[݆N"j?;tMu/QB! E5hVD],݋GV `̩ۇWc_Y,Ԋc(ݼǩ"uTmfa ʓtMHގ]..oQB!"J ynE4ψ*KUo,kuxke~ Ob*e{Ҭrn#bFD"QTؔ鏨Jz6}+[QXBϗ_4dM4jo40jxhn(!HPD !a1 QCQETx*L|CExvyiT:} k?WyDf-kh;YDU5ΈB(!$,!j<# œ&vfomio3mQPD !(熨!PDl禩W߫POVEB؁"J ynE4ȶ"J!$WPD !a1 QCE2Bb@32Ѳ.g XPہujy^MfD-aċS3ICwaMs _F́3?Ǭ)QJu36C U(cS _Z:)Qa߶"JH>@%<7D "gDQ1^Cmr7uTÜϜRd8"Ji $>1=kEE5hVDCq<߸SW`vjIJN쌝CATuaѶxxSd-k<:J\Pd ޤ˭̸e~q'nO7UXҤ^vS8Y43mN QB{VK=sN{o-(!E5hVDv`mK =7?x%w`y?m)^ 7^5]4oԽb+ 8A:aʌF zi~%stBWK Q VuM|=m; G=jtUi\%MÈ+(RZaEZȧ_=-m'UzLI2Bb@3Š8m숝٤EN0}Nlׇ3Pu SW;9&"&n|d Sf0ET>Jpp$3i'znZ4f}/eܽ⢙J tӇB/g.N%dC%<7D "gѵ1K2&k%NN]֣P\׆ӗ:9:",Qu”=*U:J|W%O.y:c֍ 5]ÈPN8ҭe5jnJEE5hVD+ێ`+~7o/vrTưgxq 'GǑ.A2] ;Cׇ,|1EB-1E48;#jy9WdAxq hYUץ >]0 bGsuqփ͕3V~\+9N7BEE5hVD_[o,%tG{h<[NBUleoksK;1aJ<9iӊ b?#LP9-]uvG,CPDF }U.4bPD PD !a1 QCaEeʲz܎ݽ(~n`Ufk}>5ŒMظ;{."v je<"J!$WPD !a1 QCQEtrI~5 e o/\7Wa WlSeW5~/^UmDCD-k͵x.ࡈBQBHXsC(yFT^ P-?;u@-?=y|y8vU`dIe&PD ! (!$,!j<# œ&vfomio3mQ}PD)BB%<7D "gdSD<7M^z}hzPD)BB%<7D "gd[DB%+(熨!PD "J!$WPD !a1 QCEBHBb@32Ѳ.g XPہujy^MfD-"J!$WPD !a1 QCQEtnOcXCQs >1CpB%+(熨!PD"*4ƾBkW]\cSS QB!"J ynE4+`M!8vowug;V5tbY}'vΡ :h~VI EBHBb@3Šmg&dL=-ŋ3aV^+k&[Ec83Ӿ/AaTdaBQBHXsC(yFX36?މM|Naj'ф㢙字UDl PTDt=+xo *Qe;0/Ÿqt@q2!d$C%<7D "gѵ1K2&k%NN]֣P\׆ӗ:9:":җq_7&Ba5 #^D=؏BGF3J?DtEt&(7p X(熨!PD"Zv;\A;|{5=E̬hƋ3V89:"vaDԖ5ϬێP>N,Gt["ZexjEE/-,C;3:"JyPD !a1 QCaETًZLYUzQ^]_aҌN\GsElA=h `Y}:NUQra}Eҭ{zFU_ &3'rI@ܾz>"ا}Ibfc>̽=zgCx!1#sͭ ZDnrCmMwD};|]´_mY3 &.>&MD=P/nMS2zBb@3Šk 6⍥cqSvh|b[ l-5Bqy-{Nbi}'&L_''uZtaHV왺iVr`Ȇ!E_>3Q{"l&v Tᴗ$8~m-BcgDGح3ɲYFot+'=~fM՞o.uT~ H3?]o^΀J؇"J ynE4+.ScvTE#Xu0{] ,lj1ntq$F>!t%]cRe!O%.) sv{ Mǖq-\߅CDu3@ N/hSϾj7=߲ t O8?iӠPD !a1 QCQEtrI~5 e o/\7Wa WlSeW5~/^Umf7`Ȍ _ɀnEDz<9NOz9FpJ|#hoЄǽ@;#[.Sr0# isΞ󕐫D]xX^_=|в593`q(βVN5铮cd{ߚK؄"J ynE4DD0 ]}ۇE[d[TSw")C_9pf_M!c (!$,!j<#"*i*Ek~`?9/qq#!ZQ hl(Iw@\(!hPD !a1 QCQ2I%2"Bb@3( (!\A%<7D "gPDGQB!"J ynE4DD%`Amuy5mL(!\A%<7D "gDۻQ>aMs _F́3?Ǭ) EBHBb@3 ]gw6N^ws:ڏaNgN)2PD ! (!$,!j<#ίۃ5-yq֝XЉe;˃âmZ&&QB!"J ynE4+j;%;0u</X[{ Zoujo꿳fPmd7ߪ,w.$ۗ;!{WDcX(BQBHXsC(yFX36?މM|Naj'+ME"+u(9t5n7|'gF"J!$;PD !a1 QCaEtms̒Fi% `#%i$ h_p™5EGG̈<)BA%<7D "gi+P^7U-aw_DK(ݺlTuzMH4(rcQu1}ϸ&d~y"n̸z6B,8>3#=<EBH4(熨!PD"ڂxcXԅ].s>Z/Crb(} eP\^ƞXZ߉ WIsVMf"Ma͓n2]#="i+9}ll;;SD 2E5hVD],݋GV `̩ۇWc_Y,Ԋc(ݼǩ.%\g9Be=<\w+g>, ҴP7!Ӊp"ZGET=<>RmPDG9ټ$LQ"[PD !a1 QCQEtrI~5 e o/\7Wa WlSeW5~/^UmKf]U˖Hy(^6zr ɍҎOY0m1 Z]v$f_%eEfD'Lx4o]EtC%dw~ق"J ynE4ψ*«Ta;g.³S'Ö/OrvSXX#@Z.ڶ?rS]X[&"0' 2@e(g F1#%E5hoaNEjPɶC%QM>'NDͯ#@I+p_L#ܲάj3zXog\1h?:HvWXL47l?*^^En?U;9nڙg_:Dj=c 8v)sF謒aM4QBHXsC(yFTc_5+{.z.^GU1̩)E'rC+7n%M-HWu] ~:i9d&ue[;:Gzp퓮o5 Zv z7AeS;# pd-nyLK]sspRD !#5hVDv`mK =7?x%w`y?m)^ 7^5]41񙍑Y}R6xd+CE/<#3j3w>̐H=]oW/`0Fkn<Co/Iv;?GlA%<7D "gQaq;i3I`شg.vrL*CDdw KDGaml|?RF>t?(In_n;$gh>ns}1fD !w~ق"J ynE4+kcd`M6K=h8G/ /urt(CaċgHIAE _Vdȥz\cfY=_K;grs E9Jd (!$,!j<#V3W}>o/^$ha-l=v3+NNr|- ^AY^-ǘpURu~QTV̟E-ZW> уQ5>mDA`Jd@%dw~ق"J ynE4+†^DVVbʒ'x{= f,wrLPOeK\C!4/M?_("jXlAǙs:n\vW~yEΌhB<^80Et ^MsfD "GPD DBb@3ŠM(x/ZqzՍ-ߎXܰ/%n݋K6zOX&0EO7$Z<[hJZ- uBdeT[@ᵈ9 \?y/o3D46:X}dhя،hB%dw~ق"J ynE4+-؈7~M]u:=4-o*6ݷPxh90}%4iE7=,cYZ|LJȠ9jʲ$Zq_$y h߃Q&jQ@%dw~ق"J ynE4+.ScvTE#Xu0{] ,lj1nt 7=,'X~jedEоVܡ=bj}4lKߣ#1hnB%dw~ق"J Kwww!"gD%u*L^T75`ƺfxs \\'P\M]ЎxiVZJ/]e!(Ϟ1L|SIP_N=IKN%IJ dhiKϳ_~d{a[p"̗=wj_V)("J%E? rn(yFT^ P-?;u@-?=y|y8vUh"lI/Z.rѶEE]uco!9"J%E? rn(yF&"Oǿ9MC>,҆_g&ۢ:*Y-Q(!csQBHX3lȹAQ'MSg,?Q4[|u=j; `ڏEynnmmMJK-( fؐs@3-dxrFt,@%dcE8MKs#[PD !a̰!"gPDGQB%dc]t\7#[PD !a̰!"gPDGQB%dw~3Jd (!$,~6 PDLDYv`A]ZWӆ٫?Qdx(!cD QBHX3lȹAQEtnOcXCQs >1CpB%QB>~g7IDB'aC E4ψ*Bc+tށ8yzoEj?99p@%QB>~(-( fؐs@3Š=Xr;wplَU XV߉s<>,ڶopjlB%QB>~(-( fؐs@3Šmg&dL=-ŋ3aV^+k&+s裩{EV,_¬n_QܷP|"J%E? rn(yFX36?މM|Naj'FM>h_X ?hK*E4o2;?GlA%O0ÆhVD6,(m389 ʛ{vq[^@q]&N_<@ kYQ%FhmCQ^-QB>~(-( fؐs@3Šhe6[()Lk*J%e C N۝5//p;r%ǃ}oO^LJ ="r[ w~v EBHh( fؐs@3Š,m?;ޫnEht뻾¤˝CH&mJrKnPBB$-Td%3B6~iI}m>9D{"ڞ &fD?ĂAWD3=g,VPD !"J ` 97<#N[фҏyP؂(o9 "_Bֽxd䯋kC\y,.a>yqb)LO:M} '$I_ޟX2i+hF{ĪF@"6v]DGs?³?ƴQB!᠈B'aC E4+-؈7~M]u:=4-o*6ݷPxh90}%4iET瓧Lny/)Ԅ3@t-T9KlMuj>uD<^2Ռa}"J!$;PD !a̰!"gQ)1s;*wl뺁Umsa{K6bJ7qj/M$\ u|Hw ÒDަwR"f~"M/v J_Zm/8*"zqFBHB'aC E4ψ*KUo,kuxke~ Ob*e{ҬrncZQRM馠y٢gAaΈ}mӷyבI40ǕjzlW~wzl"&rFBHB'aC E4ψ*«Ta;g.³S'Ö/OrvSXX#@Z.3E\.rQ\X[! (!$,~6 PDLD4 s*PՇ}X LE (!\A%O0ÆhM~4{?Q4[@%+( fؐs@3-dxBQBHX3lȹAEBHB'aC E4Ϡ.(BrE? rn(yF&"Z, j;C-ϫi՟e2F( W|+K<O-nL!Z}{VIk#i2^F=}Br E? rn(yFXl;g|Tߌ_IPÞ[z"fV4+WUqou3̖Wtygf)('՗dn"ijVẕx2(6 ~hT^4ㄈGy<[DDWnFT,*ok+z*ǠpXzmuT B~( fؐs@3Š,m?;ޫnEht뻾¤˝hɬG͹.b-cɟ;iJӆ,ds]Gtۍozy>E41#ZanLDt3&X}Pkψ}ak RDmrͺ~meRw[fy>1zD<^2ԌQ?6RE4ɶʺmf]߶ޞn ٯ%ηY.MO-\\xg=1W>e,>mܱ1=;{ Q"nB}Y!1E? rn(yFT^ P-?;u@-?=y|y8vU^^8ibΞǽ@Z}FԺxE\.rQQXe;x9o!2B'aC E4DD0 ]}ۇE[d[T5;ә@ͪ)D&"yf"J!$QBHX3lȹAQ'MSW^(^Iv'#*G )(!PD !a̰!"gd[DNDGs/^T7QB!QB'aC E4Ϡ.(BrE? rn(yEtt1E4M(7Η1~*'Nƕ&S)i|9.m)I?ScK 9&ϷI[׷*cci 5d_mƓqFھPD !a̰!"gd"e ] :6^Z&Qq,ynLퟧ1ۥtS;nrue8t#~e%]I-IVEE PcRݿMKPFRh3*A۞u|(3 :cFھPD !a̰!"gDۻQ>aMs _F́3?Ǭ)ɈQ&&KZ `ؙZxC;T#~tKE$8Ϙ4DlQM]N~Bc۞ezϐkinB%O0ÆhUDW:{ q=޸Q~ s*?sJ`DIڛRXrk%#XU_G$uQ[SH {E/#6Y".l*olr5'ݜq~}#L;.R.>$]sIۨNq3&3ۋ{CSF0mJVϝ<~k>mio=wN~|F١ 7~Dw~fzK (!$,~6 PD":nִŽcqz[wcUC'wbg/k$-51f<7Mkf=Y7Ҷ_so{T}m:5Wh"?ۨ^}>6-?zڏB(Z)]g5N@z A[vsB>fV}($v}V Vqx_ROPB'aC E4+j;%;0u</X[{ Zouj u#_RhD݄]~P7%onL@ -R%hKCO7˸Qa ZKwWrm`z%t|OYGҵIO/Flٷ*~>긤k3(]`ۓp8,Vb4v1o9f9X!f k[,kí ҝU2t( fؐs@3Š8m숝٤EN0}Nlׇ3Pu SW;9&rVB?tn|Ʊg)&\X":CxGQv0Q }HTA7xj+n%,UHeGG_V0Nt(U;fN);ķWO)~PtmK~jmA[Y .zzr*r[~۪㷬 ҝU2t( fؐs@3Š%?p嵍x''Ays.b (kKA)DQ%o9$nD>s=ѕr_Q/4oerQA7t{mOgWxXbBLв_+v1)Vγ] ҏ9SOK{6GBuNx*j[R^Q}rm8ZHofo>ԶiFm,ۮ:)]_GVqdPD !a̰!"gʶ#y Gۋ1.bfE3^ё9Fźu(Qn˂þ)ˈo #f9$vi%%cumE5 ?¸ t#^y WDRc(>,"/<ߟ;{𬳞KMӷDbtSwuͱ% ZKwax}MY?cZ+i3 &v~^.)Fӡ;KzzAw[ÌӏO`!C%O0ÆhVD 8`hŔ% N^u+E{X&XM-kr3yv- (YKeoj] g(_0 [ &rY2 +A%O0ÆhVD_[o,%tG{h<[NBUleoksK;1aJ<9iӊ˜3kdIW|&QזS"X̫iPyuofpڎ qQD !(!$,~6 PD"2eY=onG^m?u]7m׵`N>LzbɦVlC=NMCϧyuTg%f/Sk[_אLv6-B@aUOmxڇQB!م"J ` 97<#N.ïVa:35㭕uśK*4?m쪆vKպ)s"b(~"mPC3O2+ FғeR3.}x_9#z +BPD !a̰!"gDQ0S) ӓa˗Qj;ck),\Qb-mܰ?rJ$PD !"J ynE4DD0 ]}ۇE[d[TСBQBHXsC(yF6ETsU'fW(BrE5hm% EBHBb@3( (!\A%<7D "gPDGQB!"J ynE4DD%`Amuy5mL(!\A%<7D "gDۻQ>aMs _F́3?Ǭ) EBHBb@3 ]gw6N^ws:ڏaNgN)2PD ! (!$,!j<#ίۃ5-yq֝XЉe;˃âmZ&&QyfHـ"J ynE4+j;%;0u</X[{ Zouj4EMκB_]~P4Y[X0SQdmN?J [ s)B^ FAdFVܒ0'`UPD !<7D "glK?.:w zŖӷPD[(k)o+c 1wg` tO;#_y,BTykYoCRK Mц[WB,W"7)m%g>%]0ţPzEDӴ_棹 F6C$T"J5!j<":"3<C"3jcԉZ8S,9Ki_L/cJdV^ֶ^/nGBJ pEksC(yEttAu*H%@#"`0fPD !<7D "gd"e ] :6^Z&EPD FBrynE4ψ*˷w|GV}Új8gAMWYRD(2tA%5hUDW:{ q=޸Q~ s*?sJ"J( #]PD !<7D "gu{v;7;غ:;c}yU}Xm?^+$ل"J( #]PD !<7D "gyXCMA:{O[gh뽀W-a7s:5M02dmyMKm_"J!dxBb@3Š˔e{Qu^ׂ9u0}j=%Zqw 85] asf ֺrGsuuMVDn+Uyuyh%Ɠ, z4|>#h%EBPBb@3:jn&/0c]3ZY_o.B(ئʮjhGY^4\ۘ&o~5hBɞyI8=vyP MDW㩂QD !"J ynE4+kcd`M6K=h8G/ /urtla+*d4:},*J!{"lPD ! (!$,!j<#V3W}>o/^$ha-l=v3+N+hZdD͒gʜI:NUQra}Eҭ{zFU_S˘Sg̠-|Vy̦*o#yY쬋G*m)܉~ t+xKDO,/^{4wP}g/%(!$,!j<#`#X17ua׹Kx. vBY!ע$wbxr\A9崖졞-^"X̫iD4 ӇZ9xi tRD ! /QBHXsC(yFXu7rw/ʶX6Z0n_}gdS+6t!lLZ7__Nh.vI]m*׶"Om~rxceuV澂OgD}uֱB QBHXsC(yFT\R_ͭEuxcYfk[+7UhTU (ߋfuSD0uQͲُZZ(3â-mxf-$S(BrE5hM~4{ (!C%<7D "gd[DB%+(熨!PD "J!$WPD !a1 QCEBHBb@32Ѳ.g XPہujy^MfD-"J!$WPD !a1 QCQEtnOcXCQs >1CpB%+(熨!PD"*4ƾBkW]\cSS QB!"J ynE4+`M!8vowug;V5tbY}'vΡ :h~VI EBHBb@3Šmg&dL=-ŋ3aV^+k&((jrֽLk򃢩5[VE!ҾHъ `<(熨!PD"*l;5}{;bg0mf1~6iL_5TwNh! ӑ-q$ؔ4ki5;d%2Bb@3Š%?p嵍x''Ays.b (kK[,5KfX00(Cj&оEBHBb@3ŠheUlOFC ^FT7~Wޢi-3I^lu>?LR !Ā"J<6D@QETHw0<->wͯp"Wi-* jտ=ǰq4CC<*Zb2ET.#̐L_r4qENɝ_7#AJmYM :z~^Ǭ[U(!j=h^DP_,'&([cCјa+U}՝==@j,_S+bذ_1GX]^KoT+k%O,E&SAgҽз몔FHjd&o$tH{ JeF,~uW!}s[mPmDGmBfQB-!jh̰Qॿ7H:VģKj`Σxt]ƁX+1qG*Q N|fp'n\̧L6`Fz>1Ox _'GނmS?5 [~s!ӷ7_2B֭_ިsˣf !(!5E4f؊议#8=zuxWk7p—lŢ[?tdԴ3u1,MS" H?f)fLgN'ڈ Ғ#.-sG.>25OެB-_U}im\:fަvg\+wz=BȬ"J<6D@"~_?;m]˛,=iobu}z+¸`Vrb^܋_I"ح#bW'[Ok/KeT`>b~P}dݾbFD7`|^u5''ga&1{8"ɋ7kܟfmB~wru]} VE$l9snƟoyr_ZV2+Bl1 Q#PDc #nbf,5zcɪ7@weA%# l^ש.sFQUS~>dt(k//&Yͮ&B {φ+r3Ng#9E s7"4?ydDĔ[Ebyl"3lEtśItg}khFCauŦS;x-oaこx>O{w1&fX_tq3ꆎ0BeVeo3o=}DZ\;}Dgm̭zm4K%EFޫ!dA%bF [}f^>6un{|_|kѐ*1)cxlzA-Ats>k!b[Aso]iEACue u.DZNBPD !dž(1VD}mkCcs|wwkvwcm)މS7;'>ly#~[kr}ЭZj^<+U~X#F>E32ޚׇ(B&Ebyl"3T ~Kk[¶v݅/n~2*;ڏasI,~Nͻb&Ҧ^.q퀡[jW?oT2&6<\U}GDx"'5BBl1 Q#PDcFT]׀EX^'ը_-Bװ3hWCUFխ17;'u%I^^KB QB-!jh̘_N4\A+m񥮨&O'[QB!E"J<6D@QgOPϾV\IqpOWeWi9's9SD ! (!5E4f[DIiOЁ[s)B Ebyl"3(3 (!rA%bF ̂"J!\PD !dž(1c""}jPҧzf!5MJEBHBl1 Q#PDcFT} aǟx+揮ukCux-h)B)QB-!jḧ*BGs ܸon~cvϟZPD ! (!5E4f؊hu }G.~wcޏmm8 _ jsz-I1"!~׆xlkDOBl1 Q#PDcV5aWwC02}G|M؊vcþaMwy-M:߾LvzAFRH$*Q3𧧊Τ[)ڌd$vK*My}n2E̙3$bs)u fѰ׈[9>|l QB-!jh̰Qॿ7H:VģKj`Σxt]ƁX+1qe"LV'}mEbyl"3lEtO'8z6~wں7y%Y{81z..,\W˜<&9_t3OȈ:" ?o42XOk/KeT뢩?9sLyuim ^荈^\O7"ѦO~GVW"zxŏ(<6ɇ"ZcmBl1 Q#PDcx?̽wmhh;~ {o-l6un{|_|kѐ*1)cxlzA/N]HZ1DYH"c|>P%SmBso9sv8y$V?vvhޚ{;M޼܉C 9$j"rDO&^o^I铨GV7ʹQ7 ދŌdYk([cCјa+>˶z19>͇?;5VVĩ^Oc^KCԭ歵aV\S4 M!;BY~Xoun+Z߶o]V.'?)~՗_x h).*^lNS)|I|r{Ǖ8י׳k6PD !dž(1#.M/lkǪ]xi{ ~/6WԼ)^"oQ$-{K`IVIm-^\(Y bzm{\ˊC㧉O{ߚ{|5~1VߚۋƦޜe6<"ΐ[ENj(Ol."nDIս9ЗO_ȓxү/̤M3u3&<Ӈv@b+G%279ǟWcƦCcT}mEbyl"3,z-5Zu]uJ|hȩQ-OT[>~D,+dGhbTQIyξuQfd9tُa\_6-)rl QB-!jh( ?{jz|zHE6h~QJ]8f)l."//2(eQ<οwQIyؾ?V<䖍o1læ屌v_@%bFƌb()-rE,tDT._@ETha#o͎\#y{y޷qo FS>1QIy_}#C2(!5E4fPDg ~'yGT̋H~zJȩ|C22+dS#y޷rG9_mL}a ۏ\?t"J<6D@љEt"r*Et™[qL;展#v_@%bFƌo iCMKjŚ4) HC-ol|6PD !dž(1#qxuGOiݕFGt:5CEPDgl."gNPD[9>|l QB-!jḧ*BGs ܸon~cvϟZPDgl.")E#v_@%bF [n9/p\8z ;Gӟa14]Ax]%)&HC-ol|6PD !dž(1VD;{{Ծ#X WlUa_zc&H7f&;yY^Ԉ7ΤMF*&ao{363#U-'E?'`(3H3GkL<6cXPD !dž(1VDs|#X.J;SWubFĕ.j#Ū`# $*R}I"#|J䶉,e%2{Bl1 Q#PDcJ;9ӣP܁ǟOy%Y꺆{s .|ʖ^,Z+ӑdDoh'rۆ"J!\PD !dž(1VD~ocx yyW'qMUoz%:YiҥF [UܟwskO Um6{o5+([/Ȕez[rCqÕzFsq'X 8+jܚ9#(!+([cCјa+»8ؾ˶{%k=h!/Tm ~;ۇٿͶ;xϽPx"zmtׇ[s9"J!dbPD !dž(1VDهM[=_=Dߡ}4ǰ}l8ʺft }mXr;[E0 Lvj#c.Ff3Xg)DANP":QB!Ņ"J<6D@"l[Þ|Xk[NaeN-`46? 2o0(Rg& 1 V357|B@ftloxJD;Ab^ .^\B)2QB-!jḧ*KS-,m ڱjw^ނ_/nj@˨?h?m':5.djP_S/e~/4tPȷ,ۗ>bPF(oovr]'}rw޽5w5bB)2QB-!jḧ*³շkIJ5Uh|pp`*64ʦ4?Aψ:'m9yI\NrRtE?B!dbPD !dž(1c"" k;z|<_^?l?Ziow{HJJh}cnmz߿rU?¾f]K6AyY⚻_]٦B%bF [^ }-cJ<+VQOgN.M`Dl_Pqs ?Uw?n]lη~~ } 6ۨަo;L_,7WuB+dy_ޙ;>ѷQ%m٦B2V7.>>~uu}PD !dž(1VDwu{kϧ,u]C9DeK/xh)VPD}>Jr!nN}ׯN/.ԕ$f;Cg̼qzxަFfx ?]f!fy3yLUXgTh=6yk yl>t>}݁PD !dž(1VD~ocx yyW'qMUoz%:ً 9gG(B.22NU6ƈV.֬yL[0#ET]ekNٿE\\f_n Hy}`g0)_j%|櫓ϳ/YZf,y$ߺs-з7[([cCјa+»8ؾ˶{%k=hgsCXkg }9ے%sُ{C!-rcl_μF6I]yo=u +a m,ouk6(!5E4f؊7;+}Fэè>Mw&Z'|jj*c9j'Œ\'dl $,]M3BDg"9b#xQG;C3}Mƅ"J<6D@"\>}lB!:!=cs9T5cSlmǂؒ^/)s_!rb-܆"JJ&I/45(xw:f Ebyl"3lEgٶ6T?=LJ'=p;zGfw7ֶ85|[ilk"sJێNN!1t۸3XZe.(!rA%bFƌ"4Ղ߮ovw-[cv_S.2CS\uR7 1^RˊvQB!"J<6D@QETxv]~by-XV _ÞΠ ^ņUٴ"09" 3\,mRv([cCј1翄hWPڋ?TK]Q.(ab3Ed_ZB%)"J<6D@QgOPϾV\ [s~ja0EdH%)"J<6D@QRZf$_cI%޼G@ng9_Rh|K˽\~ƗBfQB-!jh̠,fF-}T21OO$HߚXf !"J<6D@љŌѰiAEB>2#ڈg_X !A%bFƌo iCMKjŚ4) Q!2.QB-!jḧ*oDݑ!Sow54uM}nE-%3ND57~,3[-?7K!$?QB-!jḧ*BGs ܸon~cvϟZ<uPV'ߴOXN$[nsRBEbyl"3lE>#pop1hǶ~MwOwLg%2Bl1 Q#PDcV5aWwC02}G|M؊vcþaMwy-Mѩ̽>|D&6|f+QB!"J<6D@"*[I_NJՕxtIWyw8p75z%&USH`eղӑ;ReNDcAbRD !L(!5E4f؊议#8=zuxWk7p—lŢ[OP5PD ! (!5E4f؊Opm ~u7/oJqb>\]XMD'+{*2gH7*_(#ڭ J }I&+u}x3S5܌T*)yeȈeT' 3orEj[F%bEbyl"3lETxg=vc4cٖvx'.CKVᕘ7޴&=)]ESQ7lM ҾA_ͮq> ye8:8#{TQB!PD !dž(1VDWىD_q6Ǝn4F]Ylj?7r68ST~WdʝeR[n(uM ;"z_Hџ7/_ F`s g:ϗk0/4ǻ5xDkK%bEbyl"3lE}xa9>Ct|ZGCz skFЧ֏+%^SGSd/;3괓ed1t$332CRd"韠gD#SψBEbyl"3lEgٶ6T?=LJ'=p;zGfw7ֶ85|[ilkc -ӥ,lT2׸%7oܾ2EcQQu۬!NNl}㗹H&㗻)BBl1 Q#PDcFT]jo7`im ^֎U-xqSO_FeAUwG1ln;ůԩyS\D "xr3;D}ޭg3?w3ۧכ 9[s~Ok~2~Y! B%bFƌ"*<^}KM?O,QӿZZ֏ag bC󇪌펈okyBġBl1 Q#PDcDD4?wy N^Amk/P/uEL(!rA%bFƌbVg_WHQ8PD ! (!5E4f[DIiB)QB-!jh̠,(X9saYb@%bF ̂"JE.T !(!ܘdž(1c""}jPҧzf!5MJE (!(!ܘdž(1#qxuGOiݕFGt:5CEPDI2{Bʍyl"3Б7`x[|z!~_Eg)QR,(^(rcF [n9/p\8z ;Gӟa14]Ax]%)&QR,(^(rcF [jî4FadR`*_ WƆ}=go9šZt"H }dyR#eFp<IEYRz&$'_#GrwyD>2}2{Bʍyl"3lET8x/8ͷ8+ZX(;u]q*ojJL\٫p$.6XjY$ G>,Kn]Dt?$``GDM磊Lٙ,QBf/QBH1 Q#PDcJ;9ӣP܁ǟOy%Y꺆{s .|ʖ^,Z+dӑ(LQw$4g@L4աN/(^(rcF [ ^.M^I4Nǁ7 Wde3@E F[_Nk:&(B/ &4N՗-8KZ`쏎^F<yZ[0S&GD2ݚ;|2sZ_V<|ef`ѧ E ERncCјa+»8ؾ˶{%k=hO{w1KVY_&ƈYGФ3,+"̎yhNH&>w@Yx|O}[s5="SHd^G1mtƫ6/12ǜ*(^(rcF [}f^>6un{|_|kѐ*1)cxlz.0 k+:?jY  ǔLP`T(}'h,PBuu [n92{Bʍyl"3lEgٶ6T?=LJ'=p;zGfw7ֶ85|[ilkc -ӥ,lT2׸%7oܾ2EcQQu۬!NNl}㗹ixk)XD-_Bu|l aˣ +k'WǬ_n(^(rcFƌ"4Ղ߮ovw-[cv_S.p@fET-ԋgv"[lgK/+$g5O7*s0':' ֖/j- ee"Aˏ)bf]\0MX},jB~tƫVPy2{Bʍyl"3,z-5ZM5}iSUMX&"JE ERncCјUD8<#C4Jkh:sP!^y"ZJ(Xȅ*07ŀ"J<6D@QETHw0<->wͯp"W(!rA%bF [n9/p\8z ;Gӟa14]Ax]%)&QB!"J<6D@"Z܇]i 5Ub+ڍ z;%s5߯4D2@" F)!6 U<y.LHDOGn(!{([cCјa+KoőuX]Gz%ʝGީ+~W|SWb^#qAR˪e#)T8~gYt`' 1k9"J!dPD !dž(1VDwu{kϧ,u]C9DeK/x\`q;3[&(BEbyl"3lEtO'8z6~wں7y%Y{81z..,\Wd3$uto}M:R 똠 aH{0WndB[߇>8U_R/Jfrh?:2"z ,jmL='݋xk.!PD !dž(1VDwqc7F}O3miJ{xzn=ށϱd^){MlғQ:yIFA%tzd/yקo+jf2upa}5Ϋ4Έ.oRD !XA%bF []f'6#ř{ߣ(;vugD[x$OS]z̒*w֗Im1b4)L:3H}G0#F޼|~50_ ϝ/P??_h\MDB"J<6D@"\>}lB!:!=cs9T5cSlmǂؒ^/)\)^aVuI{2:̡hP2uO3QB!%"J<6D@"l[Þ|Xk[NaeN-`46?1AR6*V݂kܒL n_q _v^1﨨m֐Q_[s' (o%RB([cCјUDZ XZۂc.~q ^ԀӗQYP~ Nb+uj.ȬzNQw}e&Be\E"ߠe_VD!dPD !dž(1# ϮkWRO,jVk4_*#?A#~Z޹ßo!2q([cCј1翄hWPڋ?TK]Q%"J!\PD !dž(1"*/k#)QB!"J<6D@QRZ(BEbyl"3(3 (!rA%bF ̂"J!\PD !dž(1c""}jPҧzf!5MJEBHBl1 Q#PDcFT} aǟx+揮ukCux-h)B)QB-!jḧ*BGs ܸon~cvϟZPD ! (!5E4f؊hu }G.~wcޏmm8 _ jsz-I1B)QB-!jh̰Ѫ>NchF [pnl׃/q#i~.I'NoGW 5N Qa ysT%gB"zUdB1%*[zhVDǓNG3EDݑМ2A%R.([cCјa+{z?1օ߼+RߓƉ8p&Vwa7u&X!ި{k)rVX}VCr$:>Ʃg}T2SCё˨/O`Qk+f9^Mw&Z'|jj*cTLjˍEIagYWDR+8I5HL`}|Lr %Fj"zM(!+([cCјa+ [Ǧ|-}z>c|>6wCe]3:>ֶ~,X-Y">&{ameYPG-##N %QO>#:!3 0 '\"JcCјa+>˶z19>͇?;5VVĩ^Oc^KShH.eam--ɤ+ǀ(eE󎊪f uu5wbݞNqDaa"JcCјUDZ XZۂc.~q ^ԀӗQYP~ Nb+uj.ȬzNQw}e&Be\E"ߠe,eEQaB5E4fDQu X[jxbY*~| {>8K80x?Te8'hwD4Ϸ|^;w| 0 D E"dž(1c"" k;ZzErz$Ł"0 LPD !yl"3-PDa(!D0 Q#PDcEtfAeaS(<6D@љEaNB5E4fLDD7xS@MsjZtUS/T7~Wޢ(3&^L0aM֍7<3g0yB%`Fƌ"*t?;~ah8vk٫EJEMe+L hqB|(cCјa+-'v9}{GaG{?h3 ~5+=xU$ń"̦PD"ZPD'(!5E4f؊hUsvu14z#cwTaXj76A8{{4~~ҤDd7#+fmSg$lg /*Ig-Dix$EE8N>QB !jh̰Qॿ7H:VģKj`Σxt]ƁX+1qE"NBF)@;%|:<&ID9"LPD"ZPD'(!5E4f؊议#8=zuxWk7p—lŢ[O:H!e@[J hh`_"̦L?݁Vje#ћߋՏ8JՏh''5986"zh'Ǎh )Io6nlBoXYC%`F [ ^.M^I4Nǁ7 Wd3@E QSJyHnQՐ~a6do}a[c=#HUڧ/4СNxY3süy ,nDtB$漎;͘5+~2&S"JBD?/˨!DO:϶/SJDO:ǟ,C;;wbcSohB9!jh̰QaqD؍Qlӌe[ڽ4[ws,YWb ʹ&=I]:SQ?-m4Tb'L]E ve'+٦Fyx"hH,nˈ ,hQ]D')̴IETF7Pȩ/JY25"g#ZD{Ѵq'9I(!dcF []f'6#ř{ߣ(;vugD[x$OS]z̒+Wiˍ(Vyv&}E_I5НϯN*6>#_;ھhj.cqb1W"ڊsay-"z|5~xo\f"F?а#eΔ82F%ڬʲhjrfZHCδw{˝DDuMh,S}}HGY-C%`F [}f^>6un{|_|kѐ*1)cxlz2o k+:ː #N#>f2*+Zʏj'B=A"bnyŜugkIe{DDCeGIь$!"__T} JH1c"۴;e8XjJ0 -QUɩfK(!5E4f؊ϲmm {cO{.vbnm9;qj׃}ظ'D2#rOs-\[rIV^+3? .˃sLi]1϶ nG>}p s."'5GdTrdi)jd%]?/g?L(?JV[_0-ϛ i Ebyl"3T ~Kk[¶v݅/n~2*;ڏasI,~NͻzLRQw}e~+r#rq<;>vk|kTuA/+ډAeK.?#c#{ː)тG4|™o^a')QȀ,z |j.I| oPD !6dž(1# ϮkWRO,jVk4_*#?AZNYϷ03/Q'57L-8lBJf?EThV\s|v[m<3*z#^R"J<6D@||KX[߉+h:yC^<U2y(lʔDɨ!!Bf(^ 3U"*;"*Ě{VcȨMIGHu˳Y/)C%`FƌbVg_WHQ8PDٔ)ٔC,]HyEbylܗ8dIDAT"3-PDhPDY'?o4TB%`F b"'PDihPDi+3(QEʕ+~:EaF b2"駟RDihPDc#9>"JH0 Q#PDcDDts74OMW5bCj("*'}(3?aMEp(OD۪>Eىyl"3Qwd;]i4t Mgc]S?+oQDKI(3&^L0aMS8aMS8aGD !yl"3Б7`x[|z!~_Eg)Q~Fa)vψBcCјa+-'v9}{GaG{?h3 ~5+=xU$d"oeaSD5E4f؊hUsvu14z#cwTaXj76A8{{4~~ҤId7#+fmI[g!oOOݻwgr""0 Ô"rN9uΞ=//_~[n?ʹIQrsEC!Jh̰Qॿ7H:VģKj`Σxt]ƁX+1qE"N ."QDT^OSD""0 +rN裏p9\tIk䋢L?RD D [Օv$sG?Ju \-XrWIVgʑ5$p:lD Q \kEEa)Vrii\|Yk䋊 sDT]QBfaLJ((1VD~ocx yyW'qMUoz%:YL&P-C $TN>;/ &/8l`G'z*r9uyYSlv_DǢ\_(S( UJ.( 0L"cxx8~"J<6D@"*?31{lKW؃s!|%JLLoZf.ψԩȈHʟ6jreؕL6d(z5a%LKCA;eEde#M_}n[ ) 0L">*u/*EԗP_D !35E4f؊7;+}Fэè>Mw&Z'|jj*cC22-7FU:nL:3}hgHџ7/_/fB ) ?<~÷K{}ux'l9y|ZFE}s sڙہ2 0ŊSrǍ|>B"RD D [}f^>6un{|_|kѐ*1)cxlz,1Wr-;3괓O bN2Hgf5G{>4=<|?U"$M&gxLlL}F,[fy.Җ995nKL=GQ<7lBS}o)F m2S|Rh;W/nٷu)k>8z{Nzr>џݿ;Mܺ28y}E}Mͳ/LYmţN0{-#7r8qϴ9BhppP?>Pr/)GCPBf7OL$E4fDѥv}ֶmX /mo_܂75eTTuw涓XJw 9Ȭz OQ \ȼK/+$|݊?ᇿ/◁zNT[{61֦/Q+–M$~eb3mEey/z>'}oM+}.avݖBۙP='ںtQwK[s>} u{{ +wWWmv<Ͽm3kq%Sˉm{^zmy-3r s|C7!|?⏆-"JADƌ"*<^}KM?O,QӿZZ֏ag bC󇪌Dߚ+.i;*H2* 9J. FFFń|GpB.0dT"U9e?akX09?ȹArAS~ŗPr󍆚RD >1ј1翄hWPڋ?TK]Q%AQ_F}0 ^N|VZdTn UWT>;*ʭVr!fٖJ #!e hɹ@ rns+rs?jJ{φ 2}b"(1"*/k#)ڗ0GEdT.BA.AT."DJra!_ƒafv>c6Za=rs|s3QP[ GC ݖ+!Դ骦^yHMҢ&GQeR)0 O@qm%"J@ )aMRUD8<#C4Jkh:sP!^y"Z"eTNa2 )aBK. 0L<)&.F>!Osތ͛7SDc@T:ҟc ~Oo?0tk4{"F?q"OF #ŔaW|/$TQ\F=|P zj$x h x\>տ=ǰq4CC<*ZR%ɨ>:* RG0 0~NP]B󎭄J!3cFB%xܕ[jî4FadR`*_ WƆ}=go9šZt")}dyR#` IN)؆MDhQ_H)ss>S]Ngc/a0s֝ucab֝ o;~!'/3}5wsvU׾Mm-hmήÜi-ǿؿPW ,E "| /y'J(t03JM6!k.h Qॿ7H:VģKj`Σxt]ƁX+1qe"H`eբ*ttSM۬m:y_ـ I\?'}SHRBKiFL;XIxeQ⶟;7E ;u3S5{Lܯkizg{ۚgwЪͯ;9A?W]@} 5TtBf6OL$xܕxw(1VDwu{kϧ,u]C9DeK/xbTE Y?!"*#l \?Kdԏ)/:fo -Jb캙-Zh`فEH,Z4kʐQrlkuw=̜}ms.~L 5Ky2}b"C޽{)1VD~ocx yyW'qMUoz%:Y1L&P14CԨ˓I?$,qgGUCr$:>mְ {"^xe 6<u?g3e0o^OԤi$Uwx)TJ`qwq s3X6d ª !ڲwnՅl!gb~ܟwMNܾr,^<[)nF,N^WuQ8Sc/ƏMud;F[Ug]J$I-176u[ 9t/x x۠d5qQYH>u5%4pB>1!rWn"lETxg=vc4cٖvx'.CKVᕘWiMzҕ<#R"#g#)ZhdQ_O s밎[.'lm.8/Nhg`[M;T_x'g6 ;'GDL C !5- +aW}1p/޼#ufbYctaO,?_B#پGLLb, k/7_+}PCמcxR' [)$Ӣ_cg?^y5F^68 ;;_V>%م @ "Jfa'|3ł avv1C!aH۷RD=Y60 0Ss0x(E4&kO?8e&aaaa+7La"1L޹saaTΝ 0ň"LPF):|?0 0 0ܕk)1" 0 0LDt-o͍a"*PFaarE>J ݳ+UdsPXYصQ-fiqA eaah';"R:+#)ŢL1ф"0 0 (gDEpQ H!( 0 0 %JD57Q2&uCx}Ns^r[Ĝ9ݾX[6||ie2yCM׫_XFED/L.ˈa*{{o/5/OuB%ro@2 0 0QEtSՄ( 2?t4auӗU@ϡ>)(_xQa g|P]=_j^Oum( 0 0TdѸ0J IQL> ,(!MRD%2FafSFP>_H"m2 0 03$QYnskϼyM[s\kLiRޢkFJ"c`^VhRDaaE4F؈$ETD)F$[ ".:yo]W/+SB˨+z2!,9DEIQ56EC9#J(0 0 3UƈɋK4]PDaa E4F؊$OBf2 0 0ShC  0 0 SPDcDfYOBF2 0 0S2?ao|Yͱv3=QaafK.1 0 0 0Lɓ0Keaaab"0 0 >2Bo(~}JeaabJc"0 0 0Z('(0 0 ht0f(~( 0 0 {2 0 0Jc'GD*0 0 0LB`=QT`aa8{W&PaaaJc'GDȿ T`aa8{2 0 0Jc'WD?*0 0 0LB`=Q0 0 0q 1DCeaa- O@aaS('(0 0 ht0f(~rEQaa&t0f(~( 0 0 {ED@aaS('}z#Qaa&t0f(~( 0 0 0̔%#f!J~RwBY`N0u3"s%?7=s}2 ۦ(!a/ cR_-e5N?rS ?:/Dc&~1F8?˓cG_߆,3#uTӦg[vwV 0 S4:*eIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_installer_01.png000066400000000000000000000220251322762156600311610ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsod#IDATx^ݿ$ǽS\F=/}(7`y* [NH`m(u 0ttTԷ9sgW}̮|}o_>0OX/~i~USO9$ɇ677W\ /^ڤO<Cp~v7vt2EuNo;OڧWxO-?WOn??|꫽E W7?6)'2dx@(û 7{c1$4w$qÐo$.i̖`1S~5쮬w _W~zS]#tSw? K"l s9itk9Q>Sx㏡ W?e:^OYj_ MER/޿Nߗ]YnK?܆F;% I|NA: L)ħ˦EaYe}mRy8Tuگ_6>NOf`!%" ܉2_n}{&ExM]>y WU͢Pn O9Oݣ't,uAV ὍMᝂ9>ջM>O^:xx/~ΏO)]7=6]/Ho:Sps9{7xzE/K~ON*Cuk ^_4A[1ʜJʿTWwzU u7a%" A+[ANN]b:wZ4)ʀT>ð.^/ͼv?4ah{_GU"s/(7-_0ڶ~8>Tܹڲ9=})-='~@ɵ1$Rm7CZҲT\/ux/M?'ݻ%O;ٗFxNOޓ)߽a-;ǥx5 o _=>Oڶ/s7 !27WGnOޭOR@L(y)1^K19.ov) FxK1›] R@fbrx۞ٝ٥.ov) FxK1›] R@fb7#٥.ov) FxK1›] R@f˛͓'g/qfɳݵ›]z_<=yr޽|2859ުa/ p|foN˶cq Ov[v- ݯ /M r  9ު!mޗ#SH-v Sۇ~}Cc~]x xo~~{V"ћnhqrξz}s~{Vj<͏{@Kv9^xO葞fW!'WpY~9(˖NٿBWkz{~֌aP~5Q]m_'=u}E)0G~[Wc?ޟQ_[2_YXֽqyrc:Y^,^k4*ԿKt58l`pZ\CѲ@4wa\+y-8m)]T.Uַit5B8Exl`ywĖ2߶;üq_O}ZW=Qd[ۛѼ N wasj/v-Ze6lٮe#~Ex|;~\,"8 ZOgAs0lh6;z7c;qgw@c_,B5*r}Q,svgy2|$) ]@| nwxNy(.tίwr`ֆ,Hk0d?[4Du }4Yh8k>?7lw*3pHm[/[}Mx &5Y{//|>_ @aަAQw}ѷr_^)vܟ;Sk;\w+}Yr.zt<6oȃETŸo/ۿ+_%nmڍV[;&@9 }zChϠ3[;Qk{s.l1h=Gw8>ur&@_g#_àY_xJn4~y 2 }l1&Zʶylsijmnt~n5}o[ަ20dl#8~,6[T[??[|9o]űX63'AUW=Zz&`N?_N|f֖|9 Xv? |1˖:opnM]lhG޷?9U?A:ղPC.liߕR߃Tx_Ō5/AᴳVA-KN+MOkO)K tCܗ7 ?ex|Dj=+kt[ٟEzXj 2מ')[u.u3w\mx e)SiީWS][n"R-j-=k1]w S֛,ׯ''l?q%'R=l׺C@L\TAOmz"M!tx('KRɉ۸h;l1EAv:n>R_覦f*i=2-C7͟MJ'e=/!]ns;5Na2u}cxx7q׹.C2Z[눖^/Bz]:q_l K xx'smLuLKRe'`;Wx'v6mNDWeSOeD.9 & -ê|/HMe'r^DTWy"j#y~ X[Rbx>SB)Y;*%'ּhy}ژk.4[T;^S` ?ܖ`Û} f_brxUs%/% &/_xf_b6gbrx?Z(y)1›] R@fb7#٥.ov) FxK1›] R@fb7#٥.ov) FxK19_ov& &W›} R@fb7;@K R@fb7#٥.ov) FxK1›] R@fb7#٥.ov) FxK19_ov& &W›} R@fb7AٳIl>lZǖsBYGk%/}yɑnnw剚uQ~<yr{]֩3wN;aܵo[Yay%u|${3S[km> ٥gu3]ky峡g&3;֗6Vi~Oӭ:mNn&>VLE&ecCaIZuMX̯n\?<_N?k4]֟oD؟Jetւ>[x~vԯsn^eިlQGIY_novY/h:_t;+a`_[lorf5j*7G4vc<]Mj۴Ns\7-aptZmN[eO͟>ɅZ]pTaez[}򦚿VOZc촬9.ΤyS@xKB}Eӭ $nls>78x7Ca~ !-fj{Vݪ#ZvT6mw10m:k.?MOOEV%qh:V߇xΤsfz[r^?oX?řqޛm#!٥g}@^wlY`˺L9xNpzF`(HOj 3MヒזU;a@6Oֻ)N7y#Ѳbͼ`SZ6Ug󫛜D<] A}#|,4md_sy϶ng:VŲe3uΒ\l񅵹enaҳP_k0į;\5xN'O~!] .םy{Z]ԗD@rb7S\p$Z6O/}MQcںPv{od?/agZn ibߞv}ۛ(՞m}ܕu mK (dv"O>>y}\WOm}pI·K範7 T4-< Py0-rY].U ~Z[mMkWEno%kuS_vZٕ>26WZ%ks#rekrfNrs,SQ֕~?5#٥`5`w9EkV~"_ ⭾Dy-2iz1*ϑKMk뇌Ogo;:c{~/?P`3ݏd8(SB5O,-nLU;͏ʗe\nm_Ll[E.Wa7%ߩ5)Ϳ1Z/iY+ϑE[岺Z#lY`˺uEcnR邋Ormʁ(_+zOWa|dlQw0T6[yvTsZ7ֿҢrEo 6Ν_;u`sjwӹRDYG ͼFXy>Ff`qy۳gu΁DU4?C w5# OtfxdU!٥.ov) FxK19J^J@Lmov) FxK1›] R@fb7#٥.?Wx/1›] R@fbrx?Z(y)1›] R@fb7#٥.o(y)1)7#٥.ov) FxK19K@fbrxڜ ;ov) FxK1›] R@Ljxfb7#٥.ov) FxK1›] R@fb7#٥.ov) &W›} R@L^31~.ov) FxK1›] WOR@fb7#٥.ov) FxK1›] R@fb7#٥.~Jx/1›] ksv& ٥.ov) FxK19?~9ɛ] R@fb7#٥.ov) FxK1›] R@fb7#٥_ o% FxK19_xm7#٥.ov) &_5PRbuܹ$G 2xBx?dӧގ|!?ٽ.d9}v7ɇw}/'/v߼~uMiEهq{DX8'ˤeow==p)| (yߧ+"=Vt"dUCezEe張Tx>zx㍐ο+͇o= yUmY.=Um}U|O!/U˥:xyo飄wjxx_ugRx>Fx_굄&ޱq$;VxVx?›dVx Ux VxmyNW+IfS@1vO򜺯)g[$I^›$+Sx$ye o$LM)I27IW&I$I^›$+Sx$ye o$LM)I27IW$IZv/V7vIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_installer_02.png000066400000000000000000000407061322762156600311700ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsodA[IDATx^,=rbd=`kM]g>AFq;b 3ƕq,i.@QLfHdWv?S$Afoe9#B8J 87Ɛy?G_^^#xO/X$V- x2l"1?y<;wyO/߀?X%*uZe+w_~KφDI{ibmڸt ӛ߯H^FB[hnz[r-*мŌ.}5oO!̻vLWVz &xO<׼ń3ٸyOjj̼4/]R6/]o'|q_7r{8}["mD~}oObٌyGTG +lܵaYF(b\~S6ʌ#F6{skno7?٧7q_{ޓlڏ2nimx>)Sҷo ._O^0?i_|mh2I;xԽhI[ǶLRonا=w]-,/0 \ ~t޾İv0"vm~ӽkWBtl77|unٸt_)l'wpbXT{>6̯Fd:Ƃr߫v:߹8wr4|C1G=;w-ya2lbR&潍6rZ34fLe>Odɯ0dur4bv:]*=&wo#Sˤk6oy-OI\$}@jߘgKφbI{mjr<I~τ!=LGytw/߰&__xѾ^y4bc7}ܛysy ``87 p00oy >/OW  >M7|:<3<"0oth?0yGļ^o~,hLYxyx;z};46rk|Jcs:tz_<3yty?=! z&yG`0c+ y&J1^Obd';o֫msL9N7"y8+c`3}igܓ1)asΧ12']'N>ߘSB_6A$9H^6@綷?yz5>C6ײ֘owN<]5&%n͙5g\^Y9r1w OmICڸ3?ɯ+we6hlfsyi <ǑUL>nE<]5&;[65#!Zߍ1wB> =6z#yGjn6A$EHyJ:j}\iu1"oc]GηߘTP~~^ӒvθڧśWC#z-csk^<mIZߎ&Ob[tE8ٽueQכ.OZ6[ΛZGbdf#}FLV,icjki6dr>oVru[uۺ[w^MZl=VMt^N2wN+/oާ'|6A$İ+:HqmzȸBߪzjSo:[mZm-[K^z9=qOm:?=)6j/P#U+w[1[}^kx-ZKlx=̊~=Jt1eSޭA~PɆՈ1t_6ys=W(ڗmRr4bɸ_ׯx{z OU"ca|{u{\usδ}=85Cg^Mu6~s\AU<76p_ z&>u/HyGȼ/>N˻|.WyhX0o*rNǘ lE[o2wʸSGjn^ y$0RFX=qmkZ}xuuN0dMĒyuk ^ X-BgY7v0>8>FhL2+%,.^#0o;ɮ|?eτ)` z&oXt7|: z&iG=|V#0othLYӡMy3ã)OgGS p00oy ``c5߿#BI%wO2|!B-!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼Biw;B!$x(}y=B!)׿73__7 ϐGyg#¼v3apPϧۏl՞ڼִ/mi4mE[4Tq[[^y FtضP9'~^MѾ yD7e*LMqܼWoF:c]\Q4~}l@3452A>٨#2.k枱XTgOkW|E_x<"ƼUO.Жooe]NX~U9jZu\T4X\U9c2&Owm٠YN-O)tYd=cG2k/sX>yz3dwWyñM(n6hc_>um[ѫyciqiՕEN}>6ZeFsXyb~үgz3dm[yñp6dR})O2j\h-9jRì*wQpO_F}ZN\3v+Si\ eMa=¼XlnrPe[>li3L}|5pM^}Gebz-;u^O5cϨ1o1PTSOo ¬'+f֊_a]u;s.2icߴ8uk|0{}Sc͸eҘ7yH5dlK;1}s^KOƙcK]XztݜFu?aR r]xuҹ)zϹ{Nx<"J6K%mNmހ`TиWz7JS qQNt Iї;>kmOŎHQuoZˬk`0 yD7x<"`gϔ{y'gqͤŹ4~ f̏]r[ vTϔ{y۪Z10y?nYq 0(x1gʽ¼ `/4'C,>Ot|yϿxd2өEQ7өfLr0ox˹7}%X>Fz:oS[eK=[Izo\"oFйye]jK w+&LW7| &'(f];Yɸ0v:%jU~mFйYZa^OqTb ϔ{y|Ԭ WpE? j7qFbVu}f#ҰܪFn|Ԡj7'De/&LW7|-P}d"m$fuKY7 aDqwe Gf#ѕ] hmxnt>3瓽?{غW}C yD~6Mpݡhv-dوT˦=W6Uk>(țKܹ,mԮb>p3M[ϐGy[Cn|i91jvԦ_Ю*q}j.6:]VS(ۊ9Z]QKcqz5υԗr_ꩺ*C} {ߵynq1G0.>NZQŤZ ڰV _hBrUc w10W=-Fn)krh Lbzι.sz/ez7Ij_#oU*7*sןy8mYo->q5&h}:sX0\n(,u&Ӽ:vznnu\JS.9И ᘅ`LlkesjނE0 t0?k 0LZLwBs闍ti_=.Bv -kl߱mnm sSa4,\U>osvLz˹vq+ϥ1+ܶ֘&f9M}.l\Xqqy b~g>^ G yD4 Qc0Azb $u>i>Ol,U5pS {'#Źe a< c!\3.y}_=_ '2/k.nк| +c0 )[}y[Y~XGԏ6H{q-Gkij>Z9x@\{15IMZ/TrXΛ1&sZOT%yy=຿e_ӻϤ1潫8/\._ϐGy/7|\WmFc(;\~ bZ13a6t|aYƪL!H9-"Coz؊*]ux<"̻ 㕧sHZuټeFWz-R&ұ[T6V}]z-lk2AW!*Ҭ6Ψڌs{dN}HNkY*UT|6\A4[77#Sb+f|3T'yux<"̻ cˋ^eq7]z-cln&ſc.o5Q3x4wgm7w3/}:(Vt13wկP5٬v1Sߨ]/dy'3axXZ_xp{}#z-ݳDɱ(l-~ UF?6N7*r͵)Ҩ_\|DeqT#0u~Sٚ@I R]chRb2B4F)k]g#¼'gp~ÿ\q䄮z-c9T,Kny*3q'E5lSHX'ZeNh<\Ixe5]˔[ƚ]ʼ.choqB8G΃wZ[3aLWx3`3awg>b61U~kR>qԦȍ-v ߦeNo~1qT=b.-9z8z)w:p&foim-VE Kq=Ue.O,k9v),Om[?26k|ǽ5eg`xzE}Y&s yD V/d9_ X׿7,7n;/n闺KueQO-&jqsug`9ϲU=a>&R I[Ċs1=lOT-;%5ܿ_R]7rl̼̯I/fר1F2kV1}}MjӸ`3av8sK嵿ZT^RԝK{b8q4ƭcCaDmLa`nmY'":Du|9;(7gnO#8qThk|e5űux}ۅ1u#/X yDwu:H֋Nޡj5䄻9"SQ*yqvEl9ߨ?'8e87&Elj7jAOX. rIܬs{ Qck}E9&V#Nqlcn_RVG)ѻ|] yD7x<"`gq"uýG7HAayux<";$"|Ģ<lJz{El׵qaφg#¼#f(?l̻[W6{]lx<"[H jx<9BORf]}H1m:sW#s2';|VX΍s7Yr-Uqg?z\9?ras Mɚp c.tuym6X՚۟yYK*>ϐGy/70Z MZ9P3Q ].\V.>[^7+c+YQ6*7k[3j3+osc)e9j]*[di׾'|c*fPK#k/עl+c/N4O`:zrR6֥7j yDw(F-X[E]`#Z1d+1kŴTEFTXxsS [gsWt۽\^Rl?Q1-QUv|*mG[mkg:3aM--E6m拚N#Fې]br67(-P.s=V(hQl7~t<6?;KkcX5%kL1ǽM5u#社g=jS0jQ*Sز8# Z/[֛WTRͧ*Sql 8s9jo9J\}^Kg.abZrUZŌ]C*hgMOoE93aV^Hej1غzn4E|sG3DU+YQ斞ָ\۲"/f#NsϺy`,s'h7[zưT1)86l;ǽ qnu/ux<"`OZF~`Ǽ3a{4=I/1ߤOUrh=]b\ ϐGyI˼/s<O?^/oYa6ҵn]S?q9z yD7,Ɯn/R_.L5'uYi-S^rB? yD7T`-n3T횷Kx<"`O1{:QTO޺`ϐGyIUurtxۓw' yD7[gct׷ʐ}zF5Ի!'/}9hm0Cޜ6pkK},}x<"̻|1NH ڧ1B],."/i65(稝!es-)sPǩ})'5r/rƽ56u:TuVR6b/yT6p7]7/r[}r6khۖ}:sUsS\0)*sh߁ yDw&Hn0]_nTvr3g?5Jz9hgqF򬰛Bp|mU;H[;r]OS}yM-c;ŭ\$ty1n|}yG}G9[l(km{ }dYJ[?[/_P7-8x<"̻EuMl`VㆫͯwQ|O+rrax"sEWmj1WyYfG$1G9cțԗr_H.WSu=Wq7ZAam*GbK~:`0fyW蒛^?ph-$x<"̻wknnEߖEu-t;STfvC ~,׎Y6!_ LOWMO@oS:v"nGŝHO[똃8uc~˱ͫ8lyv^ l|Ny>q n4޵Yʢqkb֨sYw : h?rܘ9[yEK9<+fuGh>ǐ*qwci>Doy=,iqZkQ wq}9kЍ[``)[uwΩxv,׭8עU7m_rM9f:=¼EgD?ϐaG-¼H2$|$ɸ{W3dQq0oxJǨGP֏;a7v^#1o8\LZ:p>a]wNLA}Id%ވ[C'1RY|잏wY^_q25fn]sWuuFC:oyRfyioˡO4]mBԇt6q ClZbݬm96ia.'KzXlkz6?]/a/\kϵʼz쌻#zk>y|nijBԇ eBylLu=~9ͻ^+ձazQ\V,O^}+=_Sn0*,3+}\̼l-[Om:ܞdAZe6zӪ3O}콞y8ضm|c^ -ON=o[t}=8u"5y_>&7 &hˆu)K]ǹcw}g-ӹ$f# N觕gGzs*\/ktr}xbE{u.ZL[ܶڴ먝?)gB{wٍ-otBg7aިCivK#!B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼B F!ռB'P7<7y!zna!y#BBL7B!t0a!y#BBL7B!t0a!y#BA9V^|tQQ }O*:9*A?9uZ1m ][=֭F[sݖlR^,{_ݺ1oPxۺuZ1mƼ}ay֭׊nK5 W=T,޶n]V?o(=ט/̻ݳ=T{,o//U?;ur_?}5[o|9w˘wØ{~{AyjC K6Jѭjfv,=7o??/nuoM]AS kpǼCO۟YϿv9W<9=H.^Z(-O=OWyj#LOP=OMj9ZTG'`޿o{EޔucPe 5/@{^??hte׍Mmnj\\6Iux]{d!s\Wo|Ȝyu#w=4zwy5ucPf\k!-Җn]Vu4w:xϸEz2u~z<'ǻ}|P0h.u^xu[? %w-Җn]V"[sʾQ=\fޓĐ/l_T8OO{dzy]EoԭFwcyᭋjA9]t}l>={j:7.?ޓ tOO'Hֺܹ߰>6ƝtǼCdms1b(σteňV]6\SOO>z`ޢU'8=w{o{Ƹn]7z0k\}Tż?n]7zXmݺx\c޾0}uǼCmk\y[?*o[.^+-=ט/{_ݺ1oPxۺuZ1m&|{VqOuǼC%7(j˛kGy ][]t7g¼B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:0oB`¼B F!&!:VF!Q7$`,P8IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_installer_03.png000066400000000000000000000422171322762156600311700ustar00rootroot00000000000000PNG  IHDR iCCPICC ProfileHTSY{; `#$@B!TDEepGPtX b(` l{vw@e  iLa-:&C;CdD_aYٌ׿_%I`1d>@ jOgM`" "|xm{vMx'bdKiӲI#a6A8aӴ3\a?$3^b%Ix]feRYJK 2WRșե0?>8dyE3;3v9,yD3K,/>ա~jp?! yN095YyH XX) E>wLXZ+CNΏdzH<̅S}%0ɳlY|+` d&͜is`ͤ#%MiVvܽݽ;)j\쐽U 53ː-]j Y j i T 87 A1`%`.HB bT ΂* zx` Q *iBz d! B(JʁBP TUCЯ"tC`2,bp8Nl8 5Q߄`1 D B(OT*6 PeTՅQX4MC~4ވށ@ס[Зw w 18bhLf &SŜ\ `F1X"k`;lv;Tp&8g\.qOx^o-2|<?E! !apNM%LeDgb81XNl"^!>"#H$RK*'']# >dOr|AO~GP)nXJ&e'rI*e.ŐHmjz-M֓v^)-]&}R AF_S%QR̤̐,UR6D6Mvlur89}9o9\!Kr#TUIeSRSPG dBc= r 6 k*)Q T"_ԕܕ+5)+}T^즜\ܬ>I>>};0~~ 61or9 ,"iq0=(X/B!C3 ߖb2V.}jF [!#(aa(3R:ryd}((q 7cTcx1me,]n< kW\_2uUҫXNa⾲BX5xF|Uۓ)%8'$\srZu붯{zz97To6oܤ)ohonfͷXl)~k<ܼ|h̗msvG{[o߷{FEaY7~靉;{cŃ\wՕȖdRJ+-(}g՞e6e+[1PQ\V~n,754ȫ?2:V/Ύ\rxdV?있}#|3v;wGۼdN>ac'Ou韻D}y>+k7o?N(B#Pb@Ƴ,syVHr㑹0;@0Dfidf`kk2HH4)~dB߆Z">\&-X$ s ۞%iTXtXML:com.adobe.xmp 495 387 (#7IDATxml\y KQCh$([)\ʒR EhD5#%. Z!BB"*-u:D6ڒ+ Zalz_/ ps;;/伝;1;s_y sMWww@@oH?3o&P@:Y'@H>1#tɻ#(Pu򞜜,>Uv6" NZUW)-y?5@h@M[úܨI3! x iGM{^ƺd\:'vɹ]7?euWZc>]boxtm3p4hiVewuhE^ޣrsf5cN\=ra3=9iΉZΡ @ رCc>ٹ_%&pMܺM#-Ij~9rDۻ7嶹=-EO9I( ɶs0Mܦ1n%K@Ğlܺ?m֥|%zyh{bbMׯ7nϒU5x~0u޶Sw;FĻ-' x?xPFe$iJ=Rw~:]cY>3>:x> \p@& %pMڍLi[K/^R[ߟ-Awdfq֌i 3=mrICgd j"9(tn!ONinsH>as##hZܝʉ=iPWr6ήqQS״˖7+9SnuLϙ[O˶/;n4m;=,93-߫'}f~;V @4kq;nFnG)-۟n]~ _N}tEfFDa:e2>t$,wP݁)qz0"F3 =#rr35^9zSwOݡ.jۍu}dm;d g(dϞ=G$ex`FN']Ox١wg\tta̎ ?#'Rzt!%2 kZrz#\d4=`Af׹$CBĬBhshvw72'&owYɨ?jؘ<6qvwf/hV_8SXzܨ̘l´qq频EOy/0wf([ˈ u nEN;d?MfܙV8?(w5.6 HH {^@Q8q6D>|tuww駟>3Wk>SNk55(']j~$@oi[Xr|f.I͜fv5$l.?͝:>FQʴ$oݑ>s:v: ^׆*&! GzRrKEX~^Qm=Zsv(:k 3p%O@4Y7==ˆ?ib۪)8?$d[r6ޚ;. NvOޑz!9V֠'T[c{`jW knȕjuL{Sm=0OdYmO9*3@a捾]R޹ϵ o7@GfKhAk|wծǪ G+0|;}sq.$tcf;( @ 41y/Ƀ;yh)LGnqp&Gkĭ MɻRRаIZK;67qN-Nߝ- )lY%i{~,\w`t=Ǣڬj~p'ȰDU ,Q8pW*w5t7o&/4Nӻִ NN+6gd 9PW4QGI\^!Mhph]ѵވ7]i u:;k~^#0dr27qI~$nARfje 0˝~ NDwE4d!AiKlͫ~TѮfQEke響kho~IG?~tTmegs2qYQ0u#ˑha !IoncgӁAZvX;6_G8Z%z ;;nKK+;]XmPRۧ˵geؑ+!V):=[儘e ]gF4F0'|aA5uqbgsu,bI0nԆ |W(W:Ɯ&.RQߗ%Xv87>S>>`kImI-/Xݬ\lߤvh᤿qy{qSߗwÖ3w ۜ;<̍MM/Hm'93PCB2rjb-:V5$F}Y1;cW,`m :6˙HWkLW4lw#VW1e~l2,]a<ާ` T܇ռwSiZӫ ߗxjic+ckBtb-M[ۦXuyلQ7xѤShNG:z Zvs {qR*cSZKitOgBk8l/u;چ k}x,6ĪTWlE߅NI}хIauq;{ʭO},*(ևռw;KO닔}퍕F6WY{m/Yˌk,m*ݽgix!w_:(+vUԩ𐞞='zcpv_XNҸuWN ?y'mF-07H6lMI7uNܵU# j8@ ŋ- @@Ȉ/m: n; y yʌugݾU&wd<ǧݓb3GF.>.d*Cn(לⓞX=cqF[YgN.%'2:60%9wܜPvh6i=*7o޺9/gEIܚFfe8XG&H?<D5x\d\θ3hh)m31Hτ}e`TgGb#{Gw%'ËW KWdVFr%:e[9^hܮ -MWfM;EEGrptF.DХq^X\0z;7nu[l4!֛5'dLͨpl> ZihZh{,K230,mΝHնPVY6^_[Mx@>tQZgX{M0#ND.FOlztV4|\/l4{قCls 4W-K@#&م~Tг5.$ҹ&ym>]0.u'&]+:tŎ=z3.,ܕmM=s234"➟.L3"5>P p'iQNلܰꔵI#\9I ?YzxWA61YѴލo^ož >3 r^.,ȸ[_tR<SL!siCDևO' Le,FF>ԸD[\MҩM: ӧhX gm"(th},zn# ͈9{`c/͋ӘdF\7' :лI|g&6vDOf/cvnܜdj$lw"b&K&\h\M>֩g㦾0agFt]4)s{|]? @KwB2vŌG= %26k )/4qkp׉#Cִ:&wmLMZ21-~t5g5+LZo*\w}f]%zQkz1<+g8F]!sZS4u-]e[.~gwS% @Ktx2 ^o^ds.>R& WAL%Ff=>a*5,8kis$;٩m7#aיfّ׃Oτ)m-s$lG'-z0o3`7Dr/S 2ޔlNLB EVדsb,6#1j>(}9NϚkf #w^ϵpKe֛3-yQ._~µ׺8VSon3 B0rr3r)֪'#C͝GA`bw@: m/ٛo۲et|u:[:u\kYdF4Ygj--=z\￰6d>BȖkj}ּq7O@G~% 'D@kͽ&x@,@^3!  \|TW^@jhz18@X@ӓGV," 9o @Z N#d@ ywvz@~ڻ!SBWڼʨ @K'oUz駽jt|A|@ 0mN  %@  ygi @g _C^+Z h}mB֯__F! m_;$돈\S4 WYt@['.1){#ݴwˆ mGesp0Zv[)M1Hdև5H6/ @E]+oZbm$ɽMV_L·EEx P,eiwqx}||Hx_a$F2@){魯m2K@)7eV! 68@ d\o hznuG! 6w,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N$X" ۓ"L@ID@'E 8` '$oO:0@p$o'@OHޞta" HN% =(D@ K@< y{Q  y;  x"@@'@v,@DIG& N1}r%% Ȉ<܏Ww²c+&b&$y&j/STn?a] |G%[XF#"{,/UsHP@G |ۛ7HikNL{nYTt6n8БQQ":Z%'KK5]9ycRFZw2:=Ly6Q1* ԋޛzo#o"@ۧdv䁜yh\GD6˩iP^;tDIg7uw2I{2?-LPM??O6ʟLPv>햌ۮKz69Ѽ,ns-Lkcz9RL39=FvmGMFmBo_*=P]Î֑GtkW 7q@l.Lxϳr@NA/*ef GPxx󧯘psZql5ׯǦ];͔ͣE7ώݞ;)rjDk`V{Ӟ&_ӊiz[ԏ/ ZOy_`#/褙N77 #Nc魯Oxn9$7L^ֆ?k?inX DGl]glGɗ|IȌ}ȿ5Sv:ï{u]sm&=U$i͘4FNQѡm{m @ N| D~ 'V$)bz$i{2ykl"L7b+ m'@n.! @ @ y] ۼ[F@oQY@oޓsnR2 unR  w㍩@ Ia 4^xcj@@$rR  y7ޘ@ɻ @Hލ7@*@+'! xw㍩@ Ia 4^xcj@@$rR  y7ޘ@JкHa  POaR=IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_installer_04.png000066400000000000000000000177641322762156600312020ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsodIDATx^ͯ$Y~\̆,ذ`h5ƶ HL y|a>fvbJHR bdٌPI=|zQlFi8y"qDd{3z^ʌ8q22o7ު^}_\[DDDڈi,[DD(orwUOZZDDDuyVo>YuT~9}T޹Tܫ7EDDN{w.er};W{¼YsMO0fuh""r|'\ZRO+Kc 9'w,G7q=\IxoHW06LGDDgI1_by9ɟSչͭkf;[oχ(Q^{\)tn(ofIZIז#N%;~8vJsM"{GoWy{6;7iG؛7cnj%%~C8""Yܱeo;Wީs_O*\/ruyիwbQՓ~8w`(k}yv|e30?O!Kex>UqLwN,o~O&s{Ѩ.<,Kۏ>.Ǝ~ld{{vJ_KS ?,;so[)TG/TXg(Ѿ'~=|:}jEsO_|#EuO坋;o;'?Q7\#T֟}Y~;TXT|l>W~_46c4PS|/l9SB? 7""W)um12Y@I.rQNRyN*XPڔ\, /mJ_f}S~՗؛}ʾ/u/n.c#^Du͒;v#iNS%=Y\vοētYy0]ߘHJC.-֥1N?*O?^'}sBwI{Q""r,*,'l~a-;xyy>b-""wdyqWvז;-"""-""XHcQ"""Ey4-""XHcQ"""Ey4-""X\]VӼ(oʰ5sQ""ruak梼EDR+Ey%}a3碼EDKV*{.[DD.k%y碼EDKV*{.[DD.k%y,?q߮8(o1ya}RqsQ""ru%X+cWqsQ""ru%X+cEy1k%y 26碼EDKVDz%ܷ8(o18(od)qNYǺڎ碼EDKVWǾNr%jjWEK^t{7/ǷED^dj{Hw^i'msr~IE[sܯ_lv{w\wprqj8﹜7x5\<Λ+7] 6SC|s3ϭ+p%w%m79soWR-9JnX۞Cl*!%X+%f{+Qy${.g-r7\.{Z7PrɎPZ\ o翙|c˰8v%{TyO"{.g+ݛJjc]ښ+\}"<J,ZI387b蒖u+ooW9VfzꥼDirN6:sqytoX1~.f^c$`$Զ8﹜ޜs9D4zo,nX8l]lϏ![0lRܹǍ3?ƼMr/{.<ƎO,ZI.~}(׶8﹜:o+{'`$kE/ն8\oyG%r┟N8"%X+ɥ򿺖*ϿYEDDX\"\Au͗K,ZI.:9Ͻ碼EDKVTȇѕɎu=-""WXRaet$u2-""rd6/_Y*{.[DD.k%UIjۜR\\]b J2S"""XcRqsQ""ru%X+ɨo/cK,ZI⿠WY\\]b JRyEy%`$/U\\]b JRyEy%`$/U\\]b JRyEy%`梼EDR+EyեVK [3-""XHcQ"""Ey4-""X~9pR>+oFWypٔ74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c(OxںlɘSs8\.1=cSY2sR]Tyi\/vs/jmGGkc2Ogٸݱ6uSes1~{3k;a|4s]\TyO~WEU9|{ HohrR~3cƎoh/h|"ۧmc;|UsO6o{㲩}Ott;nO~9m¹(׍yng3O=1TǏsn5~nyG8y|37Jձ庑~U[EP{1l]!c}(r8׼sW1ce1,Ar}_[>ԶؽmpMݎ7|*ݽmoiܹc< ]ǘٮ~{/.9[pC_yyMscmoucڶy\ߩ}Ֆ\Ty// /m?*c/1ۦlo?y}gqʏa1V_3v'-/UޏPSsة}t\O/3S/b(=>pr##}={~fnuYW>`92Fùϧxn}pw:?i]~gu7GqQOx/"ؾ/l_\h|xSm~>қ^^oR_ coNN9ں^.Wy?[^C9v=qv|ߏc+>&^>òaN\߯ OnJFx>Kqi~{uX_Zcj˃[N<UN+~ LΛқGx8Z>N_Ey_{j 8s-~G/1zw 8qKᥞ疞^.2|-;ӥ6XurN) i{ɛFsuP+_|ς1nj^:I3_t{7B㿯=uw.xǾo; Emߟt^V5X}?Ǖg?6?t~||?ö:ewF0Qc8z Wiv|]Qon1͛rS[kcyՏ9gyWݔb޺YgnVsS79+'8ׯK|05r]9`7&Qۦk8O 87+~\cڸrmyԖʼñ}Sc&8wSM3;aqھ{+11|:47.O;zc3u8;+(O7gm,/Ay${n>1S9nqqD3?80;pѲ1~y;'+{1GEZw?u8vʻEX?FyqE)]as8^7\ōP'úMݍFێ;~| }\&8~jú\㎎Uʹt'a{8/KةECWޛ7Q^,e$þR~obޣujߎݛqW}aMCۍaQ|9?[^@;s>vhNc.o\uqc .c]t>qy3+.9w@WMW4My@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c74Fy@c~9pR[DDD.;{My@c74Fy@c74Fy@c74Fy@c74Fy@c74FyÑ|{cF>Oo}ة7IbLE|#4 մZyƝ|7K?ׅ>/ մK)o}a_}_Z.m{y)oި=ty+}k}A¯ϼz;^??_\oJ?&Muy)oMQ}ѣ֝Cw*?w _w7멼}_\ϯ?~ھN"?/${‰ oTV*x>nk\ޫ{ŽO_O?7*y~Ȓs{d5z>X7\w|˛EwW[Eq7W9oKcIZ(~ 'w6N(og/tؼ嫑G?<_? W)OoDL{:P_?+~I8O@FC?ۏvQRދh:w^kFZˊ8})og)f3YCocz,||GP?귻.;i?t+t"ۖs̍={k6sU<ω qo"Me&5ԛ0|ŝg:2IkEѾϨ\{FC5O}l^.9Qp!RGz婈Gݛfx6_X۾Y/?|e{藇N?ߎŝ>.Oc*uwb枯7yOZV}>NTKP:Ofk>O~.U8 ݪK($;_jq.Z)kBxv)O~׿k]܉>/ մK*>e }^.7iVYoƔy)oިʛ_kb S05}_;s(oh(oh(oh(oh(oh(oh(oh IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_installer_05.png000066400000000000000000000206301322762156600311650ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsod!-IDATx^ݱH\}  4n8:>l 40i,.p6hM;0:@GlˢXR?IQG%sbH)Î$Iޏ}x@xpgo qVx^I%p =~^ti9!>O ?[xp}. >}a|x|ǚ6ӧUFʉquV,w Lepx,_E!a i\ bmjV&[ 4:uOe6Sw]3׿yJ覻otk"Rܖ!%mA5Sgrp_C G׏2oG;\f#}3D*RyH{8}_wg/ryx܇J?&-)ú|5w ex_'V}p4ryouePfꤠ`f7Ӿ|g'| kоVp'Δ?in0/^w^L.fQ(F * w}t]r.g4O{;sz|Oǟ~J}<>R`=Cxc>ƞ[v=spY?v/OSXo?*Cuc ?4냶lc YJo{bӀmbM]# ֵ-;uS)Ӻˤ*j`}ȕ8 rh|}h}=V?a{Ƥd|trnd(5!unASsNvQZOu}Euٳdk\WZlN?Vˏw.|-;޳M*)?}`-}<{b x:axu/ؚ0@o !37w!ݯd3b7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI>v/_xsm7tS ab+aax.Nhޟ_?]OK\9Xڡr1H\=ݸϻ/gqKxV dHDs Νx7 =O;mw q@^as~M6A~l7|w;q vm8wpn̆׻3ạ? ?BSxYz=޷=ƫ3}lY6sZe1'x#w{m 3c -~,j8"1}ǰ6=/㱈\V8|<x͝5Nv"=E8)5?yO{;^W: ~'-񾽘3hqal{Har88;5LdžFZb:wtB/j}Ebx۷^ִ,Bb^-lҋY e?Y)=}(Xoh`B^VuR4eV{Rc6KM:uYٯ'e:+㊮uMqwᅫ'vez16;$PY(֔[ϾN8Q/mjkƿlq"*mGc:*bgL}{QnjBpxiYN1 ǣyN_H9v݆)~z1E\(FDhMkL0:yүSisi'Ohk1q>Dv2ic[u,ی*X`aq/3-鈎шb4þ|@o߾n9Ѷ_̈́w 5wkBrgKxXS67m/N6yfCĹ6cQ;.'}I]<+gZV鮹l[_̗=6G;%X8kZ4eNGy,#bEwܙ! |`~'evgL_/aCҘ¾߃U}\x'wݩ^ ׭4O0Iv?hL&5e]ŊOaf6Ir„v9Pv^?iuc;9{r#xPCe^]mQsb\۬9C?Ck3L*x~o49Ӻ0?нNN-&D&P(֔ !>tn:Gt[ZnȴxcN&~Ɵ~lbtt]P"jV#+s,Kc9X>M׸{P{0ݗ1O;f{jsN^{t'/=dxOɣ_Y;-Ne`rl.>9?&{;簮$DZ{ymx/v.ꣴV7-=mfnyM+b RKԶ˖OץdjYmwM(gR;Kj[! Nα:ePEZ;™i_Wɇ:s33ݷV4)DL~V \6jk|l\awY7St%eByfҺ5wǢh<i6)R(f*V63.קi9 sM5˻]4QH0ZS,Ctlj:SnĵmF9ԛʣ}*]ښZth\&{.̒)j-Cnl2ʾ2Q~E5ڛ.׶Yp4)th<׫K͕yNw#*S9o[=5t6w ZsU\ٜrٳ!٤qpqrdL@eK&m9݇6֯S<)mDlV[Cھx__^h2vq{\s=k*›Mz)_܇జr:%5&qt-~1W1f8f`a)] /_汾f!٤򺛬7:yrM2i;!=.wӶ>wwT݇TcF9QetDd'm? )<1h<&|f,'mmMv^r:ݺqaO;6|_q3z߇f6i[oNy|:9;9:&qmr\&sacK4#?`:EU]wYm9~?~u>&OҺi_ZlKy'dJPzxT'?@gm&Gm31݁iI1dxyƒXֈc֥!~G}M(MzX{ -+vw1phg zݑN?T;]ݴ\@sr'sPog\fnA?t49ɧIXoaxN3qQ~]}2іuKrtI~|~6bO*++Uy8QKxb[S0 ~t?J6y_&w帪tۙpibpl3>ry,Qe)Ǩ^*LJlRjቯ&PAxc@xI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@fb7#٤&o6) FxI1›M lR@f^N͸5›Mz)$oo6.[#٤RxHVnf^J![5›Mz)$oo6.[#٤RxHVnf^J![5›Mz)$oo6.[#٤RxHVnf^J![5›Mz)$oo6.[#٤RxHVnf^J![5›M4/@|[#٤s nM5FxIGxl׭l+I^˭l9 iٜ›5&=0)Bq7?~#7vk7|NxZ6a/< ov[<6_Gu(1tozk}F?5vsk7|9_vߕ.'>=[WWݫK?s o>[#٤3w* >Nyy]1$ O#]lҺb~X*iQ;y>6i\W}h(\7>|XJ}t}涪>l?Wl{?nf8S)SXZpaxww+!TnS:~D [loQ{㲩m~Owrf!!lG W]}se}-cG^l9q)sG»wg ?/GyV^^T_G>1Y|pp[_۴<}Y!m8]/L^ѭl9 (sQxII`m0:KM60+덌uzydzn]_wx\ogQp<ם᱉w/ .kFnɱ yFxI4esΆwg?GZӠ8 lna u9Zq@xl蟋dde~Sz?v Ǘ۪6&=09 פ)~vkk!J~enfi뽄wy6&$)›Mz>qaLwk7RjIʭlK]<$y+FxI/v&Crk7RjIʭlK]<$y+FxI/v&Crk7RjIʭlK]<$y+FxI/v&Crk7RjIʭlK]<$y+FxI/v&Crk7RjIʭlK]<$y+FxI/v&o6) FxI1›M lR@fb;$٨O $sIl[M)I37Iw&I$Iޙ›$;Sx$yg o$LM)I37׿3o9uGkl›BLOX(kţ9uXMD[ ,ϫ&k Ux5Q e*IDݛ7?>]ѻ ^~ +›dsLo~aC_B~{Rϭuy;:xKV oY»Ğ2}u ? 췻__ގ7WxhOny_vo?aUֽ7 ;ޙX]6>67R=mqMTmoWY»=ng98L}W>̋sUx$VNj$yh;{N>Kxׂ rIw9u卽 5`^=7KVw7g|Oz]ٕq^FwަhCm~=Y{F庲lB7gr2=3ͻ׿auW~a_}.&/o=wa9zl>-뜶›dﳄP8&d&bֆ9>q}<&/o=wrô N {x]Ӈ,g7{9޽R${M{Y o&XὬ~^7^e^Vx?›d2ެ[S꜌${d|jţ9uGkl›$;Sx$yg o$LM)I37Iw&I$Iޙ›$;Sx$yg o$LM)I37Iw&I<7IVjX7|IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_01.png000066400000000000000000000575021322762156600304740ustar00rootroot00000000000000PNG  IHDRsqzsRGBgAMA a pHYsod^IDATx^ϫ$˙Wc ^x1kΈU!]f@Ap@ݙ6LLB4 󃖯Q1~1gw YFFJd2ʌODVe|;2?ѿLC!B 3B!T0s!B 3B!Tf˿A!BiĔAL~_u!BOU6mRȉ5=&eB!yt?Ǐ~˛Gϫm1쯨wǘos S}}IwFe %jcgBA_}(.Mcg)9mjN}u6,3w.9 $cV9RXZDcjy30s!vfNbة5sżɟոj8XfaVH>wGj#M۝eb_T9BhY-)˴YiKEiɗ11|bDru#rl'8[JU?o} e*+J3`U:oMouvZf-nKo]}t0ǥ.ww'eB]=cBKcLhIi󦷗(3W߂>:Fk`V?yGo^,á%'h8˧m˶7ydy|nΕ :U7oæ$-V7cB1g s$>1qk9fN̛eyc2PRu 4_)gDrPXGZ5=z R4lʸku㒔[BE5opIc~2HKI3'olnZu۔Z8y35*vQ~z6 }}oKIU;$B{MXBt35o ͚[!5̭@11ьxcXzRSN[(1h~USGhi0号E}NˎKw]9!5aĕ7+m 9$֟'4C׌3s4ry2jߛl!h~w՝ ʱ$S_w{A̫bݹX_:Sx[eV4qD|ܸ[B|cz6FKHbʙc?ߗW'WVT%0P!jI .Mcg)9yKd겅C!22\}#|]R03M;+/\+X੃(2sm7f~E9`@3s_/n691db̦<&Sy fYNUƳU9-1iV#V:ج2'L$+t/+v?&?A"dcc #5ȭS1tbڄ%ԙ[8d%NL~ΒYSd%.Z9+/1{zgc{tQrw!XaߴydMJ:eOT8n$`7hsfNVڬ:NEד>5W$%%_8NY*J7"1uYbv6PP~҅(4='_io9 1n9I=SoJV8g3sZ4Vc e|1#5^R_ ҟ/t[m)gTSZb|S:9GX9!!>rcV>3'+FJR|OVt>37dpkJ%mJg1ɪsX{ά>g5sK91EZj4m\jx;Tn(MAI6oԩ[X&0}  c$c0vfN#F13bd*i(DKEu"F1/%wKyΪ6V=1u9\ VrfI$eS#3sjUn髖^q8^!tlN]5qZfowc3'{42*ct9Z\?.Io|>Sc{ngq3/7D#3ƀ"\NZBh!c%O=ADmyY̥Mf.Cl"b56wb:B,ˢf.5:~Z͜~IO#9oΎAnk>67mJ{x|t;JϝVΟ[7s;1VY1s1 [l#51y˴/{EG^|Hy !ux\ܚ&v;1?.7ϥĠI^ ExLL.q"FL&'҃AxP~'-N.h12 m鷾mp;IsK﹍mĂތ[:p4RN(fbpcmb0ΗK_݂;Jy\bY}91\:[1~,.\J^R, f.NzŠ BMD &[j'\9똕/Cv}/A]/n;>/_Ҹwb6Py[ *X^~m+ߗr FZo'XNv.co]{s9?VB'ot&H I"=tk[^4:4-_^tC~JBXQJ)=s+s1MMmoX~sJUtIHۖ׾eLԘ6ƶk+61ͼwtx0s`3'x}FV%\Z\8ۉDKmVk֧DZivrۛ?NP;q╉ܧ"az,aĹ1h"Ƽn7JX|oȶ5no?З4]Q<ֹFr<(e¹rݺ{g\:`mV2sh=dBu7a>6F9yuܶў7|ʎN.nGԮ{q۾sTWk?~{:vb7Θt{̣ibJhьw\ޗ>OO3-jٌhQUVӚ8~SVa¹ yXCcẸϥoXl_ʮ@F <+"]jV_z@f`0s(@` 3P09 f`0s( nz_\1ֵ.̜e΅,|B]0seեa] V΁ f!Yxbfn.V+`3B,\Y``\cB蚅+îU-CpH]u^[ig~ q7:Ī{?=߽kMs{{wcHy52(Ʊt{VBi 3WaN)Ij?c<ΰykSK?~߽~crnG#OyMs6sFb :緻WԘrCq,\}KVf,0smYjV-2iSYkUMV9'mWs}YYߎ[kNwX t!f,3sDPLjTLh0ĬM䘬VKY xEnJlŸ&\i3bNkeun5X:2 }Vwo]j4zܖ㾸Ӕuc}o[7Rfen0n'fu;uP&{[=fV;]usmBy!RX̹ cnk4-!ۉh1>1b c~_SkU+#ޘiz;ӶPEv\BQ+zx8:X2sĕ)1)nV/wY=ۓ f,61sq?ޚLWZ\/Mǥ4=%)+ bm눶͜3o:|UN%5i1ֹ>iH\ JJ۔םO˅dѨ8&W+Y] 3WxTҽYqfIh̹m#wUGt) ۽dGkBIfm4wɾ~fuOj-<)asz|o%ۄ5K/=ԗG?s~ӿ}﫯=О.#JBW'\YlbJ G\W>Pl[41@^Gcvo,=ۃm;X=&tΜ̩vc13}`S1[}!]LEL7Sݿ62O֛]0p8jsՎbۈS'5m^۞.#JBW'\Y,o`bbysFd(A\ܒUIT] s |YzY3EYC!0sesB텙+ 1sV}+?`B蚅+XNcB]0seQ2+׀#t^k?\&Wl@` 3P09 f`0s(̜KPycpk?\&9X5|B]0seu^`Bz+ 3Pva ![A:y0sGMq+t1shHX=w fWYX>ҭ :v"{BuHk{[ݵz'woUH}mZoƥ빭bZ.U,C=1XJƪQ.]nV5lOsKꜣ݉1nꎛW4g)IY+E] e FJ6ژ@{T\zLt}.c<]3gm2FD$Lnɻ.ۚS%3RO4ؤLGʻ<SFRnFaڗI`&>Lrb9b=&V_2c̸ύ[lLQ)B}̕rfnact*-371Oj;8xv>>ifk)';&ʥGVIǜ/+'wχՍ{?n͍Ud"VGS+O9fKkL<=(jx{Mܸ5J9myf 3W̉Y;LD(;u^eN}24q?Cf)2綛z~-iW7+k:{4rmݤ'gǡeMҚt]CnG]i<3sJXN.#HK2MzיrQ>ж۾1Ih2Ցf%F޵͡L~7Ic2xJ3}IḟqD%9mmzu\ˍsx-]O6.N>1K}z?Kz]#'\Y,jN~W<䎛+zrc}Ich}Q~qwPidƓ9G!6=?ι*E~ZO66N{|>/a D8t{3jzEi?tZ87dz/~Qv=kt}w鼯zO '\YfoPkz<1"Iɥ}S̜ĨWšt+\\iifNk'o3ݩ˷swי~G'5 V.4hbddVzZNjV\r`ehUKX+?qin?O_8]xvwʌQI=kq߫qt^2﫞f,3sbdu1qem8-͈Ke<:=`9OCh+s o۬}?/I~\fO.n&󓆺sTwBuɧg_NoۑSoV8IND_:$%[]user>KU&Mʥm!ơVb0moǔHR=u9V}Y#9bF,ո^N";uY2~f={x2l!KO& ? GM=IO2Q?2bdu Qot ˹V>c#&_@5׾X&G`}3^&[1{qo,)wC5C(ԓ`!\@f9+Efn:db25z&V =۝Xs Q&״|+6O1FY}ec1OZNG]_XF-3^3wJ,ceWSP$*W)I;*odzۙX񶬋%-?&>?[TKG*ӛxC_>kvNejY#N]V~i')@f掷\?Uzx[*3yL,ќtEncd|U9{+r:x郮/)9k e;}fj? g61-aט9JBy6sy`*\LVc.f橃Cp1Y!y̕fdP^|> 3W9 By'k^nW}qLpϞ/Ʀ fdP^|>驚O>c2lWϫǰ{xwspi}@ދ?z涺{!j>s{$g0s6g5s[NfgrE3t3{I)'xfN 'V{s'_ .\̝[w_O䢀f}>Vw;z"h̙xU].ӖKsq=fοy.?>WiVoe?oR{(S_>>ήL.eOy+о.r+}FWYf.y4o BhQ} _! |&s֜_AYz4.3MTyv,3&Olw-s?Jz.׆JWX|vӈUjpHqο!'~f`M|4|6|~w'xrfNXZ_bFʜ`5r̎08;w5Kӣ$]_<`E _RږV6JMYy}AM|r D>O۪iZv7ot]<3oM ae- ՗GIz\SR^w{WbuL* ~f*Gyzjfί}U`"w \.<3ov[W:rYuzR>.eDFbnl]N6s}cf TN2sφDO̕ʓXSoC*>]f-΁\N} !_(XX#FW\}| }f*E9'4>2(!ĵky̕fdP^|> 3W_c*]LVc. ak3fdP^|>tXq5nfdP^|>RN!Tʋ<]{:`*@LVc0s僙C1Y!y̕f!BB!f 39Bfn;0s!-v`B!4[s~373BZ}W3BU[B!Vfn]0s!ZUu!BhUa3BUUze2{#߫w9BVޕ!BhU]B!V՘9wWݤ4`B!3sY>Ta{kekZ!BhU]\8f!Va3BUuf.N?3`BTqf;gԱW_%&7{uF+C!Ъ*f!B 3.9B*ܺ`B!0s낙C!Ъ̭ f!Bj 3X&`B!4[sf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bٚk? mq0s!%̜3VPC!Ъ̭ f!B 3.9B*ܺ`B!0s낙C!Ъ}xWzzU@0s!ZUa^>_wJ3BUufW_޷3BUu+sWջW>ջ;-g?4r1#yMՎ/3B!VE9B̗7Sw%&ϗ 7Rec>sF{4=ӎl3BUuq+s{cZbĸWetݩʯ YDs7B!Vř9z̛,9Ӝ~4qI!BhU]knۢY3Y+gs!BhU]ӷ@K0hc~ɗFeN3BUr0s!ZUu!BhUa3BU[B!Vfn]0s!ZUK973Bٚkt0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!la3Bmf!BB!f 39Bfn;0s!-v`B!4[!Bh0sہC!lab5\ f`0ssv3b>N6s=9 f`0s(@` 3P0~Wv?~_ĴjXxLȱn>}1M8_s?DŽKxEsCJx..!^\>JpM/Nw;8?݇\\u$7\c]>*躸^Ffcu3_]3h"&ָkNZqi35V ^3b5H1sC丿U`Qi~/ަ?[ʸ&-܂ݶyoOoN(<{!ٿq5DMe5@ތאp-bu#'kN6p,obC,sw<ӾfV8`1N6s֯GO0sBpx44uiM__݋?ic$k\༌<ϭmH[ɉe4O\p 5ꏦy$skUip]M\=quMemN0s}#V&/V܅4/0zĔ%u2cEQWᚡ?o]Z]wIq)6QLVژt 嘹—^$rX:C \d;wkcE0gS)^tZXY+VXzȥSQ:O+x u6&WޘdR6k+_3/ʒomc R.fx[5MmfTy]_e]4R'WkKve91&1nrݍqO_c[1:Nͪmkoh) 3>ͳE"k݂pE5%\4 jd~鈟ou1MƼԴ=~3'ҺלX6֟ƣ9߶k;WV| Ǵ\ސ`3p^'Fjb0s=`.@3%`D0sf 0sP"9fJ3@`Sܳg&c0@37E9X@"̜8y_x%77`uPc4q'uCuv``hDqs`_kGMл˚MI19?u|W3̹߈p\*G)g|Y2i/IcLF!f kp2Q[bv֠܂Š@6&_ o'0oս冎Kۊ$7^mwqb'{d^.+$98Ԫ9A=wSV#IyʄJ?a90s?ϫ}{շ}IfN& =r=6LJnRKFPMn~*- a\&M=[me|$|}ĩ691-uدyc\̭2}ԥDZi>ELuiﵯ?ɫ{n#apn~VcP~C.׿~VwwU/U%]W2La[3WO8 @\)5:<2'cS:nrϥqtȊC;z}ǓN1qN10ȌÔb>V9>4!}Pz4jfn$?p)lK|V܉<O[SNduu--M͜p[F&̄-ε}I걶orcқx3 /;lgؔW1ǜS1C^jr:ό>cԌfnr ;NKrNdԥdI)d/i/ɽZe,N)3f Uli欉NsMјt^pB"u/~5cmc|ᶩo#qJ~ɶUߘ~>Z1L|:MGoŘqh/W tޡ]_S'V7c(<37۷o%_O'xs,U%p2^┋D:'{1=G- y~ Ovf=I44M:6PLИPi9bg+U~h<ԣq-r|A{g|zZ(=_ȼftsr^4`ﭱc^:l)0S_ե[m5ӯ3kpffn~_Vַz< N  Ol|~SmʶB ޮ'Fro|=xLiĝv1uc; u-3`ĺS&?Gk{>obmŜ?,+5lg@<1 ח:"׹p.MHʗ"[V="֤5F"OjmCI9P\w J&Kc}^k_Y,IWsh/[}n*?K=7_2D? :{ېPOdintz~.=ׯ\zLҼccZʵNl`0v|.KxWzVk,21h/W tޡ]_S'V7c(ۧ 3%rfNя~ߙ|V[6'7UܿDK_&/D¾;"]7i5'ѯ4iWI m[A|V{v?htWc^:l)0S~K[t>fJ͜y6N EVgfJ\Dn3q%֪۬O*2@afJ3@`9(@3%L5su a0@37E9X@"̜Eiq2^MvvyD9yڞuR33'`._HY'S+眸Z$i0s9ƴ^2S :ymW_} b1)loO9pfm3qmշ̊9^ƴy1hŐ?a0s -#,fN&SdrqWZ~m[N7&I(n;e]>'Ӫ#qhON'W+Mu?:ns-`YQiʵVO|yaF.ێ9v4Z52Ա_y?/ I3887s߅̽y1s͜u #lmB'z'/ҵTcTd%ov֪GOl2A6lnaƐ}y hZig,EMN+_ELuiﵯ?ɫ¹sr~ yB`63 ",ɶf$݇IŚxu)Jwmv\e5^B%\Pw s[w<+tiV?!i Ff,}eyy{KVBѨO-3K ܊ fz'Ut1zqJ*K!2a˶5fx3ɓam7ۙ~5Ui1鱘1i)e5V9gcLLf0s6s_V/>c/vzO=W3K.uOͪ$&!u/~uhkuoaiOHV?:}3>~mś8'n̾żc-̛s1Vk,fk_Y,`ycLt}iLXXQk egNC9Y 3S隹՗Ih^|)ۏ՛q/ݪza`I3s {Cdpz& iDUΪSZO~wGO^z_۾^#P6MPl[\KSՏv7{g1֘e[&awʎkˊyD_[1~䱍#KC|CO}E.Vnռ5s4ĔZfMo$}:%=W#lg׮_V+좑}gy7e 3Έۦo}ϫO@.=W5#bbs._Nb "q>_Xb<eR?>`ZRo{z̘6~_?KۼFD9Xfxf.`}ky1> ZC.=12s ެy +pcF<+=WO~M0s$9(k,C}~&3翱`zJ&D9Xf/ fNL<Wh'E·S^\/", fJ3ע6JfN ٗ/p/jr=\)", fJ3g;~2p8f3%4`A%@`63 ", fJ3ea`I0sP" ff3%1 T3g\V=sN1sS565s' zn;>\김qf K&~30d*6}?q$ϒlit۹8@)̃ծ΍1s \kVcq߿f涬. bߙ1c_qc}ϛbOuDjPI{Oo<=-LX=u:{Sŗ/?m . @`s3'g̈́lL꾌0n6僑j&؝: N<\›Ne0| -m&FMxb9[CnbxRWk3̵&nh115Q[q?Mz|(=le1*_V= Ҥ ml=bJr(3t\|ݾ&e6~>3(3'z)ɛKiC~H\x;PJW|hTzœ@tM$_L?.sk383N_tM4^jʥ Ӹ#Re4BhX31:?4n6Qw&7+VUNוZ㞖)@q+[~mgܤ%-O;S4mbrb*smu{Go+z?iǦP+niz;͌An˱Zc*.9n\Qk(@`S3WBo`XJlf 0\9fJ3@`9(@3%R^}{߫oW7K0sP"m~_W?~ջw_o[*._h3\r-IO~Y/`ǿQtĿ 8m0sP"kw`۪oo??YU$_-D=?bt"L[L3u+=&@Ś۷oY;/GC':e4ǴT\k\S_}Wca}.}̉d%2s./Y}[2f@\lj;Yo~Fnc#U٤'gHB>zӉ/Τd&cǦ7w=fgk3PmŚ91kQrk55rKmAL׍3fOHKyo 8C}f{!in1xB>깏4|œ3ӯ\՗4Xm%9#mŚ̥ǬOrrPz1ce:ru[;3k۩w~7??ȿF#'%)fܮy}AէթPs1-;i;6O.=ׯ\Somc$\{|S}՛GG>S=/_|Z}/5_pǓ~e՗:JmCҔM]2Ez:>7՗oz/T/޼޼͏k+Z sk Gێ5s~#wΜ7Ȅҋ& ?>H:nz[6>rS)IY14M}~'N\DkL=q?~MjLZuLmwZcj.d&}X˗/Qz՛GozӬXt7L4M?Dicin2cU1t|*ovD?3m/@ȳqey `i.̹ 0cX2_)՛%*ofҤI{ /eB_ŴJ*gbWշt[gDێ6s*ɗ[o\{ԓ9k̎6YVّiV,:f+&n?ieL3hu?:s:F-U[u~(ĠQI^b9wN^| h ENluZ^kUB.oӮUwlw$"vař9o!ѓrCцF[+W#ӼQ@ O'NAc㣍ȔcGV,*WIǸY5b$Wb:ex'XK mc_g 0sہ\k 9O=MSvdKLW+& EfW3Mku㍯zi/A{""v`jIS7+mnZt&ouzSV27:ϝk{'C!$Swo,"v`kDߙd{ NJvy񓿠 kOmz0x=}5k\Y9nk-YnKZjBvmv6j܎Yqu[|[9@qfnL'Ľ30sS85X$G.{#8*pc!!crP$93sM4kArC^Vi>odE/25(0s0su;[saҖU6\k՛LͪӾiOsb3&Xĸ!*+uvLMl7El7K3XrH'cw9g< :;1i{x·ӡ 0s1saBb̖MV{6ӯM*' 9 7&%bmvUN|!MEnWo]&Φ\,quNyVhČ|pZ}ԍN0s1sznkc+{ѻL3Eٳ37 ,*f3h^U߽-XW>A_NОzbK3OۃԦ'Ǖ<ɻ{IWc=o֢ [q6gkYQ& AwƬ[O? YҴ E9wgĚ4êKқq@33'Wr1kbu RV_0sG0$j\]U7X!zfi97^y8LnZ&LSf61sW%k3Df|`(~0s̝3fnx`b 5nSxY~qXX61+Џ5nC` 3P09 f`0s(@` 3P0/c$\'@ IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_02.png000066400000000000000000001011771322762156600304730ustar00rootroot00000000000000PNG  IHDRsqzsRGBgAMA a pHYsodIDATx^߷$G}Y/{v}؇yc@j>cf=k,F09W2BjhldC [ Mlnj!n  c<bͨU2?_2#WftDf߼ nͼ}3̇>!||#1=>fNGɴch   5k!P/&yV2'ӦӧOga%sV|vˎddɑoL* =AB>UӼ$9 b3DԺ(sҧw}6je|[yٟuq+'?~mUfw4 ="o"nڴR2}_i sAfRV)iK"M鐇6>9 zm.s""O8TgeʏRSd !)Xv1Z䭶EB>$کZXrWK#y\r>*e|]5ǖ  *HϪhM/:\/|Ms]O^\!r3bYIM~B^R¡KN~r&u~eFݜ<9oΖ_U4a$$-3}b}% FY2ĭK$Z˜țh$sN^H.+SQ^'~E$'#UNpԨUP_z=&]¨"p\x-A[tl ^FUCkdNYc6.s4\z>QKԭ LʜlvI{t7ڇʨqjJA} rWd.<*#t,iܨX"m@ #N`"N*^T-ڮD$hnThQSa,W.E/Q};yl CV)yK"jeNDO8QzIºIu yb ([I?ȏey41Wʬ(SԿQm!}QA]Woe̷U)4;>e?lFAEY"꤭n[ۨvGdy5FV#!PAATB ]  l^^uo&74/;!b ^kHnx2?N8'W/y:'s 'O<U&s"d"f&өsm0dNu TDVhZdNFtȗ FD$dNjHuDIeDdCM`H2u*B'&8+9AFDtTC~5` _yʇȞޥʇX^G"W`̽~+iydMOJ2'rHR80KMB~!%oP2'#m:"L͆<*EQ8)#"MDV?úOLgt^˜Sx"L=t!&+{W\%[.eC}u^~'Se`80ѢT-)k`F,^R_iGod=!S7Rۨ>J[n?#9!|p]rMF:x$)܋'H2u2HptH;+ҦCGaJXh9P[(ỎGDh骓X0*S}e2a7ԩHI`e>>1Ǡ!9AdGFȌȗ䨓9-KF(dN-"bԢOv5uRϨT=zsˁՍ0jdNGN )dNѪ\ݲ:ȕwl%}Y Mf)Y;p0ſND^ᩓ u2#'sR]&&WǪ%(L7=ٶ0-u7l9Yj򔪌@4MB tʉӱ̈g{ڎXɅ=z].]3T OkܐOқ7s`\洨hpC&V'E:&sH#dA 9:Dt6H$ʲn\thUBC'夾h2]`\粿Pe2Nj2'_G瓈#\uO6Au}p\xi2G:7#iu㊘f"Dl2WwFW->򀃴b_SC[w}#InlC*u&bIS8(ELCHE3~b4u$z&e:DXfX 2'"XMu2KEFb2'")]/韈o,P#R;f)G$ٯuPZd9!j\ģMR_u\JrW6},dSyb]MkF UjPO7ebrux0ʔĦX߁X"2'p3&"#GDI`JDdۢ1CHաzO)vR)#} mocVGeJ1@Az 2c9d s=md02c9d s=1w2W1@Az 2cJ@Az 2c9d8{OBr#tbdoJnnS̽ɍmg0 cxǬ|u:t;2Lﻓ7ڲbqmK͉:~dm"*Sm:XEc&fb/`[r  wq9Ѕ=ɲm>.ӱCUe@h.uɌmcZԷݶ"a g.gam"*!s)'s<' jͪ/.˰l:~NP~kBfP|ߖ{a]"*wߪfU'ppT$Ըꋁ#?-(rf &S3qrՋ{1Ul 'mJֶ;Sa{v(W}ʩ>?KoKUFjSJٲy mm:Oԇe/ 8ڿ=k# sh%+&Sž s;X|v=^J>ZXȜ Fq'6ϕ .A$}4w*ץ~}.-N.oG6mo=mgD <}}oC +J/[ZiIcõ N>뾖}H_ľ-O `QoM^_(th^:+}ݱR凜 EJY̅` `.qԲ \ԶTZ..j7S}Q__E{W'{[קer_ҘLlȆB(C QJm^ w+PN6zsմ{ɺa>ˤʗ붽>LXk9wTD.,6-L]4b_$NO-k=Mz/tݨQ)==GVl,;qbgdu(X|Dmke%IMۋ5˼Wn{!ųcej9wS52*a…N/vafM]`o 4xo3>AH>&]S{\]ͱ{}y;cҵ:.J$si(PvzK,RpŃ x}@2c9d s=1@Az}+d2s0s?tS:A1@ũS@`y9 2/gZA 7~A+9 2/V/s51m]D;2(ajcۖȌ[]gw:mU}Or5LClZl}|ϧ.f{iQc[~qe2/!smʬ CD.7 2koKY\nlDpI!huƙ3 u#sƭGK>coXWAt>~'c/U*mb6#c6wEjxZ,鴅'm,?:9{ǷWNǪe(WEĊ u$b6WѨ2mR$ zZ1gRez<=*@2}ْ}pKm5 $|Qx䏥*ն9cShsS۶C}gv̶Dfdna_Bu۶kNϗĂ2[}ԷYWn>~[|{G W-7"EN "ѐH.OFӊRfEZ6T4^-ꎗ>-n[vn:游UUѐy2FDRE%QLε^^W_];2:A d_lddN(LC#B!b4]8ԗB/zBHU}.7hˢs9fPG>ͪy!be臿ǪrLtTw5'7 gz \Lu')ɩ}+iT;qrm{DN9X eGńԏ0:ZVf~$h sԩ{2-~"m.rt X sdg]#sA#n siVh2G1@@@+%und s=1@Az 2c9dZps?tdZ!t b dZA 7~,2G1@#s d㱷''eǙh sb2;1[ [[f2MYӱo3f>z_bʜ]ĮF V.RAe dˌX]窏o:6[t\J4pQˈ\bh/p.V/uӥ {I2yd pn2Ѧ0ޗR>LȽKGVc[qMSٗ1q?wrdg">>MEǟ V\8u܊Ũ-b}^ZRlnt"s [*/p2ҐL ;KȥZQed}1߇jߋfܱ9b?EVSب?Eb{eKGԼG!|8W#q|~jdNdadƓ s+c d[[و&qlԌmF#}/[F`:MFe]Rsjꘌt6ݷ_Nqt]E-S1's#{Q#"R x+ͷmwBEu&Jdtˎwr\u"I޲Uٗ8}l_eDE#Y3G6=7;e䎧ĬZO6ǡ=Kz" d_P,VhS",kB\tTXee> &䞾N!re9BVLc}틮3o%"pztݖY-H̕SESF*j"$}v]\zX _g"6>E=U-߇&=9rX'DX}X_pqaz8^(DfH'sxJ>Kq=~/x?Vt d_n5bWFP8(tdd.˕tۗ-Ӓ9\R~Yo"d.EY.p:\yu5YFED}\,L f}{Fl];'5*WkC}(sX'zw8ۍߣD*t:\Fx_bj=JU/Gkj/V"Z$%%h#s0g߬̅F/j]|EZUp ^}&>r]z܏7)X}#A.~{b>V^Ѭ0de#܃d[EH|zq鿸]On_u151BWڑ ե +#y!XsL\$+}s".tUY5c%k7qj1IWX=.*JrMSc#:u:ne$ISE})6I RZY)7{<| 7(',C eY%2Ir2'˪҆R$;>g۶9/Jsuru05,2"qjAudn^E̵=x]%蒴W[UfQM]}roUyC~fUXې 0<UwubmH+Q}in۬}WhYauQrKYT[]sǭ%ga3H2/8ͺby8"ّMv֎j.GUL.=ngb dnL}]/@AC d_t[栳 sA d_ s d b dZA 7~d|er#@pI88{F6N^җ&7@Az4Aʩ{ɍm4 ɍmg s4 H\ @B$'uN+d 'uB6Hܜ#u·afE,RI$Թ8:Ǥ0+ԇ< R'I:RL^!>B|"O {l|y/os=ɍ0 RfA A,w]X9\S~!u@!t!!w  +$>spK]|kdn`O4Ko X}Nc9?Op:@,q7͒ϱiR+dnX̅٥$N[8|(׿+Dcc bK]82' s0H¿i_|ɟϥ-;-uQ:}O ]c2wybF#3*2i"e3L䶖1ޚէkkENNB,qZd#|k_s ~׼]汹̻^s_5k~w~[c{Td]@ p NK] u)}@X)[_%;6c5ޖI{!O{}&d.%r~s5w ' pA3{{{_sUGgO͟yUJo\D2|֐ϼ;˹<3qyBY/J#5E9'~yڐrq5+!CU!OʫmwyNDi`=S?n75?~טwE+}E^^f[o2_bN?y}יEgNżeי\j?>s]åoK>t鷨YwhV~GμOҢC:GipTP^ՓdQ\tsϙ]{n"x"v2Z'|:dnX9QpOUO/,Gy*"eFIA|r.KW\!2+o%-yt]Mڛ{fu"]^kZ}昹;ը7\}sw>ŋ3/9W ˗Tܙk8cvF_Dn{< vq: TLέmi9TL99=:\Ư=spȇ2\<*/'t˿_ue2l9Hv~%ju4l >oIۖ 9G?K99w=rOV#sLE2XeT.< {/d>'s{ǷͶd BGJRiMBя={BʆrBVd s̅“32g97BwܦpӓUѩV;uLٺ}3z{0ȵ-鳲 V$}|BrϳTk9d s>;;m%G QnHF;6E ΈXUյ; }vl۩ G"'e.<!i S\19]q=蝿ans6Gubq]WoӼ7tW?%G8,*SSMӛ=_<-HY:'X7ynw7]-o՝o:ry=˹Ğows-p5!\5#~Z*gNŏcǏ~#//COOߛsKLu&Z}rż̉3^Ȝ&"sAl.ɫ^^6-?%ٕ0 ';7us/5A rkEnد̍<, u܄ΌȜL/VIBɑ,vI^_n9Xjm6 |-$dN& sZdNF*pOV=PBB"d*Y]+&.m{RR1AD5꤭Il c2ψE b3!諓5&y2o9ba s!9 \A戅̅@f s#2G1@8lFC6QsQsiA戅A ;yN>d>l=>t{{{z:Aİ9o:lNxΉeȽ=2F6)ONFYC 2!Bv]SS6+Q\Y(s;/E 2WCr1*b7ŴyI[.}u;{'IWG3Ysӎq4փ@٩|+WS;cvB.k-SKٔU5} _X-lE sAdNSYq ӧa=ɜ"'H7?e9qXX٩`K"v6q|[ kC sO n}n)DkHS'FfdN LEtdʊ36îtm%X!*e/.%,vD-6܌ٴjv:jӒӬezurȜ0555]Y[_BWLoQ}I-k[20l[NCi˥W̅iPXLGye;#s4NʇK5Kra-6\Ym{bQ"Ear Oxͪl)PT_S}.7hE s7k#A 2G, d` s#20l$s'ud@27 RM@d`A= dn sD7dnwb׵lԧoMn̐RsX-Qt6eb{#>yaZ{戵FgdN_ z/.\uע:4ԌGc3Mn[nq{=~-*7aM Ϯ?]vHuˢii.z̺kkܷ-d sD'enw:.֣ xOndח1)\dl'Y&.]3)їat'*_e } Z y|Re]۹aibǦ/MnmټxOR_K8߹}YlY_C,eEm?wlt?w\~FHpaݑ9w'o}1طf2ݯz\:黺eI<S$ 貹yU]t_4}ȴ;U}6,DemW٦#̛{Isy*]\UDV]w,m&v%=8>fu6K+'{%{BTzȦ'S[U)/ Xh/G Jܯ޴l\Gsu}^T^o2UWw*=t&>t.o%mz=Nz]^+!,x 7&OJD2J~MAkaF^^dnHKM qٝ[6["g^ӛMyzNMzWwQzXO _˲%r^^e&eJ9{,d"#`Q\um2i9hMdFܠ2iԽoEz1=F0v'a _]\EقL8o2aـNmݧ禶Bt2ќ8oӾuGl}_RGc.o(Sۭ7ܗN} Ri~ʑ8*>&RA_9,:fvthM_dҥKa2w/ӬÊ~Ȝ, )pOM t"7WˋT qT}&N$ˮ\q{{J %"s/Ʌ*&9d`ir#Rgʄ:4 ) ~'I/%*#> sʫoåe_Q50/gM3;!Jꫯ)/r4_>/Sy*@ttv\/^t{~ I.%~ 96:-sZ`"ё*07';v]\}q+JTyiR]KjY^U+\[|{:orn +9Yic2ғ-D2@̅05̹08]oLo~}I-k+9KN i䅿:8+Dx2t+i J.}.2~9}t(_uNf]W_];2:@ 96(saTt24_iV^)HKyצ_KfQٰP{\eٕȔOyfr:UQy5; Ax)(7fmTOTc)ɩ~Tډ%ke$u] sDmQ藿xMuͪlɲ mBI\6\ۗ\">p7H$At"+ddR9]Al<9υDD c9 ȜGdYsA]8wz. sDm sCa"s1@< t9}9WI'Qݑ9X5A ?9Ϣ9I?z9{!9mN>O=gκeP֫b(x91Վ+?96"'y>Ͽ抑9wBsd$_"yOJ]8kE9|_iG 2G20lȑ X E'vN\J$-N} +Rs3'Y{r:+ArkGo2R s投?]E\OVtk!xv|__Jnf sʕ9=j.~0a˳rQ/FM˴d-2җ:n20l8{fR s?QA2G20l d sDm sæ/2:n20l sОv2 *9a 24p6ܰAd` s#9 d@27l9C27Z!LaC*rB~+dn sD'eΘ s sæ=sÉdlF#3x[{v'fkkbvSM AMk$7ցu3(s_;2oYaH;vsOh 27lZܽG!EeNOEDDs3eL|L8R_٦?SޝfTkou}vym%Pa$zRlݡY3]`_ sÆ92'&.'re.ަbt7i*m\[a=N/ rL6\+JoZZ d̉iˉ\#N$}nKmoIi.}2J&wM@ka9!]N䄼)=+O. IB,Sskfu2=lO nfrfM@ka&ɜP9+5YVf7{ih*z]? 7kq e!x$,JO-A1J>؇\a97RLnKzuzX sæ É@g@ 2GtR斥*rB~X+@gAM;{RtMVC~+dnش{R s6FfTtG` s#9 d@27l98ܰAd` sæ6ցu39a Fd` s#9 d@27l98ܰAd` s#9 627M!20lajddnP dnش9Yp9r\>dn s27`$Oİd@ 2Gd927:@Rdh䗈>2 d dnA+iaEdnwdFfWKW*m%$3;N{>cwvZM>nV\}ng@9gn`1XkT&2W+ 3;f3ǷGfgΘV_\za2FfV se#s:ootn_Bt9ׁ2GO.:yv'an'5!A۳RHm365{1Q{ci'[eW.=_f=E sD7e.oSn$"r/YĜ50/Rnφ^UigvB>W_w!=R^F5i|_"Tb%r:춹~/[_*fy% s`d.O0D#r!tr}2VLF#s\;Ǫe.eK'[ga2/uӬO%AZL&/)T]!BeuÔ[IKUVr9WsKߦۨDN^x5N./hOP0dɲ~" meI Ax†Ȇw|8yhpw DBNUTfN,ꮤ:C^>EY(dh&s~=Ӭ>UGXJr>;vrt .2=ֺI?̭2MH #9@dnR9]DF s܀YA d90A ?9@dn s1@栍C 9I}5ܰi5227@ 27lZӬ d` s#9 d@27l98ܰAd` sæ46ܰi#s|6ܰi5246ܰAd` s#9 d@L7as#6 &A 2G sN sIa@ldn s27`26eDdnwdF#3RjJHaxTe٩ms|/l1>}{OL26Mz0xT027)Mllv'v"^+H̝;cvmu'g^rz@` sæܠ28=tdBEpv|Ͻv´9$/Gd6 27lZӬ dn49ĪQ sM dYӬ\-s"]r.-R?ZlP#p|=D] sIa9٦H l=D=sfNJ;+`;'g#^S d6 27l)dn(9;R}U#6ldnش9gn0 d;&AM+sO"s dn s d6 27l\=s`.\wM V#sfq-8Ms0qww棿f:1.7i̛o+@: 2ם@`9z獿b9o{youanrn=9]jrM}͈'atB`h "F_hw//׿u/^xٟ?/|<+9X"RA G}?ovww韺:9h/o娝\!׊pH2A 2A 2Át "h_W%螂K=ܹsGA:?OO}S}Μ?ޝǟz)'x>;˹^rk\ yw]\+u#uM͐zh-sM6A 2709aA 2709aA 2709aA 2709aA 2709aA̛& sC602709aA̩S d` ssdn:(x_VH2,!w&r~ db*s3f<J<ٲ71>2Y%-'m:6lH.ɖJ>Ϝt`:9d ss@E2H헧tT=*͍i elq6Vvyʆ)ޚc?! 20l9i4kW[ȜHR2tJht0lsy{H矄q9C,}+_qȇ[>_җ_ewt'|Ҝ;w<#@s'> O}ʝ?ϙϻSO=gux99_r k? r}kEn)R{TzeI+DDQ(/Z"eQL90zq|򓟄[ #sæ?2=sRS?e99} ~i @qӈy s H|5G*_ XE+Fu(-\o s!K|́+*3gū=sMIU=-VBY]dն^o s˃̭dz@ sd`M syՀ́2&6!sO6"CjС|9zhd=?s@lJ9|}dd95q2gEn4:lN ]$'[9|bVل̝?z Qu|N d 28XQaSRfф99X3 sk@e΍6'҃T8r2HH_m+s=lWK~;Z[L܋ ske.) 2dI!ZiB^w:{ { hOӴ%A@@X.sMFte[`4s2g"V&$,P  sk@en{6$p2W{ϜYSSIi˥9N_mGE2V,^8/,eD(\ӬTt8%#sӬ:Y!mȽ d`=Y9/8zMȜP9+`~8~H[S׳@t_4@&d/lJƁܳwk\tں<7xxbvwd<񛤍_q@2[ +Go6W_}y|{N^NDI/)Ov'[f߆\M}k,Zxl4n:G^ܓO>iWU''ݫKz*?,~dŋ@ ,'u4\=KFμ[d3Gd|檫G+#sO2_#sOi%y4Xmͤ-JW-V"h.syrOV||_EiD_dǗ 9;ü o0gϞuC?ݫKlHf,#srs,2Ќ@qӈ@=#'>[}߿e~ɢek_3_z7pdsUt-ەcl8]oS(:D_|yd!rym~TH=ʗ`{29a#{OG{2^?6ϭOi<2GTim}qޞ뜨lʜL/׶|S72.ڶjx4'o+'nYr/yc"s?k_iֳ\9:2BiV=YsaTTT-aow2fg..5ছn2gΜVOKE,?ǪY3K@ 9GY?+ ^W2;斫%y={ k\x@^ >j]-L_6*euA}>Y9=H\r$NĮ;5rb$D:~:Y#~4*-S36ܛS3Ce?j=!=  }O]?zeٓk}}s{P5nN SÿO5,g?~}(ݿ6eEc8IZ#6ċ/2#s{?t-s>UҗT}khd.`<4vp#seq2F"_Qm$T9}Qz&03~U>慙㷚~i^_5W2]cz\t|_4_?nW9\2:+sr|H|K37'9f$ |6rSEz Jwܥys'd=1 sEя?s2*WrGAgeN{~yeKl|f ӗ+n~Z3~% YGr:2ӬңiTYCzfL^ǧ='rubtuך?Gj(/.# .-b 2G吹i? %;+Z9c*c]7g? ON]xb rO<#N3?s3?cKo?2@א@Hsc\+\9?ޝȅXsr)VdB`2.\ NNr"ɐkOŐ|lNRN,B<.q2@בsj8ʹVιrܨ\jU2]9ph[ftNNW91ʹA䤱N rTD]]GΩ*Z9ʹWl=='XCIz{藯.d4޹0* IB'R''9h7 Z2MZ:*X99Wνk9 "Ws!s_s-ɍu s%|8ntNO:99IBNr?8DdX_N&rR r'R @oO-t9ʹUαA”圜0Z7*dN_+R m^f2B DN&a.];.!sOҤ/*X9׆n89'˹YO69d+w27<ɜ B'7 rRFt ij3]e|&|W/!g:b>ڶB6oUεr'd97FR"d\2>eS׈5d)r_l?Xk~dJb[VS)bk"gYhOգ\e^טn~4}/yykO3㜹hxŜKY1nq]E_7[{m?D.H\ s"rA~KיSju-2뼫eN~[nM~+}sekSWC~6//vO???9?7wwwۿ-;¨*Q*S9^W$.sHT=%j>|.?nnjs!9|u/Hu~.~y<#а>M*-Teu^ۙk W:O6W(cn+̦?~ڟ[;RfX"'R6 >*C>~v9t qOawmzsV>\{ u֦|<1*[-3#I2|Tįa}8se5UHiRocnBnꫭ4&2G[m sm&W,^a=M%e'ʋ^k T~_j@R9DP?UO {>l'樽vvZ8d>Q.^7*sia]^Sm)zcuگ?Fx92yC~7{F`~OλOf˽|5nrS\cΏ9;fyƾ5w|<ߗrzpʍ.ɲHSE(Qyrueݶ(M^XjT˩z +d1;ob\1,WKm>\NB.;-xAFdZ7 ]"ga ?UO8?)dyץ:mߤTa=l./q1{ҿ'p=;FrY7_=Zo>in>[a{5O=eOaesQOi/J]R)r_W9+v6U2ie]A,9i L}7~+yr:W߉J?3QKŗGzHeNh"tFiҕR וZqUWæHT= k^Qvn/ȷU鱹kGS:XIzTa=l.[5q/˩cQsk(O\GjY7_\Nn͝g/z!+p\syZNn0qf2W *eTɏJi9q3*.SV*uʶPg:'jcɳ$Es7K|ދc>zZ?:-uZHXr,r<|r3;lO#\si|\ً"~E.kGe^8{t϶K "=[n7:' >fnS\zU`A|'U _"}reIs gS6+0(Ƶ7M監ceRb!>o5`=cq} KvGmz`lK'52wQoۻh2&Ӧ"m߭{rzB%!O ew߉̥A~ ) GR@@7re.H rb`i嗛&mz$m3W{~.Ls ϑ: Bcu66oZLܜ#u·\]zX$sU%c u:!+Kmm߷L- 92W~2'%6-R?\:=_O7HD 2!:0A*LID.oEףi˥3P$XA:sX26{"%pwh2>|u{.s[ dHoy2 *Aލdn5H sJ9#mWo}[d sJ9#mWw~Ց:mXV:4zCz- 62L s}Q@?32i"ﲬ1tU֤.ӁWd>q.jd`T[:~ơQUIm i's| \/%O1y_\X1k2Wº{I9w _qT5n:>Q,9󉡎 z6mv4Xѥ[".OtMfߒ}uVYsi "T)ڊfOVZ?jMP߉Cݡ>Onߒ}-qGt_úJK'\Fk#e_'dFeGMl_:uʌ^z#s0,ܲr#YK_X2]fY9fa@A<d@i-s5On#tdHk?!''|Ҽmo3zիOOWYT~6 sGZ;~-eo7={|;1?ݫKldye@λ#e[̻nf5${qRK#9Է$sĽ^BNl*V2Čɍu,ӘL/6c>ϘwӬ*!$_k,Qϭ~:e%-Iʄo@?٢ʎ<6{ތn7Xnɜ9sڣ>& tOKH : Ww6WկuA3}NIt@Imiszӛ&ftd#s?S?Iw]?zIP#Wvq,W~l&4l[0vX P$@*?LoL>zƮh?Ng?u@vntL\cSz70g2G}dnsftׯ?eY !S .!Er-+|Yq/ӱ/S6ٞ"$UܒJDd|>׭3 AxD$_XgfrNվy%ue@Km:hsWfMncld.ޖʛ4=-G|YYv#IHnta=NT9}Qz&M+.ב;:!h29ڜWL@rc4&׏H|Mܧ?i]g.{Oכ/.dNMS#Hs8-?UNo_IzJ:ruuuCh29ZܯzeNNя~HD~~k9.d: 9HEHE$'83rejl4' A Ax)zRE|,6[Fף?J_T7lkI+q9j(E$Wce8.a{MB6]/ omݷKLݲ@<]RHq4z6LK%kO:=./cEK_ѹJ>[_ox!T[I|aMIFE~CkJ/HbVFm־T4c\299O7eΏ s0QhD&oF*_WXtܢ-e6YUlKM%% qްC;~ $~Cx{^y>hru/299OWeߨFtzBdVO+FfHhQ4IHmOFhOR,T;$(G媜y3efX1EA+IթNUoXVT䟵U5[Q1+t^$S)@<ݕ9N9JWyDbF?Js4i0&k2Ɩ|c,S #`ƬPj7C}+P}[ryf@{9$́x:#s=Ch29ܽ d@<@;$́x s@62ٴ62:929 sd2A9:89@Az(Ne9#d2>x9#gY;tҤ-dQ۝Mmlf:fZٖJac!_G[f.Ȍ-w:˻;W s\2!O.ԊAܲl,:&9r%݉V+Qɞ_ɖ+7-S_~>ږ^x<5 kBr}d,j47ێhD/lb[z2̹ױ76  i05/2涫rz{9*'524.S춐e$PQe9 cڍ%c짮Gm%U.DX컼gz+y"2um9q=74{C?@<9Av"Ed UX'ӯe=*',9Ixjھ6xTj>M8?y2,e0:ҊF 2yAr~/QB]dGF d0YOwrR˾ˆ~TyFL?s}ퟯ?7*mӵOfKH{hWm ?V\xCňMeLqzD r#bv^mYGWvK|öЦ+[lK%Ιΐg֮ WW+Q~Vg*Zi^EcG1ԹqztaдS s0@6*s]&!+ZӬ0Dܲ<@A<@@<d@i-s{o'7 2}Ӭbtupr.@isr3@9_iVd2} sG92} sG92} sG92} sG92} sG92} sGڜ}$6S s0@9#diV"d@A<d@A<V2Ӭ0D9#mW| dHӬ0H9#>x9#>x9#>x9#>x9#>x9#>| A9_z@i%sLA sd2A sd2A9f!@is{` sGڜfA@A<d@A<d@A<d@A<d@A<9. &9<h6ϩ94+@Az 2c9f1|@a s=1@Az 2c9d s=1@Az 2c9d s=1@Azc= H7'?IX@-K^:n@zʥK CS{!C[Ɉ8׃\ s s;9+ddn s2pՃd`@Pz ʁ܅DisB""gͅԶ;2GGi:_O̝?z ''5fd9ϵ˜跑`eC|9 :@`լS.=mΞctΜ7d2g/GhQ5me2w9|ā^d9z-2f-2w ɓsU72wtH|{]->Rrl$O!OJΛ2m_9},ScYNڕ v%]˨^8.OצާEmѣ@Y]0N4'O5r9 bI[s֊^DlA89|"ΕiѨR%:zmySXA9tx}t9M+ZDcd k32m/I3+9Y;}.-u,bV u>G[>ش̽( pRFAD$z{ʑ;[+>*O~ ĂA3ț0%Vl=]jtol^ :t؏9I8lN lN44W\=s~dMM]\ޞzrW@|}!s}f2Y枹r]dn5%[4͚stA7O논4Lp3g?*c"__R;2W;͚xjߓ8@YyO=s?l;)ӭRV_!ݐ|4z=L%us#DWӬ+tkJ~?T=^G3딹!]8?@AA2w0=G9>Ճd`h{z!d s s;}c@AA2w0=2cDVqEIeI URm@?dLj!s=1@Az 2c9R2?yNIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_03.png000066400000000000000000000620361322762156600304740ustar00rootroot00000000000000PNG  IHDRsqzsRGBgAMA a pHYsodcIDATx^ϫ$˙Wc ^x1kjBr3^$0҅ ;ӆi\kԾp}z _{1H|mZU[=d:m"Bg_|1KYJfNMׯ_gagsM ͑U LO4jQ>|x4oFf!:c.ILο];VfOO79?3-'<_+̵P=j1ROcu#Mۭ种ľ0s!ó)ZRiҖPӒ/9kbȉdu#rh'8燭 TXӟ BmlJ㊒j~}p|`2kXx:3}M,M<.9.u[)[B\cz6FKJ7}FB~ V>?'83W9X5m\'{2>[bp۔xNW]>m\]q͛';\I '8fZXcP-B!tZ1>0GKJw*#':̉yy"̜7/cL6\ʷ@ŘrF$g( *opԪU>OI0*Eæ,;>Q9.IE!TZV1Ti)I|a6kfUަʥ%ɛQk4\k.iϓ>$uV휲㒔 5vbE!Σ\4r򨏗(3*+t6knULD2[bb0"ѱtRSN[(1h~USGhi0"ݾ'e%[Bc|Naĕ7+m 9$r֟'4C<׌3s4ry2ܛlC8V ܃7(:LI|U 1qsbIV頾OmZes㒎SvlBiY-!)g^3//\JO_;zW.QB!PKbxpi?\EVRZy9?`'wV+۫E\+g3s`?͛ +oz+U>Ac:clfI~2o"͜Yu|^OVdk6I'_irn9 1n9I=Sc}}qO% e 9Y-J2bH//J:63)-1[V)H}#9!!>Ƭh }fNVҕY uN XE\jtR-k5s%yt>QڏtsH}ߜlk>:#E֟#5b8DX:,n#9Շ\jDb$YK?ȟ͜IY풸$>1c(J]#RNꉤWʩ1s3w.̜iĠMR_)̜erJ1+mz,V=C[',KfN,4dHPYۆzVqCoJY]&%WGDJWSYPZ&bJܑ4)Pp̘1{z%LLP_9I#h01SrmhEL6:4r]Ic F1Ĕ8`97s@` 3P09 f`0s(@` 3P09 f`0s(@` 3P09io~( @` 3P09 f`0s(@` 3P09Yj?nf[6raXpNvhՇ89o ;ś}fe Sƽf f 08yk3cBM{q8ս9X78a|8Z&ooԶld '&l|[ܶچ›ݾ|^FbF;MIvCvyzn^lYu󍼷c1zS د6Ri5'Lb/=6F+U6[g+WޏeK)KE9q:GdP5zֱ/r,ut[lc۬%MWu{H[u?LW[WC|X `=dBu0iB_weż\hO>fej'_#LjWd~c_F9L﫵?~u"#Xo1GŔ(w;O=/}xF8n/W z̕ec,E4C3ssmsnؽ37ʜOy'\8Ѹ6·Mu{Oc96PK=WD^ 3WnLJ;}<Θmʘ3fɪ lr:mչW?:7ל ıՇB-,\Yǭ7:F5iz%ɟGc**դۓVm46r#}vuoƚ_#V}=5:_Rf݄T0WۧqVw.5 x[=o%/4垺뱾ϛo)27KYD3ֺ:_(\N͊Sd=SS=fV;mu]By!R8FL7ѐ\LOVi~YJVrm}\buMLml6ϛVվ_+t\03qeJL)C].GQIհKӶKcz.\lNfv}ykdǙ6smg i̢P3B +)ќk̆'#υ5Ʀ4]_o#A,)Vt;:VB펙D:i>5cV9ke.qRf37p|+Nq u>'ncvzMylODP,kPG\ܵNߧgOn/"OX5@5][_GCGR^E:mtϛ1ge&~f.^oO]iJ\ JJ۔ǍJ˧BhT꫕t)B+\0Hޠy3fm\X鳷YuzR>I1#\6˧Wr۬i̍cmm5aszxm%͗^KɟFkGmˈs 3W̉)ېPDպ.[҇d*X#fQl9Ymkx=WmV]3$&ę:1@cTt!f;Uo#cCuÙXY6GwvtFl=~yvrqo{(=G]0seI*&aEo.b[R|U!Vf,0s¼vjK+ BՄ+ ũVB/\Y`(0s!t̕f3B+\Y`(׋ f`0s(@` 3P09 f`0sp_ z3G!/tB)\Y`(0s!t̕f3B+\Y`(0s?8+f,5sf6MyN~L ͮžno&Mv[V7vI77V=c!Z}O?QH-1ܣq5s(g8eω Bs+W,ln_չ3[w}>wf#54?n[eHܽ }bvzHe{cmDönRcgzmotoc!u#c6nR +eiI&>5SV:W.=vǷ1F7L2|:Ҭݲmsh Mm ^nL_q8}ѯFɽh4|Xi#n>r(7Cqjד͟Sd=OFè{^ϒnVPGX9aFrÒlEVg:bY\Evj#8& mSĜ닮3׬CN1pV<]cf(N0Ll$0I&DKp:=N|u p}I8r&\ch>䮛+zrc}Ich}A~qǷPidƓG!69?ι*EyZO66N{|/asBcҶr1XSp,23hh"<0ij9n+NhɄ'd&һz ԓ\O㊑ԣcފI14>$'{_c7]sQO%݆V3΍_ԭ]pZ1]_o]꾸z:ϫChH8k m"1MJ.=w8Iq%,Ig_ŕ`2/uimS&]&;uvno;_|z&1Q:EV<h>UOz;/oŴiLd_ۅ_8FYc%=}i&[}cb+w/&ߣw]ihW{1叭9ZxFF=FlJYԱ:zx+WYp#S>E~e 7,M*3'_Jh*#c3srb6(%f`Ĝmۉ9Ug+\\\ \v|V~11d2$7&FD(rɔtH[(N'P|D_ZLnbyHOckzbmxc啤ťk:}eG#gXœW9fAq?7n?Z!i%ƃ%\Y,hN@j^.1ٕ"h9tq qcѕ 3WEbվܟ B]0seqf.B]0se! 3W98 B]0se:\/{?\&9 f`0s(@` 3P09 f`0s(@` 3P09 f`0ssZ3aWl6զ|~>׎DfW}Vb_mV??TwS77w}4 N͜N9qcR~[>,ƴ2S ǔɇ]?uocAtr};mfn:9&Ym|v7>'{q CcĨ˞s==Kfs9N_}mbnRvۛǥ>Y]V&/Zun>k#&_@5ǾZ&G`}3^&[1{uo,)wC5}(ԓ`!z]@12sVzDmݤu0z'/e=jSMjz;weLiVl oc0zC}#MƶcN4]_o)ԱZf fXFԩJ׏V>H 2sqU"RwV7T?[TKG*ӛxC_kvejY#N]V~i')@f[v[c^8lKe&\zz={%.Qm*':0{ե[mEcGA/nǤk{yrh.,V4  P"9x'@)` 3P09 f`0ssfP8bB!\3M!T9!Ro 3 2`*\LVc0seCp1Y!y̕fdP^> 3W9 By'\`*\LVc{lT|f\>z곱'3PbB(/^XgOgϞUO>̼p{x^=}z/wz.fk=xGfSmVwzf'Ϫ?{Y=3̜YܚY|3:9 դǔ#yMSM[.[)3oIJw󧵃nVnR{(S_^^ήL.eWy+о>6T'R\iC єǃ6|~y/5\mΚ+9KOy.=2s4/J/-2>cvݒ;Pwqun(oם71h]'+i7' BI™׆k%&3XcZj}2+s՜/ʍ3;3T@wպ.[y su:=%^'FajŒ=6Joo5P):9YV̕AfGlF'\`*\LVc0seCp1Y!y̕fdP^>cC1Y!y3ǃC1Y!y̕fdP^> 3W>9 By'\`B!4[!Bh0s끙C!la3B̭f.ۏ_v|C'[]GacovP1u=US(>o3Ly5s?O`k܄"\)0 ys|~ѦүEuTuLNVJ;VK^m;T^Ąσ`{t/ Cfnm=ӭ>zcμ>YE+w%Sҹ̝Y{poͿ?rZroݿ\}GzO-d5yhj&˴zݾUzl2ĸ%9=2{Z&>x};-aXHkp|+zu|NEnc>_w.eA2cT&+](uZs+6e4[}SՇ^5 D\!:K_L6ZOn 33шvt@{(=G^d)nMN+w_}}tQzxccQ_(EgƘ/}+1sNr/ǼqM`%M\!]X.Rmn:ㇼä(n h)鄳ÛP;C}k,%ي;c~eNZ8mO0>D/%oj= 6s3R[REZ!BX]s^]_zU|>&ݧYeOȣ7s7Gy@-̜\﫷ΰ~{2s1 2B*Va0s!е 3wZ0s!:̥۬og0sB!t*u>3z֙8uW{^:C!IU+B!N*i!B̝B!N*i!B̝B!N%cC!l5sp<9Bfn=0s!-z`B!4[!Bh0s끙C!la3B̭f!B[B!fkH.M!Bh0sXA f!B'f`B!tRaN f!B'f`B!tRaN f!B'f˗C!IufJ{u'T0s!:.}ŻջVZ`B!tR]ʜU~}z>y]~ʧzze{}S.WC1:BW4Z2!B褺3?'|eBzzM{o{{-/Mϴ#3!B褺Q_F-1zbީ2|k` δ2mWiv7eW?ƽqbrJ3x?RGqKH3L>8gR]Wޣ`%3蘮 ,9wۜY$c9JӜo֘cLUr~kQi~o1T޿ +ouV *x{o}~p@!8!f&r/fG,lݹ#+_b4鏊ly4J;ԟM-+-\obѕuK{/b^_;aҚNk` 6s֯G0s/kT>wʟk>^c$b5.p^ƼڄhCZ41'ْyV)G17Ѩh|o\>1nl7MZ@f.!iM\=7F#Psx_,3g[bk|ɛ\*YE ؽ4#,3.56-׸mpAVIuK`LS\o,Vژtw\1pO[c)嘹ɟ`K>Öi2͙)Oˇ"lČ$+kޠ ht_Y+VZ' Uhˈ'snIWq V@?fakT}aF|_po]I~*ߐgq|kj9ّ i]_'1fNL6t9#7hޅmD2ג޷3&ݪ:W@arʍIog2:_Xw9)bNˏ9cc1b=Xtzs}=kǨ'd _{rnd]<ԥdI)d/i/=Ze,)3y8 匜g欉NsMnhLz.W\!fXC_6y[8z$N/yqZ>9/_607G+斉Y<3k;4cKcs ̍vuww%3tV=15їRkVf0Ѱi/IcLFI'n5 ?ryxjYJiկ?4x;I9n{5_hy1_1'uOW,;24ǜܗ=1{k,&>)t'xh<>ԗ.buV[Spf_򗿬򕯘x\$/pv~5m9ty"2]OL3|z:ř<;&cǦ7w=E!$[fjOݛICcxfېzR$]=o#q OmqXd+׮^Nk94q\ǐ>s1duq cc]c{+%iuz"{k>X'1fn*mX=_2Փoa\V9}}(=WϘ1J˥uҭyZz}דcefC-fn96qfN>'~d$u&햬4Ipm[\=cJuқs51-͗;c]oÊP\9Jʧ"Ôr}e5V9ޜgcLLf<0sX3'N#>X6[r]m0˄+_ u!硞0dltzy.=ׯ\zLҼccZʵNl`0v\|^[ZЪkc_Y-`ycLt}iLXXo-frX3'|{GnI>|L閍{㏓C*_n"i/?raNNJs;"]7i57SO<ϥc_izӮVbq:z+;2o+6~2Yca0qLS>IwCa>buV[I!o}E9e 8< Y=ŷ0sP"m"*/9ȷVfxO-3Hf`D0sf 0sP"983wcu f p~P?fNf pfN~e`n_8UUvvyH9}Z9f p 3o}mS̜{sBʩ8d~P[2FVcn_;?G8bܣUbj~23C3_/`A18\4roǘSd$k9ĶjwTfia/cڋyҼsb1 fdI39I4s2"7w:k߬wJv1OB]v$˻|>OhUGnSJ硝N!OL׿W>8~t݊[ҔkX}sq1 xW]sdi1jdűcۋ3>__gp1s+͜u #cdTL>#7I7~HDKFPMvn~R &^- X=L]CGRLitXVx#Nz:%o̟U&Wץ{}^c_Y-IG78 {;ṷfnD9Xc̜51mܰ'__aR&t]G&$,Lc҇s+ml.=oDW9n'h/({W&ԝit}Pz0jf@0s cĤiC3rfN&S#oIVTzVMzƤ҇s+ml.ݯ8/֘Eg':c]o3jʫcgc1clӼSjr:9όǘ>X;Fx>a m>^|qqç՛է!7zfX3'DC3rB45?mUIMqUC^|uhkuBYyI>יԳ ۯx3c'z_Vٷw`ey3bn 4֪`Ōz+r:x郮/)9jANB TfEy'CEeR?>`Z\>y™16\6.'y0s$SrXhʂiU(!Y/Ս|hҥ'FZf.7a.n>Toɳsׄ3Kyf2diz3Ucs$F7ɟ^?FզN*F߈yz[5zu/_W;_z~x? \9fO 7 ٘}1a2m6僑j&؝N<\›Ne0| r,m&FMŸ 췇[}n9bxSW3X̵&nh155Q[MWtzYBt0ķ.z,DsƚQ/Uq۬Fݡ\߬XU9]WZo^|M^7Ջ7o7o>o'v{*c5Ʌ#̭Ś9{;rCgNYdBO WF@] B}-?rnVExriU.5xKF]5&:&⎻c-yJ5ed2Wi,C(p̓J7siV,:͛GW&&eŴ}4SFV1>7y;c"KǟA[6s qey `i.̹ 0cP2_)՛O%*ofҤI{ /eB_ŴJ+gbWշt[gD[6sBɗ[o\{Г9k̎6YVّiV,:f+&n?jeL3hu?:s:F-wUoqn]w}51xqRǡ/.ƦXݓGZBS3܉Nkk<^mڵD["983=)7 mh丵r);2h tT=Vy1>ڈL髯ϺzTqMnLoŢdg:uHZ=ͪ\%M6.+=z]|0V:x}_n939%Ɛlx4z;eGY4ybiy10P4hV}}5״VZ\}1#F]&O7&YUơg$+)ZyXо2hV \ݩ@[@2\XQ/0t&#H=-àWaLV&ͨW#\c8Wf՟퍛lKJZ]hӼ\vnc4MBcz^3I{i \a3T3WOU5YiUi*_ mX@I=ބdIB3t=YU fz_&:UXhY[]ǧ5ɓ!{;7fn=0s5saL=YI[u<Ό_PFц5'i q.PiT5\7-Y%-5l6uzUI PC5nYqucrP$9f.o~sShM4kArCn+j47ێ[P9f.5r6ǭ7~ms0~'ĭ0i*ʵM&fUN{\i۴k1|,b\bG:;&"%ؙqzV,Vn$֓wܳ{VLX9tP91fNOŴy3r\}"?!+D՞cG f=FMvI ޻XGtU_HScѴc'}\Siug:1>?\kb(V3uc@3'fML[4t9#7I9|\1ne*W&=2nǬSl,1o֐l9_:]XrLwcN:fgvImZq. \<91fNL6t9#7“,1^2+05nʏ`>KLDŽ\KˣKcUm\Lzq60s9fn sW#'%zŦu]8u}M=b r+bMꮬ'_F}>kM_fƒKS5ΘЮ7A~W\ks+L,VX$mMZv?KW[ߘ70V?bcC1m7XUj.ì候c概1;Ni`9(@`X@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@`9(@3%`D0sf 0sP"9fJ3@\2_@h5f`0s(@` 3P09 f`0s(@` 3P09 f`0s(@` 3P09 f`0s(@` 3P8?O`k4MЋ5nSя~X6fpĬ|zt۷m*bV~A#33gM뱹m*~0s\?1s0s3H3٦求;9G f<0s3H9{ze2uoumAV1sm'M{l=T|pfOqOT^~f[>qwk3O^V6On[,)}z:ɵ9g>yl-f\>9ѻL3Yɓ37 ,I{g^^}5[}+s^-XW>A_NОzbM36c3w\oXgΚY.n&,ɢfNV^Eҕ9}Ř5FϛhBV9genm\VwU:ylVDsLΝ13g-)̹Ϝk2aCLcg^=#e99YyW5saZ[K0sbdL:$Xvsy\gʚ*5M(3'#3K L\s.fgJ~enhժsA. ~-zݼq{5nG9G۬>=_f!?f$f.6kp̜^vkc ʿ bduN_C̟|0s\?is`]f|`)~u ım*~0s\?S\M\4t`gyz"I10p`9#f?{QF<0oq7 aMP{a.ZmKne1o1G~_v07JX st-Oz"em8^"aM2mI-mbKFˉ9e"qu} rƐO0>|9Gg#:٪R+`m_m>T3 kqM-ewojԞD θc s&l$oY]?'07s$,t_˃dR Diߦ<)5/4Q> yȦhQ~M Ƒ>dVhr3R`˂[hww`:ǥwɬZ%&쐦sׅ` `Q t7Pu]r].>`fm{RayѲq[J3#m8w4-ǚгu0ڂhS+--0/ſ|$.?~d YzTg/CKeQf+\N+be#mC%vՌ:C-#؆j "(c| D3#asF80S7$IS#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$ s?)/8;?#I s?!.'],I$_Xgps?I$ߺI}Qav_wZ$I\/Id'$Is,E `$I>Y%n$II\DH+/ 'Id'`]|DjLLj]/>د [ik#Ik\n:@-b%nђ$ɷ泄0F"參#t1WZ+K$Z}0Wcja/Fjظ]U$Ila/1r]'-oaRc14$Ilav[EC-$Ir s1V[ǭb/nͦhϖA1e15>m -?hSr6Ma.S@EquCj)UU?k_R3[Xco-3}BV$I>bh-k?Z`Fb}N,?K#u6h؇[r1ֹ$I>EK֌hKa.Fʑ^hGm)Nm*o{"v Lu=->g$I}0(RPSE*ے0WXO~T-C&kn&bX1Fr q1X;zH$Y\a'M<"DQZKa.KۍLr_X s#˒ẽby7nn)ȨY(kuI#sK#L^i0BP-d+̕UuǾ#WyV:^іkۛQtIa.:1#9ƸUI7Rp*G sr܏|ku$-osn$|n^m<G\a b>2E[Y~bu$2=&Tjǒ$Ia.[ydO&0W P%F7c:u ]Ѯh_2@ǰQu.}ldGXOWS=$Ir' sR ˯hm%"ՂR2|2ҖZ^c:I:=k6] $j ۴7[Q7SZG2UnO灲bk>24.Q&I\#B{"DG"-Ջk!,T,6"m֑Qhg7S+Fh~ƭ5΍cA$a$I-+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I~v?ұ} sݻ9l-ṻ#Iva. Nmr?})돶^*V's} iX\.,[َ==α[m&Iʧ s:b6e_ʾP;>[dkʔe׶ Fw-m&I' sbt'wy$ʦ[_lpFeZ\}۷ -vnKW&peZX]l_hǻ_:}_uzyu/w޲QhCq ikjf5GK헧)^-:~يvuc?.˦qYi}ʾNFuҿKue6Rs1[ҲmF"+BW_ם//51;Y[cG|>7{yg-:i~ci$eim\T677u,oxOǿmnx8g Nfr); ^*[Tw:N6-#Ҳ5[[mWkJe7Lj$y|1FRч4BTgI6QB\VݲLjkކ1ŧxOǿZ)m{em1kTt֦VlYގ6U>6owy8m?t)$}FKYkCܸڿ7i6kK?"TVŲngz4u[lT.Ff뺲ֿKueaMip[\'}[ZvҲm-W7wuyk?pe$3xuJ]3&wNQs;:.NW;k/~;ыp+x8emqe p9S;6ՖBґu>}?YyOt5e>%}Hnfm- s7xuv!~BN:`E{ⰷOc?wC0Gu7knQ>tQ厡s?0>F:=.eHnfm-n}|w|w_~1 t]|w--?zO_w#Ac\EvlՇ:z]8F0}Omyx9$DY[v,dż2xySwu poOےԿlμLn^nw<ʥ7oV/^fnm~lf܆M!0[I ߬-ō\Q/]y0ׇqTn2B\Q~g,$W^lk1R˕eAqX^#IAeqK_N[ya.S./d<A<^Q@wmdZ˯͏@ُ-o^u[i޹0GuCknq0Tmt˴5o|?\Wۗ0k7 y/4]4,,ŲU8[q5_WYk)׏ڲOmռ|Hngm-n>2c[@eOa. 0o was破..HM5u07>k=_OQq0GU?knq0ƌ' H_vhd$o֖ݢ0w}pH_ىr4 Hnfm- s72$%ang9$y0)܂0$IqIH$0G$y`9$+̑$IXa$I s7$I?d-cܢ0w܊0)Ֆ$I.s;+̑$[ HΖaӻ]˷aٷw߲1ӷ4X~w}[ԗ 78$Ib2\\΁RP8xGo`˗ؾ}9ݧI?֟EO_ˋmwr/$7g\`b::Z`H:[;g01k>;}ֽouZϏRA|s//=cܺ#}9sMwx+/}rX~=CzΣeN3ԍrCze۫z]ozԎ|0{%= 2p˸}oufc1E;z$InhGN ?Mɕ6nc}ޅ\VVF>:u}j} *~-|6{y}yS)6&0u^|Nddecqqru\9-Oh:nv$ s]GgfAb*wƍ@ruIORl牽%#U̗kr[+,NE\Q#ypz#ԧs!΍(zβ>I09z,uKZ m<̭y\jWwi䪛7F#siy^??6:r[+hYnbx?vǩjh[<`7C\?QQl$I ^|n}-uK5A'2sbYge]h[jk^8M 0 cYnkz(jk=1I#qצyttkt\֏eӈZ1;' ^jT$m ^\Ź<c&GHZl9wξgkJ08yƻ2y0\S/7їi:7qzqWfjgz5G܆͏C qu[Ѷ $Ii ^ܷaDe(<󻐓n1@`Spja{=$I> sYPѻ.r$IuuIDa$Ij l s l<$I?b-cܢ0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I<I=FoU$Iq-ożqޗn޾ܿu_c_ή/:>~[;$Irgqd.9 aeZgBo]K[Swa^nkz$I;as a#jgqC>-L#Iy\ggR~:`حj-#~޽mr$I&a|vkׅ/}҇\3q5+y߭?m*gˣ :}Cnޭ?IcLbK# u!eMm)h_52by p%[םw_|–$Ins-j٭)53>Q5-|h{1lR$\Y9:u: Q٭> [K:ovK6k-oO $}aӗ ve,Ͽ7.eC3 sv2u4>nžc_K$y/{dG $I zIP#I<IH$0G$y`9$+̑$II$Y^dax%]ax%ss 969x^pYzQuH,0\\Zud8 K/*?6o5Wn!rqN?}v UO62=~0ނ0tbNNGREp;6-kf !507uH4:xOP{׹ s8^T۪[1]##k 5|w®#-p@Le{tmDڈgS\ç s|kf<׮Yy5a汭6o5 ^ׇ]:׿===98&]Oߟnrbz\ W}B|0?KݼOm(Pr{ `ȉFP0Vq;nXZJExywi~ܪv ~}r>e\6>tjRپb:vA/[״ΑkI183/$Ie*nmld,wm8 <*Gڨuֹ3Gt5m4R1vx]JmּCp.9=O s}H|BF[@Oؾ˗w98O;kg37_xἾ00p`9#asF߿/i\7x!0!jrq_K _ Fg?К"⋄f_]]b,{vzyƯ.r=/Hqx;㯾m_=uuFMX~}̘ʶow[-wuկsY-_<~bzxDqyEa..BOS#.k˷9Jze~8m ]0,z E,+_om7/\zLPSYϏmS|ƬSD}]Qg*SN~q[ֺzg9++Xsl:XY|.\ ^}l9>ѷм0:)םxm/C}[c~q>7ӡS{:VGyQ|e~kzs̷11u5Z~l:ܬnkiӮyc|ks^^Fuv )ֶۦ5<۹S1[VVmTgM%Yֱo4؏r^yE{+ sq WùZy ?ɻS\yrXzB\$:R{>Z/ZOk8ѝktg]I\ P0|"Oś2C8B\\kDXj~lG{&ڿ:a g8f s#?}ss#tc?!?zgm̶}JŶ.W s_'|!(P{нMe:ʋ̯=^7k{XB❦[o;u!ٹ8w$AvKRzJXtKRk۷ZƳΘeYEs]EkY:fx~*x5a.N_\t\lً /p]4:ţ\Gq;vOp5fKIOO:GR9MdpY~`>t vf;a׈Xgke׶60o3m:~Nֶ1ԂRTvݵ׭[c9kwu {6\VWLxֱ\hsuḼ0*oo\7x!sF800p`9#/l/bƃR֋p9p2 ]/AKPW}yPg׮ngN3_8l%VZGLn9"@~}9Ct߯,=B4q-AU9xEas-9/ ΁'ZW_-«m e:?xE#sHW;7NM)-4"ꧺYgu>F/~[b[ݼ|umwiss.;Caq\"xM֞\+~W8۬U]7g#sk9 wjW:⇕Ω:iMgJF^>-:?,:N|=}FۋSob]c>z1|F?00uZ~>uUu`0]{8!.XԮXyU~0^Wˈggetm!F(ߪ[I'SOW|}c/͋2ey1;v΁ŹV[}ŶmZt-SþUoWN~4/Ϋ5?ne4*ʶ4/ʔqLѮƹ8Lu]+4Z}_-ҵ\1 oWt92׿g*-$u? 2u=hkj?˷Z<ӡc8Z0Q$wC5k8=ӹkX{Լq yxE#s]74&nHJ]٘_v,ttdTnSG72iJ:sGSֵgnHe/gΗiZxC2;lyCYkXwvc[fx>^Y_`@w~:4_iPwqRwgug ι뺟.~϶~{y}aykF800p`9#a:^Wuٗ״^5&5׾5ҝj0~};_DwEk˄K*e}ɩ/֗x 0WZ7Z+/g/~+Ǻt*&魾L4ʬn[,3x)07/ԉ/@#R`t1|q=~L\2nTkK seGv/-pՓUp=qwŎ#k!>Og\]b۾!5Zpuޗsf=yEan"\ Owz_e6'/vxsv l&"&9S)rA]ܗfnUb;(C7ݏTwr^WF>oMy ON!o) Kky aۚ]}XS&hu=7uòֿCsq'<⨇`xГsYanvcg`sJ\ۦeG0 lW|EQ Oˣ[XvVt=hy|[ݾ͵%Qf/O07_dI}!`/}ݱCwwʟ?Q^"O3/nwM߳2+ Wiem7Fܸk5"š}yM U#asF800'e_;}g/qK9>*H^&~~:ߕ0 |󟽪!o_iWԮ|_{O}i1l^W_ԯȷ$S؃9=B4/~! jQ ]Y=ɫZ@ڑV]Oems]j]{i~kyN} s}'N`\-uzfs8W4˕8mY[Xj\kk3WQp[z1R~Tt mD٬LN x2ft S?|ڝ9Q?IV*ZLGP1abadpqv(Ո2W~;:41ЇɩNjHX=J̮۬|.BW_iw\3@:xant8L/~{iƎ异mx$ʺYhWtx4ν9 yy>2W :vd;n/OƾBv^۬Ͷ=ss |?:~j"nƲT :fo4(oV7o$J\=⏗s8)߰n^|ƙA6uܵf%L5[ԦvQx=apDӁumKanHFH)~e/@8<0p`9#a0_;|hB *eٹWr47Vfig⋄_/P;ھG?QpW?*n`q[]¯veW}/c[ϿƱomǭvnF[l;KYq =SFx#sŷRܵ[hZŋd:+Xǚ2AZF(8[^[?},LeK펹hzK IlkkΜv->iQ(?~rr;n j Z۾uRVםX[n?'8yy+\y R;by"T;5bkϿ670Xrr♈OwhuNًw<:<~e{ ;FiysrZm Ѯ<ݲ\SN}kαƶoiwżW1uc筲ve6X\Eh{kמ67 sO 4-O4='ʿ5?z]by J߁̟ʟ1oSOHUα- ,s{!Y32Sݴ~ID?.NQju ڷj;GV+#_ߚ jS[m~5۾Ƿrk1[m;Kιz `vL׾ٺh3$5{C0XG剐 ^<ΖEv'Z?އnS\GMfژџeUTΞOFFK/u6#mN9+Smǧz;(\l;_s F[ا?*uT->+?][wz^}YZwcQTϧ Oļ؇V67N4f~zAmcO¹$^#K2K3ǹ^^+^7?l6?Qv$Vl߯Ƶw@Ψ`ڷj;GVkt}vr?&5][ڟʭ[H<#,;1/߫^ faj7gakAgW?,4;k˃̚:lY^Wov+ۊu;Jgyy}i)Xy S}7>/1#4o~ڸc+Ukvן3KX{o7̍ҹv8u'۬uyAk>)/<f 쵳cnܪ^4Nteh\mԟֵ=KjmAj[NΜv]Pylu2fXNtL2c_4kkۍ(jhfl;Kιv Z7c鹪{x~.lpR ?{y+;] n=uy4[O՝uGq4^eiԍs5V3TW~~m;@9U-b6q ZwT_FM?~ٵm?nkYwmdu8מ۠\]f޷%nz NNb'D a0p`9#asF800p`9#asF800p`9#asF800p`9#a*̑$IZvzqa$IH$0G$y`9$+̑$IXa$I0$IXN/2`\mI"Inka$Ir50G$[@#I-rM ̑$I&H$wZ_s$I;k"%k˓0G$\k.H$wkWNIrM- s$I/Zi6a$IE 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Ir50G$[@#I-rM ̑$I&H$wp\s$I;E 9$"Inka$Irkż0G$\ ny@#IZI-r4H$wk@#I\&ȅ0G$r͵ Inka$Ir50G$[@#I-rM ̑$I&8\C9$I^ZN/.̑$IrIH$0G$y`w s$IqkYkMI$Q#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#I<IH$0G$y`9$+̑$IXa$I s$IV#ɃGGbݮ3䢵Xk ֎59<ٟ kz.[;nչ0GoT䲏 s{ ֶ;(=IQu>>U{>9| ~LaH򍪃\V1S#7w|?r׌ڲ %zg~7w_rߝş~:_6 [a$ߨߝ~Iӿع0w[ /5OKC_N?,0Gڧ s1/2YtJ_{BϿ;\Ae_O? 0G' s1~*\>2Kv.n{:|E8n n~Xx:ݿ.M#yQ[SZh sQfv;wc_dja_w?G9{Ʒ\(̑u0问w̦2u~r}(1:s cp|Q]\4:͋1O]@WQbɮLԹXFrS͂Zb/_m?Ra$ߨ~K}Y|{l zK__ ]Gzwm?a.ctggax0tjY.Nt7any[dGHY~9|nVK#i|zg٭ R,ȗ"hY~'SKưׄιڲ6V~9|nF[37MG'zD?"r6km\؏qY6^M[7Ya¦Șl0Go' sO-=s~Rׇü|Abꜷ$_Jѹ|ĭD<^#PD.O[yX|v~}$T>e{ ^/9̽69| ~LaH򍪃\V1S#7rٷ.lzS#7rDŽK#̼Dkm]km}-j:WH*œZ:i[>XI8uZ\Ud~wvAay@n9uպwwoO>nܿ;[GgsߥXR{qކ:/^lގ4:::::Lx E5h[v8WčaC|@NHT'#8w=չ@.մcLn9[W;Rõt5{y{XպsXз˦>qjL}KΙӶ+=Co\0WL?g?z=M w`ɴ>@G_z ^րc,o=4uܰϲ̨tZ~[ruKxZ~sq|xMӰ ۪8]m0>m;:::::.6>G9q0cJ点@oo@&MDvJNUZm;7cܧ#0Q6[(s]ն2[{t7E~Ά9ӬKq*{LSkH b ,Wan?o[â-.bg,Λ)T];:::::nO\v+点ʡ#6u+6"vALH ,Ag- `isX.v7el2rR[_]^mێCm;DfLIb'`=|0'&h([w, cp4I';_:Ҋ7kOe,ZuzfA; _,K9`?[6_kG).vٶ/=C>h۷fc/Yqgcu7 @uttttttl9`쫗}9T셹1vRw҉Z8Www4utttttt&~7~4ՇMg!eLh8Liv#= QZ?>7uttttttt\_::::::::.k::::::::.k/sƯ|jZVuOajZV0jZVuY0jZVu0jZVu0՝VjZ[ s[՝VjZ[ sougjZVVœjZVuwajZVajZVajZVajZV+ag۫;[VjZwjZVuw+a?jZVu9\jZ%V__jZVպ0VwZVjnuVjZK~N9/OWqVjZcv !n `vljZVkOϭ[fێo[VjZVj.4 cVjZn_bƸ\hZVڭ~ookZVjm`&OWZVjN`N_jjZu!0ǕI׶ZVjua0:#R3F k[VjIe)mt䔹NѶZVպj-0G87[ KqỮkǶZVjn]qίt8]ŮZVjU{n}f:;oySjZVuUt`n--+|a ZVjZۺ+aӶVJ=l9ysHPT7S&n@V}#+u:u:jZGS 5pBuߠ MJ<,Xvrn4}\j}sZVj67;*u5x 3ॼ 9k@ԍ@u)0Z;F}y=ZVպX6Hx_/wGh$U_ ʙc,r$wҭU{ctzj/u9k X6ͺfc=`m_ZVպ=0ˍ8<`b}0K`NYc,CC0|5*6_;sVj6,g* @Mj4;rXq#yw_jZ[Ӆ{OykG+ULq`jZan1;@<Ƹl0+ܵC6cܛ:h}fjZ۫rt2?V[`XoW☍q4>e7VjZAan :8tc9c>γbH|ZVj]y+pZ:LwJKsyc獛u:}nZVut%Ҭ#HZCܾ~nce[kiJP!ߵZVպu%fFpZB2%6x`C.[~hK8R4#Fצ#Z؍@b-[VjH*Ȕ.>[B@[v_wša R/Kp(*k,{=q_K]3nZV_sK`Ss tWq0Jb _7㴍m~׎Yjl߳eZV:.5̍}vMg ZKiqƘ"uxR()k.c-==ĮF]ZBX[Vj]j#2`ot@оlk;Sk1SOu9ラ =OG]8K7RVjZӥVjZVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZKVjZK ojZVպdjkZVպjkZVպjkZVպjkZVպjkZVպjkZVպJ{^jZVպ59s;[VjZwfg;[VjZw\jZ%VY[Vj.zDjZ%VY[Vj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.ZVj.?0jZVuY\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V\jZ%V_jZVj|jAZVպ|Z{_F5̝KGjZV.z82anEkx?VjϥRk|panZZ1/Vjϴ|Kkp7anCC_Q,xjZ];z_8ָnR\hLJ?a,pVj-{|55~[0Z>4ZVj]^Bݿd5~[tanYx-mq/EjZ KKw4-WZB?Vj.P{w x#؍P|_Vk ngmO?mZVu߻K+[B]ۗ0G sD9 Fp߷ZV:;,nK7rЭĝ֕an r:-!n6XO?IAjZVUzp7B]]AЍ|0rWI5̅Ƈ @#QWoۓ/'ߤ?G[Vj][`ゼ%-]%Ѝ|0rWI5̅F+A΃.7 :N'_hZVuwqAwuAya.Pr QG;wN~w7yjZ Ts5=~3@7rWI]IȭrjZVuĭr .#50л\*GEGGGGGGmٳr\L#9ҫ`s}\GGGGG mW)W3mtrݗn-fhK4œ4ܚ+Ax4a~uЍrҝaa.F[r-ǎ!4uttttt\O4EX8µҭgs swҕp=h˹~g~f^[]6踈[oHW6ѭk5: ƾrhF/o]~Mo0q7ܤZkdҝ_s sw `Ss5\k_ha{??ҔsRkZu5SjS W07|pQ;g͚fa@|0œbߵ8~~eLz!_B6/0Wa;B{{wnvo{vttt]Q垥-^9PGQQR΁ѝB`0w([rr[|EZs#¸r6,Aln/e@z4A\ 30wv,Aa/sPo9Tb:se]K^~'jnkuXĞ\m{!z!n^U踁9+suml4nY N}>X-]⎎[z->*L ~Ԫ>s׸t'@w?Ы_H'Xb sw*LJ@wwrW-::::T4. F^_8ߠCGܑ`+s~[Ww::::::V\ {^yjZqE`};Q sW+cT\GGGGGՊ+s_y:]{ ]qE`՝Ǩ1cw\ aauѱ;}`u1auW00׺W[yjk:::::vGܑauW:za;_>_8_8O\{ǧɵg.k1k8i]Zutttt쎆#q cvZ w @ ֮ؕٺѱ;uRf ѓkɵ~ ˇ?urퟙ8ܺgsӵ z o횭Rat<07;r`kk'ɵ;>Xld}ޓk~|r`Pwiѱ;s&lǮ)+M޷u++[kѱ;LGs\0 `&%n8wsa.ӱ9Sh;zncq?sr;} HnѹuÃ,Xpe5.:::::vGܑJ1}@t4Nꁓk_5;G_uc l',!t\oy x~{ܻ+9v{\}{~? i5.:::::vGܑFOMX h_ɵoZ g+6~聺r~1Wi|z5ТMrqC=`-v^^cw4.= t'wltҀXPԃ) t&mܻ;Qn\9r-9)ZK0s=PW}FAe9"ӨqIƑrU{V!ZmK0wd0ђ44&)R+5: }͛' [q9c+x# wO*T]F*rҽ}pJϺ}#oxx'sGt{Ro5dUutttt쎫s50 'hN7N$wW/{p& 2`Qӿrr '|OMiǢZoq<52+mji4낵P7/{ |qr s(]/J00wJat)a.b妁 [=0hL~Ğ2lh+ڸq9X!!tѸf[\<ufJrjD2M 6s[R˂= m3cܖ:::::vGܑœQ&"9 PON@@ҤG7>6ӿ038}ɟ?5trWzQ?oAKi܂0@~OB#.$^j7S sGK sW.ɠsqp? z6P t[=m?ךϨR07:yJ'/ʨTn-m^ı@9uӑ:ڧGf 6etWvan0wd0gb]UĕC\2@z'W9iHYk>=:SHf6@ʭ{*3T*{nN:V`Pk^ܟk)utttt쎆#價O)Vĩ<_8g`O:R_9HRֽOpHa`;?pL {O%)_;N~R>i{R9?._{N~髮dWvѱ;L jCNG#փ[%) ^;\L6NݷַSxq%=uӉCӁ; ԰G?Γ\95kbҰM}{0FY;_냹!/r^ v^K0wdT0Wa}lNV3̪Yt|S 9Np[ly>TIɉ>? -#,wŵ 8[֛{&@ɋ9p 5@V܁R}s-Ӭo[cw4.Փ?1tdn|p8Z@O3gntl&ޕbgc[;< r~($c7 EIr{!:.`sOF: @mˑqO 3 x+W!:UK0wdT03V#eN7ƽq\9wФ4r xx'{6 vr8׉uK Ǖ+{r}pi;G/1~ޓkv@ckŏL8+^`msҬsv^M~<{'/\vrߋ_w\ckµkq/|qp;/5֋^h;2 g[yLJ4n*iU}Y-'q |WR}O%ZW=q\#qI'8G*9K:=0 q8x5j0geq?>޸pF#^AP[0/_*{D}/l|}{Er_ZY6S뀱~/x[z!^DAĖ;[=qQmv1M-s|œn~ƫqMDܑ`0T<8 LrR&xh7pc"_ΖuXFo9.m̄s+ە9l\>_H.\:t[*cqn̩;ʁ9U0ǭ;e>K'/㦵.wP?Ewl??%pȺuQm3/S ~mJ:˲z-lԖ|F/xwM~s0wd:̙k V+'MZӑU}9#'j)N?9xp)rg&7Πu條 6S!}x n?=AT3)5x1@@Rb4+qѻҬc[9`e ΫMarW~_8y!^XX2Y.mr_xaŹY\s~gavsEF @֍qC;";#VxqǵΝl/6L9@iLM79}5N}U9}Ӵʽ\o SH\(LI"]i R>r_>M7،uRpp6F>́\=߲ in=Nc@%Nm_S8/s/NH씬7z.cc_e*k^nz'lsM?isr()vY1~.퀹m;o[B SSS[.d5FPk؊s=)֟ͮv_{mo}at0pq!R - b XX+=RWN4✁(v݋P:w'g3 @{ຽ0 ʵZf=9_{V!ں;C@#~h9ԾST¦ jkq:ZYel[vXc޿dubyy=N˿ѳF]v/8{\6yy6{mox}F7޷Wc`dIm:/8f )\@҅(`كnR斓~eӄ'N6iOˁ ^t`6CǙӖEY0a;3g"kv^;CK??2?[o9Zsm+ls-{ee-s> w;_okqVϺ)c%ṋ2}6u} 쁹8 ?ܶvL9|"0c`NZ|pԠ::ǃ}LRA 9Sy7Z8?y -ei:)LI;{x#22֨W@}@y||'#o݃A;-jDܪ./՗sڷάZ{:ŝ{c_îsǾFy/ku;9CÅoSyOwr2'~ 0uF]oF8ZFܑ`0'IzTptgrlbU6'J+g?uu0P<X|-ydd+Gsz7.{u&MսmG)&x<Nf_Bk_c>NŮ?yi1V=W{z{nk\y|ogsQ掸pg.d@Nf;x:ugeG Fyj #`n))JuJxi66RI~${$P@N?2ȁ3&}O};WsLk7SnF 怔@ΜxI8;NqU&wP[/3Q^c]ES/|csq-p7^\ٷS˾z(sG}/c:wWso>ȳ|^7]盏#`N.s)iB: J0~o1.Q@u8q,| +?r) iy$pq}"^\A,Tb{: Lݨ[x.}~*wm :TL/ӑ}s㞱ﺫ$֎9϶}ֲkq޲֯?1^)ou~9g-c }c`v3>ijmto!L9.~\RtL6w[BgpUn5Zҹܽ7F6T.V\; r9G}DYu8p9y֠j.@|ix/^?k/ >>_n-bpmȈ˺z+[0{Rc=be}-{V֞2nnx^c/7?}sg9YgkVeغs0wd:̙ |&ViBZ|jZ~*gM8\7:}ҫ>e*p4SȁW3l&׽{9o{Lۦr`hlS q<gk>nSw3{9l4sRp8tyˈtwB[>tf;ݽ8U_8\ns9c$8]=_斓fpIry֠j.@;fHORI=3pwat0QySqCeqX.\"R z~Oç,is)kŋbya@\U;+wavi?<}_ 84+ (Wj.@w&&w6CUinh]ji ey2kOM Q^4KsqFվ\ͩg@/>pԁs&]Zm PGGGG0w_ [.S8tgMz\7n]I*yo (v[yҬ=z`}5GR}m0Ot/anVѱ;L9eJ@i4IrǦ)83 ~H5z 0~K@"w3O`h]Wt$8(8ה$& \yT s{f0wd:}N)V獓fRmF@~sO}@qR^@OMk2ŋj۫~/ty]oPW2vMѱ#`t8)V@X8TmdFZ'p`m*Ͷ2^V)VUsɀ!j۫tGd=AGvmS;a0wd:y>+(ӏ.?)tffTTy퉀1(3b$j"y U^ib Jɣck @4YfP۱}0qGܑ`0W#E?+O4>30(Kx\te@t@+ f Δsڻ>63I/SJOwI/ U^gL%Islm3G!}^Ou}ϩ[9Ү 0qθ0S8q/h/S}x1|e:&Yu=?mh+=Ӌ)USлo> v0ܳQ>rQ} )Vj۫#L+O;nd8=TuAqR/>SO}4XNߨqe]/g؟/p. N@wĹHq|,+ bw;m֝zCo}%Ĵ+^~rO}7\/Yzh Ϋ,._Ugn̈́~9po{C0wqA)SNczb{f\GG9at0qSW˙S[cuƕ=*5 )R#I;ǃ5Zꑃf G$ N%0 pndq&D|>mfY0f[Xe}E,_#Ro_0`BܓĽ =؞Hz6kw{z mn>:dmuSgZ>0qθ"0ڿqg.*]^ I7ӥ4ca>nvK2fw9uҬsՈ[DSrMV@R-2h@ ~ٽW/LR!`U.}O즖 994h2սK c+ 09Ժab)INfit/}\4Ww s rM Ų3A;v9s__UΥO?w߇)I9^-1}tVʽcw4sf%#2 8lүY>+dҋr sYoЙ4BL=sWڙ>ok];::::vGܑ`0W6BĥBv0}Z+2H#gfj9_0sFѱ;L9/Ȗ`F}:q^,)1G lS9'}uQo;ѱ;L0y[WZÅ9W !_3WϜ/E[\3pW{tu1`0%*LpVPGJ<&iY9sBܕv|1|2N9<8t8s s sTPVanmUA9I`}Z@9$}~窣c-L.*(+`Vǝg߸Q>K㹗I`15ɕvkHa]GGGGh;2ִl}׾rBNUq}ܛ?OOutttt쎆#Ӆ\r{ھr2(Oɝɳ{?2[ \uttttEܑBa_>u3'^t^i|ɵ?'Rkv^]{7\{+Skt^`~~:W8sxސS\{Ž>ǼVi"W=@ɥ{C9UGGGGZ4n+1}~^}tQozx(?0S_}0hި^F=]Pɱx @{=}ӀKә ȫt#?4sѱ sG 9*8>q79sTx*I:먇w5H;6 T-4q:U5T_ }d@Y܇i9.xv/E[pwMuq\sBat0Y h]Jݠǽй)W`7Ꙁ<@ a/UH;2)ePiթz?>ͥd㟞/H~}2y(џ=u}0'׾sʖk_qk sG\AZ؂},[_YƱ p%٫W!2Y Z.㟚2,?7`tROʴ;LV]MW':::::֢at0{x!/rPDr}߭:4՗&nuZ]wmvjJJ?'ɑ3(F>@h@Dp}_N&ѱ;}caR]VEvcաa3ZQu>Cwɵw<7 {"3;g+goپ}?Wk0wd:(̙}ߋKxtΖ֎;k_UZ{/LtRkv]37ij]ϒ>;g>3T[_ɵ/]lJj@kX#`=;[Ep `V/Zk7n :k5(!_'η_2; szlRT:Ƴsr֥]3\Wn窣c-L9/\z]Ǯo%#kcN1%%W\}9<O=Ӿ;s%'*tcvjgNqܹ:Vsz窣c-̽WwsU NJbPߦྑ4.@+s {~wٞp֜"/պk}rmm`c>r߶'\gc(V#l{L}UGGGGZ4 s>vq 4@]QRcT>+qFIrx")Z_ 8O=V]u|ܿn+U<ϻ Hݾ3ӳdr>q}?z٨&w6 ?Wk0wd:8pU[㼜=+׭@] 5ˌ Dg|qpҡ Y `(緲AaOj#`qK xߎg`MQ?1&z7Sn9\;>>sѱW^;Qs@EXuݱ5리P %kC:{: YcF-C V9 M~,*esϼO<_t_F=fW՝Ǩ ]"(Y&y-G68ega{Drmq ۣ^uslWp}N^ -G^6ݍ0WR7y6\9o.OvO\uttttՀw]ݠs(0NX#Ӆ+gFڞ/~=~qi`K{jr8_˺^5l9f|j s7GYSOzK@'<`ǙS_iXvү˲vgh?Mk u\uttttՀ7eu10G^-Pߓ)$+5U/g>u> Dfc3Xm~dPv?7-#9: Oe9{/V]^tcF˽TqlTqRw['n/˜$PUJ]ce9>8U}:!_)`H)LF p+ @ ӷλ`n r/y52;1a׽-Wmwtttt쎫s=u01^>OpBz1snW~'q5X흳{4[ h9خ\@k||A-fIɂK.Pu_t9̩;*9K\\uwjs~S^3I#m4 կoկX#`΋SM38+:qT4jrJr8[sŁ|(5Dǁf}Bu yYeN9Kx:'Կ=UW=:{կ'Ҿ+H^bJ;1@n9?VnRQJjO0GNRn DGGGGh;2 xUOFv2zeldA, vy!5' `<#NA"Oh x"Xɩ~nR6T9 qq}N`_?J:>s~k%@]tE Uvn\]1o>R9#_}G&I㼟X#`N (1xzK'c0>h8NxUڳ8LxhFk/LA˔(E=R{!pJ6+:֍%Ur0GluܺW_ҷ=OQNvqqB4##٦>~&t|嬕FW4@0sc8r_怸hsW7wC<ˎ0wd:9/c)2$t&Q/cSH]ӒXzi4)V@iXgqTYw)On_\msԅ38v0~o2s@8hB{'&DCҽiLOC`R^@4X]@yx9?G殔OMёӷy&6s3'QGGGGh;2 j  ʼnӪarR8Y @ORR&b> m +Ɓ`~+,\\AsM*;03IIRYwo@hV@F_c%+秋ki˧,`'T[ZJkWwI\)x.(7r`mD6r@{we g& sG\/8 7qF꠮_HTLR g;qb@^S" ^JF_%ESv䬻/u[߹`XMq#`R¹ƺ!]E9Kl8~_}~(T)0;x%H4#A.u쐎8! iCc=T4^2at0ߋ JM :NX@JA`nL#7CX\9k Xr_#ZqKК57ҹ29׈}uYX'i\׍K7I[a׳3Үg.ҡ]ZXzG΄r?1\7΋gK}+X#`/an _;9S^œMJ5'2Bx' vd[u,sJRcZAsAd9hs}7_g5>@gʤ6k\6j<ء̜l9aLߴE#I9zw vPU}Ll3wNoP^h;2 yN/a%l5/^NYy&I,Z4s x/88vyܷl8c\X*Dܐk×9s9');`1Fگ]+Ӄ;]OBcҽ xsn9]`e% t>O}p\`R@ΨU#}n%ߗxy:vat0"r'`察^^5<%T:X\6%y֍Ow~n0FV,g[!% ȁPB^ĬW1J@Ǎ qLB@N?ǸsA cڵxZ̑OG_rԗALb~䈫9r[nqo FA{g M8r:::::vGܑ`0D2KѽTME  x~ro4-+ Z.g&A& 8G,6Pu'E lc rl9)%q r97p|ʒ{ Pi+Г_QA9 5R'.V sj8 8o'˴qOǗ_<O<8GJչouoT|V8 '׮wbFܑ`0祜''+UZ#E -K˛+{G,^}Y(C tqrK]a ,ի @)U tJ` v#ȍiV`XK۫/{,Wm r,s:0'])>Gora˻I9#q h~s9}ӿ2Ԫ =;Sxn'[~3su|IK0-^3Ϳモ/n:;OY^8y!o,7~ D3_88@+ϼvDchrÈ sG\M\/@@&zvb7\ǑMX;ȺmK: -i qFJ(PPo`dXbA#́$ 8N_?Dd5dr x(Ƚ.5b]i?/k 7\ Ϲ\E@lѼm= T[zښrn׏]{A~uJ=*sq*s673|[-6י7⺱^OVY47\#9oZFǃkm/#˭{V-o@tOk=㈆#`yf2^ .e!E[@O7ZwⰀ1p]Q^dcs:i׀/eT9^ZS>WGu Թ @c~u u9"$=kT,W@ZVr8q9p"9m3vPXsqkd7Id@$wK95|€#oAܛr%AX?7Nm%d^5;HΜ*7`|!}@ _"%:O:|ϕ3nFܚbEZxԛsBDrK9nU>3%gOtzoxxj'm??:suedS/]wq{V\-e\/ DzPϵ{rr6Ʊnur9kw9랖NJq۾xbYXFcͽVg`."ahX -Bߊu)g㊆#`y g4꼤9d ں4*`+W8k6%8I,NL-8Reʴ-@0P7q-. 0 `cҞ}d?_ʥ39 N8ѱQ@q")Vth`=C9K6\0GF?k#0 x;sj>B|MK _:]^@F" q\l_"cs֮9 _k@Yu[VƮ}u bzoNؖqsrDb}o8c(m5r6`s,{'{=AP-sOW0w0g)Rԗk@)%΋^m^zazO87rn~o3(JYV_6l{v#IЕ(  |X7piON g<.<}#u[_ݛ>s&@֜,8tf-ǽ5X~ߢէP U݀1v91pOx/=hoᾍ읧?9H~y V8v<<:f|! /tG)g/0[Oe;s㦟#3 ,[g\s7las\ؿ%3NmmeOl ayEٛX{R?~jh>kiS^l7?W6w9k4s/|8Vu7FedfN9 &hY_1륯7L;)9ur:ۗe{sq^uw/:paZ( hƑn m r4\M?EUs;@qjnI[]}\{u+֦\[ωk#WLx? p ;Ha%ei=V,/ y幻^L/e`eٹ:nu=a` 2c׾{alӽόM/{ڊy8ksچxkMoquU{={ZyqDܑ`0)R/wr* }m^^ dqlN=%X+WKPe M烲<ظT,pʽ}u-݇{ptOҷM-}9*tk\ug}95R7@# C\0. 0[7œ@'437ހ r:xF́CY/C\OǝU꺅80.##`LU*ez輰 Y ʁ8. )ZT6w Pq6|f ؑku95 FJ  ^\>*N hz-N7~tDp Fg@κ2vt4)ߨښD`7PۨwJ͙0\sF)DjMV`XWykw8:\Е u;Хý;@p)͞ sG\A*( p9S Xmm(flkqj|R r6r<"IZ>ؗN urJOoϱCU=>ɉ3]zp6 euNЁ/-+}j~w|CRn 7FvT%Q;-0J:q`9xtR#ܸz =oȕOqv&;::::vGܑ`0`"N kUw8<г)>s9L'E ʡԁC@F3lY@ RIJor_ .צes Ir⌄t i. Ȕm<}>6 &ftw JgNZj[;?99z`q 4Ui;۱OEܑ`0'%Fp?3E/a/JOrq;$͍!pGUў#C0P:)7$[TYs 9P"@ LYr &tQHԁӦȥ #x^t=5X9ʮT+3I=rF25 e~1w=z>LZ?9ӟ`^yBbWζ:-i1gl#`NJd r.ত[6Wm6 vI`$\0;Cp+HIrܹ72^'y\%iWm]@,u йѭ5[ rrρmn:n7ҙ,z|yNsqz/W64+WPi{ s3c{?Лm22u6 o~uu|>2VE]w>{p6ε^rcy֗q8Vgͮvgy/#;u}Su<1ku[=|Vyѝ^el_&Zs=N|{+3[k7R/yBsʿ )L9/X/`#=yҡ. o\#-gmËLr}@;` z8$rH:R@р]֌Ƶ?cgReAru= ).n)uHqFDss>"mn`S wۭ{V 渑E;q@w^o?E hsr x1uzԶ[/:ċA7o_/_$/=?y잗Qל^D[n]s͹no>wmGk=F1ڷl:/3[wULj=msmܷ.CZj#iodT9k{g~FE\ay0wd:q6#Bpu7`1Hր;/zAۥ:f wNŵc*-@ݜT)_1uw\"8j9p}.J sKn^q3M}tv]j־J:4W.;4%$HlBmys??suq;n_[_/|.̱/--{V;- Y+oy۶\e]+wDu\+kyk׮U뻎߷}O[dV1V]Y.iܾ<&Z7#cqrϵOEW{ktFܑ`0OC'E-׫>/UpMno`E9Z[FȫkP9۱\ZA]h5H ,ҥ{tֹyΰ_ڵ&@Ǚ+N DIq0R]]f@U'`, ,F4 8/)֜9 )qԞ56y^3T~ecو/ysھ{^Ur9Θ}qUXIͮ7r207n_sg{f7WWsιMmyf6&C[LsqNjPjn]`Wzᥖnm_wrŢ1&wc{YcUioRĩLuZ}do3يL1[w?ksmg>yۦ.wV{mbWlg]S72^wZ-s8v<<.=q3 sGt}8L ۋJTmU+rlL \_gA7pmc#G&5$3ZcT.N_.)Uӕ:6Շ(W,Pc5>nrx߈7:nZC37Vwcط^swŕonL4_`Y++mn8F+xSN|É6-P:_9ywU'u4lv#82> Ƹtі0l$:Υ4fPD7ǵtvj)9Ip\Uׄ挄8A wULxc{@W} Pm pmsUi;}.X䴱pB |ײ&/;oCܑ`0b9Q:3l}tFpZ›s *-WΗwqm o׌i/~9P` ߓ4\}f`n9("dj^t+૑`3䂹;N`NQxp,+ݓ6wy>#>6p=uQs zﴒ)X܇ɃG~5If_)JoVA0':::::jܿ0w0JO;sm@N\ 8a n>S W] oR?hskwOm|:R]LOb`7gT9t\&_Jdݔ'nu~p\6ۚ@8ؠ hVrh@-vH;ߏ=/r'4!5 Fj[9lFj|N\NcUZC5͍=[Lm8wuՀqiրV0ǩ*##u;DIAso٠& 39NFkJZ±s\DcN;x3͑3 htY;I:i{`i/0\}&90go KB|̈V.Ё[@^ֵ9[t& W_)!5B@K'T5sukߜ W.~o 6$)Xׯ9n@8#aNZ2SSp0ǥ*DGR}G.Rn95``QcAs~+IJg.tN 4k:bK֟qe~76~jx)aӯp7hWK 8w,"J$\omҩ3Շi΅tlo踠h;2 &q@ EvrqFgI rrô43 GXA y\:͓Bf9ؐE-9P7Zg@,? `>V psP~5ntmѱ;L9*oL 8xi/w旻EըM0e @m`Pjs`Oߪ?t >%uklMK⛦L4$`\g9z|Gwj޹tlIgHWZrʥv6 sG_|e0^‹b7W jp6?q<37n+ҪF}q<}dt#p|BL[s@q`;V[ѡ&zӬw\\ߵPwA8Wñc>)ԏ?7sѱ sG(\Ft[f7SQ\)l )S;N]}"Ae5{" LxaܝrJcW62= 𤏥U0-6r_X#`.;Z70/Z0rtҬ% fo6H[r™D:iCSpr"ွDS:[_<Pʁ9.ݦg.$u 29sŷk@v5Z*~^C9j\aRR:R|a w 7N}8MR_c0ēS:֜i&z&v 1Ϛ% 1jD9s.Śadk*cX)`:sRd:٦On?>sѱW澱a`t9 a~sb i֍΀jhrL lݤ9Ecs\;}L&̕o`C+~Μ~rózκSR)WSWy|&9sѱ sG:+ B9iֆBn+ y;#_8FZtu/o.x9&P9I^]+;@TDSW6eGGGG0Vws~_ HU9nЯ7E{u6q8zC}ll/DD;0'%q ڌpgY=LSntkB]rA21 cw4s_ DL+aV~0;xmt7`N(p50gN:.]Ni]S;s3I0ʹ'FM[L0ǹ rDk\[_9@.z\,H5^_GGGG0ҝy/.j9gtiGrXOgc@g(-s%\G]A7ѱ;̽Wws@ϗ>s5i:_Y,)9̩VmM]sk/gPI|]B[+ǁo5x3ݧ*<ث kz.u:t:::::vՀ{޽u0ZUb(_;'պ⽲$I rьls9)V`Lڐ[55ݹ8M eiViGfWt_̅sNU=> 7<@wcw\ Ɔ9NGH6u఍.[^Y0wd:I.do`.xϝ[y_]}~| 7Qҁ9I@stү`gɝsںFOUJv ǵ<(׻Hat03Mx0_*Nj&֫. Aϝ\{u}88tOwZ9{HtBٷK9s}P9rKWnJ^ҔkGGGG0wϻVws! nd0 v5UW ;Wi[)d3V ,mѫRRaɃ+SvOxIJV9S@gF+q%ѱ;L9lN@#N"fw4Mu \FJ|sϤȸqFĈV0'tv7Q_A g+[Q .᠈q5`Ӭ7s">;E JᯯCթIR&HE#WfD<0iN]hs=ewg~9 .P[[9tk.gYϽ sGɂAt/:)?R=g >piko90n~%Sp@??MO|1M9md5@΁8CZPa.ɠ0wd:}}X2㱀V)Uџ~zr}D@ր'A VI [rK403YWzBsP}匘5Y:Zl#)WhPDGGGGh;2 8rN8>ӭOLg9F>R2F@Pjh+ 8q Iִ$̙GsNhJZ6`9RC=\ۮtk sGXt+Vu7IJ#Jtه}+Iń9mʙʖ~<)YPL@V |Ȕv\_p} sG>'N:Ӑ{NOUP~"s )7laHK:}C69'M=u@?G'o|K8.)aD@+t gKnm߸v*~ TGGGG0wO ;H_/v#FarL( Z3۹QtW-I9#UBR9 8sI,@?3S!.@4&F'ͪ\9sdvܨ~epPDGGGGh;2 >/QScЁ)B”nm:x1N_/@'٥3cLr岯 _ɵ?ҀOm8t5A,XokE[=C e}W#QھrtPDGGGG"0M;Q9/я\:9p. `ځ6)DZ-s@D {K3`BjЀ/&=&q ` nqi7} MRӔ8HhjW#l|Sasj,A>se#J>kP4mp:::::vGܑ`0'EtE`'0e>`CL,?^9epj zONp3b =mSFy65Qp}XT$ d1:f h0wd:̽xꛥ\9t YQ_oNJ1G`ؑ*^v3 gjCrn\@ 8S Kڸ>&S €~٦F0+8;Ͼq::::::vGܑ`0m?{ro|^|/ y҆'oXM[w*/K!  Ji+̨_/"(6)@z-8qܔ^}ΦV=\րWZW>Eq  sGG?7=SK7Q %x]P4;N*Y׏N98"ٟcQ]?@SX}9d R730`i-If k; `5w zx:{&sQ }~A;QMS;6qNutttt쎆#`ΜfܗEebhKrI}OHMیn:T] PώcuN|6-^wrƩ?T ktϝ#Z}~_mK@G:LA&#3D#G]#|aipO= A6ʥ'qԴr>VGGGGh;2 漜#tRRI9};{n;\}K^A}@vn`uA] ==#'Nz#Oӎ3mM $.2ck@僦.8QTK+0\LgzJYIKRܸ,uը{~yM[{lcWwW܍\ptGLJ W.ӮS#iOta )_:R C̀w^9yc_8eN l4pH]SGurL qܻ-M;) h+m PPT%ao}r=Ԡ~ ҫY} 4yvo=m/ sGt^^thC/bInzzѮ\:WPǙ֍PW$pЀQT&U>M咑߶W7s|5cN/8 d']\W)āSU+j&]6HyyC5Bm9ijZrF9#%wK|zHp 9 ѩvMM;::::vՀ{\y:́4!uZ@gDkA$Sepa8]'cN+t~8]Ozs@A_V}8e\3U "QF<~7h䘕+蚮 s͚Y]Z ~pV6޵rTԎO/@N xdKgn a+U:u֮U ltr8t&yf4QyVۤmO1u\W|ë;Qxs KDݧ;J) @@Ɲ `s@u3AY^/K h%ͮ' \-o%}[ܥLƹĥlF%_,Ip|67#F 864Vm+"ҹO3}] Xuڅ3i+=wW=g_~SQQ':::::vǕ_ܯn^_//yv՜t|/ySԕe\);}Hcc`% @Ϥ>p︄CKVnT8@!_pTu*a8GUiU8P2 g9y7:(F;yPF1{ d [ g{mKG6-A޾H :ѱ;=\y:̙?#:*  |Kjr^ҷҮu`IJCL`)k@n㲁5]m^WnoJ7k7;y0F.ǢN\B%0qrWNssPC g+A./+lޤ%9lm<"~)#ϭ LG}A\aCz6ڂw.]O;:::Eܑ0Gč@F++[DžvumåJz T%9 ` HXm.:⤹^9k%na:}㠈75\W-zp>59 8roiOԪџj5@[.)<"u =ÒbXUtf*zFj3@u3ҹͳhsɱf sG\t5(b tV#8N xI;TxS7:s'`خT,/iR\PTk tW$P-Y0OP -8P_}6M-lM%mkϾAQS|<;ӛ_~rR`KK,v):::::֢atpM5^x/]:2^j)NjHrx 3T&q}jf9_+]2#$$Z/X@q$FU:u)\o_{<8p-ˎg*}i 7~ekw kPK~ײO_9)ᜄ9}@NƄ8sr@֠mgh;2]Q9t^4\ m(p=t:}UKm!}0uiq@XbKs*R-sj_0K3Z9IT~c9h"ICޥT],QmIv'w oPD s̠>V#08sG3} ݈#G3ata0WڸtB/tby qzAOFAHBY܄@QlSeF}f-e!8uR@&A+=Wη-}qRgtkE}Q xp"Wqɔ㓛 Ը@.yOAy$=Yȧ:::::֢at0GcrJ@_ K' 8V@e@wށJQR6p`P>qj3yʨƲbQ>^̱7^R@PF@ IRm_탹]s>3g wyFpJ(Wǔ3:UmEak Wќ^g:::::֢at0V9:נx׷5k?`tɆAOɲ΍|d! e`2jR4`& b9Ơh4# H Z;y'9"ʖBr\_7cʍ?É/O_HHv{{1($a-~C+`4B>G@l`>S8mÑ>stTz}k}%Z?9PvUz(\uttttEܑp0Jv&0̀L\A^'3Rž$AY"@9r/X$8x `H HNTjYU0T&H|`S9RI1pG}ҕ >$YA5l(۹c[=YUǗnˡs,8xM6SGmsߕ^|Ԡ nDrۖat0,lߠ&U b*e90^Cqm9uvj.>xI7i;K۹tc7Qe=\0 Roj _SpJ)6Kwjj e%Ֆ7:Y_@ǡM]k}r<:;OqG/P էm4#w <_UGGGGZ4 stCG.^tT@S2&K#@`\tfUTs_`HYS'iAen`3.pMop@'(+m zil'0! iIFmmr4Ssvg{]_]C@XRٱIw:rf@zhKG[kΥatp+XsR$ PHhs H >͑ ** &GL.`R dJ q|RY] 9߀RR<5ʵ_s\*#o`9f>M #_s ܤsI쿸w߶s8Rǂ4FŶ4t]91z;ꠟ7Tzz\ @e NޏN[sd #mZU׿kUGGGGZ4s͠F2Ȁ☂0ǐ /󄥸V?wOAJR} D9 현C*s:prP@lQ\8kg)zȹkt!=rb{Yiymc];hsUz U]գύc. ʡ#gq &ϸUF,y_X#Ӆr >C\)n\1PSہpc~;.G΀P 81:@~uO gs]kR#Q:w \Z@W.Ly[^ĠuM.Ot$;{j:̹g>t>9p^yx灶LoT|[oTr,vtttt쎆#`\5>R@GA ;[Yƶq{ p(f>+q:?lmֲoYAJ[fC\S@^t9%(yWSء/" Dilh')U0g޾w|l{z#`eN Ļ\GGGǾh;2 6\_(( 1:tRw`QnsnۂPB׊6Dν_ T#ݻiZm7WDRɩϛϨ z9VRdCWΜu)Xܟ|S?Wk0wd:%܀]0Brh @\[gr^spGf@sg_yoXu{k ̨ʱ>xN*h3pQ"ls 2gܷҬ\F-zyb ^7lϫ9õ\30~/F}]h׼ګX#`nt_*Xg>t@#-@o1ut Zs `|m;'7Jv s..q@Gar=ڽYgNzV85ɈS-Am%mf Ve \F@~}?Wk0wd:8Q9t`r;YlR>F]l@[,O,ᘂڶXrڶQem[Z9c!EU5?ߓξiOY'WM` e6'-S!k}MܽWKmԪ+:::::֢at0ݷ]0Brh  `2Hʔ5p+Yn_U@Q,e_AW)cfvYXAl<'5W VE([ñOʕ3g<6Ҭ@L]c@Πr 8(},MG=ur 85F]lO$Y/6Y]m娵m ̖۶-еr?@oePs׶W@\l㹿ק)QF9#'=OIo9U_wrOt0qQ]^q0wd:́(_(3`]PW@V@*;uX6@g96u^n_U@N;gMx`l<<XAl<[h3uAӶUR? ')XƝ3T?oc|Kz[W_ro{Mm±mǬZ sG?12E>U z`nT7 An<. sctqLMnrW+VҸo{Ln-oߛaOD6~SӹwW!l??-z'sOL0 䬿 8tJ9ѱ;L9Ex&`x?Ӻtk}^'yPж ؖK\`l-T]>Cvm; ڷT@-3֩`~j,ktq@QPqtzc{R7V9>pWZwRoLOi\utttt쎆#` H#Yߏ}zrrY/oiyupm) (f]ʶ`neYZBڶڶڶ:r[ѭ ho`r=ޗFU\]pm晓n}Ǧ_rZܻ{ern9ʾ5ž0wd:̽%wKW.~ ȁXrl[|sR;w[XS FYgnZ.lm lеQ#йϛa]Zz.򌟊竝Ǿs 7Nr9~tҭ@N:9k8v߇m-s3ѱ;LG⤾ly:G>5Me|z\ۗ*wε3 ZKKp ^wnKQ(  FPU]u96G[nb[GύpvXQ D}KjԺ}wܙ9}j>o..=wgyF9;:::::vGܑ`0'mʁ"6 u}pܸEʡnmE2@\pu-+Aҹm<8@-f}0wd:'lʉ7z S'& 25˝K 5gmk)Ui{ mmrʬ{@G\:Ii jJ3VղLl!EدKrOM1?4x曫@mp8yνqZ9Ko(t#p!ݺ#ѱ;L9Sr͉aw >^K©r^̜9 68o{a.BK6 B@\[ fSQk{~zDz~׺R1W\M ۧ;t6LtݨGܼ>Br[չ 򾣾îArQL4];x9u 8r9﫦s;I3.::::n&L9i{8^v&Mus;\3<#Ⱦm+7( nlW? еg9qOy rjjig~qj+}}ձ2JnvXc J [q\ڠTu ƹ й/@L9Qg\=uUpZ_w\~""Mw'(q[jܽ9 f ܓj_cUΨ~k୶8.i]$˵S>Z]ݧ,y?9G+nQ*ι{X7B8޳~&m~rr䔖5OA#qt-klBD;PGGGGhgt0q#Xlʽ%@N_:s0knt]Bݼoڶ"k )@)L؀T蚠K9[޸miomEin` P{Ҧb}e}:k=@Wj#rP(ۨRD[j;ޤGk0}Y7[ZMU_FZh׀9Xs΁9}ktutttt+̽{u1`0HGw/k/ssIzd=a.9Tk K[/5&@ЀG-YNx*z'oS5Z9v ̱η;6Sq _mj>TMƬa~ 5k`sn,lZR^:ەkI~A.UY+5. s5yz6Q.`S>?qͅ:::::vǕ~e޹''WN:#\ҁYגRTkPGGGG0S;Q#.jW}rtrpq@Aq`%a6@:ǃ5 bȩ[ qBY/X u]_\>[~6X5LTX U0V7]9t@ 07(KgW~t*!ҖۤzC~hjDU/5o 9 oR~4:::::vǕXy:(I8)Vf (-@_:NrFPX s~(a.k,s+4T0qӬWXmho`:cx>gClu蹨z>pn5">Fk.9Zg2\vK&nՇq]A':dhS̽ia㞋59)}@^:::::vǕ\aۤWH TʍJa']r_90Ͱ6-ϳ?DKr`FN.`&M\nҡ@ {cC -!6!夓$`(R`0ϏsՓѮ13l9b w tq^]K ظbm+g2Üm0>pLxzs8p uq_:{N;O{_@=5ǜ}itr}q_ucߜiJ|5aFJ՝ǨI}NǨؖ.dU2SrSf-Vn/m+rrM_4֓ΖR4.u iظw$RgJ K:TjHW bvO΀\prp Y\3pH9gڠ ϱ̹꩝rxv T!!Gu/0=K:LG2(`;E[r1R3MIZW՝Ǩsف??ioĥ)wx\Kj-\rhK^r0L#m`=J4>}j ν;@c Ȃ80@9 8uP;LA6C7o3"n[d{ur0Hie:/Һ:sܻp~,7G nxbD&Uo80gk|"'bTǣ}\GGGG0w;Q91I 0!Ӕ"/gPdB ݘp1ܚFn~CG52e׷Ӕ3r-3%%E `@[N t}ɾhTN?>8m+ @z&}`M3KPVa]Ulܸj'm!([ YA\ɹqK&7\itqv 8Y)L/&*n58s@9VQV3 ۔Ye:R`+gN9m^m& hӑ9tag^@lr||ah;2 Wh9A-Δu(L @ h/A9P56[WNL!p>!E9NG҆^]ж& picV@qY)v8]u3 s{h˵M!AZ<\(urջF0KRSzd?ĀC a3 gor~7t@UwN5ǵsz>祿Qqqy:::::vWws5%(xs)J @_J t`Vq.w \:]q>.R~ul4bzvY92 9Apz5+e9tlYH; u- iYĤM[ A}N\:ϳ,jiUuWLӭ Ish.7s|`xFfz5h\n=Hqۦ8sѹ6.?`\GGGG0 (z)c +s<:3TV`$[Oلt搑:7]?ǃr" tp}N9vKҩ@.JG IJx9 zq`'~>ʈr2pW^W%W}^s/Og::::Fܑ`0eJ*x)w%Ų 0x{[/C)#hLRmtҥQgκ́r@:/PX%ĹI{U_9Mw\G.ڳ@teJ:)Z50B{k7e'eR`(F9WU=inNp_^@Y]X9M ̑t\;iR`UzesWMN ⲯ\\E{3qf\ ݫ;Qrg[d%YI@ f 樀.SeEG\()D+a 8ı`LqL\:%e$!,I@nt uf 廧麶)CYpvF ̂?O Ƹ>\qЃ{J5Ap[Wj5Sk>qȕ39>s:`ugָrWo0\Yc>sF6uttt썫soyc`'F˼6Q" 0 4,%m/"<%q8T ҥ ؒLg.@BY6JqoVj9bLF] J\˽C{r~Jlr{W9`ϳLX5s8LJ3:oA +Wδ$.!'m9^5MCR(!Uq䀜ss\s=co4sPRyp `08@)t+P9ˡ8t# XT pls?Ƒ+Xo`ا~@@es^G(9K+i#]T'iN{MtgIۧ~{u/Y~lwg ʷ5\W !}Uh* qݤW J0wd:́038Ra:XULg[6ʾZ%xPr#"̩") tϨuu }q:OqW3a. 090 \-p%ǀcǧ {o.\ձ\Yu.[:wRFrʅA攳n;~moJlVW7zT$q_UuC\GGGh;2 @O@`_90Cs~>1ؘg8-.~0" @0FR}ޤ-]6#"#ORs-v@JʱЁ9uf꩝ϣtТkǺ{{S\XR[gu䮫ͭ+,S?9}ڸn@z_T$& _Ofzu}7LK.!}Ps_\sr sgՀq04-3r`.@&ӬW8Fp8C%X6s$jlε>]*ʲa.Qs,2Em征Gq,t? Fz@} 1=W$ҕR@:0<:tZ-켪v \314akL9Ʃg&E[rR31wW.dF9?W$ '+g3 qrj)q5`& g.^^ୖk0"83  3X:OՇMY, $,T @93՛f @q6e<8ZU`Dq=Q!hM\q`LtV7rw\7aN*5ҪL}ұylXO4۽d9=oP`ڵܧ62vʁyVWAѫL!ne<[iUɕ* 䲯\\GGGyj\9pushVp~j22@_2eD^r"f;@B; }WkH29u \PW $9 e ǀW8q6+A5ֵiUդ@.ӫ:F[k;퐀;[w g_ Ot/ШTm&P< mFlW^AfKjQ6 6SuԄ~sL7y0p@Rwr@L#y.c?Q6@m NOF+;&uM<tVzWkЃѫ9_?MlY_ѽ~ >O\|+PGGGGh;2 ̙ @a5@84\L0>b hyуt> \,K#r9Wɑ `>|v 7Ti\#!%  x5a.uF:s viOKu]^}42wqĽ+gl~?.wFm%? \}{ j^ON9JU?sʍW sG l sĽL.H\k,w:KdOq~;)W@!rRqJ)=X89rҫMj̍acӫ0wd:́+QNX\+/M'^ ( }\e?X@"OrTr'ۤ s4f pΤW?W /Т7uqy0 nU|˗N`r `d뾴6>t~SFkvyUwm"P=gVڄ#S]U]~qo#ArV4^]LC0wd:Iqul#ȠLst CpX`@ҭ%ubI %o;ۀX:ܪ@Q prߨ:'P~n MʤF@#8"U4筀"x́q},M\,'' 5ξy?;r3J5kG J-kORYl8tr NǍWV9rǍWOvըt~oWutttt쎆#`N "F[B( 4 5Weٚ:0"9bR/n^Apu!i9?˽p@EZrc*J I 7N` 9WYɹ_n`˾w- @~.\ܐvqqһ] LPQF9[@TF;P>3ŭBA..hsmSĽqdwqǦs\q.Nzu} sGo)+@ҁ@nc7,WNt 2) Ȳ] 6Q7L%8( hN Ę:2]0qJ ζ?-O\)fY#8åV>4 L` /=l;>܏{$aVhI X3zM8} ⸊5?1,֤W0m攋k'WxQat0@J?/@Qw0vR>Hm.Kb?;d)._H8p6JM,[9nRm?Sq8p[lNP8@e:@ pM:ߜ8d;]ۺ/=rB~RtLW;KAP!iYqvNZKmb9FJ$[6}b@WRGGGGh;2 V`HVř3 ö@))70y]np=k>pj^9ZA8ខgIsS@K@0,}*VloN7WM"{\kcX_p0!wD랸څSij8up%ƒ3 [M ]/ A5 =ڧ0wd:y.)%T݊@2u+J+4+1 r*A>MXI1r)} *]n[ `83xONTvߖҋ<?@n.`U/\ot9cՏ0+%6GiA/}r@0?mn\/3ݸG,0J5)GlM=}ܗzw~x L xG \+ӫ0wd:q33MxQuY r+ȁ4\r+T>a~b•32}T>h 37Yn q8lhʰ?5U3.\ܣ::Vdq2d?x\ҫ_. G{$@ `I ;P8S~! j.`N]kA\M \fqߪ\Ӭ okrCFܑ`0S>Ww=oY0SRgp<>'ʍ3X%)J'92>a$}B3ʅ2!@-0T|@ǡvW% 0FNKcOkܿng08DYL8Sݵ(ݗcՁj9Λq5HqqtW._yا0wd:́i>Von6J@L;q)Gȑ@@nr G8O6\/p xӱE*:wNg Bw(ԁ# x>&Uߜ-;4i8-}AQq n>#ITqygv,HTnTVZ Njචij`+xK u&= sGœT8bf`V9@ÈMSVѝW&L!~ôVG U~0Rn( I1Ё#v5:N9_ /SNis/Nn\~6nFdH@._>vq4ݸઞ9]*m иqN~W;i@w*znTatPP>75;#WzA w\9%r&hjrq h`V@oJ 7>a~'uhy+Tn*mɥʵFf7#] t{|T-ҪFJs,wN[A*32rRc_pmtoKk'D:::::vGܑ`0ɒ75o `,^[7jڍ%*] &ʥRp2]PcɡBFzѽٕ"}BsܸrJ9|j8iIN/ 8ct4i`>䀛vצ? p0quzC%݃vq#f{D.a rfpv sGœU;4,wd;"]œo;Lr ˕AQ`H@\9 盫Ҡ/}G r@ J'\f`qq.RЩoS5]̙DI-jU:݇ kslT]8K!ȫR8Z0;Ei9*H:::::vGܑ`0' 85`3NQ:tL7Є8!oeFK+)~V͵-`澓z4)JP'˙2*(ӫTpj8<^*h)8O0b;GnLZz0o3ǃ5ljlwf=d',Y~K3 ƶ 3` `Xd Kvn^,ٚPBBC4ꗖEPh$h@!Hs37"8tYq#"cI{#rޓCޘ+qH\t,D 3u8ƕr uk`=YX0 end&sr2d1U9[C>^D1l\dԩ#`vhs,ٻFB4Kf.\%C:1.D Br!# R9c+Y9&$LT7mH .Đ{֣tȵ|<. UcȠ.52k0"eY2J+ב q9rCH,@~v^̸Nqn9hKnLr=[1ސ=aݡ̍d*bŀ'o㡵,P~BxP2s~'K.uXc]nOCB4AXFV0ʫdAp +H,cɏ iƫ!4dJv A搵6eQIQa0?7 iAڐ7`?uBPB 99S'3ʝd86@bbC6$9"{qIVDdo؍n|~Lp󏱂 IMp-XY&Dz[i}eaݡ̍d̖$Nxfsg("`"^H2mI"e p"H%Y* =Bi5J RCy!2)ʊ!1K\߈ז,,Ў d2a[Hd!u#B9rH] tG8ʔV)GF^96\c(.qd㐱!pmd.\M,KX_aݡ̍d2%|0^%Aƍ2^).2y@/+1;)r&AAY[ȱ2+1 C|"LH r"G1jdx/Y&JW\dBXh_.X_H"8+хl"_Pc}'g,?8"GyD&Ό休8(!o7(K\ˏYaݡ̍d)Ƙ,J~埗B%SX,=H= c,MR@@rYUg~@Z2~H!۲?ʎ8~b9“c,h!3J$:!.,5:d}9CȨ!Y#eW&dt#ct"vHL]ĕsf[ڙ4˵I!,_H\77J熐3rPׂtӶd"[al=ћ̑Cx?܎_zE0ȴ-eK 畿2lW~,Ix0ޤ5?.h'Udr{JVYY+D(UQ^%!5y Obs|m ž+~ "w#2I1&.6UaDq͓1q2Xqą}42!B4m[0QCBز5HYH†q k"K7 0̽UHo2G6 1c KX!yEV,x!u< SL@(rimdBx9dLA&/=$\7;|j.c#W[ú|Tkǽ] 0PFFo2!ryV$2CxY1$f[{-Ohd Qc,8fYC;2l!rg&iC(7P>eF+v+CV.JH%YEJd@ > rH Bפ3>, "ųBgqmxAo&8aM.cH0!zȊE;c{@egD/~%db+cQ mY/DžHDA^b`?Ԑ Cl3Զ1? T$>&3#?VcC\BRygK~[N0 莉ܛc7C(!W bXUرYB?9E&e]SneZ%˿#DZ_W$m*r!; =_zVf #Cy s=( Jc^i q+cN0 end&sX5KrdS9BdBrxѾj䚄Ⱦ-cqՈde;G1Kkw0 ;ћγ\ՊTJd,x:9ċ1w]db("k|%(M<\Ad;&= s3%JJBh4*ޓBrYZ%:s<ƱJT>j$ί,"[>^ 0 ;ћ!@LWQY,Yx|b ^^'ACА5$,2kexO[!,c:Jlp|+)d'Dgmϔ]C8~2lYJ %XCT9xȀJ5 0PFFo2HՉ^ 5Y!Yc%iD Y:2j#uɤQREYKoqr1}Ǥc]%kdsLq" !m 9\RM[fvΉaM搇6BddLٻRx%O$/g";^L@x-a<,:Kǘ:/+<8V^\^lUc 焄r>63㢤:l\a7UHo2<,d.B8 DS٠6E:LK6gqxD7~)[d횿둁%$tLK _WB|B~;ryC]v$cY8 $q\aM"UV],-2yT_|c(&q0=!{ !}gY,+rHO]v2lH7LH\o#π{Q Ԡ1 0C\d(E4nXu+E/$j!ṟ>.;mE[ C7|^f~Ť1 0C\d~b!@QRȊ܅PA){AlW_ Yd/+sYD29@$aFw(s#7CMK| $/ Su+3x!Y!q!xAW"WfOɋ9w7fc̤icat272'sAK"{G.^Lekow,c;X집À-ϱ\d1 0C뗹ReYZ.K̠̺"G;Wfj"a؜̝-zo)VHD-q"=ayuaݡ̍]]Y-ᕒU-.WY-0 ;!sj=;+ܕ6+s'{Rx*ߋl^^Ij)۷ s$^6`:6뾴v#j̽=Rm#ʜFdN[Hj9^\([#zb!yPdJIAW˚Ddn~mKLZAY=PVȜ9eNdZl<3WLVD!sw@# s"Ym9̭[^rtj2eN$\BMR҅u\ZvlS[B J\7t,bfu-/e_en5Y|'cDظQNH[?^QfMo\2zt|ҶF%sqYyri\,-)9ki A:'@+m[Ufen+d{Tm#ʜFd,R,_vDb Md.g9+xyyK"rDX IDATX{wWn A`yCh)_$x>t\OGO(sY8F9MP٤ XPV3/>jQDnQ62,sHq(s"\7(sE[|̜ 9u̝2Yd{6eND@&sRN]een5s{c1̉ ,M\ w ,M횝IÏ}8F9i1 {VLj2'""2-&!s8U)>jfN'7fs?`x\2;}hYd?2'""2 d?(d`vǜZ9n2'""2l"s/f/)sO=Tw8f̜8{f32wVs̜蒹g?9B'c}\7f_:snr_eNDDd8oߜ=s}{yT~I!?$s(sʜ8)e~,=e _2dqWtn??я~^wٝ;wrvRL֚.s_g^ve.d=n&SS'%˗@ַ):=Ӓ9 a1 ,&9@LVJx9re&s$yBBBj-/!s6̕9n^YjƸ9R| 9@}xxi%֐2+2wtt4tmӓ̕R+V"""2ϗkb\[v \ERkLR+_N ]`Jfǐ[n|_}k_}_yXFKKK?L|||ڕ*}_N2UJ[J Z\Zޛ[m+̝';q0p2/#PG!w!xEDDgϥ?o&BE3XϛUW2t+Pm+gع("tgB`H_,L"""?p.E,vSv!tܤUٹ:|!bP{Kؑ( bHEI~K䢼*+2WC/2ג];KǗ/NdBBDDDߥ8$~:ȝG䔹.#:L_ ,-u }n -r]Րp]9̅Ѕy̝E0{ #br'"""#\_Rkȅ̅"5&\"{)QqP`(o>_ (4"""=}to57Y殼)RAA#"""?C/Av̽jT6/CI#"""?~Mv,s_v}aDDDd{.j0 ^bn Z??D2ǯ6ʽQˆce.s/{uQDDDDv̽j6sy eNDDDd(s""""F0ʜȀ˜YEDDD\^~(""""\^j6s{˪""""eWEDDDdidj6Y~j6j6s{k""""e· ̽Fm2o eNDDDd(s""""F0ʜȀQDDDD2'"""2`9̉ eNDDDd(s""""F0ʜȀQDDDD2'"""2`9̉ eNDDDd(s""""F0ʜȀQDDDD2'"""2`9̉ eNDDDd(s""""F0ʜygj׭,SngS]PDD;wp5}ܯ~+@(jmeNDd("Q.29F8fPDD&"e(sA(7gGG+99]k둭\F벡]*s{K.-?+q(s""e;2w}v^$e2D<{9 ]E"$UM2'""}N}hvVkyBܚ]_]ҹݼ~xr[gG7o߽| fǵ5̉H߬Gú,e[I^Nʯ4[Z$*Mye lSn~rlvby d`d:?).ʯ6EIoջk9,7̉H-"s![ikFL,Q[6{MBUK﹞(η['׫h3̯[~-6b$jydb~vQ^7VEDdUDn]/̚ CD\w"Nקk k2q=]ܻ{dp2׈[dغ6Y{$w2'"2Qr_,#Ea+奶~ڙ~پˡGׯ2בmvKL03r\d֚L2?;-WDDOzhcEn]o-k-ʬ>b[djcq't23k!a3s+ˬsiʜZd{6kXg.EBDiDe]b2ל_zpڼfNz6뜮̵9`{?˛l2'""}N[2769F8fPDD&"e(sA(jm ɜ .jmeNDdjj׭,SnYԮi(s"""" 2'"""2T{9rCoUDDDD}M*ʜȀu(s""""C׽C*ʜȀ*s""""C% wfgQjFm!p~^.?yhwj&xlVh%U-sfvrRIIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_02.png000066400000000000000000000427461322762156600327040ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsodE{IDATx^g,t",EAŬM%(&*XP (("%E4"vP4%Q's=g枹ewy)gΜ;3-҃7!BM!,țBIY7!$﫮*;䏞ߢE!B"%˻EKe*aj\Uu7!R5Z-ff썼 !Om]X5%q=}L]kGǚ:2Usݬ#<ňjSک2­fΒv;s,v]nDcXB!xjU4'z.Sl [ ƕ+ac=BF(#l5>Վyej$DoGO?iBHsw+|WZ'xyy {꒨Y^Wlw|g5=^z{jy䮗;5~+Г'ҰI7x%lcmlٲX2NgR{zyNu8uOgL>EYgfvZX|m(4_%g! bD<6E{E !4|\YT:=o-b+cWLymVjTdJ!IhaFŞ$vqgiKqğ?BiҮubm .f5 6,$o.NzT0n"mp>9u8:tY^W"E#adK6vΐBiԩ7yk1f3gkGODa]^-l7Vu,Ju:9S/!F+n.5E{2L \"ײ~L %>)%Sa !s6{%ny7I[W/ciLfy !4d]S[W򞩄m /ŵwgWZ+}PӭYOtSg-;9֬}V_î=n}m:['Ҩ}'|RmۛtO\Nj71IBil'gbSjTBex)+$^vB=es^7!4%oUo-p{B!XyҶkݤF!+oB!4 oB!$eAބBHʂ !yB!) &BJ7߈ʓnw?";~ ! ~ ;Hˤl\dl]cd'&~DŽFw6}nK:M~dJZ2\A:`<\'p`_26U,]v[DNZOq+h7j:Mi'yPVCtt8tK)Y=)kNBޞvf'#hw}NA@ބF߲A޴_ұM ߯tSnNyۃ)Dq=^$ȣr:EoMX%Y{kY ;6Nwho#.lݦ@!z/fX-N+28$^yjRBH#ST[-^/~t:? F?͓%zN0 )_%pi=ͲzCV%@PNf4,+o #^υ۷ώG돉WBےD!Ǟ\)m.-=G۾ M Q+=|i/QG?&sé;yXAs̝| :߼r U=n#B4dV|+[Gmȭ.BBK^yMRc9Opt8ywe/].>)~}ymҺw+f꿬?\Rԩ"̢V^9hx*7%QyW,SKgTV;Ox%!wmKBArY+!t>zΖ_-Fu_t'W<1|ɳ/l}U^vYj窷}?믿.?dRg^;el {`'ΫN䴲"VGM ϝV '+owZm!F%m[k%m,mvo/O +__ɝ/}RÝ,ի/@$7-O{G֯_/fSVi9Q̼BRse563GnwP6N9̏߾ /ハY>otylkMBIy9)߱&JI:T&GB8F~}Ҷ_բap*wR6pLSW_/2ۺ:=mn.It=-kɑ#@^[ǖ8Sۗg> AO"=<2uդm!FGItNT кb;sI1ˈj$Yr_ʶyƙBHȚw^[)YO͒?Mx_(yhg ,p|٭C,ў0&4\5۽Jt=wR#Uzkcz_||yBir1pV7)?t=t=Gǫhʻe~,wo|f7!&n]>lsvO:forq3Mjүw'N[v1ʊ+!oB!M.?:ZԺg}6R~vsʥ}أӾH]/vwۦrrw2mEw)6l0ۇ !4L{tQYU!;H١IҺYo{vkV>q6TxL:]֭['_5&2H)H#N#/U"'z(a[Fb1_5 C.Yjy\*&Ҥ]K T~Yϕ=wt7!&[Xe'jAQ{Ζֽo3Hi5|l>*n\+M.ZpͺAބBd>c)O$55%\2΃HIcu=U_E.^>jy饗ou &$W_ݥ$'JԿ֊VsmIס3eο)yxAZHJ 2M;e.țBHͥ=㼥ySiJ}fHHad?=W~hhO~"w{H;^--s#\e5ˇ~hU oB!M6˞~IMZ^()] =/+ϑ]S'2,y7!&-W_}Mf͚%/NO?]."cs{2w\{gQRU{=M;=kŜ)]*K CirmɻロAބBt>sdݺuo6ws-Oe9gk8iSɻSslr͵SW^1M7!&-h} \kr-y].#0q,U^-ӟ_WyB!yYݥnviUWYt&țBɓ ]W,VWɜ{{C\M !<ɑYHO/Y-{Β΃o/\ͣR7!'9>{|?is:&o;A _m'4<;!|K;l֬(eo^]Ӑo˶:Jק6us>Ք>@x Yj,_ܼO|'xBV^mʮ_[Wm~@ЙD}TJY.]5iv|+Pvw첥!JmOE;+e5\[_C헴|n;!|+347-9s9#p't0r-K.^{/s5M~R6B)Ôj w`ʫ֘YZ\Ɠ]䫣PIXs]q64?qP1> >ƍw_իjHOHw̴6̔e䠃/]GhyO%rN[cY΂B 56SN[<ֿ>ȷ=v;_սhZ;ʹ'.O]lPGvZ z5[;ͥ|#b;2տuZyA]=Bq>>EtR93{tA6|St1n8sz=?~@s0^P&X>"+;="gl(f=Wnc#[LiwgnquuO2v|4y{?}SZa߽mk[w0yÝmL\Ny=Mnyg}z~UȔW=/vfz>¾ .A-z[},Z৞z^4-:O_uyكw yuDh׾i춹in}qm Ǖ/eqqtoݑ}X\'(b?gϛ;ݳAA _>tXhvG˶n`OoV[Zz..۾}{9_7}m(Dk([W֝Oŝ.T}DʘĸlI9%]w\e Ӕn--l6b?߅Ŕ-㑫-V+S6{\mUᛮ{{P /tO~ܹsN[e˖ңGqeĈ{Fez6rHUinfk׮]hy>~Wʳ>[x;:7Dp:K-_isw8S1=Dۚ]&}AYG a-;r].J)h=z}qmzb!qkƶ?\o|"mrk2I{dD%nyʬ// N {C uk}o/?drG~39sϕ>[8 ?\{oau9zO.o>nstbO[l]>:=_,:@F ;sR֗su=`e]!(Aԭ=ƶYo8Z{8\b;m?g] |bʘBhZ];7vgj,9r>!"p츯hC#y'O~Ч|MMoZߨۯ_?Riz?O?׿I&7lH5k̘1Cz0aJٱ+6z\K7RnbmgI7 N%]|A袋{aۭٴCY׬Y#/A?s裏.SL1RfhN[߾,ۊ >X@ _!>Cy6rէ5ǏnFEO_vyҚ> Ow9/ӟm'4<;!|++/<#F3gΔ;|K_ްay.W~%+ȥ^*Æ ɻSNoWWv@Ã'b}W{1y'eʕ%{Z 7cS]ymVvi'Y`AP(,HfH>o")EGnӦ :Tn;׽y߲Q|J:n8v~h*'R/nps͕|+¼D}FmڊmBM>57x!y믡釽hy֊}}hH٧4Rg~G5'2g3w7"]՘ekum_kC8'(߾+k4*wBW>~)BT?Mw\[Xy}{Џ>‡le_kHwMKغ3M6Y]&H=u8ӂהḲz:˄ۘoe@y'O~~ؐ!Cd-[uL\E n7Nwژ#L[&m =_Y߰n]oz|ܰ/bqCF'틘nz|o;!|/ niw)lFT Ӹe}þ+7lNjǝF˅su[G\my'O~?o_Z6}yYYuzmޱ/5}{Szвz\mnYpFj:[g@ǝnceU۪ywE\YSwsQy'O~u^/i7Nf1|6O M};"9/Uees-o8NoLO ʙ˶[ΐ%/Ʒ]mca h@ _'GG̝;W.BsW~uhp vЯֽN:\^l~bo]Q|٠4o/ ;!|KԴ.]Ȗ[nizZS=}~%\"wqo+Ѩv6$yi=^./4wB~:Ӈ~KA$̟?|ŷ / y^nfN\sr-r}ir3[| N'ݻ^i/\P~a‘7|<*Իm'4<;!|Kii ,^x\׮{}>%O7׹NbwZ*y'O~I~رc宻2OMm'4<;!|Kkw}7h / _Rx м@ _Gꗓx汧z>#Ǐ7OO{f5o;A _׀>2yd#+6l]. | N@{ʕe]fNuvƷ / E֭[g{̵˗Ւz v@Ã'$Т>sev28T}:}ӦMe· ɯ6h#U[6worAYMNhxwBWW_}U*++;ݯǣuQwy'ڠu}ĭlͤB~iO м@ _m=UVɠArݮ];:t̘1üDWGmm'4<;!| f4*ݻwH5> &Ȋ+Q[| NjpҹsgiժiF'z y43wBW}Ysgo..ȨQc1_{̓\|uv@Ã'ڢoc=&3g4OW;餓OK.Ds9h^ / w_{5DnMf͚%ϗ{W֬Ycz|U y'wOC=$?9]oh 27@@)y 27@@)y 27@@)y 27@@)y 27@@)y 27@@)y+VX!wᄇ뮻z\OhH7m$_~3Fz!ٸq|O>Ļ<@CЬF&M$~_s5oy[?餓]nN/-EU[{dɒG}+od l=rHsͻ|G>x=WyRYY]r| l=lذ GĦBϩgD(ʹ2H Zޙq;T-v绸ȅwyXi[ݓNY X\e!pGVLt95oqi촀h f+o}7|U?z.<7"hL0|u9 ^m< f-o4 kڶ9M, kVzut^d~pq@-oJw<<=ȻNA< e oRH e oRH e o?>8>T>ݴI6}?y䑋/?VU{F9B1Sֿ󮿎m N4haam*Y6yz!2e RQa\q Eerɋ/[W y'O:~xnQLR_1HMѫ{ Y"6Cjg~hL۰fTVN5y>ajtou[oG+S\8T1X]Sga^G+&ڜp;\9qMxNs*}ǽek}Y"ۖ B s[/'\&c nֽ=Z=Cw.\|Mo}<*sJG fZeup.9x.`=vF1PLb}HۘB$ P;!^3䊁BbgeР!rEkSW\} I{էUDYҶ{U^:'DCwיkdSwz|'XGz Nx:3b[E[./BvlmO0}FY;-3%o N ڔ].;?w<_4B] XVz;[ugH;!\QSoyAR_ETYJmkz-?FB$ͅq{00?~stdnC:C˹u2E"s` +=zۦp=tltzl;^)5h[gMLL3 vyz٠&;?ne\mȠZhæ=8(?T_V7JܙՊ }{/>Um.6$w;ͅ#ܠ>0LwpsӣuǭW>n؎{Wl=o8|<!nٸͲN/.FHj[p tߋ!#p2to뉐z&.Cvrv>Vg qkqDQ ]QGN=zlBu`4ϝۖM޶;[;pz|} {/nwzuDaHQ~ϸre W6:]}ex)gH5;! u?+7Txw 8Df̘)~apBĞsppHl9;w gz;iz8X_(񴹯=1Lv#TOgՠ.5ؗ92uۦ5uG>3ւ6ϣ%\b~[gTB R }\'Sv%u_߫\ڣZ.wTއr<2p;0@ihOA O?>骈+dz2[72}3x$6]#ܞsC!;!6ooKn,.)srGO?n y'ڧ);=^2ܤ8_ܚ}-K>n y'3ӧ^Jڳ~>Rw\N;…?+ݤ9ݬ }I!~{RMMGT;!7NW2EӹYyw߾}+z+ZG{ms! WPb[xצ:hS۽ڌGL7|-~}>xK÷tA qa)qWֽyegrLmsrGy\ f͝+W-,|m5U7_5dE, nj/Nwܐ82".vb{mqQ,R.;)eݼҶ `]=YAQD \~Su㛞ӊWqs7%+yeqfEŐoz,c?p Eˬvnz=y3ʗYwYJ`z/ Y7@ vŽ0+ږUɰmȶO=XyꩧO>JXJ2d9U=Hqv\jY6vXoM`]n;?n[_u2ϴK=틡Z>q]w_[|+׎go]qÊ.ۧ;۫d<ah{ܺy'=wr}VܪjY(%+2`9'>* cmw4WV1yhmsŔBd\gɷRHi_P%sƳuwzѶ+'giu czQ Faz܋62!4y'. ~ ݮ\J{s5Yuw[;GQ@馛eڵ駟zE1cСCM=(VLR\Kͅ0)ՄN{7edr5X3*8{j;[vG=.H(; ^J|lE[pܺBm"ṴAץץOhCmQԾ]3Qm>ZGhZ̺y'S"KZt,={ҧO_i#믿Yyf!o_oN;Mvm7߿P>e~B$e{\s@qw=tKumϮ'-nZ Ztx rms~;n:]>#żfŭ˶/f8m k䜩+; 9u9q` ů;( ;!^Y[dtuU~J}C_TOzG>|/9䤓Nκ@N9 %dQ;޺u_Xh/mFO% p{ĩe{P Xrե#2#TNrXg}p;Lo0/R=j|;~{y -n aI&Lw[A iydr1'Z ?ZQt&QLPhq_8t5o ЯeĊq%-\>| }|\SN6m NsKȣ{VYrk6{QKwU P #r4m N-M~(/[YHZ˲<`rLnҷvJZ}rCKbe_=3V')dk3Z}l\C^q?xBEkYrU.2KOC Y|ܕɊK)5nV>}˓Ofڅ;!$?ݰA>shcM6@:A R/|nggrM^[}Rس\$}mVW(|= '_==6@:A :n/nJZܿSo(ܤ޳gh{|mt"*KG+_=H;Gܛuq=YIP{RՉG_ ӲQI ~#Ovwm{; E BfH';!| aw}~,6#Nq+X?u08|mt'Lu,?p[Jʡ2s)NwB|^iƢʕiI'= "7 (U8Txyӿ_hkg{AfH' e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH e oRH͛yB!q'Gv4n7@@)y 27@@)y 27@@)y4nȃO-~LbAM}0xw{ q?Sd< (W9  ye<Ȼ0Ȼ~A`HŁr%2l%7AޅA1gy>Z󗋥[a,Vmy;&lq<@Pԋ݃XMjAÎc Kg!X~0%cd3m1APԻu(Tmo;t%΁ܲuG[moB=2(譛2zrdX 4`v_rL~>[lߏK zso |B$PV?)aB0Ӵ,mvϜꖩc ?33h|6~?u;@`y1=Hb;Oܚw?"^^"w}ݿw7ߏl o0ԻmO<Ÿ6Oo4rhy+K$`.# |wGb>qy|k C۞LҌ9mi庾ki(yUʹpT[Nψ,E9;憵`Txis'ZGB o0ԋͩDbv>LLO kكe}Js-7egpXygz~u$C};ԧJZT@`@. _78Pƃ   ye<>y3U[LƃO>aA5g~Po H e oRH e oRH e oRH e oBvKIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_03.png000066400000000000000000000361251322762156600326770ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsod;IDATx^ U{;#t $yLc @zFh/\P!>7A0$%e3Qs"JpE/]g׮9}^u_N~|{׮]>}A7B!!!*0oBd¼B.K-T~___BVnmʪվB^ 1n2ƼBkJmyo(olSoWȚmfwLǨ0&kVk%+ƶ5Žׅڶfg4f3{,~|܊O.mٲ&K2RMVldmCcv~y}5^`5fG9u| XHtoȪ&߼ǎB5TĘѼU|}kTSN<>Sy䚗e.kl;j3M-kνSV瘻?C5n gH=v"LlT\5C^V&ldۘ͛2wam]{2 ]}lYS}\iҾIKzׇZJ]r IrhUa:'{M:0Jq3x[xA:Tm͔mvVFl6v]V \<<žrG8)kFʰ*bVҳ 6)mꧤV݈y[m(φEwj#"f*ClTߌiVa~'d(1p\#<.;8}Ӛ$w)E6w}ź} շ VevUjL!q}x6Ӿ>8Y1oB]+̰/ jHa{mdcʸU2rmn1?u}Lӎa1ݾ_oM:ފf9Ͼ>fޭ'Ox=~TISO<6_%CwjHvK)dyyymumjy#-x,n]r!e&yRyLTؼ՗̣rw -١mgSS-/BR!6(޲52py7n¼BS mFjǵb_RC!P4oBu0oBd¼B F!J&!*0oBȏ~|~)?\^a!P~g W^}[2x2sps&r?_)W~Oq F!O"O<\?o9_+3~s2cu2S]Z(]Ω8Zy#R•Y?r'+2p2kzx<2u2sRy}A2owg-N>Go0oB^O=QGwՃymƨD>e[.gy#B/$gl22u.ekdE7B!N]~?} ukˬWKkwG1oBmzʞwGwS_'s*>GYF!Z_|Q^{ 2kA3kϛd+/9G( y#BmӉ&5 uy2woղ\ղ-NB!:[/o!K^׾Vv:q,|˥Ot˜ldļvcMccE 7M2WֵB_iK6Cy( [dؼy%./ys\.M'~1֛wUɛ$!9-Dw~ҿ{eQseӼ7U$sbʼd̺]{giV~~`ʹ26UOX$mb;{q*k'IRx StBk^{cJWYΞy?Կ~e]N01״BoOHW}1~eJހĸR#λqYZGvN=B=/[2{[eǤ-?t\Rx‹{'%\]A9/3<2>2wT|faOOW1TcЁ~f5>֊W*l'EӔIv'}Ge?>3 2Uoy͋ol#?]?+m|\95Y~ݲe 5_^ɳ>+/B\ya޶O[L1xQb5˼SPh>MixBz?=#C^5<˼.9GΗg&_}+qĊyE~/~-rЛ믋M_YKo3??C hPJL@fwl%r; :BhiwWLZuҿusei[|Ig ^JrS}V]w%O+nwE+]ǣ%Us<ǽky+%E\sV2bp ,y뚐m|cOVؼHh8!P 膬`֒u2kG7i˰S?:v|[ߒ~:Y+c]TdoBun\yCݬZu/\%C^ oy9/M|ùr-7o~0.TM|m?y¼BKSɯ{bY]e׏/wAןe-q>|<}c!zNW~j18w78,`gYt~d;Hq,8=ѝwd4e?{NBTۼk";|}d2sȰ "ZQ (d˖-ߥb!zJg9EzB[VyUUgw}F![w~IwWfM]{PO>kUa_,3%;|ns9GN/y#-=rkfFbط_Zf.@f~lle{ ;,sa? o?mrW͛?kB^x%EF>ΚgQ6;9"_q]2keƲed&;;Cfr-9W;_yg?y#9Z}ciYK s2g {8d@vPfg?8SfKk#ɼ̗ߵπ,|bߡUL}\~ #=;nOĘwV?*.zjӛu&wSY/>+3-Ȭ_.;,/w%+"~<{|Y,x"YxnŲŲ*>v~ZU7,vٟfՎ~OuBufę1Q8Q袵NyX|T:);YGf}\s2jel7]e2k}wyW~2CƢnX8:`7v{Ӭ7{ [5]~OoFn̟ouig*p-e7>Xa[?TQL{V j7?%wSmTY_ҿ˽}Z.jyGϬ2Bd/""E)C;tچevU߂dFzV2:xFn}Uj89>\_|52Αr;ݲvlnڴTpڷՖy[qRm8FDOW2pzl^RSu-2\c  Kv2ke^{~>['ga;9×w]nj.֋Gɂ^Ht)el:/H,HvL_|ӟCvt݆eFrv6EwjzRw>ڲ뻱<;V/jߍQR(MoL}UƗ*N2>P/NcD; /ȡGhȼGFy1sekeC? ,?A^wʱǾEedƾ˜}n77)>U5BK-aG~Jn­\TU],->hccH3t٠Ty?^]k|GnBZ:7'QQWGw&Я|vf8~~Pcx6]:gck]y~Wo]mJe[dξ.|F7|#rGG-wO?].Kdڵ|EĹEie#N=S_ӗG}){wy+E"ZL"]({+ 2,+=1GI׋P/V}Hڍík#;VEUTdL_l# s$o@x{[\֎Rh?%7OQ+]qӪ(<urÏ8M>dttTO|ߏvmr˷m,?|zÃ2pβ J[|t6|o~3Ľk\]gި-ޥO%*ГPӥuəg)'|}}crWM7${6UuW_B.XK/vȼ[(N{9hؽG糖lunKo Mp]c)re!RWҏׯ_/_|_|02?Mu7z ?MYtBC2cM^W7,?xqa!zZ>oWYpҿFI\+NPxyꩧBw=p~!ʌ=ŒuroW7B!gދeѹe#O_-tqmA~j3m۶5'c7B!yG|p,xQ2kp~AY-2{dd}.CV+Β~w/瞋[O7B!|Ǽʢ3^/sNf.2숥7}7ʜ{!{|G)soO[>_.7xlڴIoȏ~#mʸ!jPdst~eɅ^(^zK9'xBO0oBA/m߾]J|;I~D] F!2fcpejwֵ8t)J1;oB$ʘI(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy d`%(7@y#yCG3gژۡ󆎀y4 h{:0RVʤ/C`y C+'e4bĘ7@OyN) S`&crOF qUnDF6ey2dnݍ 7@`&`ӮxC歍ۺ[7emvq0v2Rmַrxʈ=͝:Tln7A#Uf5ۏ}wNeTb=-;k߅L0oj& 7tq0o7@Lw :@>=o P20oy d`%(7@U2MϾqvlSF[7ԆGjȱL|ڮq-[̱{J3u#Ǜǝy}_$[7f8S6ІNavz n!Ֆɳu}҄۩kNq#]S.FQ]6Sz:Py\by1>O֙n;dL.0/rL_lQif[_21 IJI8&ڶbelh;^\M&( ;jV΋7iIf\" Y1T=Oܹʄmt{ۊK/n9_vsBǎĭo/nͣ[:q+ok/3? v^޶k;rE5;Ω1E=y0oziyw;r`%(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy dyy3-{%o7@c`-g݄h ̻ =`yav>103ny4r,>+(}24'=`yINey=w˩pWFƛ6׌}c8M1iCQ.oD7qHtot|}n7@c`-b`w!MIҝ#!kWB>ٶ0o[N$Sm㘱9{2nyh ̻TLRqM癱Ǽz̻TL25cv9eQL;NO>3wc= rFB>5w:2reIZl\9 `-6ny4r|M0o[0 _ wTQN0oc`1-9|z޼z d`%(7@J P20oydxxl52ӝnF׫{b4 O~Ȼ>9VO#1u\KTʪha'fZYhqu؄<27, McbiEinzy}c*4n&zR谵ګcHz|c _^qLL|}D}ڎ=0oIu7_V#ݽcYz>o6:~i4SqC ]eGxjTY/8??^=d՛=L/_\h"T/ߺ*;W}a<9 .kC*}Qj3.Sm7TmOcH7p.n{sL9e9:xߞIzh&P[&6|MnܬyNW~XD}nSi|+iG(7c5qro;mf}yZipcΑ"vжݶto[q{x端mo;Efs3~7;ڎiL5?sᶗ*w] fCדَckT[>TΟ`·(M@ft@/yt&}|= P20oyfYm_:ٯVcsk%I|;FxosĮgS}"}L`~q[ x̻PwG}i0oy d`%(7@J P20oy d`%(7@J P20oy dyy3-{Ѕ`yC󆎁y4 h ̻L2+7@c`ޭb|DM"y4&WE="VHz)`̻2>0tzl̩j@΀y4*26h_ߡPc#ՏۭmevDm$Zm&v^y4蚥OSl Gf>n'wӆؤxrh ̻hc=vMXi;o`yr lk?N)T/9: wx6S瑵mξTzv1>RI~a-]`yۤ{102y h : 7t 1yC;gOϛ7@y d`%(7@JjUռʔF'OVY5} '. U[}y1pϋoSousEc?;~يR/\^n:.8w3ר[ ^,c _^q O'[ͼ>QOl{*]w\ZIѾ)Mn"[W 21ڧ_u|NSf_я㲫8}fTiݐ#oIs7?:?9qumGvo[D><:Ͼ1Ўˎ7cm;;?Λ2Ouq+SmEs(|ޜ>J0C15꼇}܁a2u`n<+5Q"3Ӗ)o+ǗgU>_dzƸesΥ.gܠ`MC]Vg_x}AX cc1.[RD&=VjGշ۷6&,:-[̱{тT+1tSjmTϏw]q1c=2eCQapˤBIeqc)*k}c^^1MP}mh~uBu9\9&O]S\j ̻Y&c}>כprj_]LtkTM'bʅm2v2j`}u rny7=o3un(n8j?՟ioNj&~R%['/^cj _t̻Id5cp$e+cQk]~Nmۤ}2yf-z>i&!ZYetYUqGwẜi}ug%wOlBqtoU~`όQOz~υf1kymk:4n:[p;#Q~"pnL;x֛j 5Sι[`M"uh\<Ţ_C6LYbы#ЖMbvжݶto[q~'ʂw2MzL.mq_v |_d?{rϛ[m4&ݚs{];fL<j'{=m9ָ9s.uL~&qܲ$b3iG;7I;xvt@+^;sK9uiqRe=ZIRcPA46y ùY0N҄ ~#FY0oy d`%(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy d`%(7@J P20oy d`%(y@1oBu2mJ P20oy d`%(7@J P20o;8}_95U|Ƭ(7@۷{Te HFz0w10y2 ] ̻}`a yn7hJPN2k!w10o-7hڱPIȸ\i`k.HlMn5k6ʤU0S0k75M^A6Y#'4̻iL {Dƭ~ݼP|SYTА4ueĺKYi-.:kޑ޳A.pO%6`ݙ_1lu7)ט|v^9/9k&OU$-&>-ΣuEwLm7 Ɇ{ļIo{LٌE0oдݼ#Hgqӟ=H 浐N<"V֏ҭr.\:G-;t7=6w"MM[}+#6Cb,vjꤾ/0Ιw6is;a3w-[bZD;o[qi;i vwYiy2wy2 ] ̻}`a yn7hX(` 0w10yF-ƌ2(cϩ;P7fEJ P20oy d`%(7@J P20oy d`%(y@Y43KʽIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_04.png000066400000000000000000000466631322762156600327100ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsodMHIDATx^ ]Uy⦅索! p ""PlhEj~"Z@!=T6$@ŘC!l=@5遊5%G " < ȥsα1טk͹֜{{˜sטkƖ,YBhּ! j`A2! eyCAPTʼ;H! Pi;V0Va W_팛a[7 @;μѤIܖ8~킓I*֮riUkM KԱ{-5P׮R!mncӱsUE-OfiΝQ4M8OUilNҼqE潊Vo`Lx 4lHU֥ǑUl?ƅ[4j;APs͛{=W[QZ*4o6O>r͙yk{6߼a.Q5dެVi:nk.)s'zsMNp>CwAcpU`~&U!ռلq;޾}{(6ƐYJce ! Ȗyv)'m&!>Jg]r$3Zkē~HpՏWM:0ye.󛱴AP Ř\FXYy;3]WU_wSz2 Sds&`􍽫*̛y\X۾t5~R|yc/ þy!+0*L.fI>1ܹtfҲbŊy;μ9;Lv R;Co*qZ)Cm3PaȌWzN\7k"6/n̙0~ڪV< uF=^@Sy1w&61p6tyBdG8ذSqynLŚf~9q@Jgqx. \WQ6} K^ b̮.CB7gjE={h3p~Df}w3(vAMew?>*/Uys].^]0D7N6bkߞ9Ox]fX4Pм!ƙzcglܜ[1$ͻA\(+3S!:WmxÓf΃߬zTE{)'y󗤫] *!^3lqB&]֯͛y;qq Y; \{z4/8OU6o{TΟy.vZCA)d ƽsg5 } 6!FyKvc⾤AAP 7AA Z&7AL0o j`A2! }G}N?y4vyCAP~xO颯muWJn&?Z/6߳.b=uKry  OD{x>_oy9479sZSN[LKZޑV`AЬ? ge>꿥%mo4;hao|y]I ^}<Ιܒ^`AЬcx0q1j^9c뻌Zi!aA4,=t;qw Yb)  .;4-rmHsobZ7A M7C:lf]Ƽy>0o Y< y]î}~#ωϥ{-9 AAC;޻qjA?, iӓ7 qn!myG^J ^rifyp% &i[֯M&uMZQ) Wqďe4 _i KakhKB \Z>Lk,st6f.ܝFVF A򗿤:M:ȡWҼ-xZti&ڝ#dKolYng1\Nqm8uu]?lZ]]٬L ]Y+ߞaX)v+AAu~{9t#-8f--9}py6L+d=˕̊u;^f轙orʦcrm{Wy'a<APߡG]Ms.bWѼҾo_`UcZc~?y&?r ]7?Uygr7׼432{\\ yeɑk-yr V?:7L:Ȳ47H ߼ޞ֨Wz쮟_z?ʓJ)[i'x~TtANV56iQe nHVyc דO3n.bFZxkŧD߼iٟh77sW}ө?!=ci-j3hXSbi^eX`y0Nvɕ>]PU歍 ^S|?:5HmyG}b-zBDt>;]/Zך̮?y +_ ٳ4U}mnZAٰoN.׶IaztKˇp NvҼ]Flq1 w:ATrݭ?E9^C+UTӢax 4;3zꩴw57WdV3o"Qgopat=6c<u.*[44 nΛbLtS` 4/+2OL~/~gC0o_;o (Vw;}~lz/^L+NnEY3hU[GIGn`AT^8~@:/ђw7ϲ5c n/:>_?N<@w0o hiݍ(həhGg~}ӢyyYN?]wEO> qm[^ -7~'}4+hC]9>O󟿕}Yt7g2 fxqǨyg}ƁC)g.Cs0;C9]f k/ ^B{/=30o hq -yhH1E#L{j 1/bԌ/9vi]* Q{K1ư/9*H [V}3?*ZptoNnG} A,}G?Iy!lMZ/=÷Ѽ#.6 s=wAUE_2?yCA3K?y zkT53'3O;B{GhGzΡ{^:hq{K.۷ f~Yn0FɟswGMvWG4is,5z МߘKsӼ^@ OڟOؿOj A8M]y䱴jcKa9^E]v$=wڋ1zw޴y47O.8?dUijy~b]lWiz~g//,ܕ7ݘhfg}p/si*c֯^H ^?VcRZhib-_KGY͋D3[RTNaL}_H) lL9gだ}\s助eߒ{khژ+>ُy֨<xĬ2;l,E[:9k0A~pel{vbty0P?ɏ Ѽïҍ4Ϸ0J/v }Ѧ-zW@_om%aw/;(jyt^<yjrAҭ=-69iPxCԑEۡ+mSY7-=G\?'wm.3ޢ9rY2\=nlۓ4C's>y7"]~NwҚ=겍4+?HwEz"_NGtg.;zP5ʼLF؋k Z*VHKV?-lOIc0I=&^kv <ܦs_ ΑN\ZmP99f*jo3c8̳{s`G5/enm_.'y\6o?1 A ?{ǏK'5kp@tбܣ_I{i8 e ? /҇>z>}ߧ_WiS;/6f,f QQzZeH\_lN&.\ƍŭ~=Y[d hNJ?ndW꫿EuiR~>Y%ڦZ$FLˆWBV :cI%=}ɘhȼ75|? E阗9dzt|uy!W$֧3khiS3*5!4h!i~>.*/dwl^~ `bޔdF?u&1hM]yXoQ݁vbq|hʻp(> v254&S2<~&G#WL忦2|Vc7_ Ds1/҂#.EG[Iz?WwD:'[V??L}kiJ _|>t1^)W~3'_QXق,R2ɪWI >6hLy2'W>}1BAcTgŞ=ε:j˩z|^9:.(- lk#0R^۝<׎+_īt9'~,=Cp!O󎸒~kc/e3~&֫V '@'x"ow>yGׯo|5gТSٟ=]%?G7;ſq9}t=Tw[~g(ĻE}cfK.^_MŹ|-sHNJ\3həo?-fwQ SULY.6;;6l@z*tgg>+믷ʻ|~._,{gmz)qcZLK[ki!]^Gm&T0wMVb@AD=}qFoo[n1~''6y7zM?MYzbZ/hW&ӕW^I?OҚ z'{w~[3/iCj̙;.3]h ѧ>~ض bG༳ޟ.CKhɟy'.Ql[HkO0o *Pμ8| ܅w?ןK7p"7A(gޖ+/m{~-{hiW@o~'> /X|ɴryCAP.鳊y/{-84 ư _A_p s:a/zwN85׿7;:賟,q#7A'zA7q#ݰ};]ךմؗB/YGb襫^bL_L^{-zA #MI'dOO?/.ڲe m۶oӏ~#kMs6~ AA}hف򓟤:?|(_W쟃ٳIS%7A)}glǎtg?~|u`Aԧؘ?cp6k>bgKyo޼ ŏ! %2ofZh0oeZh0oeZh0oeZh0ۦh||n1y$e󷑦q&+<466fVۆomޛz.\DS3iy21w\\2  eR5ATUWܔE)}RqMKIcs}_<2.~Ɣ+sBqc4-'LE9dz1V9ƺlUꚛ~4O7.EmiEbNY\.syƙ7^0v-3z@1r7C`@Zh0oeZh0oeZh0oeZh0oeZh0oeZh0oeZh2>`0|g5S 3hyzg{_jZ<gMG:66f!{ 0o=D5kkeyP0!I3av @}(\fh{-ZvA2n֭[UXˢSQ͛įZ+Vpe\mYer[ &>HA$Ɠgm&m12SO?o23b--DyU(<䘈0L}&m&\ѫ~۷Ɲ*3BiZ`[N Lm +5ykJreisoMӒN\X֫0#Jm20#~bj{Jj}OmZZLOdĴ^_1FS㦎i%-A͕bynS҆[hX;o6TiEI:dFmywi ԋ9cgY R]٬ L7f򛇴M~X1? Hbr:cRNuPi7/⼍Oݦ4M8S(ݾR165gܲqYJU`؜~_ \;>K*1̛q cٱfR`v"Wѯc~2)HWz^# ^7׷/^4̤lؘV"^c6&hZKV5=lgyseCRU=*OG*-;D;ogȽyD\=P+%(&L_#wq*?^CeXEi^HмMicg7l?SygwF"w(OLqwz>^R~\Ƨԑť}N띚z-j">vns?sw7׃>c3i8,6_ [h睿!hCڽVt;0V;qY}y<~ M"pvZ~Vxmwf>lqݝjZPޡwL;ʼfuvN;?,q{rKm|hgSUJ>6i} 3H:zQmS$1:SZX:WZcമ~63QvN_D_> 7d_Pv̯Y]bB~/XsE[ Il/}cu}1L(vJZ#R wKf SQD{keyWܥ;Iv1Q?$D>>0Y*6aGwݾ5 @ yDUG̻]L9/a{J3׺yK)%y7TœY*͔c @}*6h>|Ski! [3KcȤr,|_¼wCUyZV\V䷿xn.vSkPmILMοLH)%y7TyJ-b-:5;6 xU9Ksq,5ۤr,|_¼wC?C:k~[\ әd+ϲed,fʱ} >` 3U=!BesHBLB&ka6o/iBdzP)%y7Tlμļ}CX2Eb`.|lÔY^8xŇg4SKNY0oPi,iPָWK!9侰f?.x^8jr2IBdzP)%_,7n} H)%yRiZ7uQ㟼T#͔c @}["m*t e U"͔c @}g:;(F)%yDUUu}3"|z`i ߗ0o P@ ̻fʱ} >`-LyKS0bX)%yC#,6i!ZՉ Xc`i ߗ0oͶi7kǺoH3ͦ^4SK7F(iyA&/Kyg9Q7ivL9/a̻%yFykvŏ7c?%y$8H_NYieֻټprey@L9/aH.cߗw(2s!r`-ۭ6AEh7aA7|\LN>c\qz{lcsٞ'ؾ0ar,|_¼74BI2P|Ymp_8srƖ}no/`1e˲ixyi{q]12,͔c @}[ٶ.2ͻR|3m:l͔c @}JpywOXgi ߗ0o(ݼ[ K3XyP0ohZfM-y4SK7nf{"F&bnf[;H^0qk$̻;oَ[#aPcۼ@<f*n|z!{GcyYs筙9i x@mApk$;wC74h [#yܺu+xzGX`CVwރ6ټ1qS>nig[ai2_WP|^{u3"c;Tog⪻4FzyEY=74Śz_ }:qͱ ;b;L3觿uC^lucM^e[o~8K=djTU_b̛xrp1m*Y,{tff- }I b4ocPu[gA@pk$w]~0ohel6o4gw 9i%6y7M~ϸ6$]m.cDejOsre$^yDX$E?b,UT׎4Αg:]17nsL&ξe}0j6ҼU{Gr]HyqjjW b`~Y__&lhPc?wO*Z;26vu,~Bi' 9;_%%piu48׹kWc@3pk$j4oG-batsWW.c-&N,bQvӺźO<>m8ޙ[JW;LZ^_hpW|Q}JZFĘ%˼FOA~{@O4F¼[ټv܋;]H1ƙ=FwyC :챧  ?voAzqmx38Fߏ,W~Ň, +.;?0K隃.?  X ܼ sqrA -bK PԆ֦\sbZ8ޙ{ϧ]Z|Q}|9fI_%?_6l^דvfHwK5[wPq3vts Gr K8}̇E8xm1Emda6W-ޠ8y͵a^,~exeXҰ_P<njYRԯb _Q?z1齮'0o1e޼{a 5RƝG@pk$j`4M0 ;o@}hhnyCQonBLCApk$̻;o-H #i`&2Vn q q[*[Iy@0o1y@0 ;/4Mxe&|욢qڥ2=?>ESX9I8pUw:ڋ PX^fMidy6?c+eN?R Ǜ3(?ϱmnj:XWݡzh/:y[ٺfݾ}{)|c|m0T Z_7ٟPFضcQDcPu[g<`Pc˼nfޮ.?-Lj*}mڕƋӝxbbܤO4e2i\N}I289Ay*es},I;mgcwIm\q.w88o'̗668BSS2\ye~ձH? =fI8_EutMƘ7>͏v=5wKUΛwz)ƼL ckkȼ}d;:|2NBd?irё\gaz =(ߕdxbdz<ܱ߆v,I_\e8WjY^dž11|;ߟP}uϟį+|W$\v~:4\wt<40`LթJvhލiw)̤]4]|Lp<=mvo|A ՟@}JZFԵѯO0_Q?؍:t]ORձ5ogȽwLA(_$"ӊό2q ?ז))eE6Ԇ^{NFQm&AFͫ8/7Lw?|^w.Zr+.;?|0a$ȽfisP`L)ּcUdElZǖ.ݍ[jS+7PE,.'&GYoXⵛ[`cTԆfgAң?Ļy:=vYkE%BW_%GA3v~ an߼7^}SsyD_&Zn]NW!:+CYq96LInlPx/;>~i~9]DS2Blv Yvq&@syD9?=?Qnf>L9a9bмh/ k2OXd9Ks3fIQJ;?|E`ҾK9["6gy&W%6<628,#L/fZ6K3wh:07c^}f.Uqr0o Pҏ`0ohdy@[*m*$?6Ea rGqBARUkyЁyC#St`-U;a T/RV\ yTuT9  rb3ĈM Rձv;lI%7$;Ƽ!氏Rwlvs"f:4 yC9%f1^eެP|{&L_]Jkijy\ڱ$IGq%[*sBnJ41")WN~XێAU-PM[dB}ecێGqfG7X,c\lOU T:ٟPFضcQ c4>nyKT?]Fm=>Mt?=!:1m-N+x@[nsbڅlWcI?i;A>mLMe]hj༝p2_ڼpOďOMˤRQA䋺 w0ohd*ke;?cꌇ6%$0NO(phc{yL\fh>>56cIҏ)apD%Zǯױ!wfLkGS̏Syȑiq}x2fs;;/=j^q`Pv>pp~ kpQ2-_^cU:cΜܸaXIcEӆNm"!/\|&N>6^L j["=#\cI|)i73ga9bǗмhKWS (3kPyTu}|rԏyǠ&f`ԯyØ{nvMnݺ ޯ|KYq =ӁyDl3ļ|Aü`x["6秞~:[y1Ⰿ9~)Ww!} +Sv̛2n9?f[y;CE/f20o9ٳ'[1o6`'gȱ1`07o*wPָY~9߼9 _a-0Λ ,yCA L̻rBsapy@0^aP7429j`nj7o-,wy@048`hF q#ЌTO{&ğ1ZvM8MRbH]Zzϩv, ŷxCi\J=113р)ck1eŖMCFٟPߚAKQ4`Pfy7 ~7PpVZ_ٟPߚAKQ4`Pfy7 2F퇫L Sx}b֑OL #VW&˵ө/i#\fzӶ'4H6;Ol`%itlނ>u׫usƽ'1FFw~ц2x{dfy1nF3P=e͛]q3pR.i[|g2M,pR.0zr&)]G%c0>>56cIҏ3~kX2,[=wQFѐЎ%~zuc3# \3P=7Sq31 .E.ߣ5"?G8O 5eyhüc-h/;>3~欰M/C̙la@{QHAiQc3YkLkF;p4zY&2^~2e36elfr62x躟9+lSsyyP?^T~2^c3YmLkFy퇫_TC2\6<2sfiP v'8HRc3FqN9YoXⵛ3>ca6oJ&-W_S7YǬ74SƼCFd)S.._'})>_Y`jFGLbX6lM&gřppDsI31} 0K˵cq~}^cf,04ӏyM;h@1o#ЌTy8fyٳ7gM\r ]3˼v q;o qH qAc@0oX~ڹs'mݺ.": ^ym5GyD]GyZx鮻o^[l4`k"Fg?yCA|qK~<V&k$>$wX/R{O'y _ _ !ٺIm h0oeZh0oeZ@Oo:7P+0yw ̻z`j]=0oRy=\:W:=L V*5qM>wr7Q yJ;{t-_Ick^> ҙ{uw2k?\!0oRy7ZyW@ V`P+0y6P=\Zh0oeZh0oeZh0oedyf4VyCAlu@y- 72`@ˀy- 72`@ˀy- _2h8_GǸ6ziwpM#,}Hp-6 t5v=  `F9_Τ|dZ8`2g"p#Z th}],{ //h 0r`:0rh``޳y̸Zڡ ъkcD[[gƚwMלvaF1XAMKC^$9_czsV4Ͻ΁ޒV'1k#xcѹUy8G0cf".e>14޼:w ެ竊9,6o9|Vf>0-1y|E,΁ޒV'1k=#:wrj7oc q00_7x]2o3'OH+O.4ޕWsM8gGNI{Η4:?ƲȽ',2]w.NN~h61k#w.|S; 9_0xWqҀẊ3xl1a9+[{3.!-e^mva7YX1rN' HZs,@Zv`Q~`cFOx9O 瞾]ypVfW;4wZyGsw D\C(V/pOk`fygAN~zB;'-YseyӴNjȋk.=.1I5…ז\gZ 2̎=)fy2Ģ^Z5"iri_\Q=Z-@[8qmt{kswMyؐWr&.G::& 4W? =Xa /'ugX/@40HZs9r7v~6wn,~'GjEeymث)t-5mƵ; Q6I|g c|׃a7cXqɵ/._sx?8a57̧\['܏3uTva!9'Ĝ͛<- jޤN^@ryH}cp ȟ"sons_X 5l;j31a7b'05[ 2_[n Q=Xm A^$8_F>ǶU-6ۼG8e3,{ /GwmC[8pmցyCȋ 0k#/̻=X,@^$8_\a|u`2g"p#˙T55ok*,C% 1޸y :4c5 l.0oeZh0oeZh0oeZh0oe7k1u&=IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_05.png000066400000000000000000000432651322762156600327040ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsodFJIDATx^ ]E}綢y#Bx&jmmK;me"z\l.bLMZo PrWPQG7{ڳfͬ9e}^kof:{5|r7B!FC7B!4b¼BB:2/8 KOLL{! ulE&Z0oBhՕy[VԸ'65F!f_=5j]cS}+M_/w)TrnٸKX1IQ91von!!Sži5a,B!3}wLS 7nۖwyoc:[syNf3sSsL!`2PZ[M5;wFdމgYv` c8ص]e4}f6-o 펫Yr IWTIk_Ml!uƭμՈ]g?Y?zfɼ9UcΤmj*ykl7wM[Z8_8~\B*k*jVy=7%M֮]3o}W3oڍne lNch2uFʫB1ro,ʎ礱~vg%U]n:s;B֜.tLmڔ6 \ _:aٜaOm[RjL/*bQ댔ϩ̺qƼetqB q뫻ݩ*>(k }gfP b6kMӷot7 ;p7gIg腶ʻyk^-c_m<7-̻0G!4l u5o XޔSn)u8YVf)é/cbmg.f>n0ms YuBC%ӘIyζt&~5FF}%yB&2s~[U[f3 ;>͔*n*E_XϿ!E5m+ݶw\%5B[QF!p F!FL7B!4b¼BB0oB#~Dz|h&ʢg_#Wogt;2Ͳ7e-LA-vwG¼B^f}?w7䘗,?zYfK2þVܖfr,QI},_D7B!4Wz=rH8.eY|FYe !K]~ʢ#hg݆-`ղ˾'/oǼB9ӝ_2d݉yL},|,eϽ1oBhSO _~,X}g,87ΕO|e٘7B!4gz[o4(?|Y;KdSɲo;SOmOPTur4!P>},Od eiFۼnFn}sK xpyF hKd̬ɺCqςyε'֯썁%tβ6udm_웁xZ$AB췩>#Pˍ_"R3e?WջyǏ[@s`ۓͦaے M]B-FmcP Xshfaͻm_ۙg~yUs߮~kݺV-ǶU[ybs;4b5=ԯ;~"_ :.yٛ >hz491o WxvaFhhٱȏnLCH6o/B!^,_^{*$گb?RoƊOy.m6>#Pwֽߕ_<|$dQVmE Y%{4bXdv|S/N,=FYfk櫷=~y'LK557mfEɬ 1&fQ)3\|g;3B6oWijj>~y_CF]쳗y{] Ճy#fI?K9%he"KD~~RG{J?}^9wF=b[Z~sR~S \'ȷmyG(M͑y;Ud3ٖ/,&o4.5!5,֣y{0o{mLsi!埒EϜI"6?* _Xe|(?{Io }3,[Y>NnjG g>#>JSj;O$;o;)ytߍnD-gh.zҀkQ5qܫy'm?h/=^։r I<4!ԛ~UILtkT۰`fYpǓwd96oL]*_?yڲ4o4*#Bv}[;f'_,dIk>V"GrM˿ۿü?ŸBK^RV9ϖ7>Ao1euN8zYsWzwߘ7Bӕ_0g(Y*+WVȲ#K_;1U[dQs?<7BS{^i {yKwWʾ'My5p 2?;>&y;~2y#;]yU-֙w\VPYo?G|;.\u;zwP7A3E'^,zG?2üB},׾ܥղg˲ߔe>C]!Yxdeށץ2! i׊^'WlZ~yꩧ0oB㧫]׿B9&FMe_D>/fyHnsT!XQ9՟L {'21%Bo˪oE$JYr);vǼB77IyAju]_u=5'^d'>D@Y;?-?0BhCs܎4hf^f؟4]x2舷˂CV>Mv^_5w^o}eΝf-7BғO?=Gb9w<] /m53콏I=2ɂNy)O;hBjBZkg͓y@L.X0~`~y#;M_q[AC;&1GİW&O_\R>dB_g=_]( _,ڰDb?u~\}|~)!M}~"򺀩6ߒ/|d#&ub/^,{l_Y򪥲@ȲӛfOeׄb!\{{{ke᚛1[cqvOy^//|k夓^!e'd޳;`0 YN>77a!V+6q><)l,8~Bz,=29d"/~;{5y]^{,z"Yr乗ƼBLW"/~df׿^g~s[nE/=#,O<|pdŻWs_,\7%˻裏^7B'7oO?]7˙g){Cp rmSY~#~lϞ=&GnFxob\&+2Ζ*'RSޛWa!Z?O-[k뿖+1{__#6u6[|)+^&ם'V4gJnFy F!4z䡇_3/~a^cԼsO8KJ̻ʲg_)}p|[2u"!XK Zuf7?1w.|,8sQl~K_?Ow'!*Qμ^)~,: O޿dǎfߋ0oBD96^tI= rԺeB\7¼Bdk^۱y[Yu޽*F!JT0w KO{,\s}Ф$7ry#5t.!*Qh#e]#'E:)noy#B%*~RVR}[dށԲIgOɂ5ɂd{a[9}\ῒݻww1!*QѼ޵,} `f9<3k*,&Yt-ͲȪMs֟!/zyի~_>[>i- F!Jt>0em/G}L9157Ȣg,{y?mrs&Ȇ /WR7g!GL7¼B= ~?}IncN9M&3Oʪoy> F!~yJw!_׳{] F!)Mլu3v{۶m0t^aB m`F `F `F `n.- kZ&'e} 'zYB~=ܼwLF9N=7ּBWaamҘ]n 7B_¼ڼwMO.iLW2oݞHf膆̸i;yr,=74t.1*kl%/]UHӴ<6Ӷ>y#%;L[-5Ft۾lFY4ؘI5ih$3x'Iʵ5k6͓/ULҖ̓]F 005o،)fW\j3fcn43̷IϏ~(ݴiL'gB[BN1KQF 3q$h,̌rny?/'3cϠC1oPyyٲb F4RI廦Nf%|Z6|M][3{-yG'CVaa0o$$l|jj~ZOcqO}C.͝zm>[&kӼα~5ߌ#HO%x7NkވeiYݚ?KޜmjO+?#ڐ;}Υ'8ٛG 4¼`mH]ڤJ陹&F],ofG˥yvyL/529tjGl5KL.Asm,9NMՃ$m2f)ے(:f[l*یAhLyy~yOom\T$=wMԕ-oo,jvdF،=1n3tƵbVn&헳eBپ} 4Gw{ls01n#?oPP5,Ut]/d;qZYxs/j̸'1&oL@\B\}̺P<׬7ghlO҂'B 9*1C2\crؗ[>4o9ھ)Ht=md֮fsƶUHo|{Z}Ոi@hydžP?kƀpJ\CmYjn+Mw*j٥yL}XFa_ύNmYh) _ۑ)ȕ~jY|ɋ y ~PF4Dw7&ws3r\wwB[`# 0b`# 0b`# 0b`# 0b`# 0b`޳ͮi]cJAD.cRԘɥ4N k.̻7Hy09ِLJӌYM(a+t]tbӻ̾κӎayeXnȌ-KOg}7=WaW҆\,ðK'mf[sqvYutڒϟY}Gy7# 55kxizb3ͼ{>=3ʬ\,='tIi1hB+Uf}_~;uJwd>綦e +giknz,IٮF4 u5N[b}y׈N̻`j1#y׈;6aoF铍Fߘ`қˌ<]l<Co87=wG0yw̻F`]#0ovڎ e݉0oy׈6{þjя~v.`kD/ ' ;v(w&+I'_G[03\!ݚ53 D<γ]\Ja>$rwiNjBkDyrUȸUN A>c˝˷&k7Fgra)YzoBuVٙnfp6f:cyl)㷡b|߫,yW/7y/v ڜKLh}1m ̻F5q:yg~:XϯMso>j ]#w;K1dmI5#M7sy ͛o-u:ܷL6[L^A'3-#e3{k3F`5bFle#plɭ̻Fw(ќέWZ8eqW 0`5`k 0`50yw̻F`]#0ow;Bq`nkDyw"``5bۿutPr~ai }; {PE'tykޤ0lXc? pF=J?bq5ݚ5nЂycB'fa6a%8{>xO Gt17wƼ}VU2tviZ3;g&o(=~@٧Ms"mckYi9I66+K)F ]`}%1L햯sMk}~?̾{zCkDyrUȸUA7c˜hMl 1cStKg@FQ0o=ޱ\ݡӮnGښΉ#zyf~m$FLX}~wYmyv}y׈2VsV3nU'3,Ou~gn \|17^5-癌s hX'rNz>DY}toir.fl]^]#[x̸U=,7C/Y.my ]/9V_~֏k{P30Qż`j9&oзy'մ4]1lYw`&X#3ofx~}gAH|XZy,b m>/Ff6FQkCNqXV.F`5bl"plhͼ Uy׈2P3ҹ5C "Bm>`LkD/68y` <cXZ{q #>uŬZW?4 O01aw?;.|i籢v0h>3Mw۴}\f>^ٲ4e€av4N涓'[Q3,ӆ{HǮKG'bWlsmgzo]1n:mo\z7*j} y׈A]l} YU[@a¤g:Zq3w߯/wbyknc(7dǽmi{:x=g^;ZKݱU{Bn6mr>t?]_+ŏ)ݷi٘a;^\vR-vΣ{rʄ秛}ǘ5kp01N3l0c6LKr܏C1ql(o(˄ڐ(gQnVWg;m3x}O(wPȠ*驪PenӖe9?غvEA`5bP[?֟U+̻ "K!be-)w󻳙vqF-~Ghk}4ow?㴩 oW(-?H1q;̻o`5bP[=޳gOjaqWa;P .4]:Tlya]l ْ__!+˛tmLlhŴ{"9/o_뵯Վ }W7'^-eץrX<^pεWoV6Y%~+|nJh;D]Z?T]twyk>lkΙ~sаKu3']3Fx*ԓ.MuvmgqӾvnpʭI/.ď]sʧm_m,Frc_ 䍝|PSGai= k /9ͽÚ~_NaMn; 3pY CzB7ׇW01 [3mR~\_xoswtHsҜeumCh{!RբdecV*ƆJ`5`k 0`50yw̻F`]#0op/?x;o}zT1k?Úky׈A^ .@.Ҷ6|cԼkԜx'A1c2, e8˻a5bP[O=ԦE>^:lo K6O%r<>Kt1d@֟kKTo}е7s%5IX_mS,]#u;<پ}1/| v5< fwMyۘ`/A?ߏۯ-@u7ني5lm[{:]#u7l`>VL;dޚҧJ>*줆ؚwlHCV#7sϟĝ|VعNOV])&[W_yOis[+!7Q]iߖvױwwu:گ*kĠ..ƭhJĦn \e3n5B{;n[onb6S)k ֛s담ϖ qMvmwmwyܸkĨμ3;}K?Q 3?tJՙ+w:bT#3T ۡ[W,Ǡ} Ǐč-'Pw(b${h!I =KfCiUʆ~(=s4=X,vՍi蠿n7E؝0e+\7 wϰ`o=hޟq'gǶc+~zm3RG%nZX\/UX(Gb4Me|54o'7ec퇶Cq4c?)_1n =w{1F׾V=Xj[k>t?H,1ǚ2?Zt_%ld$hd鲞RGl޿̻F bS;=kZ;t]#y/K\#zg4^GyVd[ng]ީ F̻F bt4_a ]tWcO Rm n8B鶍}P z^zqն. ]#u;<پ}{j||2|{|A~M1[?)n֞ΟN ]#u7l`>"}ʘ>-߈ 3xg^xd(iH?}&4:icseAPV4_1xźr.<ʳ՗`#}3sqk#ƴLV_>/M2 )7|.kGK۞u .w^vmj_bogf:0:7HY똷xʓߊ7 3!VQ߶ۡ<͊=n6NX qZm0g?ö179.fϋo؂y׈Qyg蠔 ZfgMA-~b);|s1*WZPy{ܭ+cоq`FׯyCBhK,ot7v'1L6m Xy׈A]l [VE;O:3 PKMs̬Jbic%J񂔘xYowL@CB~h;G:9~ Sy3woٓZtXz\6tljCqY2lY~ јeJ- f#Qۥ[6+!Mu#ˉ/{,;6]Ӫ#=n;kֶL+gw?x^q{k /E]d~wޚ/`k ӛd  A X3ڑ6=7[w҃u,i{/?ŶZW=?[jS.~sq"kcZ{e\]>.yhCCo`k /9ͽÚ~_NQZ6 `lk0\l]ϴKir}{7g88 (`,kD/68y`Ґ fc:]ӴxPG01kL5d;{pQhMϙgYz數њ4>wI2uc>F{7?~S+uejje4tRR3fsݺtl,A8䝥)fm ri>}6v=X6|6SּA(;'(w(3o5g5ik1w;KwSS*_ ͦe c'IJu uzuWdtR e武x̸{6ocTm. ]#w mf.x~kNiwcزx>N1RknϮOUuWW|k}VwaSίO) qyB!$PބBH` !ByB!ꪫQ󛚚[BT]MMWHVmEUByB!^.nEwӲB{SބBHO孋 Ѽ m5},٦ovctGsl%%cmKd9^fےَ͆n}?KK~rrl$֭[+hQؼR2JVcY3y=[fG-xn/7yֺ| >c9GE;E}A߼L?wB)J[{ܷyMny2>b/WK6eJt[Z]5^)画Z{u qs;!K%We~%V8[.n]ޛ6m򪨼b^Y>w\uW%0 (^~8YfI-6 ӲۇrU̫$}Eqwq?UEhOwx}evb,YǹB"\1^y"elw?^ljsBqNcGŘ)iUvl6ѷ_B(akq<}żyѸz?/e !TRtQ.*noy|E.v;6cƌLy[TWMH\Ƌğ]*jRmzWqILX>=.I̷63m/~C긨( s !kǾW/!SNEb~yjZV?*WnRW5.ZЎmJy@.y)oBTTޚ*[ ? \h !d-ou/UCjBuM! M!ʛB ,7!X(oB!$PބBHy]g~'^|#ZPބBHN~RnYiQ:ڵR9c,ZLn rÃ7fljʛBl5~ȁ'.\ m{,C'.],ͻ[/Y:NGF/6=9 !Qo~x=!gLZ]aq=Qa/nhp7.S[}8 !ywsDE]Uw};*e%E{JeYc)oB!^yw7G]zukD>.#玡 !zfэߓ*ꎭI7JeĜ<&B-Z&̼?Օriy 08}oʛB;r1e*LX+w ;zg}n9&Bꖓ\'-:Kګ+*)IG:7M!! i]>]+u~mq.M!-'#N',-*7!Rrqߍ%mҺvuzg(oB!NƒVͻi7)#0B:{y?ߐw՟~s&BGJwJM]Zg--$?>!?,GyגPބB_>qJګG ?axt=N6lS2;ontur ˬcQoI+ k>qߟ_]~dB(oB!o)uB^QZyV}aGwma2b!Oϟ랒}?]1'YyUoZξɯky嗓Q !+ #m{OB]˥uoK!2?˵7=)7|ѲˣzP*,Oo.P4 M!XﻏHS7𙟐QG-~[2K-Z(*ފxtL[" yꩧ䭷J&B E%Th\Z&}\U<.ȣ>*Jg7!AǞ\nٴj}rKeƱvk*hdϗ5/ɽ ! \kUq2梱2'EW+e.v_#m](K_L{6Yc7kqL&"7Im㉾}^ۮձPcӫK_-Y1I8˸e^F}z:i _kiszee˖WPBMO5UQz~v[.#=^8~rޔ])<}(t9^<*z܂lQ'ǟoBj\Z,jue=t^SƜ?Y:?w؅dXtuu4]# s,#}ny饗WNOp՜}O~Hd_VGv'+IE_* dnn:-B-Zϻ/yn^}J_}(bsʼnm{?{Sc^(]x;R8޳ T.΋FȘGɘ󜽥q<1zivL&ͻN U گ1Kn{NywZX;yPceOZ]:)1 sr5 +?q_NE^i1m7k1-o?H+yJ47yA2d_][a =*lm R񯚩~|埿.[n\j;<1͓sғ]f )(p`}'8ޞHʗ4E^lm+ݯ k]cx˕9N*㡗(qU%=Qrxd^!nM:6-*qwFW֫ywG16$=Ҷ>mLzyrιƍk wݟ4 ZzKX~Sv{J$/w#ukN _N^,C'^,mSϕɳdq;N!+CG"<r7ʦM?Rb\'w5-=i듺o=ǶuJ '43X21˫dnvuKfIyFIam'ޏ2o?ryWt$;SrQ\>s\aw ׽!λ6FE]Z W?26viJiir4O&;odȤ{5KZef~];Rǿ]O\t}4'X[qm/d铲ZΉ5'tLI8%XJNɼ}+LqWccq*g(.8}wGNs,\N𶴳PeQa[M稰g]Sd牝2D&y. 3Zavp~H2 q8W1*XT/!B'6ܴJWz]S+ud蔙ӸFe ]YO/Cd-:;*ÆK1#eOEeN1qn1ot7N~K&[˕ e*福JHeWʮ4[(:Z.y^GȐMѕuTև˰#FFɈvE={7}X8P֝_\&ԎRބBv箒Ij׷\Z|9cruW5+Y'?p\-h˫(ByBY}]Z]+emHi|K7晸Zt,FyY57!A'Gm^_RSu-*\@FM_)\v~L=TNLtv~\pOțo]ByByJW+UZ"C')ʘɴ$:IЧc}iG45^M][=mxn{%sN4-7!A+=h'ΛRZ&>f5Z0}L>ѣcO}S^."9GJam2eWKVA[%q~ǝ?!&2hߞɷIˤe^wߔ},f^(9裏N8A>ʙg)_|\uUl2(_1_F>FF1Rv=:GW[--Z">lMMyByv'7ɉ'M= 9Oe}I'ܹs~W~tݺuC/~ o~#o\zsIt^8BFtNʷΗEW%~M~k]CyBQSOϖSO=U9믗k<*~饗K,{w1nZw4* :da.սu2qkmMPބBu?oXBVZ%wJ)~Mu5{;{M3Cg}Yǭu=g-nM^xdއ&2ˋ/(=W_Iy+*:OZ󉫤c/x} M!dPGz \]Y'od#eqqWNZ~ӟ+޻PބBHN2=tXV+c?xeƍ_ByB!9ɔwl<{褵2}UrUOބ&BrRRJǧ>]uy7w-QW%]߻/*&BrRRQ-8KګkM]/vlٲE^~d Շ&Br7Mv=fi޽zL\#|r{)J !~{?NFq4kS꟟Hˤ}:er7%۶mQބBHNJ;rH飤~w.m{=WK eCN\y`}7TʛB(sև}-<~yTؑIkmdشdgɄΒ>E9#c?^N>d7otMO@7 !*'6ɑ]a)]..̘}8TfKw-/e7o<':/7!˨bV)M Z}^+rI˻4(6•7!HJ[O 07 @`(oCyP 07 @`(oCyP 07 @`(oCyP 07 @`(oCyP 07 [(3g.\Jozj/t\Rudq858+MMMp'QlN^tj~:\YZ&O%/rYjv]2,k^kuyT}~WL-{{h}wenLYkUCc gF'lݮՉ//j-[}anw meY5Fk~vcso.h0|_PjѸYh̋c'/[z5S8'̅erV:FE9^<8senq2GI>sQyVvkyyOHOξm8ϪueU}>+վ>z8~:6ijߢ򭗙Pٟt c}pUkϗDk?m>9lWO13kd~FC?IO'Lq/CWO6}2L/hkrB,oeպ}L͎Y?xϝ!mNOcSˤ{_12ž^<\|vKm؟^.eeutxl3Z&hl;LW|}5ݷkZkrxus풷g:|svq{ f=^IYO/~ B.MeVcMyqxLcty1bq˛.~QBɹlr[oמ7k;>zCdHw]!Xciz1Z\2ki/nkoߺ&߲%X}nNN@~|Pc._קG%O{)u֏FzzN2F<55Wַ˽tL5Jn5yne4׺z9{d\Xv; U//C? mx{vzc0t]E{~'12ckIay\NLv"5=Eo}ۜBo}ٱ-(sq2q,ּ=w}Pt1XӋ>T?/ t9E̍zF>S>)sۚk8^eQmy8qs7j[艑2_ yB2?<2OI՜.5P'==MV'$s %d/5OoM3탽w=jdyU};^8%Un#ag:1-]'bΏ{Sj}Ekʌy%6 n^5N61tg}WLǷ=|/Eoy8Tq%õ빫urk+$.,J\WzsYrxupM7oolۜ7ܷw]ϱqmS/tk;k,{2eⱬ?\3WMycζۼm*YEdW'!sLk94=U cS[ƾzr1P2Qf\3*n/n78[y7WܾzBͫnWw1baL+xz|{;m;K1;/uWyj{e7l/Y>o㕲0y}Xcan7-9v޶ a]rzy<> '-VYi$, IS܎y;3^ĵdْnr՗7o'lfׄ 4NT~v-Cy 4NT~WM ƵEy 4NT~w9}/ʻ(oAqڼ@fX ]_ޛ$ǒe\X_G?f(oAD5I szyQމlyǵǚW wɼRI7';ag%Cy{5yD_`ޮ9^ $( YY#s9 Q|c.*sSXn⴦dG=mF4?LdA4] f@RRc6t|:-; Ru)od-޴7Œyk]T?_+~>u2]B#jh9ʻ6*~@Rk@Mڈ|PU6O"I%9I;կ,X㶾R|_ܵ~5O/c/rc}Qy%Zk@}m׉kQW IǸ /w} ׍o8E}{ݦJ_QoZ'{휷ͣ۾3l.Gs$"ئvy$w#3vʵBy{`7{ܞǨhu)/}K/XOғ:d~`-9Yգccq'iz}}մcKyL";H׀ύqҶyT7 Qޡjx}P{ʏ.ǵEy 4NT~w9}/ʻ(oApqc}QEy VSq0}kz1O'Waqr=P:f @`(oCyP 07 @`(oCyP 0iyPtsP~IENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_05_nsclient_07.png000066400000000000000000000776251322762156600327150ustar00rootroot00000000000000PNG  IHDR"yRssRGBgAMA a pHYsod*IDATx^ݯmy?儃GpzgjbQRnʢR 9hrX)l‡Hpev V6‘ǎc'( ^}νYssq]Os繟1Ɯ\kooƫ{RJ)RJ= ;#/Y)O|J)RQjuRJ)u{iDC݇G)RJ^PQJ)RFD=}xRJ)QjuRJ)u{iDC݇G)RJ^PQJ)RAFCЭ9(RJ # W|h9{~O[RJ)UlDNň#zݼ2WQGLWs4"J)v>sums>!r}6]_雾i<CA5~87uh<~5#!҈(R{ЮjVFgFfu1fb4+5 CG435!"RJ)c2YC6"]L@)'5phBɯfzΣIe.̣kiDW5ǘ}xFD)ڎvUĬj<˄3"lޫF$"Ulg9.1?չ\#b@1!"RJ)_ʫYS1 >L:9#1!nO,֍>mf%#BG USs:yWmֈ ڱi6mma ĒQ5" _ńZ؛}xC)ڎKvUĬ^q{Nֈ86٨Z2"N#r1f"RJ)ʫYC/3rFah>ԳѯFT٧͒Aw`#odFiDp֌tCQJ)#]y>13ra3h53"1 1"9}OۙɈvӑRJ)TWԵ]Sif4bF #f6R}xFD)RMdDڪ!҈(RJ)R{(RJK#>+:M}K_7|fW^c(j}uuuJ#XA]ݱ҈/51!߰X1#=#œ0 9瘲5݋C OPgDυzb6#&/~>|Đ$6mXR)f"1vxmk?Vlh lnRk4%ۏ:¾>1q-Z%ݹ49E3R"z"vm3oToC%aJhG^)z<ۯYY2-}܇a P׻ԚF$: YsybN̍071e>FtFRMHtf7p}2}&mn2,CI;#_}s Y~E¸s%}Iw|\Ot[w{]ZW vֈЖ>ÈA$'59JxVfBsyc.̋y"3?bZtgFMHtJf$oZ}W?mu|d#_~/Ww0K>F!sIjr.MlDoC6lя؏1%0GCK{,ʈɤG܇шpq:e#Hs|uv&ab>[ ȷ첉Ml~JŢ9Llf&d>ůf mKFdk&$:3mzcD =Zt&dN}~퉍M|SR9<1(W撸sƭFbIy-K NScfzLk}יھ^G~fsIJ߻ĥW)ǼrGccuc"cynsĆΈ36c9m2Py9IQ'S9ČQH(22􅈫ysNw!T{|ٴ򙭪HzЖ>4"䨻T7]v/pɄcI m[ٳd kcGR8O]5"q״yH r^U]Qss^.7miu1)΋!sm= uuLsKN=6"=o>l!6k~x9gMZE=7^U%c]WjveDQܱoB݂]YHױ>QG vs)K]ݰ|73F#BQNjkM=s>yx Hyc$^Yƾ)MgP"nMr=l̫^k]6wo!8Cߵ*Cm_<:#9ǔ~ -G=Nň 66F+bw5Y?9zSǎI۬1!+֡|#9BlFFdx6w}nz5MH~M6D8&R>]7l{i>cf&൶]69viu:̈d9c2F4_p:E#fzT@yn=Dk}?8>s޷xb`of!6zĈ >[0#|(ODlnm>M:ݥ?\vwLH7#77cDT#6ֵ.Έ'&HMaOڞSxZ2׸qα}#HΔg3uijY5S Ҝ|h_F6Q5Ukـ#skDc_ihzD< Ωx_#r]z"DSFmNk}UY ~QLm'ꈩ}xɺ3#.݌ Aqއ}biӾMΆ|&6&DKW4^~W~x#"6qʉ5ȹCzLۊb^geUsS%NT3r&$!a三Yۄ&O1_SWx?G@qP4QQQW҈[O/;!4"{ d_3+ Mʺ-j)b+{ʺs#.͌ !!aU1 v}kɛ*޴yC&FSvJoH»p*:Ma>^D=kpWnC["@c_a/gaxe?FcʨQ}i7#fsҹsIX)+ی}O)n# c⭘NjDZIX)VԻ҈UdVJ)U*4"jRJmUJ+RJ)RQJ)RJ=4"J)RJFD)RJ)҈(RJ)\RJ)ԃK#RJ)zpiDRJ)R.RJ)Rڈ|PJ)RJk#oͿQ?PwmJ)uz'u[)~FDmQݵ)ԥ@QwR:1FDmQݵ)ԥ@QwR:1FDmQݵ)ԥ@QwR:1FDmQݵ)ԥ@QwR:|`N#v6ڔRmݨJ^ш Y2#S?GuצRnFVJ&c4шM96tuhu7RW57λ2کԟkSJKWVw~+zU4"jnSM).]Zݍՙ4"jnSM).]Zݍՙ4"jnSM).]Zݍՙ4"jnSM).]z}?W?'z^՟sn'.IЇ}?~][EYm_oļ}{Ww~wSݦ]RJ] >{{u|ݽGu_ЕmMo|sk՛^Y>q_ufc3"蓟uՈ$ԘQ}2UbDW??pcC!(϶>4QOF#Ynz5p}kWk}n\ujTsW:]@CHE|B?;uls L3ɋ|ܓ(FQ?_&Lw}w9w{CtWuG;KUltqF7&ĥ #ei_ZI7c S"sH}mfЉc6Bݦ~K2"5tϧ{ .mgW0JqZfgF4"o[?ȹɻh|Q՝GQ_5_Cs)}TE`?͛iiz ML7={uǵ?;敘~QWݵ͔g烸\Rqq)LL =c佊6 e]#Buq|כ:_/峀}/e>".s׎jmmyM,9%P0qԏjmufc3"͕*+o֜S:}:ո7RV`0jݾ63UP!pL\1''r1O15'.[s5EU1:1ETpuELd><Tr&A'v'o""CpnS?SLDW@)L`*jy1+(>mH"ϔ1ZO|ާUuUݳ7msC̭ΣjyJyr-ݽcɘsT^M{l}Hڌߞo.bD1rqVQϜ8N_Ɵ_ז.vI^R}oYQy=;vQ",Y~~l+՜XsG>7Pp^M՘rݵURḶM56iW9Ԉ, C=Oy3Swg=^X?s[jZ) w6.g<+͝k|mZ^?ߵ#πU1NW/bMufc6"(MEYۏo*I+gi<Ab\Cv43"$d3"Y^9x_u6So<3L"KL=Ĥ> 2briS;eyІ9c=tbNQr/K|5G<ǔi}5R6bsKu\9k;}-u?m/>TO{keĘ96Оlk}ה tшTa>0h4"iW7ൖMm?3"-jVix e(&'0#1!3>cU|X0M]i<ԉ Ct:k_x3K%=ԽcṈCxCQ_1WmJ/pJcZjML1Ke$e7Gk7oMT8RƳLY}}8~}g3T·k )㕘>5g씡ܗRCĵRu,\ {UMb8(>]ߣn݉o?ubCF#FsdD8η1hɈ8RbbVPu&&1~|wesLSߍl1|9'e]%R8gO#ϧK7j龝:1Dy]X78oΈ6c\ a=Fk,rd!8CM96u:S@05}5#>.8uso?}(:ݙ.ƈmQݵu5&$OT~S>7[(߰~ňWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6f҈M96tuhu7RWg6fzmDMRJ)N_Zݍՙ^ҙ4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә.ƈ|k__ūٟ'>NX<#L?kkLcDX~u*_>O^}.s"/| gkkj}/~q>wNљ.ƈ[Q΃|+g&~Dj~_իOullt1F_ gv~7Lw-?""33iDd5|f ύ ߊ.٘I#"3;O4"FDDdtfc&<шmә4">D#"KhDDDMg6f҈jΓC?G껿>ڽeo+{H#l3mә4">P#rf>Fd?cvFDG#""m:1FDVgv܅G>SQIQV<k ~cq.X4"""[33iDd5|fɡF$ Yf>~ 1@nO'i1K}ƴ@?I,9?uLp[G#""m:1F/~WO>ݽ<9Ԉ\Tn2"Q^E A!mH|8!uu[E#""m:1Fɓ=W??}]"䡌H Aef-cƈFDDdtfc&5| y˗5<~x={j׾Ux⍘n,]2nXΓ0"zT#_Z2?R͌H~OO1ҼFDDdtfc&;`BaxuɻPƯw|)4"rܗj 8G/mk>Ġ$ֹsvoHR]шll̴y#¯a囐 ΨX`6f&iqrbDd[hDDDMg6fڼ*Z23PiD y%4"""ۦ33mڈפ:v&L\#шmә4"Q;CHoX{?<>?].6-FDЈll̴i#߇,}fR~Sb4"wCkt hwF]mЈȩ6٘iF 桛GGLjf1nsa #==_Q;j$nFDNȶL7"M]6攲|*H.4"1|qyv28%#6o՗3_\Lk>~O5"3Ru&҈{̳_o7nD>O^}+_׾N[??Nљ4"mD[ew|ӯg1,W&3*W?h9gWc8[\/ Η闱@S6aӉRg?CDDIg6fڤt0&<ےF?6,6İ ~d?Ì#šΈޫ191I~l7j}]EDDdtfc&xh#&=KU- j %w q\&J5#c@Ƥ,oPk˷ ̹'7=uT:1FDV㡍d31w6c~cF(Uj$Fj.,q!sbPZ%"""2ҙ4"kzV~OǺ=$~e)cJԺkL5+f +DDDD33iDd50" - ^|JjddTb!c3^qEDDDftfc&F~=k,s}U%QYs݇MWDDDDF:1FDVc-#wײk#RߗI١F臿Iu>EDDd[tfc&ZFײkqoC5#K&soDFPŬWDDD.l̴i#O7}< gQO9Zt2柴FbddTb v>'E""""l̴Y#2&edQL=x6Qy5Hdײk|_Y2Le|3D5Qa|FDDD33iDޡ13"#=kYKyoPΦ雅հޗɷ(bk}L=cd:̬tfcȆ.J5"@ 1$qiD`n#Ծn1#lKa:O}}A5aX2YLާ91jRΜ%0^GL5"lزAO+l dDcm#o,fp֞?&~I.kD+h6rutf]DDDҙ6kDx ccdDټIŇ,mvM}%6ykDcWCœx曐u,!"""RL5"lSl&mɈt90"""""0tfcH䧿O};#BL mkFDDDDrL6".>3ˡ33iDd5|f""""Cg6f҈jDDDD.l̤𙉈\٘I#"3:1FDVg&"""r9tfc&LDDDrLY Й4">3ˡ33iDd5|f""""Cg6f҈jDDDD.l̤𙉈\٘I#"3:1z+_:_WwLDDDD.lt1Fsէ>__.S7~7>O_}.s33]׾3#_Q+&g&""""Ag6f#""""""љ4""""""r4٘bW??::xVjЙ.ƈ}'?ɫ%""""rtfc1"گ]ɩY}գG˗/k{?ɓ'cKӧ_xbWoX={v]"[33]W~X뙍FsĘ5"""rid"d tfc&ƩhIGPϩqIĈ  1*Ո~8ˤ33iDd5N$Q F$qcȹR=[b kDx8L:1FDVcM#B"ZdDbd4"""r)5,>оF$+Cg6f҈j7"Kr&Tlq[9OL]+1F$rtfc&Ʃ$ɒQFDDD.|X`\8ɈVgݤљ4"fD$@O(OՈ%uº5cGQMLb qrtfc&LDDDrLY Й4">3ˡ33m҈{W C#""""r9tfcLE5+#GZ#{4"""""Cg6f=H*}P4"=ˡ33m҈1"su"SՈ`fbp1>)hRh8q~?:1߈졛j*#s#Bj0iÐ:&B= Ѩe 4"""""Cg6fڬi#^J63#@9Ĉ$v$cs!v4>=ssM_՘ЬFDDDDrL~#F}1"1 R_̈?81%krFիWJ)RL4"wh8L@wFc侍Hv-4"J)R33,ĈdLtbD:SSH90""""r?tfcf%H@51"@j 2zC:1߈}c<wLFj?|Ɉ3^ÚhDDDDD.l̴I#U0;հLDDDrL !kY3:1FdWѺ_ZЙ4">3ˡ33iDd5|f""""Cg6f҈jDDDD.l̤8gl4gZDDNeMrt{pӿߣ Kg6f҈j3K2*Yj:4""" y\|OyOY.٘I#"3#(nM4J5eIlOy*ul쉫}TSP)CƂ r2NZoD !,b7'""@N&G'R!nimmЙ6oDƟPRu6V|HyM>K  kαn1fd#%ees[p^C{h1Ҷ 2uN?>?̕vzaz*u|~B]z3y|++Oݸ6vL6"*%b+nfж dnuAj=eݘgcЬaD꽪" >gjB&.Ə] r柹:JC|z*un5JRN}giǽDr:tkll̴Y#M P^7 |p+!f<;ـj`n/̇cXX:TaDB<'qi}[?>#yo%6M\ 2KSu{HΌx""򰌹UYe[tfcM#f*䃔U6U| dSK|ǶM_/bGG昱oWϴ{H0"܃$\{ڠW6}^g?92ޫ1a#}9yױBLƬ}:~+q'""yj֢}ru]'d{tfc&;lFe#U7MVr&~Pu^{2.1οכPLB}y~1[xo=1!e(p<3cQЎ~5Qx3>㉈Sח(kL2Ts5#ԧll̤yW7T>`CTaZbkq@Y6lc|Bdӛ8vyH2"KpC\)ә4"#R71W@nhcxܷIX=4ˡ33iD[C7{4"""""Cg6f҈jDDDD.l̤𙉈\٘I#"3:1FDVg&"""r9tfc&LDDDrLY|f^RJ)REMg6f҈jDDDD.l̤𙉈\٘I#"3:1FDVg&"""r9tfc&LDDDrLcDz뭫|+gr|_=3 :1}sWԧ~DN߸?}~DDDDDΝlt1Fk_ΌSv~GxF\٘bGg6f҈ȣGǏw^xq}v0ϯDDX={Qx벥ܟ=}TFg6f#¯|W@<#~5 vM[Eɓ'cnhDDD v5oZb~&٘b&_:xF5?!Q1) }gzL\JM=t=:>L?9C]jq9%&u.""r$o5JӲ=:1~G΋5Y$pQ615f ĥ>=P7啺q%6?s uH架>#1js[Z+ۣ33iDd5|f" i&[ʈc $j|\<}y.)#]O΋%#εq*|fDg\ 5wkԼ-ۥ33iDd5xfl\cƤIbɖ\d $ħ/1"v5sI<}PƄqM\T]^J]j[3zK9)Ͻ\;}u%9Y33iDd5zf$Q*ɴn!AN\ll1Gw[7, ̣Ƅq]ta,CS$&Z_ 2&}L#""r7%s2skGd~&٘I#"qjόDz*,S33iDd5NЈȹљ4">3ˡ33iDd5|f""""Cg6f҈jDDDD.l̤𙉈\٘I#"3:1Ӧ?=_o_GEUd>1GCiDDDDD.l̴i#wgFwZǡ!Fj>y~4+AhDDDDD.l̴Y#ʷ!3/~ 37"Z>|Q][2dp!fff Й6kDf&#ʒjD:ZG t$x ܧyRJ)*o:1fȷ|˷L-+Y70䧮ٷ1"3ݷ3#By7SoDDDDD.l̴I#/~qIW~w8Ԉ0D8`DRdV@#"""""Jg6fڤas>cT;3"1ՈThKyLEö?4ˡ33iDukYCHbɈ@5oD)LGo;BRC:1F߈xqOLF@KH?C,`g5ш\٘iF>_YjՈ&lF$ FgɰTb<"WB#""""r9tfcM9 |f""""Cg6f҈jDDDD.l̤𙉈\٘I#"qό2o4C#}O""r7S;Ҕ-#<|:1FDVl+,ꑥEDa ד˳Z+c^gHll̤X뙑 IdSHEK}γ5eIlOy*ul}ɯ2RXpAQƩPr^}Q–X^y3e g}s=ʘ1g tfc&Ϭ&us$dom3&AYbh16c<91~@.}S9,]OB݇:6=[GXoKqmЙ4"k>l8wLGkq53!@6ԟ鮧RF$13PDDrorrGY;j>\&٘iF$(:^S cݸݱ&Y 18ƚ%5I6kDqvMr:G2f1=58Nnm6L5"|!(l5);F 1eSu InS&&嵾C^Ep0Rug O`>fPۧ>ø׹@>J]j>6L5"#|p8FT@ݱYs6ِ ٘I#l>c6ǐP^b,w) )N٘iF$:ґoCFs"wé}#"""""33mڈ`0﹏ې׵nЈ\٘iF&SQ5"FDDDDrL5"UkWqhDDDDD.l̴Y#"3:1FDVg&"""r9tfc&LDDDrLY Й4"^zRJ)l̤𙉈\ p4">3ˡ33iDd5|f""""Cg6f҈jDDDD.l̤𙉈\٘I#"3:1FDVg&"""r9tfc&LDDDrLcDz뭫|+gr|_=3 :1}sWԧv\9mxF>^=>&?^EDrx.GϞ=ە󚲧OF7q)CIxgncq*ԧzm\SI(}e` 2y,nx](O}>?wNe-88Yl߹dr^_?d.:1FD6EM5Ēj$>(K 9]fzxg:1AM̕vzaz*u|~*s}?cd;㈈@)yobknkRƼmK$>k}"S͡ss9Os]A &c;٘bo}C?NG<#I?$FRlGݘ c'QAHX]bS3P_I{Bʲ-AO''6QǚPhS˳vx o?~zOM0@bIHb GHH8nM}j&H]bSIt 2KSⵛ{ $̣'yXr|,'u}K9&\֫9:ztfc1"?zvNO/G?O0&DM(.I&#I5qvd\h9O'՘0˜KS!&c>+KB?bhy{Rcϥ$""GroH'ggmγ~r}!6+'Su^Ж:_sᕾ\_7Cx鏘z}Ng6f#¯t^u♭I=JR !$u}ՄULMB'>joKyԘ28N]cQ_.8~v(>ǹySs|Yw~_zPkBg\BWgC撵{4CRW]ϝl̤Qi-#I&5a.5:٘I#V)~Q697:1FDSFDDDDDnOg6f҈դ:1FD&Й4"j5iDDDDD.l̤QI#""""r9tfc&ZMˡ33iDj҈\٘I#V}W^)RJ33iD__W_ޮ>^}|??Ҷ/=g(W?+D;`.c]ڎb.̿Cŵvu):1Oܗ{m1@m[Eq CvMFT:1Ӧ߂|_k3foԌ-ho5ǵ=aN"|RVh e\H< 㮤:1f_۵˦otGÔUcr\7|G1"9nOBB ߈оjDoCL҈\٘iFcIuu"cjj0ږj4wF$F >c`^o:2]Qˡ33m҈W3L׸G |5ƣjD0iږ%H5LjWMJaƻFDDDDrL4"|{F|t`߃mƩFzzٻ9܍5M:1fH}v:G#$eXfQFDD< y\NN?"˻Y#5"ۥ33iDjZˈ$&1ә.ƈ|6WxF{?{8`HEI%6d ĥ>=]7uS^%6]=|-_B>#>kшu,]rrl}˧33]W?_Q+&g" &I2Hĥ nCM5nC6#]AĦKu @C|z:f M5ZǩgWK FDDKy7dUA٘b>@fHplDE}bƏㅴ$yM9,5&co2::t;Ү'^RNlsDDn .}'|:1FD6 ,"a1yfA6ȉLjPd9־0غAgq_`5& ]Ox8N?O~oǵz~6M#""rw%yƼKȸ>ȶLkHe.3# """rjtfc&;SS FDDDD΍l̤L9l̤L9l̤L9l̤L9l̤իWJ)RL9l̤L9l̤L9l̤L9l̤L9l̤9G]mϟ_=yM>}㫗/_^}=DDxnCMܽ>ә4""$e={K l€^#""rZM'ݳ5R#]:1FD6Gi*?O|PR$Y^S:uq\書GD)C1gncq*K{~:f'BDDƐpL>AAg6f҈Ȧ f[nΡKȵ u>sL H}=f3}@S;cc2Wڥo9uQ!s̵W"""7xQ7[Ll! %&@b9qhO;5n1ɞvMy+iLjk̭ul{(""C1/vȶL$ #1RFɵnĪ5ۀSJFBsIL)PDD.gӒ:Ye&٘I#"865rlkf35nk8^H;Hg.s>Y1a#}9yױc#̡ΑdzED>9x5/1[L$H-ʦI2N$u}Mt><pT}gau`q_`5& 7t1+O`>xc@RoED9;92FAEg6f҈\C'=E6""""Bg6f҈?9hDDDDL9l̤L9l̤L9l̤L9l̤LH^zRJ)l̤L9l̤L9l̤L9l̤L9l̤LyvyՓ'ODDR`‹/^={M(O ӧ_|y]z[CR^IY]chr KbJ9й<~xWk%u%P^rtfc&$l,6˂M4&_(ZzLl1d=aYR\y3y-@k%Й4"9H4jK'9$ )If]3&jc$=3718r}@$o€r>_Ƚ#Ɂ\`mkw^@ g}LA֕yѾY7 e5}vsܛM&'W @.]րNlXZk2/uCR[JKL$'qDjʈ#dSW%@5I1Y.)gl*ԍey@-_nP(HwDD~kne Qׂ Pי+K}]Wn:z{K:1FD6 KD@Fj"$>}QXx! I <}PYc8F&.sc/]O؁vIǸgXs>5Z򥵡f|_brܟ:f sLҼr?t.ki%$;٘I#"%@M:AFMNO_5IWIo; GIIḍƄqz:{qcs{cPsu]jLu]a Hyu1YP]זUʬ7p\nZIlsK\:1FDʘ$ւD&"""rtfc&;ӎшȹљ4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#"ɫWRJ)T}ә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#"r =>:M={v}.S>ӝ?~R9Wu uQ٘I#"rlI }3"KhDDD.Y3POimЙ4"9,0t@'ɢĥ>@6JbORqҮRO}o[wbz?RkPǫs? K='5Y>?mЙ4")jB|ORmd>(K 9]ڎ_W3^>Ήc *#f }vAyPxcFSSDDNdZAݘӳNEQЙ4")Fut4PP7ĥ>=풄k|y7}%61#%M,oP׸%fLl@ 3n$޺'&>}Q_t i >ɽT_mciGY zA5""r5_sxج{!ۢ33iDds`I(8Φa 6q]_l!F~kI5>"A9xאciKr=A?s=Yj(sӧqy-<Цmљ4""אDL" """rtfc&;|6FDDDD΍l̤L9l̤L9l̤L9l̤L9l̤իWJ)RL9l̤L9l̤L9l̤L9l̤L9l̤9G]&O{ϟ_=~`~ED.>7 ӧץoBybCCg6f҈9l̈s mA9u|nyxyљ4"9H$Iz`xS5e??=8qiW'M>7q@;y)ufD27Ȃ(kw]DDdP2l̤MQ75q֤2a&m8_Q|= ٤.mzxg:Έ@bi;^C z+w&ĄeM+ODDցP.ۤ33iDdSdHJE0SP7ĥ>=풨k|껤=.KlʙZI,qF82?ƌem1jWbjC]Fc]ZG.љ4"I(8II$ eınj|&f!wr&n$WSkKfqPǀ_ڌ1a\DD.W{pSrtfc&l 6I1 qM5ǩKdl5!qv@'s>Or1Wi[T)e'TӑycnOP9Ў< Γ!kISsll̤A%IL9.dCA6މLjP$k־0l܁~sL=P!( mPguѾ1և_OTDDᨹ<Cˀ{٘I#"r ɕD| ԍ9Й4""OOyF#""""Fg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈E+RJ)Uttfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈ȣGN'O\xkgϞ]7c\Π'""?~|]fy6?1˗5%:1FDO7s ٧m4""" nnL$T&"ogkʒ>}K)漶qh >w] MԾ;2^1Ӱ 8v9=u #Ig6f҈Ȧ f=gݸ'C65QdO,qv@̑dCy>ɽT_mciGY ]SW8*""r:kXy֦1&-6L$V$h$&k#B=IGwz 10C#ņ\uPx-c8}@ugmC]jll̤$ T# """rtfc&;Јȹљ4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4"rzJ)RJ7٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""ѣɓ'W/^>ٳgg""?[/_|]]YӧoC!ۤ33iDD > a~3#5hDDD`>0)@l}imҙ4"9H$IDbE'd;tfc&l J1ԄymyQ,1n3NH}=f3}@S6##?Jߴ!qx^sz }XQ^c=q[DDN s$ϓ)}$]:1FD6E6ۨnx%6cZ3vODDN\,ȶL$J*t$g3Au⺾1"ԳlQGM?0C#O[P.o9f^y>exEDtk9><_9:#ۥ33iDDaL"=9:1FD )^#""""Fg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&\$^RJ)REMg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&Mg6f҈tfc&ȁ_l̤9Y2Kt,πQK=u}{cbȽ"٘I#"J"E$VDYOQRl~yMYӧOwsnӜןe/k3,cL Z*,툥?91_k]~ ٘I#"{6(Iu#[pS#j=ǴK1S~'sڥ (wQC] }>jcZ,ږe#bWǮ{ u2^j{H ƨ/""@.(7٘I#"n`D,ns=~`i_8m;cMzȆ?~N݈)["s$&qKDD' 1kqM|%>Ҏ1"j?S_G!f߾P\!ؙ?Zcs'#$vցNttfc&l+.LC6$ 'kMI, 0?IJyimWILcvPuWq#IȨ^o)SVx1uޔ|@!\H88 K]tu!u8yf֖9Fx$ggM1>tㄌ>r:u}љ4") !e ,e5i&!6>(K 9]ڎ8e.e^NN8s58}@}9x.PN7uZip؉5^?crN=e ^EDMjήjh]>y(y>jyu<"q>/Gg6f҈ȦHB5بfcĆ$;'=j|Mʒxk$n^D c>d]~512Wȼ{ELڏ!ԥcrkH,8:DDMjȫ5?PtOY'*:V}Ҏ1ˆ?~(Mq~^C#s̫cgk5rP7n9 q̥^I@~%&w&f-9\ Y jmC[)g,:1FD6Ɋdj"HK\ K5iքLYcm[qIPɢ_Ə)˜Gc9#%唡&1Șdz kRW.Cg6f҈\CZDDDD33iDDށw?L9l̤L9l̤L9l̤L9l̤LH^zRJ)l̤L9l̤L9l̤L9l̤L9l̤Lyx{ٳɓ'mM˗W?>g""ȍYD㔣ЧOQNއ1@~5rT^5g,s}cR7&Wj8Č+d^];^klĄ_ϸ5u"".M$&Br8y4yk).9%vKsLyք1O[:1FD6dfTL#HK\I1ɶ&(k8m|88)`O0J? ԧ,sXuWm1(9ט9]wO1/Lj9JYɕ/c~uȚ*,;|X,1k٘I#"r Lw*'(""""r٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""Gә4""""""r4٘I#""""""GSM}qޕiDDDDDDha<8hD"yRJ)*o@1# A9h HgBFDDDDDD33iDDDDDDh:1FDDDDDD33iDDDDDDh:1k#RJ)RoSpqCzxIENDB`icinga2-2.8.1/doc/images/distributed-monitoring/icinga2_windows_setup_wizard_06_finish_no_ticket.png000066400000000000000000000241411322762156600340710ustar00rootroot00000000000000PNG  IHDRsqzsRGBgAMA a pHYsod'IDATx^ϋ,Yڈ .\Ez5;q3ݻw'w0w% nGlHèPpu"'2NS'"#2<ʌ眈ȬVD훿w|@NcSJ)RJSJ)J\œRJ)TRJ)l~/yXG)RJ]a.Bُ~M׏ͷ~;:RJ)*[Zg;/UJ)Rש_7{W7o.7_|yն*؇1Bw>RJ+s Ky̹j1mO>ކ}TV n 3ae GxBO j11FRœRJ5A9_;y0ӟt|-g?W:pa~ؼV"H}~.z"Ucano.͌%)zZxY֛vZ sEKe^rQqu} cO0=~ypjJ pԷPluW>s {{uaDϧ_ DZnoxCۍe7a~ٮm3oRJk՚s`tΪ[ܵ*̕+tuob~.m$U?V~K/p+m}ea\۾rm Oq?773-]ַabZgu~l߷J)ekMD8:g"]*E=8Ex)V1 u@eW4De+UcZ3;VCcU%U-V֊6YؾUJ)[ S ? H߳s۬'sm׷)뚛>_0jQKy` sӶ~5޾oiPYoo콱*RשaY?>w s[q.}uXΛ!1tHtzv<&Wǿk hm vm稺xܴ7_qo[Rꊵ&\"b\mxM;G-'Iy_v(k\64Q=v3m c@mY\`PxvKm/lͷ5jJG1;_v:W GE sJ):Ou\Tv9RJ)Uj6)RJ_œRJ)TRJ)0RJ)9RJĵ s {va7/&O6"o]{Vaw//v*̅㶟y.?ϛ_wpba.YS>SoKw],gJ tVX"a.!\+t.ve.YT\/5Hq.DoO-\,im\ٖ[ks0J\t+t[q%x¿{]a//cjѕ[ॺZMxϿ-ĕVjWB<.^mѹC/pYkzq/n͖+y1sh+6 dp-lZ1Kr1 G0|bquKz)UgbخxXz"UsҸO5ʽuZEkkR T|1 ^^觞b{}#ҕ ؆"l;EǶP!᥊˭\\1j$8zWܱSWӻzUTq&0\/=fu˻j;U0j_v,uZ smhvиvl0rTYv질1c}oګy]5̅;na&W\53g)aivcRێ W+0YoomiZssլvme]/2W\X b6H΅j\۱uWq/b,ǾQQjV֖?pW sq_ k^N³&Z ss\UWNks6`Fx|>r+:z\q0W|K5EXs5I۪owUű:gzx8 ?zK sekܲ\L_`^;{J]kP̚wuBV"y]u"Px\ \Y\ж}aCvԟ"յ6m*:kkN[\K sq+jy9F*&i0WS{)\^lnm=JZ=樥qs0\oA~IL\;G[[-o]g}_p>zϔ;B^wX )-ޗ#Za b96X~cϑkm;%TKi=̅Aԇ\"XXAvx^a.A2vŸb||UbU:u"֫EE;]Kc`Eܵ,s핺DjC"L޿jmysg6 $z ۴7[nNk"jջ=]^9eE \G0"pD[X{AKa*"mD6j1F?CcXV ]3Z18a5ۅ?$#$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$*lnn:޼ټyn*=n3}۞7>wln?o7we67o6>Y婶sΧ~rwKze.Kd{8O@wͻ7O!/[cSzmS}hO55.y?|4-?3њ~!dmտ2w%x '5z S_n_}x{ws>?q~}]nZwcѝoGVO+ϧmko|;~iz0{nLC뽜0Wd=P#nE'b7} Ru3WfĸO32(%ٞ\r#NU۱pmKu,> 2OwOv֛96zz_b_~Oˍ:ϵ7ϧَٟ6G~Yکd/ dwՠNZv?6}z|;(w5$~Ncoyܜ`tqjrnA#B !F޾ڙӝ^<8Na评6'ݶqَc.1mK|4(Wɑq}aj\{^A[Dj8Uƫ13v"rcۭx<@|ئ1XNˎMBݶNU~^l8#dn;z׎ynzy>7OQ?c}/<sUmf˗4X?ig~,LwëqBWN>Dv[约}jӞv#N?plcrl;zW:TzݶmvL;93=G ^x #BPs'1tODzqmX(lPMv{8/E9N!t/W"@Va`{^O{Ǫ?.Sߍc_A;asǪƠ61]Qj{ֽXN'>i1l01`N0_*wef4)<0w&㭼j@ya.)WzXMHLHLHLHLHLHLHLHLHLHLHLHLHLHLH,Utunͻk:eϵQQs얖_1q[wn Ku{< 1o.0S?=g=9OuZ/W}.3;nGxcbfvOSLӏmjzyM+b3vڶѶ;7pU~bkqÑi\ sy4xc/qzFigP{7,// jxsv<⯲+sySw:,qaa{}Ve5m}Ʈυ}Y~֛^Ӗ96^ezoX}.Mk 붍1m[~5TNS/7ڶsvR;1NoYl{eZ1{~Ow:^~~ ,u;s>Ώǽ{^gGC~yU{:(_/2 | n *~^6c\v>-7=_;U)^WVgnc}g{m^Ӗ96^ezozc붍Sanz~eM/iK7^gi+89zߓk^ sL_q\܊1}-Mqšvcq/+Mގ(mݻlUuo,8pvm32|:ĶijcnMoa:ze9svS\ufe=r*uvzf_3v2ޙu]?̾X WM_N,Sm{SwǶivfqi[zzwʴ~ ݵӋ~SQkn}~/[-x0nC_^eێeb[em,َ:[9𙹧\< /r)z|17o_:ދyQ74?~aKk7ov|W2ְ1n{3݇3voNse~6W;TniuqT}u< c3lju;<a\vmv6G<3/'7χV!ٹu'euzYc:8pz,{}ӿO/'8#sywoOVv'rYn<` zK'q!8ƕc}>\ʴv^gϛxt~7wT)ܚay>VL/T˟0J5̭2WF\(W,v+ W S+mUv5^sy+_k_@x&ӭU=)/OWDfyF\f-yt_U6*3soμ{>,dO˷휑0J]$Mzx\UݯqpX/? b99$)ߧ[u-c̵9wsxk?sv~nN :zZmCn&:6_kd?leS368ӯs]t_w:궉v޾on}߬kij5kܾ_[c1sJ\"9}q \[䤘)FDsp [v~6ͅ\Pfwj8Q ۻr[mrLք[Vmu;'st;cւ4ϥ\S(b?=1w4e;sO&Nm۰~~u݋Wsypn=KwW{g[1ƘLzM!W_=':BWO4Q6o9X3&`!҇hY~n{yk@;:Bz0n{ڹ}[ovc>sLmWo11W'i1W~xhbMm{&)~־zz18&Pn{nn{Ӳ6޼XoKܶ:ޮ-=n_vL6{]y=1s9%zFڦh[s6k{$ ⑭82cTMvm̹f1ڙ爹͑1g1Ƙ0~z?5Rh9etTFc1<3:v 9c13lc1Ƙ?bc1&xĜ1cL9c1Ƙsc1a@01Ls@01Ls@01Ls@01Ls@01L{t1gUXxd1wm" Ѳ<7p?:1Q4__xU̕.y.ޟxpb1WAVav2 .s^iN ?UNwrT ]ŎUPCԺ\GJ_}NNqj0|I.s:uZAWVj8E <5WRG*ҍЍ߫#qu,j1W߻욟:z7t:Nn|s]rom:֞JuѾRO<Wiѹ(8(cP~:Wf#y= ZW}!# ڶ m)&񈎹sӯKESU{~џcpZ}OO[{'Gj1WGNS?(+N`F^iqJ=cY:R>̅jC;[ֹ<=GಮseCKS;VY:bIދW1:)N;8WOSYQ)4Z穯Sfw՘;Q(j?WoK]K1GSg:Z~귭^6&G{:;M}dGmS; Gj̕6<*f*>sbӍ&k]!6c oכ;)Gڠ}s1pYW?2t\GڙRTCr.UsN{ؚ^ږch͚5kskK?pW/Z},D;K17g.j]ͭf[{1u~nsd>\Y:Su┣Ibn=YG*k>GDmC}u5Oss=quZߤsi%:_1ׇN?~_՗suiG,}ru9Ǔ)#L3&y?uz$暥1XO!?$о'm.sKskUӾ#gJw;k̕pHO >>j[?1:s$>vԌ^K8{̕:W!3ԛb ږ:2ֿ]1W]]}}@aDծw'u^MWR?c`EbZbcn*PMi.sP>r}-鵯9uyE\޳Mǂjtڰ=M~p=EZmӛ[Ǥ!gtz QĎg'}4.M+uKkU-ݯEXTvXcVū-_> KϻWBOVnm1|c)s@01Ls@01Ls@01Ls@01Ls@01LGˆ9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &E7gVϞ\}?Ii?ϟϳnY={{2oWo^~I>s93;مpiBSw竛_|vwXvyLlow[/L\}ǼmqSs`mom&a?y.;-^+bT#[۞?NǮlw0W(߬gK;Sg}ud=,-?k|d9OV۳ }s[~[j=׺}oߞ=tyl_rL=wȶMwk߹s|?xG6ߗvmS!rb1zCٞ<8h&w!Q>Nnwˏ](>Zf9=Ɖ}ζYw-io{\1٭w5?quM~mol{1}a[ߴ~7Bs|y ho/Ni }AGfv f5Z]ϱۏ]zGvNF\㝾vKtOGMM/_ШD6ho׃SY?}sk׹uyOIsϥ1}tyLG^#?tm4Np's'9covq\cs4f涽 u:vM୯N>x[箯7!TTi&,wn;ڽzۯU~=3{OsO[㟲sϷ^cv; E=-wtiǿwy{l:ֳ3ݫŨ}6"gcl }]hԦ1ymgryn?q<{RlSڷf}si}#34|mˮ?bX\}aT5o>0zᎨ}q@t uixqv`=^ivm}ת~:Wsmg޾YfvM#h޹y o~o&6Qݿ4wZ~z}cvu?|-[z;?SP#+0 R|*1w&SyGa)\g:79`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9`b &9p~-G^͟w,n5ph#c);Qphݗeb\vOG]x ?nhu/eL}1w=b\&>1D]}׫ד7V?;3jfu4~`S~r+y17oV>|.wVsO特wܹ}1ױ []:ޯ>La>vɘ#?t1]D'z*1)N]ϿL=Θz 6"8\V?i1Мz]?v;]4gׯ)؟#ϯANݧ]eP2ps?N޽9~n{vc uޘٽyלlv~3mvzu: d{z?E./u1)vclu.~^7wt~d|Ou.2ZӲ&*~??vG$\}6#sf[m:q1?c_ެmN:7w"cܺ{?B@<9"r4hgsuuz[?گ36i֙>g~?d-߯uۙ4ᩧZwiiv)N;s$bNN}L'{Zfj. k/~?}Kd} s_s_1DA.sF]x O#GdwdA<'3>b{dE߻?Q|9mcǷ6$}42Ay2Ʒ gT$kwIet3o< )g׏^6|,MCgxr||?ojXpi>F:F{]a=W#y#N \޾01?֭'}̶POd%~y =2kF4x'z&z]f'ݎH>%v㾏Kuqe}63}s?vRS*e:(@3 J& @(erPw)Cd󒱲yXyEhlZ8cühٴ;VJGFi!# rui"2"/^dH%A.u]'\{\}rUWԩdʔ)rŕW_./,\~ht(@_,Rv!#ƹK;w'~MK ~\i*fP8y^Qw)#H2|ِ*t1۶om۶[۶[omQ2+mU[օP y&O*EǴaÆhj ]qJ}FE)=i YwlS{Z:\{uzRXʘB&Vʼ2&Ls~p,)e]8 E_ OүIҬ3<@EEs,Mqe-]. o1Sm`]U2nݘRF!BTll }KJYNC1ٴYjUx7ސ_ +p-e|iD!Y.ddĆ2zQ_B&HTȼѷ ,eΝKJYNC1J۶{qwSu)Q*2]u2 Ƥ*ddY?jS>,}2o */}Ode¹u:::SMw<ӱuױO9uNΟ3gNliJzۥ[¯kINLӨBF]GB)dv//>t|Ķ]_ކk)S|iD1Sw)QK>C:2]|qٲ51V 7FKmU[օ3i Uo)cX-M%Q)J~MoV;ZܘM8 WLJ1U+]tY])3WKꅌ>]օL2\xQxrJe]ʌ;=8.\i 5%KZh) ^ݥ̆^qn*t0I .2V2/j˺pGäId¹ {k)K:BF ShڊP80,KR 29 @(er@)r)Its/J l۶MnM t${D)Ν;eǎe[rKqWɻta;Mw:n㢔,on.ݻLv9JG$Ca|&W躺R %=i֭a7G]%8neG?}BO_V<\躺{* hyӇj\zϭGȼ㸇OY!_qx Yn<ɫNz,\g Osr?ӠR)7G_"nۘ Lrh2"f}7yxgW͌& }G\+:./Uh+x˗j˒bHˤ'k|U2bҳ%ˏ{_wleRk|.2Z9Zj2ޢ0iٲyf[g~;Z"mtZO Kw? yg䷏&?2:㮊hr)cwcOE)et]JwD`׋5y6a)%=k+hk=6z33<qc}oc8+ @lyg7{V @'-Yly+<-i㮒w}0z[2]G.չ7 @t$:16]枲d @(er@)%O=E!B!BR)@3PR Q)32@3PR 2ʕ+ !B!dȩoxU*e:(D `x}`{:J6&ټdl^Ytiv{2g]v)loʧ>:z[5RǗp>F緞cH\4RET{Xd}4 g:o򤚴Ǯ=кk]_,QT޵2UU{g[ةc=&w\g:C -e͚5?]KҬ37pCyE迩ӧKOOOD)d,E֯__b-dL)f|doBFMӕ2{;vDs{c՛%w?Kz 7`}mjI{ZpQ>׺^ڒHe}H6ao>f4S7{?}rW/~=F-*eВ1:O!m)7y.܎{3a9SN u7]MnL #bfΝꫯFS%:@S_~ ^N\.ddԥPkF̻ki;9}۞m7X}qtycJzH|_ݟwrկ픮o%W1ON>߽Ya{޿=Ϸ^ZY=iO?yTj=6~T{xrsg_^*etٶm[4cύ)%mjɥ)R!cdUhٴiS8_uztZn!z[/vb[,dV?>}c5b}t4oyCk󫽑to>u^=o}}YmXrsm ~C[>fbkϝ;Kױ꾪=׺}Qd}}2^EH]hQ`/}7}Nr]ΰ6>j|x1ύ{ͿCy۾fϦ}_(\:O$ >;\g̙rSO%}`f#>n)t>5Cҿj?O`oݏJ6ۧ7[/mgX퓞wt}_@̛7/=k7Pz!Wq%35̩1v)u\*e]xh١Ņw{m;fmt=3:Gk>jrߔ*~2t?ZИf>F1h,+d)cFMV|NPbf0ҋk٢STBljK=G6-8L6=T6-?>2_ F̷7^|捙M=ؓKu.7j2|y}-_].HWWWyKױKzkwZ>(w)eT~Uv)mk߮vI륑sn߿^=fw]cm?z'y(z7zaOj{h]xTRSKovF4bv)ft\QdU[lneCj&2 YsV8JfǪ_ki5e<{ڷwҺv]7/e}M.Sdt=o&}uu.SjÞgvk)\ۏ̷l҈kzt.2}NF؏U%}M>K#\W7T˒ǦDH%}[$7Z$eB-&|E=_K }oܢ#i{w=wڰWjJٷx(&};u԰ iD!CWS/o)39SgTZi/om}o5otͷo.7rf?\}z\z>5捩}<)Nyc{x6I݇>=rs߾Lf[=hUg.O-}w_ytj߯jz0>>:_V[s>jKߤYw @EIA1Jfb&BF !@R h?2@ N_fAJUHaEɄB!2˷BH< @(er@)JtvQ4 @(e-[D^}U9Sïhok֬"y Z2W^ye4 4 Eɓ裏is2 P* JR0opzʕ3mRAJ2W\qE4 4 r bQ?2HB04<:FS ?2HKK|0bFC)SP @kA(e LC)$ C!,e.hh.JCA)SP @k#]vY4 4 )~(eRahx5~,lKO ܴ.22KT`Vc8O.~,}mno(=T]MU̝ޚ|(2W{P KI/eΓr0ZUR.%:4Hc)=Stד<ƏgpUT˗QM2\rI4 4W#J/NyP^h]2A%7ͱ RfǘO)3rwޣy]1<?\U-tLw9\2R梋.&jH)0a!!SB'Zm^!_~hK k*#Ln>$A۸u2:}=XYOc捕!SbsFX˺oz ď_&oB.fቧֱS3~䎖,s^*w:Zmc~RZCX\p$\*eouoryya/X6E#fj)_Ι~ϵitg^%ZG M9RZ| aQbweYsLՖھK1 Mm&"T8?7 'KRɦ/U6{y;RZCXʜwyd1=׸R&P~a/Ø*ӱEpqa0R&^X?3%̀ҸUe:_| ]fwtVwtM-f~:,2;~^[o˧Y ?sT?r-{I)!,eN>hyxv92aF4_DLy5?|f^rm>R.Db]8KJĝ/RsUݸq_=EGG%z֩N\E=BxRZҥ2:-|=i{roќtzhI }=%=}ѴWt\R&PY4__^uZosl2:m6dLI 0&iqJ;jn\(eŸ(疋w쎽yz wqL|/)e5Z.d;wEu23_*'^gF[9zGhIqK{]eN4Үp9ӧ|T â7oݤ/2Rɥ O_25(eRahx5VL]Abr9{%!DvjrMOȦ-c O]Jh#tY}L(mc3딖.?}:J!5P J⧹9EWP @kߝ#d ?B|,^Zf*DݥLPu%E%QkUWF͏ݿo0D)`((eN_BQ* _w;gi^e/)}˅?"a!JRD/2/qdJl[뾓Y)0|JCA)SP @kӗO5׽"6Q׾&&-eEk^˥GʝKtjP@)M'-¦)E8tb>W}D*#*| JCA)SP @khj)c>{ܗM_X*>A9?&]QfH%اuw[E]ʨR)b-9x ]W'?懥Ne~X.NF C2RAJ֐H0?#r9^C/͒&/ Rp )~(eRahx5VLJ׼*>b4VG)hW^S+JRЮ(e+J@A(eRή12 ]Q W2vE)\5yu!yXټxY4V6-Sʂ1a^zdh+c2QJ-dd5A2Md WB˂L$ŲqV4 rհRf2 P6Υ4 rըRFOYJSȺe 2UJEcS2<0gTVx9n=M-&M[8`xjT)MSȺI~`J^蒞h@Eo{Go7; l;mZ0Wʤه6ۦ۷.U:-QW|Rly1,Od-qҬc+B䨶zΏ-N)wVͻo);U¯-\|=)7aky^_.є_cKڅH)8-swKQ}m-e&Slه5F ,A}5Gi|kK8P2oӞ.ݞ6S意UKjǓ}Ҭcgj{] RF -c]-'׈+\8G%Mwo4]79rѴT+fV,dV z\uߑIStUlD:EGXx }Cy1qJ.:$H͂^C9]*涻_S6J5\Pw`ωkY#bأh={Roi{-|0lJ?42.1~N䯮+m)`zQʤ\T+fUʼ<tBf#eע-];m~KGbȞ5d@)ooOA2Z2ŖUTaTcpO_ezR~6O,&'I_!{>b1qߕoX2sNJcZN䯯_7r_RG)y npGA3=#}`Yww髉ilh&^G/ 2=ɧLBF֞#&*mpaookeF!n)}C%Eқd})12Վ9vωwTT {{] Z)h t?|Xc)Ȁ3&y+:R)v) Ӗ8*dtd o;u܌<ɬ:C,/- ]6|J-hIҨRG^ȚQ2;VK۔e|/׽/Ў ]uct^CFOY2?$oy-"*25F7tEMP twb-su2Mc2z*S-*e6j)SgHCU&JXq=mZ )6}DŅf`w(|gͳU+ eZmǞc?ϭgmeκ~tKבrF!2ZȌEC|vK[ʔ4W,nb/}3^٦}JjBÉ)c32s^eCZD_Ң^Y1bD4'-}c(#d"{)OVTF.tʓo^S<.T.0FL6]]iѯtSTJ a)Sd -e4QJ;w{}W'IǗ&;lL?NoLwwzR)S4v:BЋѰRf(Y?;ʬ|5z=UIGhvƁY9 Uʸ'=(tz0k%^CFOY_>2O)3\5Rf2RE)hW)D)hW2 ]Q W2vE)\5yu!yXټxY4V6-Sʂ1a^zdh+sP ?*e :4S\ / 2Y yG[<2UJZ.dB8R|2UJ=e)M!#Η 2P W +eMUȺdÜQVZU=H4]t7mit89R㬩7MJk:#ܾ}W5^MT9hJ_*bcEUڿc<#y,{Sm߃_Ж(eF2zA4$gS-z>Mv3>z1ou`iӂyR&>6ݾpZ$ޗֱh2Zee}z'kIۖf[&G}{]3`ZGcKڅH)8-swKQ}m-e&Slه5F ,A}5Gi|kK8P2oӞ.ݞ6S意UKjǓ}Ҭcgj{]gԔX>cNâ1 Y;Am5POWtF[:z/!Q+JwGtww)2~u6-*|c@ 4].6tIn;`}#rtTmwrmk<],F*ŶG${=ZnN_!,e+h)sd)I);wf7|;yѲRٹ @v=/HOs͹AΑ_8Cg=<=C;14;kғ:g}r3ueKdqSeIlRL=Nθ{3߷~}L.LELr685Ii=?6gK-ӗtfU.)ŗSV4LD&'I_!{>b1qߕb]t{hqG|9+c#ZF3 ]h{徙sLZ(dv9[^lsx~J%KL7&ɓf6[v)cnBL qK%S=EIHA2T;^; >'jt/62#*SB4LΈ0pn}BHs}TRf'#(/eOo]W^ܰQ.z]=4ۻ7jc^{Q 5 2Q^}ns-op{ iW~4+'uIפhR&uuɤz{Lxg~]7g-k^[!^7`Seqy},*ߝ<6,iZ8v0q=*m*NJ3fIj^ِt?|uJ:RK-`?J) L7Z,e/⼒;vL rٵ \[3u_ufQccuOIAΕ/Lrvdボ!kfXOe}iyt3QVN9|RKN?.YcnOY_x|םb)L׳]tk:kӿ+SeQKY=;c>QacN{ґ<#v*Mc%|vӅ}),mx~Хn.CC-e/~ְ1TE\+j6h~O4Qm< XtX+=߾7n}voֽ^,Xk~%L&oӻk?%_ 2)ȹ Arl_5>_|짔2q>ꎁ{Qr>Z;䨰1B սr齲:t(\{챱޻ZgL9v,֯k۹k3en)={IM|MiNMt$nYb*iD6>c˜u"z/ӗ@Х1G.j2*5$Z_?e,nwuu s^wr?1}uKJwk[ vbVH߶m7/Iοo&_+Yw;ͫ?Ԭ{xl{ab sLٶ ˶BZ- _Nei>O w9'.&B?7sV~4mn]rZDr$~*Sy.+q~TIq?rbt-0/ oE[o֭[cYrWr7Țuֵ+x5kfΑϝ e볧l}A~4YuBH;o>Oؿ?+;čg3RW͕_,{]֟*0QR.H%| Q.cuce{-Q?eNaTDJgr}Alhָeۼ_oٲ%$!=O+glڴ;yFy@Yu)w<Yͽ3~}xC!gZA+f4 Q?j|Ų󃪅&vL;IxsRww5Bŷ3N%cʗpKݙŰBټv 1/I&z^͢eʤSe}j=<)/w>!nwKq]•2J-]>:ߛ*dTpj-,BJtxQnnQ봦؅~c;G`1]Ƹ%yѮ5k,XL&^:%jO?pZ6lO!E]3wJ YʨO+?}qi, 7%M! OSƘB&_o޼YνJxixd餼B{r0Ō)gwJ:Z(-_#ߥI~[11v c^y5z=fݺuB_~y<3-jLA3wH= J ]ʨc̕;nqŰ)e||zƍGC /O!Y~ygoSoԌ[ؿOΕs E]ȘR-d}mFpSzQ8eڵa֬Y3<3B]{o3ƌGŌC)aPʠ>4e1xYzu8矗UVs=gRVXO!1?ן;@K-hL9/S3'Pʴ$102f[_k/Efy婧>y'eʕaTJ.]O!y'1v9?ТF/h9ŽbWʘbNi1Ů)e_(}%C2~ !ot)f|#f-PO|R/vQ2BƌkJ:BF_t:jRG:ҾpbR R؅LR)c }Կv( ( G?iMzj^oL|ә܋&2v1(eZ] `1גzJ~5f22eR32%2--ejzm=uI_hS|ã>^WGV2'2Әj(i1J3JF }Ѭ/ͩKz_)ti:òeStd2ӘFP$+\)su5^+W_}\uU2u42e\qr.k&|Js9mI_4g}!/u(-e\fv|0jm(fu%KmNaS_2e|0QTBF_ }!%r?.Ӯb2s2K'nԿ~z7Z(.mA?,^8l-;.e42,etX.<^~maѿ=c2eh+n)cN]2h6ד:}ʕu2?~eɥLtwtG:/n1w%aoj{ZY>F&,X*EW;.]dE?,\0W>)i9ɔ2R VRFOY Kmwϼ*鰔yzRf„ az??*7oTKI|)e(Sד1xz_=H'2z:4[o5!2#=$aybolH<3@֔p)b)Gcloa7&-df[p]d+e2bmk[CS [2:-d2h$M"G7ϵJs2ٔ2N>~iR)~Zg?ptԩScE'\6,J><: 'XZPǗlIКYY/yY/k+0i_&Jd+e1~=)‘2v9wҤh$7aep2YO^$2&Z/f7Z(=)})eH>JX=Stb#繁{Sjqq:?auߕӆJ뒮\؏QJ̾c|s˞N8F`KS^d]pd.aY͓K%둹0J=D)0P'X~ʒ^2FȔ5,e&;1*RTo2kʞnVtRྡX@|n`㛞n) Uʘ364=I/˵Sҕ20pWuR|Jϵ1ia-^B׀}elOi>>\)/^Wey,@+HS`4Ȓ1*d~;wn3\722t~`~쵖2g-eΙpnUߛқʛbMlXSIMW>$,7nbS~Tm7'd㰇Rh cc slcu=N֚#`x[0K=6SطF)•2^:9|vwȅn)g {ݙgmdS2CIy\J)L:bFKIT=nwY(=2b ܅jz{-wcwuKwʽU{|-U:=>OK8y<}0L)0QrdA-a|@)•2_rl^F/\x "ۂvgyfUf n=3+J$W{껿}߄W^Vѧo'=ٰRF? [oO6-:O_i;JUz.vvAi~K߫pYX |y3V_ ͸UѱzWe_UaK>}yG|p`]s|o ?iʋ ,1%/Ֆ  @:?b2]|qX#et?|˿-gJYF9{.Ox5\GToӱ7 F2ү]HkPiR4sq2]'+2+\)s/vEL<[7+RfgD[A(elI%B!$JqB)C!QL !ҨPdkʴJB! @R|$vK!ҨPdtsN&1QBiT(e2G5e!2BJu~ JmtwtHG9]-.{PBiT(eWR);늪^T.=L|!ҨPdpOn)g߳S] rьtL% !^J/2;ȼEnJ9;ܺ|LB'm qIOWT^]nS{]T +3?'[T͐Kԧ/+)z*RR)NWL#f(e!4*2+\)$W2_ɿz|kb?>9r]?*7?>wܽTh QŜjdnԣҌ:><¤2f0(e!4*2+\)3CٶPBiT(eWRf( !ƅR {)e0t2BJuG)2(e!4*2٣i!VʜJyazyRF'B62+T)[:۬X"K a!ݽѴ .eQI;*e%{u, Gh)Qc=Shtd1f|tČo{7:2uC+B\(eWRf[^>cW̕>`'x"K52ɽGL ,%Yr^יӗJW|Vhjtɴ4iNzڒq%mG!dp^J-VwyS~q:ON[O\XG)JQ5J*u ,_BR&Vwwwc6{)X;drǀRf^rbsMR)s̫導&2G޹t)%FGا(>uFoB @F2?Zo\._;=.|PK]ʔc%z*?¢^f*hbkPn)c_gZ_K9Fy3qS"Gt! ^,K: 6n[% !R {*eNX=xZl`y&DL12)Y-?*]q5|1Gx[p_x̕=a#u)nXRFG1ltčdFdYBŃ٧J?JM )=^FQr1q!JuPRG璇ʷbDͣgEcF3/pÑ2kT)e_Nma[h b.t`=ŅZj׸qiǀLOeU;z8'j!F(eWR槏n%3'K2-etRF'$bKzZ/V8NOvO_rϻܚ˟nR$Gפ'2IהRiy/4i%9ZԤ v ݟc/ub-1ɍ>& !;2+H[Zϐ]:S>q0ly2]ǬQabS)>9ʝ0e/kqq۝.CGh/dKO_*2ՔRFRjɤaVwdVoԇ}RVQa&t)>|L\&%̷-!dR {*e~ȫuGR#e^W%{u, K.2HG]T+eܰo(q.O2n1)Un>v){)Ci/W^Olz A<JuB>ІAE ,eɋK:\KZRZ(6IVإGiiUک$5Q,v1ۏcB @ S`Җ2btR#e"2CenBI;z$iXmH&cu_xH v}ҥOiPdPʴTjV ت2II*et_6{7IȺp"-aHs}#eiPdR RFGzT%E@2ا(-3)Mk v4!ء^_s9'pVRFߠBBt j|j)c?;vӤz:?uu-lI! Pd/,eN9bhYJp)$) p+eF#V snӢv0cm'!B)H.pVR4#Wo[q/k}Ng#XliN-u}ֺ1!dxR {2Req WiRFG:z}iDT4Slc"f(e2\5Pʔ 1;#Ry>{i vd}̪qBZ'2٣i!E*ez]q/k_%Pɢv;Zbk¸ϵ^W×~<{,OC)~(e5eZHJ>i/[OrTEr폒V*eBEz,va~‘cvRr={. !J셥HPRFh!aҨV+eDiǢ#U ֺ봑u)q !}ǥǧ[ϡ;GeMv(QcBH^#9%pVRYVh܏NE;Cg4Ie0#_Bo7[K}BW(eyפ򿦌詷§%EO>-E\fIQXbw:}}b#M>Lt_/Qs&nS{z!5B)^ \\Ȕo ru[Eφ/zC:钞hQ̞n둮PKNmؖ2-vM-$GhQm;LRDÎ.Gq6z =(qJV9B @ U|gV96+V⊗}=]# .RSdN֥ !ƅR {*e)^F0"Y'rK{O2Ļ(e!xC)B2[%]Ln|/?y^wHL>T:nCӊ*>uLݦ243a]WRJ˺T0rz,`'OyU|tu,23唏|DNk^SBHcC)QRGKd Gο?7feiK/uT{eYV.W^ں6w;Þ_WܯS1ISt>WF(8r)sroܑ2WaɥlJB!PdoA9ar>' ӟݵ9Os_x[2{ꥌ5\( QtXK2vU׵gx*,cK.œ[9H-,en#:K8}RBHPdPIn/Л/>/_pXƄ nDl/etaJ>Js^R)M}rYv޲YK<ה!R=2+T)Gsm2W/Fo<]fy)޶X.i]1~˧(U_%Tl}l7{-g-]kBJ8@ה9irN\EܰDF_D8}UtnL ,:*Б0|TYTTN72}ۥ֩q4&\[÷}3X/2|!ꡔވ K?|X?o Ș:,Q5i/n)[?Ov;RB72+Hg}VyhàOG{ioLx9,xqX]'F)C!J ,eVȹ)N{9K]ٔ2B|^'LXTN_Ŕ2BJQʴJB! @::JB! @(eZ !FR {#i2BJQʴJB! @:GI)*(e!4*2٣i!2BJQʴJB! @:>X̫KKc͢iR#F[AQBiT(eyBF6\ DO re+D^,dK\,mU) !;2 K"2i P6ΥQBiT(eypwJ=e)M!#Η u2%=};2#ߦ !FR {V,uɆ9Ҫ )saJ#e~sx0 1,e2BC))5e^?:U!sxyᑲskіZ$PDP*Q$+mJ:;8btr)L\aN_]ٱ̜FǞr?gӗ!T @:|LBF֞#&*m鑶F)ST}N\)cdT}. !C)•2/=LBF֜ٱdZ^8}ɢTNW.OyM\ *x ~JbP /BIJu=`̼k2LyPk5a R:'B:up^؆ J.mS.a~dO|+e/!ڡ^JZ(ddAUJ>BH^LBFV.R& !FR {+e6LBFVu3"D)C!Q^J9d(FcT%E_g}.2BJQBiT(eG)B(e!4*2٣i!2BJ{,L!ҨPdRPBiT(eG)B(e!4*2٣i!2BJ]JVA)C!Q^JW"͋+Ece1,#/GF+ˏ!ҨPdsq*e :4S\ / 2Y yG[AQBiT(eyHJZ.dB8RF):9 !$~Jub2zRBF֝/(eb(eZ' B)PL#>2Ʀ*ddyaΨhzJwGE-RubJ2B'RFZRF/蛦udlJLRU @1]ډJ萎02f:HwYQz*˳J !$(JbE)`LBFNFF[%qFvKW8᎔)2eWaJEeO:&:yf%V8\c'+R>PRS2;W);m%%2z:fx+F)sޱ_MrӀcȷ$[gv 2q;i#4/R 7R&,ej2ٴ08PٴhKIJRaL'[cnYʄ.BH[DQӈC /=LBF֜ٱd <-ӗ7Rf߳Ch2-ʣ+apl_^?.%0Zm߱Eqf?~[XӋYޮr?(G$KuX̾yat}sFQӈ|`̼k2LyPk5)L|{Ӧ1qߡ*1s SX%" or-s:R¾uxquV0e@)c,ź߱D Z-whR(Jb,Z)QK>C:2Vn:2\(錂 +$Hڷ)ib{ u|ӕ;RT)c$I2ng !(2s^eCZD_*d)cFxȑo2.k}׌ul7:vÝR:j0TJR&JQD|3=ng !(C-V)!,e2zL"2S<3wˀBs]h:>b/y$b`4uʅNT.Lo3]k~r^R(Jb*^)3geBv#cY;kE[&~\̏ ߛ{2`nAϊ̶ibaΞ{Ϟ Z%XmtIms?}YB E)PL+e0xE)e+ec:"6R:Rʴ JIJTR&"R(eZL#e!&R:~RUPʴN(e!YEQL iR@)PLci2}E!YPdRPBiT(eG)B(e!4*2+\)Cd󒱲yXyEhlZ8cühyeVP2BJBF6\ DO re+D^,dK\,mE)C!Q^袕2]Hq.RBHB)1.V),)ddV)#]]MYgz;FIRBHB)2Ʀ*ddyaΨh둞JwE)C!Q^J2oL^sib!#&/ebRB @ Wʬ_垿sL >S2-F*uXu=SSؾӔ:J;v辻6 !FR {*e/>CM/yC+_ң>+ddY?kdep)22Vҫ)RJ̢`YW ה!2\C)”2k!ʼ/Y?k+ K?W¥_-2;W);*HQ.*n)c*]=RUunjTeRBHB)1*F)3sc,'۞[.;ɓ_x,?_e^'>/a!#kϑM sMˏӤR&o1RBHB)”2y!}#>(yo<ʊ/' ٹl5gdvy5]=}.Qe /(S؄5{}Ơ!ҨPdo袔2X)E{{BvpȚ3A|%9Ũʅ~c[)J pYWtGcJMJەw9JB! @:GwyK:HVK{G"FV!TӡC)C!Q^裋Qʬ{ʅ~?^zEMKY3ka#Oua)}AرkRBHB)”2 g=kȪӎOy+_?td -eMaXd !FR {*eԊ>*nyQ{O[1z"fï>m JB! @ W`(e!4*2<(8I g2BJJsN&1QBiT(e9H>LK!ҨPds7LitDtd[;7LmǷ &V(eG)B(eZ72_U|Ʒ`w{UVoL(eRPʴnL{jUGJ|C)_(eRPʴn(esF)w(e @qyu!yXټxY4V6-Sʂ1a^zdh+(J L)=o2R&PGJ-dd5A2Md WB˂L$ŲqVP2l Rz)e L~(2]Hq.RuX;:ɗ%Dq2lsڗ}9lx)3ԄgaYL]Na-ʌ3݃bJ(\),)ddV)#]]MY'K J)3]G&RrdrrJᜪLoFt8GX8rXKnԱæ2r߼dZ}9xM2JSMXYŌ<ؗU/P(ex̢ Ywl3*ڪ]JwBRuk)QtՕ!?sK)c%LA;ëQ/5x^2&2QRF/諅/''2nM)ci[ʄ7uhD9$At s|S}GDa(_>yvQ0(z~}r*)=2<]>^ 7Q>(~|L9K :^n4ѿh?m=EVL=e=|;2îI3R<':Z~N J(L)^5ٛ!}w;d !:m6s䶇V.dv//>';37CF^NrÂk_a!#kϑM sMˏ *eb9>\)/R;*~k2GokP=)eJ2*1<-eI,2ms_ڧ/N_ݟ=1Rzs)eʧxN%OsRB%pu ƌ;xAdx2AkńρUĞ/R8 S{d5WCN9?o՛~.`kYsV8JfǪ_%FӗJpV1MXp q;=[Ŕ2,UK{db3aa΢1aĽ o7|oS冖!x7|绷}%Oy&xaWhb&9|uhU#B)P#F%rD4}/SٺMk4^sX{;o~NPϟ۫Ys<50/\7SD/k][);-2§|aoRƽoN_I,e?ӂtb)= /eԛ2,K @qLF|ʽ[2fێB#g!9w'6"FV!TةC`^]}ѫ/~Ea)H|$ LأK4Ius~L|N]JB)P)sgq9TvC6|w?w?y:dZXeCZD_sX]c&2J,Szۯ)V(e @qud1Fʼm{G~X{;='CL>\qn2צN SQ2RuC)eJ!L/21(UZ̜=?o7?|)_KncT%E_g}.2S TAs{P 4&2R8 U`h(eZ7n/!0o;4&ێoM|wPdRPʴ[:RƷ`w#oBHޡL !ҨPds$Lˠ!ҨPdRPBiT(eG)B(e!4*2٣i!2BJuL!ҨPdoi2BJ#eI g2BJqR j)裏RB-e|Iyg)eRu yꩧ(e!$F?̞=[-Z0?O)0H2-RF_4SBIK/O)PL a !zHQʴ2\SBH)΃ӗZPK>}BHRRO_΃HVQٲek͛RFє2BjE?̝;W,Y"?xxګ2Wuò_K=o<2RF_`Ȧ!~7o,]TxƪU2ZSy(eZER)[oyKkiJf_R&VwwwEۘ=% x+["3ѿNb2)LZ/ !_StT9u)i}=éK~M+e|GJdL<-ktDZr#-P:*;%/Rak}ݿvNjRFJ黮US©/^Qѧ:\]#xOЏD={̚5K~a9ss{Bin\ןs^  }%s_-eQ2K\O2z1²EOQ2ןITHraMFD wrm񎒱+[J&}3P=IȤ|t)k}O!џgןs_1fLҩK2~4-d%{^RtL1yNRJX31_ -s o]mV3/|14]Gh^c`7Byn~yy?w:2'.%qO]kZ)cђ.^jEM;IiApjQȞv5|O} v)fֿn jk3:]_p-gZ3b.htX׿%X|B!.&f\ןs^}->0#dBƽLQ22M+ebFGʸKT3ӂ#gR(ֶӗyU}F#x佯l2fB[_p o-gE4R}a/MI=O!џs]"F3:&m!cFT;uIVʸ2= /vM)Sab53RSИfѿBint?2\W? %(Rc2h_14Ō^.fv9/MI3_f} !46Zyg=`2}>21(d*(eZykJ_)cNcr ]Pu1%P} !4?g]1#dBQ2kGby/3:Z9c S %:L7BHc~Ie}RBR` Jd5/M1/}Ō)gbWΘ.i&O!1?zq S SؿOA)Ӛv)TT5c1)i&O!1ŋ37E]Ƹc /RE/~5{Ԍv11/.O!E[؅RE/ b&iԌ)gLAc4vQ3 | !4?w3pSȘ!IJ_ n9ci3vAc4vQ3 | !4?w]`1q] . e1q 1_&z|B!͏3o1&n!q RŹ/MŴ]$4& DaO!$? {{G(eZ~_\kEyVkB)F wu5Jv{l⾨v_t/·o>!=qg~ #eڌŶߋD/,O!$~~@u2m:)YD?7BHqG)2ߋFG?7B\ʬ\YbE&1/)e!@cQʐ\blٲ%@{!Ġ+JK J@!Ġ2Ae '1(e) EN]$Od\~X䈙"_!DF+2L)j1(es&2?_,2.~Ղ"?~T̬R)̨{EG䀻E>vK10>`n'ˇ ޿o{[|d71(eiUJ)s"_|R|.PT+`2u%{Opt fҼi2  ]51/Wsҏ7G[D~?*c>+tN,N).2$U J@jj)s)\O{sD=[ȧdǧ|,>w!2FTNkr׏z4`Rʄd$'ibPUSK9a~锥F#d:2cW:U),c2f;D>dA2].t k}˭;}IK32vRsK׏12zA_T;EepKu;&Le]2Ra̠cPUJ~:U-Y1_{trD˘=ud1Av]䃷|L~8#Kv`cPUJOd ]AS>qjx!_nGJ05enO2-fV OӗA)hW|9L^D߲tB)*NMJ܏')Pp1(e*R漫6ubPU_ i2vմRf+d+dӕjEmt[>A)hWM+e|(>A)hWDrA)hW2$2vE)CrA)hW2$2vU.e7"6"/|"=#Rf2T/'5 {xr%U)>z;܀8H_tiNaLN+m<ۛ} ܦ˺y2?[$rj.9l CuO*eoT9{r[|ԺQy3p~4u%O_XELX+gU0(e/ rBR)sL'r="-uTC'?WD{q%+|gd3`[]/:;_>%JK{_: 2_4׻5pQU#e?W[Jw%^O*KyW.-B̨)%mu:_.cR#qiK(ejħKZʜ@œ0t1ĶdȾEĩg)2EH ,NtD#mӔӖNr+iU׻RЮv=k+e~4tqsD=t xHt"{djU-eJ gDE}R,K9^\#x:bE)hW#U*=]ȇEtǢ2f;Dvn| ;J@jZ)󉓧ʾJ'M /׍KOSpd'LBCSʴ J@<)e|f/y"  ]uC)sUwxC)hW7ӗJ@e `P rE)hW2 ]Q W2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hWP G2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hW2 ]Q W2vy rD)hW2 ]u5JRЮ:: C)hW#(e'J@q7(eJ@A(ejāGP ?2vE)\QՈ(e#J@A(eR+JRЮ(e+J@ꤔA(es7)eJ@A(ej(JRЮ(e+J@A(ejĨ#)eJ@qQ2 ]Q W2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hW2 ]u:R+JRЮ(e+J@2 ]Q W2vE)\Q rE)hW2 ]Q W2vyє2 ]Q W2vyp7 C)hW)e#J@mJRЮF=R+JRЮ(e+J@-JRЮ(e+J@ӗ+J@A(eR+JRЮ: ]u C)hW2 ]Q W2v9k G2vŧ/!W2vE)\Q rE)hWcE)PՈє2 ]uM)P rE)hWM)P rE)hW2 ]Q W2vyQ2 ]Q W2vE)\Q rE)hW2 ]Q W2vE)\Q rE)hWM)PUݔ2 ]qrE)hW\Q rE)hW2 ]q_RЮ(e+J@A(es4 rD)hW2`XӞlHR KZ3P@)_|R ?29pK뮻n@i+e|MZھ#|MiTԫi}?}Jshe2fdh@(eJ:%jJN8!o~R;SE5YuL~(- ?k/iiJfm;妥"wdN9랝<79LZ JxRƍ{ܽO~p]M5c=R&թCUJp7ʥV Nh1SψJfGmF=fh}]Z^{F]2R&LwM2JR} jJߵc'2I-C-e;Jfi|K0ssϜsofPg Y\ad3>!IP( X"wDD(egyw $ߊ2+bD@NYk\n07W ᷐UP DSe%d[K}#}!@XT$yTGAٚ!Ncq wC Y 48<JgY.B]2ccJMEJr?#;DP;O 2#4qP̨[ 0@%gx-K( 0^np(' #Gy̰8+Ӹc\G!ÕOD/b +@neD}6#GJ4B~" `Y0+6K::dܴ Y_,+4`.?fTWOh"AfĨ?V 3vD5ַ3.0<`YS#dw܈h6&Ú A: _; peG^@> HrAʮ Ez7O#o˝+y!|Դ\7"s|$!n#l9gp)o6'@f^8 d6\r!H7Td `* ̆`!X@ X6m`'C(Mvp ܇kF:"Fb8#?D" H1Y 6d7RD!W.҃#O(RQUT5F'Ψ7FT4G 5=֡k-}af9cX8`Bl1Vaa>X76}ĉ8gp}18m~{A+F"X\ xB*a.PFG8Aߝ>;" ໙@L'. & ;!A I,R.ttI#} ˓uɶr"O. O;rJrFrrrrk5](SL(hJ:ee 0"卼tyR-G/PͩԙT1u zzFӼh\Z5<]J!XD\NSᥢl|2c䔌|XJʕN*u) )ӕmÕW+P\bQ)T٣r^ t6}9}/"OjZzHMuPME^-VmZ)n0f32kG&hOj ޫOTRתRXQP4ל9WBDՉn'xO 2׊ZGUkH[G;P[UCK']gi~].Ow?jLof&s sPOK/HO[MoXD?F@V `A4Å5䌜Ҍ67613^a\oD$$ߤ)4Ǵ,lY9j`f^n~pYD2?rR%2ϲƲNJajU`Uor'Lj`iTF׶lrۛv4%v v-wV84;|qtr:vw2tJr eKGWG\ףYep{>d w),L$]ݞz,J^^}^ϼͼӽzyWQ~@j@M`CAA]NSMB 8kǘƈcccgVǾ+뎟(Zf/!/qhM3f:,y{ɬy֜999ǒIqI>YɃl_f g#->KqO)MyꞺ!?3,m{3}FxFUHf\fm9+)$_=/C`!(tl,QC*괊M?{<>̍{l۵~gGgW;Kv~ugwJʲ==y{/4RůBSukkqMj8lyxw-8">I>rǍo?A?Q\ͯOnHh89ds[߬~jk*?vji#g 8zyNo^~b˗.on9sr+':_xաhsltݥcJNs7n\|ڭ[cn}s̻ACeUaGmcQ{_<=Wϛg ၢn{%|5z7Uo6E =zn}?:lϤ[}iHȈ%dIhJ %ܷ7@Pxn'xuYQuه^G]- A |kL٪x:?[wEVv8G? a d ssT2#سdڼop#jƲ|G ͚QZ:n{̉۳㭬_@^~sgE2;K^AvZƦ_mZQ`{1ejGqU5mNq~vb`c1a<JV\й_A.W`{oW 7|fX13K$UKc&XXX~APMBD"մSCt-P>dZIii) `p{c;gdec8' TNQN)--br\v[A?A$-;1#aZ:N9 Ox6Scaa"3DpP(xc{guϐi37lUEEy|?-\_پhmmmame Hĸ?C¹ 3*+P$+q{ūCP\RyXqfMIGf;mp9>p¹/D__rˇm* 3gh텏CCGq)D6\ `ߑc " [CrٳTşB[st;_N[§scP-z?RRSѸa8IHp~ZXsvprb@ NR'gSPX'cވ55JbLX B? D,Rl|7Xq' 쏩1|PdY,[ss 3 fV~*-`~0:i /y1x= w޶^{?,U...Ɛ~oO3gdzQaH>%f/Yk7oclшZ;/_Mo7\u?mRŨ+ފauƘW`h⢵edԶڲ S2eKpx5-r_WճѨG}k/^E"?mZp%bzes$D"mَWH$]{ݺ ZPQӼݛӏB;PT\ ~oU>g(+ tiF\= L֖ѵޟ9]._6lۻ9P(P((b-=ܰfVH$b̙:  .DMITwxRi&g/ %5 &"wp< js}G|<D?@DAgd ڡ EEEcI(0ꕁo ~j4 ;BmuYqq1.}I*:m>>x8h p?(xjVVǟqVe"h$ѹ]k c]=xr^$0b'1VyM6;w+\^vzٿ qlAP -#66 ())Q+'BFLVjUN1r3~ܬzJ$ ٹ1~=՛`|+:"j1G\"AiTv~:$ е};gHL[=[_m}a꓾siټ g#;7W/+A,Cض5>zw,'1\?,Y(?R,iVUO'BX{-+F}8͠AV\!'ffljX1S c2O/޴3"_W>ŠMóy38;:|?}z |j1X#;YR9dZF&U1 z +oܥ7E;C\~݅\H8ګ+ފEhצb'̓s}Gy_Yq1wjJ;m]atů:mQ6o0S@$ WÐ~}2BgvvvCs߇oT-p;1ƘF-L}Q^:Ti5I1t-ߏb-hP>&QZZZ_5̅qv2zvC צܮ n[w`QXXC'N:!dbB;`mi /w7`ذ}:Yq17lzhYc:㭨v8py-룚w\CI5q* ]_hچ@Patů8Q~ѵ~i?Xlؾ . Ծ oAܟp"HuD9 "_S1Jyyy.M"㧯*H)͛aͷn[Y(l,-46tZY}}O~9y: ºEUOvBR(m~~>cO;~?Vzќ3ƞ{L,-aceB  BL&;YdeVmb=JA8p6܃v>ޘ5q<0cuVtt4Oa=?Mc=z'ģtȊK j+⚖Lգm~)$b1F~cu_{r _5B@qq@duG~P(pkɑo/{6y>3{($o+|pm-r7س3c*\gcv2gc1{̸ c1x^P7`o̾7cdeeK0lh xUL1g<[cZYYղMQ[)SOm\b4zӈ1{ވ)rR4iW kH؄B떍ѣT̙W~o W.FNn.lS=UdeeZч|{P^=uoȊk,_w3G6 C &MݿnU-|*m1cu0gc;;ɓ}Uzbݸa|wX, WSѹcGU5݇}^^F..윜7y<0c&?fMj,+)) 8z8d2vIB`gkTY\RQ[p.%T8Ю->:o h\>lڸ1q-t~Q~^l9Nݺ p#())Ao;5ÑtOSY03{2;q5mS&MOeLUVm 2~HH:HA/@Nn.NA.W`|;x94d(ΟGZZ:4hi}vmM24d(^ NǡT.G1-t2$b1c&Iib뭍Wamme?Īb05|lS?!օGs1s44Ľ{illX3>5iG _G^^lllpMdfdFYOXv2`ow( 6I"S'O'_A|b }_ sN0W:9 ݿA(B&~X բ(cť!DB*_pvv¦-nySyTVmd[$ Ap|$$&aѧW[d2,,,ԩhQ[a+amu(z3k_&}v>zEKaɲt|f1ƪ̗na\=1Xh!\6 ֬5iCt&˱;:?,]"ҰAѝ:v%зOo8uݻu}V-[8 2N:ȱc|*ڴjNW`O六6ȱؾ7Dmۆ?D`YYVo޲=B[ΝРRR]nywU:d0:Tcl{fMk#WЬiS8;9a}IZ4 H!"&}kj_oJCGk˳,,,S?IS03lZ}0a1ƞd2?Fqq1&MV [())[5b={ɓxw/?q^,gN>_ӧ1kzJJJM?lD"~}%uYݻA"lڂreTvHb8J`1Ƙj(zpU_XXX/ g-ӿڴnܼ\l{Z38_ǟС J 9/?Ҡ!223=zk ^-0Ede>iOkL-zm-7|ܺ}KÆvc1_!XGthrfMEĦFk3ؽ,Ug Y`䏰z:,X- KWazbbuF_''33 !d{zgǟ6ejw z6W(e6aÆҩ#>x:A1j:"=^|Q 333,;?^_} ҩ3>8LΚ4ƴ*Ob[[@gg{=Ԍ1Ƙ(߿?c-c1>>1cՐJlc1&@`WTaaaQm*cȐ!ppp@zйsglܸ=::nnn]v;1{y "QI<ǔ)SРAHR(**1r}|g o߾޽{M6aӦM?~ѣGѻwo#GЧO:7e Lc1 6 YYY8{,\d,XۙXf f̘Q4~iӧOѣGKKK <<+W=^zyebc1Vy@T=prrU˗.] wwwH$-3L)رG&MРA,[ [lQ+{nth޼95≎FN`aaWWW^Z#'N prrȑ#jT̆=55'N;`gg#6V/dZ WM1vV4>h;!l޼-[9Zh_~Ec󃹹9LŋkciiRի\pcǎ@ իW1b 9RsEPPR)"##Ue:uꄃwin豱qF>ܰaCe7ǔahhٲ)a1Ƙ(*U 8(##RRRhĉDDi&8ˣӧO'mٲE!e W^p""Fȑ#I$ݻ5kF\r {jۉ%{{{ڶmeggә3gˋ:Gǎ㔗Gݣ7|FeT̆ߟ[JIIJMM;wR޽n\\\!}hv ÃLBBhlwSAAQhh(1BofϞݻwm۶|||*շt!@GR˖-Ue֬YCz'Os56bccۛUcKk yWPՆ)ˋN:EyyyOK1ƞw1EUJIty]tQKE׮]*cH<7k׮QϞ=)22yizGs111GbbZQ1v[[[t`ժU+T[eHUԇ~2p\fggm yzzщg}FÇ'"?Ǝ[-,,B---UerssrԾALL 233ADzm{!&&/B%8tfΜ @G"44T5w>[ ۷oLj# W*wgY8TW~d1VTl<==\bb} )$t^₻wxr;}v2۷lj'ܹsg)) Zw)cUe.7n-[RBB\Qe<==i֭TZZlȑd" `nj_7]F!!!j9|0Ӈ)??233i׮]ԫWJM!mJNNz}g뫶|M=Ɛ>ʴƪ]Hm۶U+@gϦL̤;vZ H$*}޼y4l0"z2w~ȑU[fCDn:rssmj,3dlݻ|||T9>>ZlݻӪUUS>|8t}ϧ'NPN4ͦ6LӧOƼݻwf1fS}suQ(h"ruu%HD͛7W%ƔQڳgFMR^^x7ر#I$jڴ)[N̑#G(00lllʊ^z%Iِ;v^{5JdaaAJjh׮]UN$t=CCchFFF'b[X,V-{. 6Ғɓuz<~PK|;#[[[7o2CƺuT}N7nZי3gLJA]왒BÇ'GGG:~x$Ocd><ڒ r3c3V?mc≠ c1d1c1[Vx1cX2oꤝFc1ƪOa1cyIN8X[[ #GDjjZڦDGGSN+V^T=prrˍyÆ hѢѲeKlܸQk<~~~077Z'VVVCkpWWW𕜜 WWW.] wwwH$lsE ooozXc1'0uT,Xp$ BCCUˉH5Fw6[o3g"55;wIJepau2dnݺ7n0*毿6l@FF"##_je/_/YYYr Z믣y戋CNNn޼>K,1?Ƙ͛?_~Aff&6oތ~ [n5bbbpBU7n܈oG>c1س **|-He=|Gs111u;TYj'OFbb"󑐐P 1k,")) ӻ c1XR `u]dZޞ={̴͍.?r YYYK/DF]HkFb<==iݺuje޽KÆ #$???:yZǎ^{R)YXX;RjjQe ݸqnܸqaBE+D"j޼9-Y/+<>ag鈏G\\wcj2ߴiS( dddx1̳gիWC\~gfffܹ3͛ZN"`„ :?O8{,fΜ^{ hٲ%~~q>'1o*CE-d ƞdI&t̞=~,fd>""ް7,YqFIIIU)>ΰD.]pxL:]EEEM6H$prr¨Qm'ND"F eH]e<Tzl2 ϓ&MһO+SUCӲ}vUb)ӊơ!!!!EÆ Ѧ pppAp!cbHÆ Ѽys\]]ѰaCyC=NWz aڴiسgnܸҬY'''McuATT͞=Љ'hCǎ#QLL I&Qvv6͙3ŋ<ɓ$ÃN:EtE2d7xhԨQbcc58}Fl}2$fSե\6uTɡ@m۶ՈmWKԽ{w >.\@EEEIhĈZHnݢ={ZF&ҥK M8Rc84d<ۧƪ1YT C3%Kh]NhᔚJj3ܝ;w~DEE*_v-~I"رˉߟPJJ eff2@׳gO@٨=zx"?P@@FK$cܐM?~ BUS]Y WxWGGGۺt,U~]\?2e "LV7CǪ1 B@rڏ1fۧڵs}gccChҥTPPP>4`+2c @gϞ 7o%%%1cF$󆾾;9sҒ4uڕйs爈̙33Vyi6.\@jj*&Ol2i6.]@ p-P~ze]-ZxyyBPblcb6T 077ט"b궷iЪU+e5j5jHHo*غ'O֯e2.\L>Rq2 iMժ/S>nRƘqo޾}[keiӦA*_~Xf JKK+ 9&T5押 +W 11"gΜ˗۷LcTu~M?Cʕ+5)dH$aooXd)dDJ9n.1u'O "Қ;۶mԩScU¥NTuPݖCnٲ&_yZ'yfZ AAAÇ:{nS7 ۘqd27ٙLQѣ4|prvv&XL51cݻwÊ  Bk$ iܸq&L_NӳJٔAc:uJu R2e ڒT*wyGuldڛ hc1fc1:___>}ZǏ~hҤ _Ud׉wc1fm۶FUgȿ;|2T:#Xq0cƩ פ`رtlmm[oaѢEd1cȑ#1rHfc1'1c1N _u%1s+oQ5sL3f@ ׷'io6`̘1>yQgnn777ZbaԩQDj'O"((Hoa1X%0ƍQZZRlܸ0}ZߐgϪ[bؿ?ut2D|L0˗/ɓyֱDy_`֬YU.c1#s!F) xzz֭[صkÆ _39#G Bܻw5“25kerssakk#--G6X}c?eff)S֯_LGDD ^^^ذaƛu8q" *}պ<** mڴD"FT);EWU?&@rIJJ!Jann.]`Νڧ&M3,--ѥK9sƨ2ʺaaaooo,YD]\uC)nL/ 6T}cVZ_] ,--AСC|De1ꊨ(R# $ 򨬘@oѨQƪ j{.00nݺE9994{l2rNݻwZ… TTTDFQxah]-(( dkkL&K8qQsIANBx" 2RtԩCڶmkTe]&Ml3gŋ!rjtųdxFipo߾bbbH&Qff&۷o*cɝ;w~DEEZ2OD4k,՛'|QQ=]xΟ?O( K<?PpppBii) GGJchBr@BPLǠAH&?={$o>e٧?&""1+O(%%233 yyyySTIovSɼ KRAAID3cO7טGi[ҥK-ZTۨ6mZjuҨQШQ#D"D"4Scl] ˈ2 .DLL#+#1T*uNWFY n2*fS1u۫Z/2`ڴiJׯ֬YRʒ1#4Fvqqy*A(ު5m*ŬUl!~z%X>(ٳ1س+h"<~~-O>Ql߾-֔v?VԥP(pY̛77ƴiӴ+))Axx8 x,XXɓ'#..EEEr Ǝk>5叒͛Ʊc0x`bVj޼9㕊io`…HOO… .???ܹ?B.c/5S-H,'EDD-OHHN:99::RHHŚ₻]zzMBZ.J-0.b1OY@ GGGzU#!!?@ IDATH$}e!ehرvJdeeEmtDDԲeK:ѷLvcƪxd27ٙLRmu=zN$QF4f{n_21_kb1cՌ*hc1cnd1c1Nc1c3c18g1cyVc*cOׯGP^=HR <b'N5.]u;2>:o6`̘1>Tgnn777:G, SNEnn. 1Lϟ?ƍÀxw0w\)fTbRQ۹}6 ~:*Uٳg }v߿ݺuCzz~DŽ |rL<DŽ^cQ...x 3~0w*)ԯ_??^waܸqXv1 Bܻw5RcvTヒYfoZ&77_>ҸL?|e1fFaa!233oooXXXK,\.x#8q" ԾR@ @tt4`޽2y]xddd 44 CiݎD"6lؠu&M3,--ѥK9sFk/ްa>e˖UXV&!220a„Jgccj]6m@" FBjjِaH]eC5}ʢE4h@ mUv222H>/LJڝ)A`Y>W0+;sK&MNsx<[kCׯ> ^|,#ӸIi^{IqqqJʪ'O 7'G8Qy[7r%''oZ3ر# 33ZU둔["''V_^U>lɓ':tp^Z{ @pppr4hKBA!))IQ^X:3f ׯǏ;m,;R֮] P^^^+|;ϝ87]V\"EEEƟ'MdLvZ ݺu'OJ^^رCofr~3\˲DEEڵk%''Gd˖-ƛ\2ܤ6|pɑD7*ɯ8dD=j\'*K|]d|+ݻ Yf\rEvYIY߼ySIPP4kL\b12Y`4;}%""lݺU'~~~-aaa2sL)++3###S%66V6n$ߩS' :ue)Qٱc 2D5j$z^6m*Æ sΙaoҥKM6%$$ 7o,{oooiذƚT,QK.@>sǏ޽{4iT,ÿzs='ϟZNKl1Mp%""Gy?EDDDDDO?EDDDDDuy"""""DDDDD`1'"""""DDDDD`<1'"""""DDDDD`<1'"""""DDDDD 扈<1'"""""DDDDD 扈<1'""""b0ODDDDD 櫉NN^%"?}JDwf0_PP_~[ڴiTNN}qh|~~~puػw/!""~Y 6 <<dž F Zk׮]ׯqbxY6mڄ:;vĖ-[jة-O=`ذa>(3HJJnz=k׮.N벁BauKGM֑_趗.%%%ҥKkJIIdee?.umRNeCpxIOO͕@fΜiLsa裏J~~ 8Pz>|X4ZѪ]""z;vXZ {9"z^ $2h qwwΨGxxm۶ZsM9x4o\5k&W\ii@F>W羪-cZDҸqZ]ϚK[ׅ!9sWzzs2u;k"?y򤸸HDDDEN>I_ iڴgyFȷ~+""۷o3hYm}_'{NȎ;DDo`zŋEy-[L+b5MAA *Njpwicȯ`<17&l>sy,_pwwGhh(VXa'^z ͚5/Frc: .|gt /`\fg~+  00O?մcǎEF先㘾ߕM8w}7d WԇU^^$qx>98z*Ə֭[ 4@m6.YfS~} ׯ_aӦM@qr$$$ٺuٷx43Yph|XJJJ$55UСC ü1fϗ)S={ӮEEEIV[nfZ?JʪmQQ???iJKKW_xU< *K>U3[K\qy;Lh%mɲ 79ۚ cY"y%l *KM?Wu׺lٿ? ** "Hm: C1Ǚ\}fE#)) [nENN˶Ͽ'̦ܺX:w,޲n:)**#GȰaÌi 7 >\rrr$11Q nƙ9s1cǪZZͶ`{*-iժ;wV^{jn< ={Hqq;vLn)S8T &ܸqb{1URgsvDEEڵk%''Gd˖-d$˓_|QO|ҥKM6Ɠ|q˝ぁ+G6Uff ([_"3a󓀀1bC 6n(ڵ3ct`ڵ/qqq/z^:w,V2K׹s*=gVݺo&Ү];/*͉'\v_""7o޽{4lPbcce۶mNia o^ݥ}oP76?.{iҤi?Q:>,>{HC". """"b0ODDDDD 扈<y"""""b0ODDDDD 扈y"""""b0ODDDDD 扈y"""""b0ODDDD`y"""""b0ODDDD`y"""t:t:vݹ Vm>:GEE!**Jj?֭CHHz}w]Jr;-J}͠l0/"Ɨd싪{饗o>ݻVk„ Ço\p;-u<ז`.c./p0OT6m %%Vp$N n`^: .|gt 1K/YfѣQ^^nѶm[xzzm۶HII͛7رcǢQFBDD111?Wˀ2exyyɕ+W_TgֱZ\%W^fp6-Ƴ=je>7n뮻6)9v:Njy[c/vë3U%sKu2w\)**rx*=v8N ʸkyÇ yw$$$D<<Jי3g$>>^4i"4:icG㴪6?(iWuQ=%sKukС<<==o߾h"VYJ-[y`ޡ`GHMMũSЫW/x{{ʣPPP`dZ[SSܪ@<P\\>Xs Ho IDAT|j'xk֬Arr2OckqQ?\Y=_~7|$9RU>jggp(E6mp1TTT_~n;qe˖:v̬>`3v[7htlzuС_ğwե:VbmZ?wč,9s1ݱc,n_F9sӬ]VHnɓ';v251JMM mΟ 7 >\rrr$11͛m"7oެloz-JƳƐٳg˱cdNGVܹlvJWYF\"qqqN'liUC@K/9?(imsM,5(g-%k׮)++-[RUc^>j:Z̋dff }rr=ZGddxzzƍk$WSÇ< V'{m?qKJ6m'˗ך{n ֭|uamץExٿʼnzܹZiظqkNz>W2P.[P:~[|||I&2~xP㴪~ҥxxx]w%IIIN 整KMƪ9Km0oknQZkǎ2diԨziڴ 6LΝ;,ǎ:ϝ%11Qw}=z4-Zdqm܁AiۧO7x:O~GNÞ={Vg"·D8{m ***’%Kf;`͚5;/ALDDɡ`3f ^tѣG D[?3ԝ3#UՉMdʅ]@DDDD`y"""""DDDDD`1'"""""DDDDD`1'"""""DDDDD`<1'"""""DDDDD`<1'"""""DDDDDw`0н{wݺuNsj%NN:uꄩSbNOOOmӦMCiiiʴWٳgo߾ub )))[ ׯ_/`xxx}HOOX___t sAyy4_A!--f壦g6{ǎ|O>Add$Gy۷o׼[Sy8uΞ= 8s N>]!"AZZ^X\v 6mBVV^~*)"V?///Ǽy0s:1fΜsj۬rػw/rrr⩧XK.aɒ%X~=-lǎ Ν;۰|x֪Qs7>#,\/^DFFׯ>}8b@F-o̚5K{9[;Y?/g϶&''GnʬlӦM)uIDDl޼YWł dԨQf/_fΝ;' 4pZtiݺCmתOg$5ǎ|6l(gϞ5{ުqEDDT9sF+==]̮'$$`իW#>> ƍ bȑ5Kpe$&&A Ļk򹽟ѕu#F`ݺu6Ӕi_6l` ">>/_6I7w\j hժIߩgƍҥ <==EYWBB6lp^̙3Gn͚5x-W[\]]QQQsڵkG~~>~Zx֪Ύcرύ7j׫>S2?A׮]鉖-[bٲeQz ]v@6mrJ&&.]¦MpElw}ӦMC^^P~}$%%Y,駟?ӧO#33'O4~'t5ekYYY?+++CVVy9c<={Z<993f˗qac&'ŋcʕEZZ>-|Wx'|2 ̛7|Yz8#G>=܃~!==ݡ/LGExx%%%8rFDܹ111pqqALL&5x֪jugذa4hl/J疍7bx뭷 {Ucp۶m:u*/^Wbʕx75눈̖و?^7n,/O˖-tF,m{ quu5ISժU+?_rrrna!&K^mff֭&Kw-7[ԯ_?z]rdΖ3fHxxʈ#dUnܸa#Frȑ#e""2|yZf,Gx֪JQzƍ2|ҥxxxHd޼yrMPIۻw.c0&&Flb믿vx^%"".u`~߾}@viv"z7NZj%ƓNxp'J%eY6??_ׯo1Miigq]VI`Yy2K^^繹*///9Y6kl2qssʕ+_6%%%zjCg˖-%33SDD233%88ءN JƳVuVcGM}モh0a}^^^rUMy{`@@|JDD mzX\bSO6mBnn)b&M8ڲ Ю];}裏_:___[\kR|xY|VN٘1c1zh<#xp=zTqzcɘ2e={gΜAǎбcG8w\x֪jv 111Xf V\YtX<9:Q;wļyOOO~9ZVjj* d7t288Nrx UO׮]q%Gݼy,SвeK뜒]]vصk&MK.!55>|㑚j+ln7vXݻ.\P5l7U+gh>%L:R3s﫥:`߾}frMͫDDtw͛uVtR+3oX'>qDiѢz +Wڭw}':uR<Ƃ$++$cǎI˖-U;htUQ϶m$..Nׯ/&3f̐R|֭['K?Vc055UBBBDK֭eբW^*}""3őt:%:hٲ%֯_]68pٳgV~"_E~/v…׿}sL"ٳgUow^m̭둜?I&aĉ6yO䘸8ܹׯ_Ǚ3g0~x9ҡ.]<<smܸ'O/-Z`ȑx饗!""_癄 #Hs\fCDDDD``~ӦMС<==ѩS'l۶hر#lby'\p7N5Ϯ]Я_; 1֭CHHz>P6jwO>fmذ@xx86lPJѪO_&""|ff& mʕ+ q: ţ>cǎYL_^^!CҥK>|8ƍy&OW^yx&L@vv6> z%ijK 'N[oO?a&y駟T$ʪno&]_|<9… Q^^ccƌAqq1.\Xi]eeeX`/݋Ν;cNΝ;{ëvk"""VdzƎrǩ|*u w>3믜鉈w 3Ν;i,]Ѷm[xzzm۶HII͛7-n / 88nnn&t>NCHHFZkov՘?>n:xyyh "44 Ŋ+5n-[wPP7n>С\|٬Zg%i`"""_XU^^$qU" Xwo俆RVe]zǏG֭ fا0DDDt1RVV&""@iU6m$d̘1/SL2{lӧ@x .-""'O6櫆vիWϬ.'N`?Z?.W\ [n餰$k׮NzHU} "IMM2tPm+1k.Һukٽ{ˑ#Gּ~Ҿas<dzDž|*o߾@6m$+7o6_Z} ѣvgΜQJOO`EHEETTTquuUSŋED$77WHhh~g///trYyGl޼YUXkY] /zj a=9rDDD~G 111""/ dƌ@ˁƍ@.̓y%cW^KUԩ~vt6lPȟis}bP`͚58z(<<DD@eϒQFk SЫW/_.ϟ7|`M>gee5kI0ox'f$''?Dqq1ץi۫fU)5jdzf5ox6|*+-- ~!OOO|7HJJȑ#O A/n`GFDDӸLNر# YUhӦ ; OucVףO>L:b QWynxLvv63ڡC0lW_AxxR3ǝ.%c0ng@pqRY&|ĉ*peߐj*GMYz$%%a֭Uׯw>51LDDTܺfȑ#4h-[tAHZZ\~]^z%k׮ҭ[79yɎ;9s1cTA.wwwuw^YYYswƚyk 7>\rrr$11X] yEDd֬Y@v.ݻwfrYf^3,"{b9v >,VZ ٹsCei}k&dΜ9f>|l<ɏ?䣦,[dڵ#eeee QQQNۧo)Sp!&ݶkMy7JUM>߿tE<<<䮻$ڵk%22R<==[bcceƍ@ Cݥ}f7YK 8މ'hW~9ҥKM6 h&5J\]]7^pA\]]gQUǏK޽G4i"ǏwZ0t߿__ztYVZeq|kNzC㹴TyFɄ ggg/Tׯ0qwwvɗ_~P*GiYرC "5^/M6aÆɹs眶O;w,...ri! ubY޽;N87_}]$''cXhQ1}tx1}tCNիW###GmGݑtvzgϞU޽{au֮]w}5ְ",Y0x5k8ȩRRRP^=L4k___3f(mڴW_}U񁇇ƌ>}xHl͚5õkؾ};;\DDDDD 扈<1'""""b0ODDDDD 扈<y"""""b0ODDDDD 扈<y"""""b0ODDDDD 扈y"""""b0ODDDDD 扈y"""""b0ODDDDt:ݻw7IЭ[7t:V*t:t:SN:u* -tD۶m1m4VL{={6['B߾}Idh{fuEN0g啖N4mJLL9&o-KO>?yl߾]UYJUZׯ_Fpp0<<<о}{;j-K(_Z1Vc-OkuW^,Z"jTz5g_ulͫ_~%ڷoo3֯_o5kPKj1-r\l&egge˖U[iذ!._l.]B```<h5'˖-3nɒ%x衇jO.$00PΜ9#"" qoضH~';vtU-_VV&'N7n[VV&M4J]pAiҤ9u)QZZ*2m4t{'zb eҳgO?iO?-aaa2j(mi޼:uJQSJTTdddHQQ?~\x )K,1yoSOiZ=zݻ-~k.ٳg<h5'#4|<3ơVcJڥf_Ԗbٲe2l0qs<쳲l2-]6 DD "|򉈈,\P~iW`~ǎr}HΝefݰaDEE4lPF!W^ٗ.] ʼyL>7Wm322{6Ӝ?^|}}?s2gwҳgO СCҥK&̙#%88ؤaCZh!~z͙3GFp;u$)))r* hٻw:R~}Ξ=+rMiذ;w,k׮IӦM?p$/ϟ@BI=zȞ={41_gKcׯ_oooUsc.Jwr0*mʉ'L?~\ڵkjjE<]JEm:.N:%s{͚5ӧOkZ9sȫ*""0^\{Wdܹ\՜ "/HPBBBU 111t6mڄ/W^fKs}]L6 yyyBdqO?~OFff&N|AAAL%Nmg\@ژp=m޼9~*Ǫz,צUVpqq1?y$i9aaa8q ## 4@FFĉ -PDGGcHHH@ӦMk\ʼq /(撟/~~~9Yio˲7/WVLi}e_rrrna!GDDȶmLlݺd鎒|e&i6m$3ו+W.!Pl1c1Bo߮]]]͛61#FrF) ,4f3''G5k&Nr ?tE<<5uʼe?+c\9S2g*9v^?; u|5]\\L%7oq%v)x'/^,O>_SN__yEDcǎ,k۹@9`ѢE@֭[jFDd߾}@vi!W^qIVhNg/\RRm|VZZ*?ٽy*A͓M+/3<77WUeիҬY3ʬhвrJW(ZJJJd'2٦e˖)""l5d"y\; &2XׂyK~5j[0oxy{{Kǎef_d͙Jֹll1-EEE&q%v)㏍qYt JAA˅ C_. 6Zy.jN0|a _|Q"""F0o  #FcǎvmvtJʲPcW4o^Eɓ'eҾ}{WiW=|kN/ׯ_}I۶meʕo ),,\/ov)))U~ٳ-ڵk"o\tIdֵ֭>3N=S|ˈ#s i۶S!Cȑ#GD233o߾&:JddL2E)((0{#jqIi[_[XuOrr 6LD~WILLdekTr8 dUG.^u"ҥKxμ_ 6lHz$22RxIVVǎ-[gСNm&qqqR~}01c:.J#'J-DKXXF5mze%'ukUg{c:TO.mڴOOOiӦL>ݬ]J֜Q:)\PW]%c?mۊ^vڙfbް7)i}QDžK,;<ګ.<}?֞ z!V2nŊy5 I`L6mZglFFF T7-X@<==M~Xe۝̻~둜W_}NgҤI8q"zm;ҥKs αʶWWL.u폠NΞ=z{W扈(DDDDD 扈< O+2ӧ-[fɒ%KC__~@푞n%,Q/D]~Y,P\h$no:η>ufz:JSޱex:uԩSQXX8U2*=Y(m۶ŴiPZZ ۷/<==w^gSO=T(q!?K,AAA/^1cয়~2Ig>}AxQ^^n+ .ڧ.)J)U]aa!&LxPRRi>5hX:,AZZ^Xd~7=ثhQ/]M6!++ /2Gjj*~sڲes"y{vΝ;/Y{FǎUG!<<ӦMC&Md,Yv… #::ѣ&M 7nfϞ 6l+VqqqXbESgAw> 4yyygbƌ^^^ԩϟ/ۭ z=BBBpBYpޝGEuk )FA"Nq@"U8܄[AԘ^&ƄVcmLlBP NFW;8FYdP,꣬*֪>{So>m#88X&Ipp0֯_6mZG{ `͚5OQZZ?W;h_&X9rڶ9sFmܹs_~AWеkW)PP(p) DnnZ;w pwwǮ]4򌋋SF~~Augݧ{Ә!"":uB۶ma޽$~znnnظqAlK_W\̛7nnnAV0f$$$h ]Zcxױ~3u3}VVVR3f̀+>#G}WWW?L***Jgd򫛷zKdŊtA LS[>ڮ/)--UC8ʕ+3Jj;666Vt"ǎbIOO9sԞ~AJJJΝ;2k,>}*ͱcǤ[n4)))g@@?~\JKK*ӦMӫ_HEE ٴi uSS+"""rYСQODdǎ)RRR"?xxxݻng]^Wyt ]<|pYnܽ{W*++%77W'&5?m/,,ʪuU<v.oʕ+2a1&"#mڴ۷K6m$''z{lH[ffޯ(k{=/Zp]hB?~̂y]U333yڶ'OF}pkvQ]&""#FH0:n-!!A dp;WB2˗ǏEz]64!>5_nnnr=@F/F uŋ :88."7}̋ɺuL[[[K^^Q.uwrr|ji$$$DJP( \?}jaa!""ҲeK)))b~뗟vSv֧.eR.!!!qFIIIiv|aaj[js3_}-Cyy\|YƍWg9>Ed`ޠ9}gG;={ҥKuкҲQ$u wQvtYkŋo`MRl^{ EEEG~~ ҄.ۧIS'`5Ƭ!}+W"==o&q 9/nV횞///oNh [nŁ~Ӆ_D ׮]e˖AP`- DddO,i׮ m۶XC?ᅦ;vѣM۷/N:LޫW/={Vm[jjIIIذaaeejL>5O۷ol[[[>iԫ{z>u<ХٳgcժUuV&ĤI >>,--t /"#wÇO>jSnzS^^. _ݻ'EEE矋RTu̙3%==]$aaa2ܹsҥK\Μ9#;w~s]~]<==k׮ܹsM2m)!!AmQjj[-\R%??_bbbͭ9^]Yim%<<\Dؙ3g-[h]w}v򒔔)))gϊڵKv֧uGХCoFRrrrd2tP=<B222$((Hf͚d<׺46L ""~OEI.]DTڇWyy^ZJeR^^FX+"w߉(JX-iӦK/ ܹl۶M|tHFFF(J֭ٳGWvvL4IZ|}}M:ץOYOk(;w}BQ*OEͥk׮/>u<.eNJJɓ'XYYJnnFއWWW1333{\Zz)+V"纮g C}e6fW}oY,,,Uj|ҭ[7Fd`^%z,=n߾cڵkl i?}􁹹9ϯ͛7wٳgѷo_68$++Kc 3OOƍCRRJJJPaا:ٶm&N3f2"z.?3;󤳸8X׮]C.]%K+:2c6>5j푓7=ŋ1i$xzzĉqƍf]ɧս{w꫸r:u*~̚5 !!!F-Ͽ/L2EIIIoV7x`{۷#"̟>}oRR*ڶ}7􄕕<=='Oh=n޼ypuuZ>BP{B^^NHglڴ NNNؿ?gΜC {@ߪk]v՚ ڵkChh(ukkk8::bMÊB^`aagggL>u^szFq & 8p W6\;w.Ѯ]DUU=ZXc̘c>1ci TUU'(fkk+BDD۫R̟?_ gi=_nݺ%EEErJ͛7 +VGmjٲFY.ZHLfy\\\T屵;ڰ/f̘!ߗӧ IHH^zI <|P-bQ(2fyKyyÇU1uTp႔IddiӦZ7]ꯍ.ӢT*[nry/\j}Sk3tP &cӐ2ƌݧgϞ2l0!""jLzD-733RUU%""UUU@ZhW0?|p w| ݻwz˗V*??_EPHVV@>WV/333T$//$U<]tZ}pذa@~g駟ҥK5k$--MҥKEDe˖@֯_/FkǏ iݺуy]#tS =W>}_M6ͧ!eO߿/ٙ"DD,yi6SJ?~666z|2}P(pttܺuKk(yIDATݻkɓ'CDK.Rﹹkܹ4h vZ6fyTiȔڰ/]t /ӑ sss;wN8o߾ۂK'''KغuMuӧC077W)<.ܹsC\ CM6L1Vk3vjJ-`K.jUmڴ+R@QQ #" Vi3gy&FUM6ᣏ>|Թsgnڰ.zzz:'Ν;e;VVV?s"88X͞= ïG5z;3}Ǽ1888 M6L1Vk3vVmIDDԬaÆ8PE z GB6?qTUUaرzQ[4*J=#GDYYVZ5HhHW[y|}}OycF{G#/^ ;vL]ΝJ3tPHEE9rDСC*!CDGGeܸq 38^,!?/^(Ccq?^ĉUۮ_.ãAv! .m]U7|Μ9ҢE բœiѢT9yL:Uڴi#JR:t 3gΔl{U [[[i߾,uȸqAJWvޭu yyyR4h̗G6m… fddڗ.CX}e%<ܐz:ƌ٧}333u?EY󊨨(GaȐ!~:0jԨFƍz _~e&cXr%WvQaϞ=HMMQT 2AAAbQd: 111C~bSLi􆎎L>]xx8Zle˖1|r!<}j*<|PkB+++xzz?DyyyY_?3b 7JXf""""yy&uVعs'24"b#==K.m9Eذa֮],ڵk~zTVV\>=I ƫL񆲶F>}i& 87o֚NT7oVѹsg4N:s9П/!DDD`^ӱg={qP\\|}}aii ggg#??_#B@nn.ggglܸQm}6t=WM:_g2accc]uO:???UK~znnnjmO>qqq0`/RkOX /+ݻ۾};`ii www|j㤶1X}y1_~A||<޽#FhqF|(((@zz:Zjsj=o_~nŋq >]msj^^^HOO׺x1n85s0|Za͚5Ņ `aaP;w⫯®];woꋖ=zw}طo6lؠaÐfpw^t cǎETTA_=?TX]|"""j6oHhhkN͛6booDDDH}˿si;ҢE 4O޽{b] 666q:v֮{Ɲ;wԎM`u/iݺ5nݺQwGGGUAԉت@dϙ>>>A6mM{Mt:cϞ=pFe˖W_^Ckkjݺ5rssuyxߤ5Uz~aÆ (((@AAۇ0Nsŋ EZZ,X5]ee%n޼.8p Μ9c ,@HHRSSC 44Tmq.V\3f -- (((̙34heޱcOñc0sLyxTXZZ,\P-M@@/^ܠ/_Ó'OxU ""CغfggˤIQWN>XԱZV9W1ҳgOYbz. quu0t\{aŪ.ҬO?T\\\\v*-lˆڶmxxxR777پ}y޽+SN֭[?ul5ƪ:tH\]]̌ay.%X]všCJKKĉUz'UU(}Z:Z SLW_}fx{{… Ѷm[899OSl*e6>Z|99(**Bll,rsscرW6h|[N޽++퓀yIҥK[6%]رcҭ[7U3 @?.r} iӦY+WƩ>}vAquuh""""cTU3]TT4(6p@ :X4h^it)Oǎڵk""2bc ">i&m2vXrw8;;Uf]noo//_ylٲE^yʭK׆~~~r4ǎw\}/_.SNwyGfϞͫ5z0 RϜgBo^c#233ѪU+նAFXZZ_E˖-agg{AD`gg:Xk}lllp tQ-??{Ɲ;wT娨R|uY1h nnn>>}8uPUUڵS///^E ,XÇHIIAhh(BCCJS3ݷozHLLT jO8/ BBB\~oZ+WbƌHKKCii) pA?XWu/"##ǏݻعsƝÇ<ץ y ԩSx!;逸ׯ6l؀`߾} SKn:̛7QQQssϜsofPg Y\ad3>!IP( X"wDD(egyw $ߊ2+bD@NYk\n07W ᷐UP DSe%d[K}#}!@XT$yTGAٚ!Ncq wC Y 48<JgY.B]2ccJMEJr?#;DP;O 2#4qP̨[ 0@%gx-K( 0^np(' #Gy̰8+Ӹc\G!ÕOD/b +@neD}6#GJ4B~" `Y0+6K::dܴ Y_,+4`.?fTWOh"AfĨ?V 3vD5ַ3.0<`YS#dw܈h6&Ú A: _; peG^@> HrAʮ Ez7O#o˝+y!|Դ\7"s|$!n#l9gp)o6'@f^8 d6\r!H7Td `* ̆`!X@ X6m`'C(Mvp ܇kF:"Fb8#?D" H1Y 6d7RD!W.҃#O(RQUT5F'Ψ7FT4G 5=֡k-}af9cX8`Bl1Vaa>X76}ĉ8gp}18m~{A+F"X\ xB*a.PFG8Aߝ>;" ໙@L'. & ;!A I,R.ttI#} ˓uɶr"O. O;rJrFrrrrk5](SL(hJ:ee 0"卼tyR-G/PͩԙT1u zzFӼh\Z5<]J!XD\NSᥢl|2c䔌|XJʕN*u) )ӕmÕW+P\bQ)T٣r^ t6}9}/"OjZzHMuPME^-VmZ)n0f32kG&hOj ޫOTRתRXQP4ל9WBDՉn'xO 2׊ZGUkH[G;P[UCK']gi~].Ow?jLof&s sPOK/HO[MoXD?F@V `A4Å5䌜Ҍ67613^a\oD$$ߤ)4Ǵ,lY9j`f^n~pYD2?rR%2ϲƲNJajU`Uor'Lj`iTF׶lrۛv4%v v-wV84;|qtr:vw2tJr eKGWG\ףYep{>d w),L$]ݞz,J^^}^ϼͼӽzyWQ~@j@M`CAA]NSMB 8kǘƈcccgVǾ+뎟(Zf/!/qhM3f:,y{ɬy֜999ǒIqI>YɃl_f g#->KqO)MyꞺ!?3,m{3}FxFUHf\fm9+)$_=/C`!(tl,QC*괊M?{<>̍{l۵~gGgW;Kv~ugwJʲ==y{/4RůBSukkqMj8lyxw-8">I>rǍo?A?Q\ͯOnHh89ds[߬~jk*?vji#g 8zyNo^~b˗.on9sr+':_xաhsltݥcJNs7n\|ڭ[cn}s̻ACeUaGmcQ{_<=Wϛg ၢn{%|5z7Uo6E =zn}?:lϤ[}iHȈ%dIhJ %ֲbm S$]KkdfDҵ4$]KQxO_^ xjϝ8{e:TZS\R Чgw4ؗ753_x{yJzeݦe>\C`$|w0 g8pD6OֻܞT:]6F}lZBUi1Q}4eTV.d2Y.+ (J˥뚗-h4ն @&[ki>.<񶬟_6~N/J). @RY7ճB@r9JeUGA#lڍֱ#?r9OƖ!=3 ~>^1!njhwyĢն ?Ǐšp5%zIJŏa}lk6=bػ-Iԑ1ؼ7Ȁ#ztE B/.Fi *EqW(,*ƍlt ?a>:[ކpJ"i72R?j[L_&OrJܑS1awEVPυ{,K}˫[_ 9M۶FV1g-.\^>~, _/ORŇR駵kVVt'a4O  K?JդD$IBr g*{b~?sS˵ppPɇ!_l؈ч\xExEԯ/pE"vؾ}noT89G;z="L\Lj)gSxoW0 x1e"[Wѣs'Dnن{bt QEZh akWFYXguz=v< _o/ ߷ڲTY1УKgxh4[o-f.S^_k1>w?Zm ~7cq*<0{&|xJ%|]ly|CT*ذ'x5RiiiGkյ3^~zqE?C^^~z1zusĘ$qh0l@?F# \#1:l|U' #]/aOۑWPQCL&L&ndfATw.bF*SPT8z:%eBbz<L=ZJJJg,oCѥ>x%\IN#ر}1{D6^웸gb8Ե9::B2&xac89:# $Cm~o-fCX{c=M cgb52EZ-r $ ˈ{Ǒ[~Ə;~8Z=ݹ'RGtQ1k,}DZY??5 އ뿅Z0Ɔ `hp6Dy$$`¨)CCb5|{(--ïQ^nAwؙXQZV/OL{l BĖᫍ=vAo}?:A4zLVP==uF S&Z@4tC_/:9kerY+z ~ꊋW|/U߷G7/w?6#߷1Æ >1OƥJGYwjt޽P*[{۶mcbLDmKJKme'Ga2Z' ''SH[B@&aXV 텿 DԬmƩD!5$_&v;N"3&trzikt{OM?mފ[URT7kߧED&Fd2DLfL\&9jcʸ섄L&tc[Q%$NDmQZV[wNAнs'iшr~"MZh0~bc"""""""""111c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&V9z elD6~6/#""mSz,yjS]wKl|z_ˑ}3EX˵7L݃᧟i"??|Λ^ĉZ<Ͳ٦*Q[]ۣ=ػ]=QȰyYK)>@p^-VHͲ) ɯZ,[XVVn/!?ƌn1>FVw\WWW=w:=Ӧ۾{q @Zz:zylFrGGc[nDDDw|bwkϷ֐u`ײ1* )->[1阳xoWϞI@Aaaĸ>NǺ5AǐZ˱uط? :aÆ?-[TR_^ ={eI)XۖC jr5zH8xВ !p :-XPg w?nơG{Zȣgyy#rZ59!AAسwziu4Ïp1O-^"`άص{C⋯'QRZ!՗<hOd2:`Ϡ_߾-Ҧk]1cO@Tb(,*B0MxbB̘60-bLg ;&_mkܟ1&G0=j$3PT쭉m%ƕH7_ Glu_/^ggg|ɿߖ.[EjB{k^G``ҮcqcFcݚ`Ob߮v pƛ(.. \A^n9昍3\|xzx )9y8|(L&r9FBh^vIgK#ǎ91kth4!C0ktb篿-?BP@?^xݕxBiIws`QoO?[iuGGǗ_E{ϷcDZߟbphuU:˞{~ܸ ~o[cjo:u:xއ&"ל+ehm?wS_ڵ"f4e,[{#a̺gDGcάس?.š_>8}٭zgGDnڄ/;Fq\2Fddf"⸅ s"~;hutq=3,W(F_kc)MWOScHkqߜ?__|:d߼ࠠ:;s4K}#fރw[{yUsM>{FΝ:ṧS-Ko$QqcɁ^S>߬V99(//GΝ[5* ƌF4a<=蘅a=3p!m ƹ >ʦV1}dL< qYFZ-̇oak4\7=Jn!DK{_¬$XT-mq^ܼ<&"ۢ=2ٰfd2RRЫGɯ3v8~<^+xyy6lܘbW|ee:t exU APx{{5KLe2fNYbx{{5XTw3Oa1PU4c}xyyYmS'MkĶ>34*N-)9j ^^ ""jnnkנh0z(,m8y YYHNIϢbX#ka"9deg؉V8rZ-t:ؿ__wZs=)1Fh^x1nhd2EE>n]z 1gaէa)Z- ?yqz׹SGbΞC~cZMKPlm-Nu-UhZ$&%ハ?sfW[NDD\ex4. 9]1rСCt#G >k^٣;'y\/h%ݫ˲nwW +^}Ŧz?~xu,|X|gX35 ܅qcL&My&0l`l)d22;xJGҸ\.[_ǧ 6d(^Z>[KKim-ũ0eD<<DD"dbԩnHDDԜv^$""""11&""""d/Nق#DDDDDLY( 33 """"&ơRRRh?KDDDDBFsmYtppp/\]]jl# Ngb޼yB|^WuPxSۋI&᧟~B^^pIy;GFdd$QXX'Ob…:3i$8qⶊCjۓ <<oWhV׌3bǥx'ƈ*,*Brj*JJKa4PRZT^922RsKCVǏW_}U 7773^oYG!RSSE׮]jYm!ؿ3fptt~M9xx衇DPPPբO>b׮]7ߴLUmKCTSScs)˞1yd![켳Vv~Nvkc|!HNN26F$=\1b/$}B^bxwuX!N:%Ǝ+EPPX~og1qD(|||G}$6mdv~a'F)ŨQD||x+VO?ѯWTbb>F O6mpssC/_'O-{-婯f)))bʔ)E[YIgC:L"\bYgŋPal->R.|9s#FVPh%ӦM'OB1c ..]Tm˗/[8;;#F81m4c#m4^/JR{WٳǦ|H1k"S) CBU<EZZ%n8,,s"++׹sZŴiıcǚٳ IDATgDFRٙqd8::Z<՞{Ď;Zen-婯^g϶\gku_dž娨(1}jL26P߰\)u6|<ֶPh%Fh4jT[gԩ{TTTccm4^O>M+cハvWWzտ? /4kbRݎXjz(--$G&ɦ wwj=<7|A/r1sL|~bSh41x`o>_/Nȑ#bBPZ6i${n&3gػwo|'>>^̛7zNϞ=k݆QJyYKU6mZ/߅soH=K[3f/0._\k]mv(=KJqe1j(qx5kM绔az:tH,\PtQ(J(z-q!W[nc|9DĆ DNN(**ǎϯDشiSjxWDBB(-- W^jqHHDnn())b6'2L,[L$''r$,Yb/Hƌ#~'/Źss='Jɘ/n-_:tx0Lu.0aطo(**ZVou~۽ԹR!hLsN:N{QGĹ}Iَ7 xŕ+WļyP~sYjRLE˗/ ^/^*,XPm][P;l=KM-Z$^,|6UqƉ^RqUG ___W[mc|R,22R̟?Q󞈨mڿ?/_f~Vt邝;wW^mZw!9!RRR,?{NÇdn?s6Y_rJ>>Xj֮]Dt3DDu[z5>#dggc׮]8|0{=6c""+mۆm۶1wN bb }r""""q*c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ1Q#(+XML+p #FDDDD%11&""""w p ӺZ&emOX7 ?r@AI9~:qk&1DDDDt{&\-W3q50;,F8-q0"1DDDDt{&5G+ 3- """"F`ˁsz \ǯ3DDDDn)-6ZhBjwsTq{u[-?ADDDDublmI։1GO9ZLDDDDLb""""sU]g;0"DDDDtG3DDDDDLTJ """;G7ޒob6ljrؔ)%:#vdBj>J swAѝG ~Sog"";>1^7 ޮj(()GTlrX4MlgNZ=bb\G R5JV;DDDԌ Df㽭q[0'"ٴK7q# Dh iW ݡ1 3-@hpr|&zx:17b#kw|}#$y;U5 -IjIKݩ7K $ej7a@'񩹟Ok9% rCbV1&#zz[ IyЕ1' ܶ{:1{e"PZ.;<.]%UCY/R= w^-U3ט \L+@A* 1/zupeGDDdxvUc^X) YzMS)2 ޮj\J+ĦCm'E?j*2|_KTl:{ۼ/ßu/dՙ[ԝ绮Y&uE# qMqԕRiI3z {>#zz[/ciD/l>vGs>6 xhl'kp&)S<޹YU)۹wD0dJF1_prP6ի%,^룒^'uELH"*616ߕbф.7GQaA6%/7TJE{>0i?4*%y8SkࠒcPϊVר}#墆Jl׎37`4 .~P*щ]~lWG_Zk˫3?5JoNN\ɵL^P*d|,n7[WG%愙Q٨zD+%[ .$ YѤR4eZ)GY *KQb6X_k{N sK&!,l94^n:97^U Tm4jTԻEzʓWϧґEqr Jtf=3'N%"!ݼ]z!&9[O\/o3t^8mq3uw%+._8PpP5˶nCKDLAb3vȞP*dxq9V7 IeN JjNBdk^"$e1Օ֎tw5e@O F^ieHQKMNe-W'zԞ]M1:V콐"\4JozDK!aT/<1+ޘ3'R j!""jxLx\2PTZ^k s0::鍸Q$ڴ/{mG˰u$gia0YPȃ)ڞWET{kLh WUk /G@LR~e -3`Z/)-cϹ,e2,2|rLK^-g)d{ΥC3@QHYjS)4*?J'PnrQgoW2k,zryD6MvU973݉LXhe9av2_z2WrUIwġh^SkÃݑkH U3otGp6EBR.Z/)|,  }B}{᱉]mWKYJf ġHJF8k ^ Ydd?>#q1DDD[W^^},>|rLVcLm/3DDDc"""""&DDDDDLkYW3| NDDDDm_[7 ޮj1rDf!HEX}ݮ ԁ:96 5rK FaAV_s5W3-\u""""j1 3-DDDDt%[_\, lNo(2l=~9ZLDDDDsk#vsT;DDDD4 GHb""""ccps-&"""G,+r1c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ 'W3|JeKipR!""""jmʆV:0vo]PPR,hB%_(Ռbt pA M{[+`dyuMb\s 2߲[[!""""jq]u9B.mZ-:hq9nZS$CDDDDԖ9blmlpR!""""jb"""";&1:ZLDDDDt['-&""";>1h111GUvm֝!""";! """"bbLDDDDĘ1-&Ka m)AtQ6xFJ!zb|??vqhtRyΧS-dRo2m%nm=oQwepR_GwL8Z%1^7 ޮj(()GTlrX4x@h T:r# OCFYQHi:nĭ%?J?&tx`tGv`ED BTl6X%z"bXP Qb@OũVOβ@[w\6ƶ(2僟ObZ!Z+1d[pu4P'Q}V|m9LBT밎'bLƤ˲/fN슾!nV$/Zk_:EI`4ÑZ)ஞuxB.DVOg5FؾWDgį1VT :9cL_*9f*OzWNÞs.AVG Fiu1#3RqG|6V>8r=5oD0B|S8r9r }CpR#%>Rn87E˸[Ã1:1X?V_'Ev6IZ &trĄ~Crg}vSD 7@h^FRf1!)SkyeqrwĜ x,:m'OG%#>Oꊞ\7ETlMo*Oz[KT.ࡱR#%>Rn8h8>!&)C}Wd[Y2|x8ؤvDv;N߰$ƶڳYy*e_:OUw"j{lƢ ]1,n* Âk s0ʨ}#墆J,9 %7w{zí`nRſ}l*+y5uVghT 8Z&)g`jBnRT08%(n[J{< *9uH&ueG.L7"r.+>RcdD߳z:avحilzB#9K<ym}ݎ37`4 .~P*щ]u;^Rg[m%CD8b\קvJ ޮ6(չCW_jY J9唠LoDZN J9Tb]V|syo|NAbur;c@' e9U)T:3(.3$̗oKt6۸^7'UYo.U;uWB9(\W|^i8Ww&lr*?HQ8u51I_Bfs_wf ]{}KJlyZ߾ZͷDy$hʛR!C@W^+7a0 E3q N z vB@Ħ"%["ħ!)"` 39FR!Ëϡ-wRl$)o-lnhVrF/q&)ϒ8u5'"HP+׶[HIyJDSa<ͣe7 G<'|YEePQC}UUXQy8ԂV)i9׏F@fA}U~ hM6Z^[dMRlK|GCY1m̞`[lO}Ԗ"joei,_K*ǽ^Ӷ扈Ċy.dB3`oŗy&>%#͡m1yЖ,ުP1YCވjOeO'\J>:0_4wR):T-Z!e8}:~lr>e^]ۋIʷ:bLy5qٖH)OS,=2Q\fY{KmO%>ӖsUF܉{ܺ;B`ۿ8}P r6,- F2 y0Y{C1{m({B0s>+6EFw5JB#n"ΪZ9uTz@ EVg^Tt|Vn <V9cp GP7YஞgHnH1otGp6EBR.?MæCrL:{X5|$|w ԞV3',N_ZFl.%ζGJy[GJbd/o,xB.Gl{KmO%>Ӗs6#Āwx{ v/nE w=OM_f`D &xh,_2qoW?f󴭵y"Ydd?>#ANiu;2 uߍ a@莓r ؋V߷Çb j6F"3 rbULۘU1""j! jz!` 2ˠQ)0f ^pJ C}г~}1]<0 G6{_NũDDDDDL?~4x71:p]-d{s;-DDt'k&Uq7V/()GTlrX4] W mYIўW{l2ۻm BTl6X%z"bXIm>!'Ɛn1`YYd*w IDAT:=2]F@@ MEn4$壬܄@O ' s>yzx1i?u,/kL.B~*)Zs)lNS^׈XcFɌ&p:1jΟ{ZN BܐU } 3vޖutRtF {GC!IO탸Bkadc~24tڪ2OƈNȞEDDm01z:]X:VlŲ9BnT xhl'kp&)S<޹"}}p.%SP* VMR1']T:*-:>*Ex|RW ,-b,IB$Gve;M#s0'ciޖ 8g'|&F_҈^|:C}|2iZw8;(B6v֖wܥ^mUJ+<:"*6N~~v=]/""j<,Â91,QT0yT0Fqd8ų"Y9 %7a9w+I t0 Gnxrr7ij䕼j߿ُ{G_Zk˫3FO\mt| /5TrLf|KU)VyhT K[<-ُR/""j>MД9yz|*Z`P3j@(̗/+ye75|~e 7$c twƀN r.ѶvZw{-չfXruFOE9*˓[ot|ZNh-V7yj~L[^DDF㦈64Ӝ0^+̀oX]7˼nLRՑ)4Ċ.dB3`oŗ&O'\J>:Պ7 WśՌmN})u0_>dwk&iH4t1$`511b\QP!ʪ ΀33s^V_ǃ9{{g/}{NU1ekb[R ̮:(o,Shl1Ai W<0grVž7mRO_,U'!tRN!- E=kkj޸=˵t^ mǴ;t"Nw)Z711:&ͳ]'>W7^\LqǒטYWdž_DD40daՌQ?!PZZjr3gngddgyLcL4Vv)xĘ1c"""""$=]㔈h,|LJ1q/<_Њ*n@F$GWfZ0DDDDt$  ?"""";&1ޛur9𻕡VJ.ެ&YwGdgiDDDD4 (""""bbLDDDDĘ1c"""""&DDDDDL11&""""bbLDDDDĘ1u%)[rF};2cKR.h8^C8^C籲_փ݉|j^ח:; dj ոXF ܩn s(b?pY1j] 8]`/G8*E߻;FbL{0z~|'(x$@]C+P{Eyg2Zv0z?s՚& _g6 գ6myɀq7?xrIW#mƙ)1^1Gki r>c:7QQۀf{a `kfCh#i1;($јK@@YmُC kj.w{YEp8j] \X0m"fz@.QsslwP\CވnvdJp;m*I5*YE[  ,e>բ[6`hi5X0m2}MըoRaoG<<sG=aPs F_fV  k_;=sWh5䊇J.-1]P% bbl*\C]6V2LrG⁸wlm tmQ7Hʖ q3< k%-y{(>k+9]=c+5xd/慸Insz{{=ᠴO憧_faF*̓K0V2 nOQVR ;Ŏ6LJ{h{9-I˲BL Kkڒfv +Lu¯ `u$f%)aԾR,g) |樀EzIZ7Y 11e}FJj] ԍ퉱h)5֪Vm_QǣO᯦䛽V"i 9Z h5i{o6&9ۮ7OqIh?\i)Ýz[Fms7pJmf6f{G>\EprJ4{:ʮDf`~rS? hj1 k9-oX2o8ߺszĬb,}ԾE~NaY8wUb *5MI;x4hѷyX; 6,%5:ܬod7ai@W/V#T5h6[JR\ɸ{DX[ɰӋ >G#QZC(q*-,돵 !_^+77lԾeY$R< ,i~Dƙnv3yO 1zIT7Ym'? y{:Nl*ij/#uM8fܬoivtEm[NwRahk#u,mbD]6Jg11_߯ %iyeu%eH|Z mƔ]juޫ-"%bt]]C}gKČ-b^pwE iDLA|ܮhj1jO&ذq*ա`D j8ܞ\3kbkb~y=tMzȮP=SέI@=}Y綕zhK[{rJ;ۗu.jkCھBnKT$K INfG')[[zb)R,`yWq>AxYj"%;F1?b $+ڎ-)-񳶒eS݅j':>mW,ݞ@OP^.J ]#"J42d-1m넄X?V㵔|:*B!9rˑr J+D E=kkj޸=K*I黓 V MDlyw>:x4{$*&?ɂH=Uֈ rs&Kꗔr9UOӏty8gxڡRoW;8; ɾE 1mg1VwNC}g1}O3^ڷHouW*ꨀY('KNNV^H`K^ 61?g<]ެ;t"{ B4LJK667Rg0 Apm.h8ёFt~FkoGجdn0(Dԯm/J1m211&3q}&ƚDDDDDL[rzYΠoI9TB];ip/'ugN޾h&. ,nhz]C+P{z_? @Ĥztm_EDDC烣5xkoʹDb\^j""""E1 k-OGz_fV XV#]xt/ۛ*ùPZi7r X]Fsxd/܇ >wB.a'duť0w\(=>blwP\Cވnv [BhX_OYVV-VCmKgybTnqLq5-F<= MU~5P*툇Qi-zL F_fV  kV6ߘJ`/)1l 8SKukJIX4&-Ѹ$份Y![ xae2ͺ.O6{Q\E,3=w)'3=~"\ ˯P@4 -PuZ,i)ù*L</ CcATzce{|(ჯPiKcm8bpBʲtzUhX'96U31e=>?Q[酦4p8ZR:ǎPdk Iczr N])xaEZl_bcZ_-5xx/v ?6a8;6|lNv6X>g@źwlm lK5ͦ:x q3<3R 5~6,ޟSWڒ{fyQi{fyY|8p pvUZ|,,kWz1j_ q1Joos|qO=v[kT%fk+ŰR+)}G=lۓ}%/1lJktfv +Lu¯ ;85R W{[Z}isU&)fն hYNnX?5ftQY|(0c!eY%*ݠ#fYUqWINA:n2jm kU:h54%6)ۗ vkrJ4{:ʮDf`~-7kgfl\Yj:\d8bjZ_|תux0z26V2l"n_C1Z`oGգFQx6UZYw"qhdZ]ێ&V-ҞGs;:*x#m5ˑO5[FuѫqRWIWC9Rn?Q]ׄ#y!W{oַ\QݡTXy@9ښc=mpm_Rb8~Ye u/ W߅uےἲne#R`dmWti}^5tznO5qڶCפǁ=m^up똥Ѷ}I`EXYAVIh|+bUQV)sg`O} oHᒙKlmǴ;t"NwVr9UO9!+r iV~ C'f}3n//cg_tK F~s^]C/)Ke#"J42z' _}jWG_0' z)'ʠBDˀY4fF\mpm_b8~,' n"T[ pPZ#*̙w"qJ,^HJYk&JEDD4?~;r3gngdd@ЍOZӄV#_;u(R8 qBRTiBtWDDDDLGp;;8ǔq*c"""""&DC?""iPs$ j`S.Tb]+\7tx]h\> :?w-0:wz5YBDĸc_GU݂ |AooZӄ5q~[f|w_k|cU/ c*AGGR=7QQۀf{a&9+6ΟBchJt0<^DD4ce?`,'Ņ .?~~Yb ZvUnoz>VCk MDL;5fPjZFLvC|$SR-m U!MzY/'w]g-ѯ̬@55^Ut Pk[YݎÞu}~6`hi5X0mw %=PXd_S#b5jꛡTX!ZR=bz/beP̸w6&ZaI P̸vLŎW 8SKukJIX4'h'{c~2ㅕa8ެ뒦RT5ܝl-+3pTO!d~" p)'˰p;;{䮶:K0ej[p [bk/BۨǪX?IIqO `_o/ԕZDb<|YѭLDz\g!2:>?Q v֦_C1EzpXM? _pn5L(VVPXam?&9+qXOĒIջ8闥C)jM6. [kSIo)a_n13^b|z7nK0m(Qp4_Ęh |U X>Nv6';,#))V#ƪ&; 6rDA7;[ X:J+.59p pvUtob72s/1ć{AipneۗQ'mIHEՀb(}ۚL2 IDATv s)Z|ْd{psTF",Zj1-ja)0 7.DDcРJ1y 9Z h5;9jkUשFA0=Wi;jJkj-7mWsd_bҶ%TN GGM=4(>uq~)}+b-Umқ^ЬxeXt=:?c: 9%=s_eW"]0? r DDt%ƃDI71nv[l1oS8_F lY zsү$g}O>^k:<=wOk+~z ? `q1]`oGգFQx6UZY{H-xV@ۼԼAvdRkJڿ˺rDu]yf s1ͱn5ݿj_VGe\$Ű߆fÈ]XTԶ-ctw(Vk1ap:JwKIz9+ 1A껰nq[2W}!"bbܫذq*ա`D Vž7#Rd{@U׌(qǫlLuBBsZJ>\x|ٕ 0!+r iVpкa~H=]ePX!"e@t$y8 g{ĬR}c*f:<<>U=*ڮnEydM@cJkD9BD4ɒիW3DDDD4.vn^˅Ϝa9CGDDDD&DDDDDL11&""""bbLDDDDdXʯ8]bKRo~`ԉhԑ. ,n~]C+P{{!osbԉhԑ|x<[{ o@o|OZ*-ȨO@@Ymُb""""wެˁ߭ 2 Vrf]<X yqyNv6}Nb"""" uUOy-&""";"1h111c-&""""&c=>l*#KDDDDc! """"bbLDDDDĘ1c"""""s֣ad2saLT&A衭=>ZT+Vz? uGZzL;Z7DDtg$dOD;/kKJAw~p-B"!sADDw@b|N&3ں}pyd+G͇k=eːڤ$2|Smk0Dݾ}l[[\@Ɇ 0% B@PP}]U*}YθpSLY{?:n,tt'wFXXlmm1uT춼}aΜ9P*LJ]b(p1HHHJTOT*V^ WWWxxxRL\ Rڵk@ӯ8?\0)&"q-99Y, Ἃp+%E 3giӄ^_wPwp4_}%fV&o4AN yB݁#p%>^?tH04455BYbpu*K ΏBhh!hZɓBHHg,ZHx7JUPTBjj/z ѣGV+>}Z>}ٲ8 )))B]]paڴiN1 DEEꩨ֭['<\< $'' n*++g}Vt~~~·~+ܾ}[|OK~q*l}""﫯{\.99Y ce^ohl f̓o1ONV(w;9Y_b:̝;[wa޼yNNNB~~qKnre  :iVJTOv5}BZZڠ#_cqAzY߼=-XU)bcL Jy|RѬÂGS~jxUߏ7`ljyH%+瞾PTTy=`oٲQQQ7o"## `#B^^nǺ%;;)]bg022쾧'jjj$aٲeWNND:]8ׯ8W ċk0xlnZ++- hTxz1u~D՘#}VC/oߎ˗/㗿%\]]'زe˨Yyzk6 ]bhccob=lו~qxq{L""z'd%%% !!!,|炍Ytaɒ%`oo/,]T8)b#1'Aĉ _|%( aʔ)zYqDD4O%'' WI5W$Xl\`^zt;^|;m ""JKKMs/Z.|Sx322w$<#G@բذasppFB% KDD4V01&~_瞃>wsoR~l{ƥN(ƞz=q@d\ADD11&""""bbLDDDDĸs2ٸ\ 'N`͚5OGchKm۶@NNn޼ϰ}v|DDDcOdǏ7?c ڵ CrLk qsÍW_EѲeqsCmRY}p%6ٶၒ `PMϗW(/^S(կ$IV*vu+=v Wp<p@q%.UU_ d#SFLŌ9 |Smk0ۣWP y{{8;PwZ[[!""#숱 p/PӟbW_Ano1Le}{8ӡQ_#(% //4^УG%'剉_ Tsr?)9s`hPK(OLDgO> >Ӳeh.,Dڵ ӽJZ@p}6޸i}8ÎEbʈqڱ|ٳјͤIpZLt{>|vwAqT_tVe˗/㷿-֮]˽ !KNNV^mJdll3ݾȆ^_gG)]Wcq: .Gg0-=6'KjOAL nˊ}9,3j\ GDQ+ 5!6m1+>!G*.+RCup7^/dL1e]̸7pQO_qvFةSPΘ16NG###qq888pOCDD4JKKMs/Z.|yDFFН|'W*!W*n%0(OLD^p0Lggn6 HN1'-gilOOkjL#fecbИ+yYK1/ fbch b.fa)?_R{H|c!!(XP\91KDŽhT{v='NUԧmظ;wg(R( DFF'"""{qOCDDĸw#G^V+cw+pj0#'W/Ƅŋa%iYvgc}No>:{zҤA/k’%{QtP~!!Ȭ!Y>}wtN.+ v=LͶ 4o*(hI@_F#O#""CF:v~44SSQ扅Vk}kaj%-{6oތajTX%{v\[,`hIKCa|e>+$_BL ;(IM`0Z__e]Dh32`Byb"nԞ+MJBKY{7#"Fd}^t) Z&dggcx'!""#Fq(9Ahj}T>W:M(ݸ.+V:}7ze>.Ca^۶1/6~mvZ2׷nYhcL ^|qPrYEE|9= bPsf `4xR[_e],^Bɺuh" ^[$gy}TlcCl&OC!8-mDW^yo&֯_^ lذ:HDDDې\7bADDD4DDDDDc c"""""cK8'ckگn"""bb$""""#p*c""""Ṇs2hq!̝;;h,h&4v9`M^u\"'49  cMZ.GG#[Dn@nխ1\y\U*2u9mj?WZU%_M)8'ۯί>1}CRxj为₇T ȟ9LL\n˺l[[\@Ɇ 0czdHHH^}U,[ nnnHJJODDDÓۇD؁7o"oVP0#'2剉O> [R!85wAwI^@pp1`%obׯu6MAL;+|9¯]Ì\4׿ʪSRjcヒɿ=fk4y2Q_[|XW>,mÆ HIIk͛7/o-%'' Wh11ں.+VZLL8̛gz~t…pMHM~L >@ȁӡx:8̛^td=&b_b޹]0qÆn4?Exi) \??:ehh3#w̮[e2=I&`ggg憆nDDDTiivn^˅Ϝa14Gsr0!.rfm<=1oΆ#qAcne.]Ƽp/13ez|\+WWhOh32`fj'&"/8pN&C3 o CTBTH:ѓd66A|g(CBP`pYrD%x{ZUP1&%$=_~='N \Q ,Ke3J"""?ٸ}XİF=4i˚d x^?={D/Cfm=喐+wNAcfkAxY\\L>c]r;; o? +_"""d*m(߼¨բe7Jgv\[,`hIKCa|e>+tU KRB `PŲ:6ڱ6ް:Ed$yTT<|D""PcƲ!9bCmh˃'_yEr=NKB&֭Н= p׋/jY.+WW/ǴG!՞T| '*{֬F:] ׄ?sw QQ\Y[YGOgяοxq[hP\hR5L0—k-Ή]%"""bb<1%""""N """"bbLDDDDxPKO}78qk֬n1޿?.(J\yh&5 +Ci.m ''7o?|gؾ}Lnn.~ih4xSOҥK򉈈hl&ƣ5Ysq]>>>P(1cvڅ?Ϧ2|^|E,]J{/lق$""MdЫT(^9ջ۷AR\|awUuyYyɓȟ9s@}cp%.pW${̙efef]wu[֕Xd₇J6lAs+tkkYl2~;vt_RgEPPS.[^~f梩P7(~Ixm݊ P_ߋ:ey< j>Ȭ_۪U#fJARaFNd %KL|-!˼))pw5̼|V(->mM/^cڵŢE2S{ @}}=~<3x뭷w ""ȒիWId2څ6t{…pMHML}T|.Gd&}-˨⢟f\2ӾܷtN&CXf&1qƥpDt:j_Ƨ7?Exi) \??:ehh3#w̮<úw:Ǐ`eeVr,XVVV8~8lll`08uf̘8QZZjE3|#N]А G1{1&_nVm뀓GFݷ􄾦FRR[ߕaaruԩgd,)6(OLD^p0Lggn+ hnnFvv6&L_~Oɓ'{{{S-[ ** qqqHLL{g.SO0|gs}}{bC,gՇ/CwJ`I2#%>}u*SRuJ ̞/^'bPBT¨ Mhƣ IDAT%Yr ?{???cf3߾};x 8qW^Ezz:mۆ7bΝC11z޳֓&hZ[C!xs##a3iTLKO/)[B,^ ߝ;޳N>#/+Ç{KngcSJ2W,hv… ߚ%_5^h fbLDDt˵yoߎkk@cC  4ii(VVMj*y3(߼]%%>:6ڱ6ް:yHT   ԩx벋@mRҠb.]{BV X~=x SM67@zz:q!ܹ:ێERRʠQYYݻw#""{"""&iRx2o݊ ペoۆlbP?V/)5!ݻјܠ \<wA'XC?!fDW^wO=/_nF͛7 =N۱cߏHL0 .VEZZDDDw!*h# ȝ22,ODDD4ګRX?חI1uc}t\?o:ݹq_?J!fhQ """"bb,`oogggw}8pL}Mطobccakk lذNc!VS.fΜL233q]wukϜ9sT*{vd4pO[pxPfe¥(ѣAZ**k TἋp+%E 3giӄ%/KA0['MMCүO?BCmF`j'O !!BgA, hJ{!/,LRA+BCAhVIf߾6:'ܐ&($BTTpQA ºu;O?BCC A 'OBBB:ŢE7xCZ[[J% =./¡CFHLLVu W^~ߚ= !%%EΜ9#L6M8i!""JJJL׿咓!I/}NKY@ff=RU%xx yrPlet:ᇇ*_5K;晷Q046ζT':ἓ8fp dvWUUѩ_s8p@i,A%:˗/ SLFc=+ ߿_Xi!""bblTƜL뷜}d}OOkjL#fecbИ+yYK1/ TbTTysXMsXJȕJFIe j5vv8'!۷%Ź1?6v]鉚N***¼.Z` ;Ŗ-[8$&&6MA ZD2 θe,,!,, 8u ##nnn 5#]vvȜH.\fcoK}v2$ @ cTzDLݿY $Y&lhmD?پ};x 8qW^Ezz:mۆ7bΝY~=&N#00JZZ )))AJJ aۑy-Ѱ&vgcpYbPGG#xXO4eMXw/Ϟm~)CBʂӽefB9m=reerq1=Vz3gvoӒt;X!!!½i]"00[[[CںfsXe,eŋcΝسg;f|tt4كI}l;DDDdnHyoۆ͛Q Z- Qqzoǵ5kʂ4xYQQ#\]BU),c&o ]f&:tO<1-$2FFuj**^r=^/Ķ8tfd|;6mڄ͛7#33:OFbb";-66III(++^Gee%vލn"55sxwhh{$%%XXSN'voooL:۷c͚5BCC4 i!"""sCr0EmИOOxz.L.[;{0_Բ\VDsQ._iGBngg~M\*\KH@ŤnkX<΁w QQ\YHxgWW'\\ Ŕ)޾%O=5Wu֡ ۻ&O@@Pѥ HՊ(T]z땢XkTmZW^n/VTZEEmE*ժ ު V@Q+ 1f@P99G&;<μ3uoMbݺuI .3"r-1c71~y_ s-1c'^|w">E2k1c==c\_D OV\K1cMk5dmc5c1ƞĘ1c>1Qא%̌1c)Nlrĵc1ƞ:OX:}r@}mc1{zk1c=ux"1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1Ɖ1c1c3c1fH$lj+xqNjq8^1f1ccc1ƚH޽{t=y}qFqUWWŋ)88Xт [n$ɨ_~ghҎK>DZرcʕ+T]]MW\1cƈ~NX{EEEb:7|}}I&/QQQZ˾ ̜9,!zMDpwwGIIq7nIB&OK.A*j/^DHHJOOR|,csِ5b\zZ1c۷sblxغuΘ믛5^ORX71֚JA4aRդVi„ dmmMDD4i$9cQgGiӦi}!0`Pi˖-z/I}_ۣu䄸8̙3ѣGrT!"x{{#-- * ND_jUYY [[[evvvPT?~챳3Ν 7nNFBll,JJJPXXyRXZDv R`Kͽkcc}")) 7o6 /bȑ3gBaa!j5q 6Oj*WMM ,,,6L1 z;J|gZKLLȑ#[$1n3{_~HOO!1 P(B[nT F1ĸ%%gL8pqO󷣣#._㲲28884zK(GGG7`lmmQPP~II vj3Ʀ*O߿;3uuuԩamm۷oC&ARSNlòݾ}Ec!xd2 >VUU GGG?^T ,, єM"4y6M1nn&ƍ7}١O>]sKշo_kT6X:Tg<3!HE|+m-1sJMM%RSSM_ =cl+-/!8cNc㪓L@aӦMJԋՙ&B+WРA\Mg)[%OS((( 777}3N"%$$/B9Xf\.תww&ۚ4kJuu5ő;^^y#(88n޼I>%$$iӦQǎ)11<<<ƆT*988V! QMM/!5i$#3qB,ݮ╙IDDӧOӧOSbb"F^觟~"Q3"Ϝ9C]vgR``{eݻ7edd8l+WSRZZtqZt)͝;>S+l ѣ7|CSN5Ѯ]\瞣"gZuE+KLylmmm:uJӧO˜A/ֲaÆQzz(J ,CJ껩 ?h}ĉcǎ:h>Hgyƨ }:LNN7R$M>z9}ÜbD~O&Mji?{=ͥ+VЎ;Rg -BܹsM.\۷qqqnox\3fee2:u*Z٭1NիW{sΰ՚%TEEr9>:{Bee%JKK_cС:ۓػwo󈌹"<͛w]zz:T*T*`KQ=kkkƍ,*^k֬%bbb47XYYaڵ_bknb*$gΜAnݐj?f'"44nBee%RSS5ϥ5e##.K,Z}{ѣGtRᅬ;w\95QQQ222P(PQQaYYYXjt7Ν;P(uݻ5cχZ۷l2<֜cLDxg{YYY n”)SСCwq 2>L9sJDM۶mR)r9n" a„ ÇcNJ>pǃpuAD=k.BbHR( ?z'NDǎakkTLpEsJJ|ƍ7n5sIo۶ ސJDttt$bOS}}\c1cԇ~T?BOtt4r9R)z쉽{ؓ)o]wwwwޢ uT R"&.͵P,^X3.NjO?x!\ɓ'NSƫ5㺺:|޽;УG_^kd?:t <==bΊH% 1ٳ?i,Dbt=qs8^L4#G?bi\/_it>kFFYp13QFQrr2T*ˣp>}:W cqbc̬̙C'1bӢEbcΊG0 4-IDATGsE0̎3c1Ɖ1c1c3c1tbEݣ{{ǎ7xCk٬Yȑ#X"42i*^#c2%!8|0yzzX~7ܹt҅޽+h:uzEEEXS3tPJNN]t6J(**7ƍ)22͏mZ^zlll(##~75k<6UL[zo.^ =~^?Bʢ[dljZx&VVVo>_(44BCC_}8{,]p&OLD->qm4¢+;;~[Tb|U]zORJNNI bPbF|cYWڵaÆi˖-< Ez5k֐+988Ђ /iϞ=GC;wu8&dmmM&L ZMj&L@YoxbpZbEn4sLe3f̠ٳg/Yc @5\^\\L#OOOӈ#())ItIJZ40@gPzz:ի㕓9cƙxmذ<==ښ<==/jjj4WZtVvA^^^$HPΝ;E3k!e?~k֬-zSVxuu5 }0x`TWWM2z4Fb%>^偁裏PXXZb8pÆ 38^Bkl(;VkYXXVZz嗱~_|ȑ#}Ç1~xY쌹sƍ$MT* 44f[IIIprrB\\px{{ѣzqԨQEII 1o<1v Lѿ"\.G^^ʕ+d(ŌRlذa8v>>ȀJBzz:r9#joߢ2x{{#-- * Nfl6d5qIyp7;ĸP )))P(u#._lAθ}6]vŕ+WZ=^=zŋADx"ܹs "\t ݻw]۷/o߾Xd ӧ4e;w; }:zt"¶mIv=ic_;w̙3AD5kvapbok׮(++Gu(t4eWT8vr96l;((Zȑ#&/KKK((౗c3'z*֯_ӧOzDjjQի!0lڴ fK7ڵk'OD޽/DwpuuEUUڵkwB":t 尶۷!ɠRЩS'i&Zk׮z?WGَc6f5c Ā{nF ,G}dT,/;;;Z @II ^C(--E{[M_NNN=.)a[L/--uV̟?_ ~ѱcG^NMt'ĉݻL&#Gt3gP׮]ٳ_uSY&i-kՋ~'Z;l(((hͮ_WWg1i3(1^t)[|b7;w… }v:Q ܹsU"͛7kK=zZֱcGÃNJV:,uܙ>L0[bL#BCC)##222(44T))J!""Ox稨H瑊fَPBۘ)DD/S]]я\ڵ+ >\sä::fFJNN7R$"":q:{SNi-jsǷ9;;7yã>ӟZJKKK.L:^Z15u;l+r9>}Z6ƬZJmO&___ڼ-UUU5Y.!;f$oZEvv6^|EON:ȀB@EEA۔ػwosXv-:wΝ;c߾}XnKQX|9PTT'bҥZL8u*++h}?oߎ|jܾ}˖-"\Fںu+<<<ЧOkŊ)S@D ZEk͚5DLL ?n,LzNj/,TVV_5*l1DL3Tdeea׮]&ZvU1Paʕ(--Eii)OOO|>}wqڰabbbP( УGbÆ `L2٨Bnn.BBB`Q~~~xq#""RTԸǸovHmp*Ν;P(uCݻEoĉt?⥗^BXX:HOO״yRcM]:OTIzQ$N2~ɓ'ꫯj-{אbBCCxbϽ:u;x <<<`aaϷW^y(//G~~>6nL&z`9x nݺaZ'NDǎakkvǣC'Q\\,*^b. RիW5^&Lxxx0axǃpuAD=w2daggÇk=-nǐlHL3UbSBEy7nӣ{7rA\uilBnnn-3ƚ6j(JNN&JEyyyNӧOa=֍lmm‚lmmtzV\]igaaAݻwx `Μ94|矩[n4}tZhW c̤ɱ}qb̞z|I1=z4=+1;x1Njq_bg c1T?q/bIENDB`icinga2-2.8.1/doc/images/getting-started/postgr-import-ido.png000066400000000000000000001005351322762156600243000ustar00rootroot00000000000000PNG  IHDR|aPe iCCPICC ProfileHǭw\SBB D@JM^wA@:IPBH*vdQbAQbÂE}ADee],Py||>ssϜsofPg Y\ad3>!IP( X"wDD(egyw $ߊ2+bD@NYk\n07W ᷐UP DSe%d[K}#}!@XT$yTGAٚ!Ncq wC Y 48<JgY.B]2ccJMEJr?#;DP;O 2#4qP̨[ 0@%gx-K( 0^np(' #Gy̰8+Ӹc\G!ÕOD/b +@neD}6#GJ4B~" `Y0+6K::dܴ Y_,+4`.?fTWOh"AfĨ?V 3vD5ַ3.0<`YS#dw܈h6&Ú A: _; peG^@> HrAʮ Ez7O#o˝+y!|Դ\7"s|$!n#l9gp)o6'@f^8 d6\r!H7Td `* ̆`!X@ X6m`'C(Mvp ܇kF:"Fb8#?D" H1Y 6d7RD!W.҃#O(RQUT5F'Ψ7FT4G 5=֡k-}af9cX8`Bl1Vaa>X76}ĉ8gp}18m~{A+F"X\ xB*a.PFG8Aߝ>;" ໙@L'. & ;!A I,R.ttI#} ˓uɶr"O. O;rJrFrrrrk5](SL(hJ:ee 0"卼tyR-G/PͩԙT1u zzFӼh\Z5<]J!XD\NSᥢl|2c䔌|XJʕN*u) )ӕmÕW+P\bQ)T٣r^ t6}9}/"OjZzHMuPME^-VmZ)n0f32kG&hOj ޫOTRתRXQP4ל9WBDՉn'xO 2׊ZGUkH[G;P[UCK']gi~].Ow?jLof&s sPOK/HO[MoXD?F@V `A4Å5䌜Ҍ67613^a\oD$$ߤ)4Ǵ,lY9j`f^n~pYD2?rR%2ϲƲNJajU`Uor'Lj`iTF׶lrۛv4%v v-wV84;|qtr:vw2tJr eKGWG\ףYep{>d w),L$]ݞz,J^^}^ϼͼӽzyWQ~@j@M`CAA]NSMB 8kǘƈcccgVǾ+뎟(Zf/!/qhM3f:,y{ɬy֜999ǒIqI>YɃl_f g#->KqO)MyꞺ!?3,m{3}FxFUHf\fm9+)$_=/C`!(tl,QC*괊M?{<>̍{l۵~gGgW;Kv~ugwJʲ==y{/4RůBSukkqMj8lyxw-8">I>rǍo?A?Q\ͯOnHh89ds[߬~jk*?vji#g 8zyNo^~b˗.on9sr+':_xաhsltݥcJNs7n\|ڭ[cn}s̻ACeUaGmcQ{_<=Wϛg ၢn{%|5z7Uo6E =zn}?:lϤ[}iHȈ%dIhJ %uFB!BH#޽;rssQ\\'B!ꢬ j"u !By]D"4(8!B!!B!B!H8!B!B!H8!B! 'B!FQ!>aPQQ_mPSSCY$Z\ʴ!BSOt04*پǃⅉp <|BhV_,0z hH}yE!or6jRp 'o=DkVR7 p dGn9 Nsqq܇vlAeeT^z>x9m'4宫ʖO ᕫՈҝW#[B@&zNGȦrK8xӡ٠=)/@CԻaPܹw_~2f;!18{N񈆆";p=Y'r 0n1v0h*** }7]*m6yx|qG}{V븦m[N)wB.~ xX%{XQQ `'wi$iצ5=&a/_Ez0 RNaaܽs 0l87Ou_ᨪb_Nn454`nۢBKKk()-00w/f6+=[޺&-NGPWC^e~^It=zеҤL1^UUUVM'B75sea!lƖhqXf KzЯOoLs9D"<.uֿ7/K&l+Es?{Lusu\өo|oviW# !MwӱfN0<@av`TX4Ni 3m /D]JNo4<%aЦ5sr#v$Na<{РTl1 .½8E?6 kaz;Gȫ$oR%&;P͈}faНQ XLOG!UcmvmZ#-[ɳhݪ%zVǼ XY׮uks0iv=\^™ F?^ߋu\hצ5$By[ihCZ9f;x5|PKҝp 'odxX1hWT! "&1i-{0{z?YعV.2ĝ UWs2~+ rt07j`֭Z\%=V->7X<[:q.Byiij",8(άsGl[jйÌ=J^{ɚPSSCQQѫ">uuuq纪J{&3ܧhNС8XZoKaRWj={ڵ;PYY%Ys$BQ\\$MMKuU|`Μ C_|=ʩ&sBmH~/g 0⿆qYgϮ <<|^ >k 4!^uUfss~X~'6mС/'1m8Lxjח)Du˗oĶm1ؼ999 HLE1dDa,,Lqn}{7[ Dxx n``xy-WCpi eDGpvOAB_|1r(RSCXޓ}S0N5gMbZ~gb׮ؾ=={CWW}¶m+en8z4ar&6Tq 'A n5ŠAkOغ5F|m%KЮ]k|||&#_ aؼYUs ٳ11GhgOslܸ }7GkSSNty<=/Zꍶma.u~A׮ꎮ]%ֱ S~^?p?Ν`dd6XQq9v cw^3̞]:CW -Z`ذ)8q0O}e%O}#bSp)}mm t석;sgX7PDE~> saj={ PE^^;? Uُѭ[e=ztŋW9e!fZ@4kT~x<@_>8(՞om1/^t x&8> NN_Yhnn>iovoLoc8om|>}IJioWæ==vacc?aWp')|b˗ʑX_UU uuG-Z4us_~^W#I(Ly1hP?eH$7̔)cgSl ={Sp:u>tG7OO:ч}^ٳ/^\Et:Ec0R'={` PSSCBUtH۸o'OǤIs`L]aX~'NK[tlp? n޽x̜5k9QU~T5&-6uq"$d.>'wA(LVj3$$ ky2""~BHHN<ϩ 6'B}{0?Oƞ=Džɓy2"$$L`l=Xv]dg?ܹ?b;ܠQpW۷˗odUIٰa ТEsxz.t  Xpo҄o-0L:ކ.]0طo#,,L9Ob66o@JJ]1{ؼ9@QֵkԩsJJOMrrFÿ3|,%%2UHxbujj##Cceeq6M[wr2;Ųl ={x111{_o;w脽ce6 11uiw0ٳ{Э[8;+D"N] s0`>$~Q8qO6x ,-M-,6aT# Wc%-yuѿ+,g iP~x<< Æ9Ipܯ_cBO1P"?ÆMFq6,#]/uHKo_Ǐ"*j c1a. mV`pn|ʏ6kc}qq a֬%5kMhhtCEmcO͗ [[+xyM¦MQvoJjAdA̬3MgfFtF\ܟr(zcѩS8^Dj(wxP[p:N+|C/.^;!o2/ $sݻ88#& O<_\ Wˑw49bX-n޼#?|}!FUQH*Ӻv-NN58?Bo}­[iڏ"%% Iq6v]Qp=z0Ǝ }}[L}7 ͛7ƌ2WoHC[/iix/gX3A6(,,\6{[I|60h'OK,t/{ؾ=MpU;lڳJGzm~~+3S5AqqQVE|!tv~5#˗([,ǁ':LNQ. qv:||&֭(..ANN:vP~+FutFPV{7"6R骼z|9x')޾}&с22/󜾾-rr/]8̘VZ!\\89 p)LKE$b8We]%gl U1EsAUY?ܹsƍahV|c[陘5k߲6('CAA߁/aQXxSnGSSCa1.O,X < (K7С'p=v^yS]\7~$assCdddzx<X[YRkhhmž=GXx02jGO ۷ 9 cxֹԮ06n/3->_ nnd- ,RSnN/^UUuFR@$nbI D Ok8pRr{2+x(0%~]u *3y^؜{_N[ @$&^wnUI,&LN'ex;8B\ܟ+a5R/U`;j:~$%]GII) p) 8㗈8GFNNƜSUG֨בNiɫEfg9DQQ c֬%JtB(LFqq 7 ~ԅI̛򍵱 =$'!*Y!3M DD"Eu1f'nݺ*ܿo};gOPs{;_O惇Ȩ=&bO9f"̙ρH$>m8LGG!C VoxŦMQAII)>FÇq S"Q(8״уQUUEV#%% mlR# zb„Ν`L=SaSlkp',Y!##;~R/ y]ml{ CFF6# &͕JsӦe4i.f^ a$M]L9ƎDa8 skWg knAcx|pEkHۘ5k >lxw~1z ̞TFPU;\;vTEOOA _ CEE,-szODhh> UԩS̛ 0&w]a쬱vbL N ]^,ĉ{9Ν!n::_|1 Rsas\9ϫbses6tc>{Х\|x]hժܧ(k{DSOC:ܿ=psr,mնB6MK>E؎?bÆ]?~ς\9*GnU 15jvvx9|}>6!t%4N:5?Uv:۷m[-[v+ѣx ˗6c0>>..NxWwΤ/"Tt}mn2;< ZF۶vذaxukWghiuG׮؆i}?8pϟcU022A_~̸x;v}| mm t1n|yH^3̞]:CW -Z`ذ)8q0O}eK? IDAT7EEi 8|>:wvΝ93Add,LM]|(qn?l~EGP05u=GdSt\@T!DF6x4_V]dg?Fn]$ /^˗5k)ѬRL}}[bp""T{vt|9ڶ|x1$89}fzm[; /t׮tͩ>ش766L6矆;sv*ѽ01qƮ](''k(WLb{(۴ۺh赒mߦgu`!n ]aұoFXX*5CQSm)+S矆;sv Ǐʕ[Z\?3JJJg c~W ufۗPtai)/uѐk%rnJYi111 äK`v\%aҙ>EJ,;qbcoo)Ld0L̝;IgDDfv\U6-wtlܸLb;Ýğ?@uz6oL||LҒWf`N%?"''{NK]/''{wJG6 U?HחO?-d cn0ly<x*&7Y}455vx< V3A|||}svmY?jii ANNR)jma[Hŋ/a`Fi=sj`ee&U %w矃v>PesP5u{&q-HNNQ*-Uk*=+WloI Db5 !*|};Sڍ2Gz!.Oʕx9ýҗ.st%%/ç0h0_"" 2399y>sNaTYr|#璖Xh||#.O ->fZ7W_@(..ARuaP_8>IyV6p'|}$$\Ŝ9+diccZ.ƌĭ[wQYYoc acһ֯߉[('8;Ù3B ht\n0vpxytW ##^^;vb{QUZ ֮ɪ!=,g]]L9#YY᫯>݇Uz4?CQ.JJJ矗$¨/&?JKUuOlJ&D~ZtԁPg:w6b֬Y9Lߑ#ۘ.]555t"cLQ߀wL4ܗetuu!C'YJ aƎdL׮ƌ&/0㒟%kc)MZaҙ؟[[+FKK16n#6t1f4553Ri?l~EDf:3IGfލT&ٱGq~v5fLҥÌ)ֳ0ݻwe455Νロ_[w`y32M}gf|0U6؇}R`qs_fӦW798f~9H6TW^~ 15hkSNLPwLym朩zgsN`Us*[.zX9-*9$0_~9iݺ8*g./y&?l-K]4Zzєڳ7fbbbw`wwBCgOsS ZFI-/# j͛[3DEjP\_Ґ j pv(yjkt!BСPPPG#/v^ݻ!(h30L+UmՔ!u>BNs@||Gц)v\͛! '${Ҕy !;чan>|9LM]g;G/監m[;xxNj/W^(2mTUUs #"{!ab]HYt -6R*/05uos2(*üg={)vuZaSp9xIiFS  ;w$89}fzm[; /TShk[SukT9@_>8ȩwNeij!BNx\ܟx<{GppF6B`!5ZhO%rڴ)_} *9Xr+"#WdDEŏ?,Ձھ}/Y/":z¢wq Cd<'s*CWoѹ(({1s;֬ 9y:tDbqx{1 l$&rɓ0lDܹ_Ya6x ,-MM+,Y%wM]+e]`'>lILxYnSX[@^%q}}oI0͛p.q<tt,ۢR}>M-?BȻJٗH>%% Էo//^D@@(?GPVVE'3GOc2;uzuD$|n0ii9A|nJTak;6]vC/pl y#lsZ*>RNV ɓɷoߦ:|[̜2mmeJCEs:B!ޘ0ɓ硠ǏW0(,) Ӧ-;`ccQO z j-U&?"é .FjjfpCV-p.._?V"[ 믯o'y"P4B!DDGnx$6Z@YT{HY7XY!)O y63,&1u9b.$%]ɟM@.Xt}k,-MeYmKK֙⧂(O^8(lY-h׮uaXl4B!?ȋ͂wΟOBqq c޼mw"?8x$VHYjf^ R?… BRu@(L''P\\ B(Lo,ɩ DDAdf>BUU5rr}662 W1g y@DATW~`6Yh||#.O ->fZ¹.s_ÇOaР9æNk7B!#qc&DF"8x 22ѱCE@VV B||akk+7=ɓhӦɉT]`ʭ? tL'0 ֬ف-[v02j/έx&عs6#;;;a6mD8Eex\"6mB||JJJ0z`|hV_/VmCFF6# &͕&sML4oaA"B!Ի_lsPV،4e>^{u={AApMD thtϦNe#u׿B!eo̔u~;OPerC}OyNj;'Bξ.uWQ $ +0M  w:.!JR9sp?CxxbTRPRB!ȣp: !B!D6MG!B!4.B!BpB!B޳NxQQ _.]70ͭѳH]U2+:0x<DGZ&.i60\Y~C`i9LΑ#`gB!* : |̘ɓJl0`t&!<<Gz[aMu'TzkZ* ]Ϧ{k$'߂o CPPp۷k_OgB!Hmb`ee@?o͛7T(sc]] {B H%^ޙBի׻k97Q/8:xll޼S !BH#u S~)hʔr#QWWH$xf#m^,DVV;Q_3}*s 0.. ꇿ)τB!:))i2cqYY9nܸi}4D89CMM NNh.O v\ϵ"++FFˌK}QgB!Hb*܈3F7Xf bӦ0nįwvv9/ Uܘxg v>"ulYkI,棴S !BH#u›7oR1L:PV{7"6ܼyG*j oj7f@-1n(l#m96RsmNy&B! 2CJJ|-’%^XlL!B>s;_OE@@(rs7FbƌEr#0f0N)AI,{5%b-c+o رfXBa2***qk"<B!Fkiiԩ(~ Z֭1X0?RMAԣ\\9S7Tʳr|`hٲKK3\9m:*5쬱vbLzz=0}".E^L!BTø B!9o# %G !B!:B!P'B!B!BN!Bu !B!v‹J0Jt2|9,-%_S9͛[gϑXv*+dQL}Xjx%۴۶rp-gyf0q:GM !BH#t++0t$hk!ӧW0c&O+Qkss#GNo0uꊏO̗ݮxئp 'lʙFr-"<<7}{0TNy&B! ߶-VVf Cмy3MEx27A߾gzNM H%^ޙBի׻k97Q/8:xll޼S !BH#u S~)hʔr#QWWH$xf#m^,DVV;Q_3}*s 0.. ꇿ)τB!:))i2cqYY9nܸi}4D89CMM NNh.O v\ϵ"++FFˌK}QgB!Hb*܈3F7Xf bӦ0n s^81S}ERؖ*גXGii<B!F7o ť 7btTU,{nDlyTE79'T +7n֭[bܸQغ5FjrVmm>+:::ڜL!Bnee4Zps%KlN ?xٰ#p~235ҔqgFkOGXXT'k97!K,~ cL!B ""JdWQ.Dqvuа- $xmdC8J嬌mqd={}8B!4R'|Lw\P>Eaa16nČFka̘aSXjJ&[XcWnNGyy22c׻͂3n/PE9+o'"(h3dTTT…+ DNy&B! ĩSQ(,,nm[cZaD'~ݻ{륢DG繸(ws*og0773вe/ : fXr~ۘuTU{kYcŘ:uz`E ]^,9B!/&&qwK%A!BGsF(JB!Bu !BN8!B! 'B!P'B!BNY IDAT!B`e |sXZJs7FϞ#vTVV ч ::6pIKiշm}Z~:Kat9-<B!FWVVaIC(܏O` 7L_ aؼy7<B!FNR*Д)cFH9G(,,(|YwP==ѣgTzeYBa2\\$ uS !BH#uSR`eez㲲rܸqӦ-hΉ prߙp==]L>6쒹k97DVV %£(τB!:ᅅUg nѱ(ŦMRa4($ٹ/Ap6Tqc*)ؽ ֱ-gU(++%L[2Ny&B! o޼Kn0騪JCYY*݈?p0nrO..Wn$ݘ [ĸquk: |WHuut9B!4R' ))i76 Kxaٲ ~!22am=< G,df>j)H4hN0rn##Cdg?X9B!4R'DD +7o ѣ\ pu!1:B))a[H,{% ߡ q*?eY92={"p3!BiN̙~=}bl3ɍ˜18=0>" 'ՔMƎ/ܾ ddd+cw fbݺ_rVƷNDPfɨą W/L!BSPXX {1h[ "bˆ&NwKE79 RsqQLUP)ʕannѣge^:t,-Ͱrz13  װڵ1uzYr3!BQ^LL ޗJB!B!BpB!BN!BN8!B! 'B!( /**+ѥ@水| Op7on=GbFѳ3Ataulᒖ$^&o/B!;ᕕU:t +1 'ϕب5I#Bfu'TKznW_s;_OE@@(rs7FbƌE ;c 4IJW;.6*gg9ݘI!Bdwµ4qT ao?[bDDVĉc mA"\\:ʌ7KsMzz=0t$EXX <3 !BMݽ/!B(&+Ff'^mRoU)t0% &% 1&Մ!m I[MTH5`l2i&>(xIZŻ:s 32 r'!Zߋ{ >>/z'GP(p-Ÿ>SS97}U;*,FT^~X|?iv<,33k]fj^rҳI6Z(}MsD7nts8q_H"_.WZ[sr:^]]gvڪu򷖎_0 c襙dsآ7t d Ob9lZZZ|rrZS'OLMMf ˕t`0US1" |X~#?ެ2V$I[V4J)-ml6%=)hig cHnw$.a M$k9gϞtnS Hd\ c r]42{LD/zCrK$Iee%z׷/0&rP<:ՖrjttLOaSi>_!?TPPu}rrZve5g=C9J}pӨwpANwW3I6aUWWDVWW<`9;vE"Vbcjt_--kffVP{{HXdVUo3^xpxA凕fg瑱Ϣ:->3󛺺ֵk˸mV)//'!==odc%Xr^4GtFGjj:g/;;r媵Q;w*su6n第*.~[/k cH͟0^IK6猌-}CϟMVb$ё#9͖%''ey)}_PO/1z{ĉ:|w5==t`VuuEouus? ֛aW$a ?vFfffeዄEfU>SD]{xǝ,9 ɓgx1p=Co( J۷ŋ&@ҥNLtڣa $]Nf,lRya.\h3'f;Gjj >>/z'GP(p-Ÿ>SS97}U;*,FT^~X|?iv<,33k]fj^rҳI6Z(}MsD7nts8q_H"_.WZ[sr:^]]gvڪu򷖎_0 c襙dsآ7t d Ob9lZZZ|rrZS'OLMMf ˕t`0US1" |X~#?ެ2V$I[V4J)-ml6%=)hig cHnw$.a M$k9gϞtnS Hd\ c r]42{LD/zCrK$Iee%z׷/0&rP<:ՖrjttLOaSi>_!?TPPu}rrZve5g=C9J}pӨwpANwW3I6aUWWDVWW<`9;vE"Vbcjt_--kffVP{{HXdVUo3^xpxA凕fg瑱Ϣ:->3󛺺ֵk˸mV)//'!==odc%Xr^4GtFGjj:g/;;r媵Q;w*su6n第*.~[/k cH͟0^IK6猌-}CϟMVb$ё#9͖%''ey)}_PO/1z{ĉ:|w5==t`VuuEouus? ֛aW$a ?vFfffeዄEfU>SD]{xǝ,9 ɓgx1p=Co( J۷ŋ&@ҥNLtڣa $]Nf,lRya.\h3'f;Gjj >>/z'GP(p-Ÿ>SS97}U;*,FT^~X|?iv<,33k]fj^rҳI6Z(}MsD7nts8q_H"_.WZ[sr:^]]gvڪu򷖎_0 c襙dsآ7t d Ob9lZZZ|rrZS'OLMMf ˕t`0US1" |X~#?ެ2V$I[V4J)-ml6%=)hig cHnw$.a M$k9gϞtnS Hd\ c r]42{LD/zCrK$Iee%z׷/0&rP<:ՖrjttLOaSi>_!?TPPu}rrZve5g=C9J}pӨwpANwW3I6aUWWDVWW<`9;vE"Vbcjt_--kffVP{{HXdVUo3^xpxA凕fg瑱Ϣ:->3󛺺ֵk˸mV)//'!==odc%Xr^4GtFGjj:g/;;r媵Q;w*su6n第*.~[/k cH͟0^IK6猌-}CϟMVb$ё#9͖%''ey)}_PO/1z{ĉ:|w5==t`VuuEouus? ֛aW$a ?vFfffeዄEfU>SD]{xǝ,9 ɓgx1p=Co( J۷ŋ&@ҥNLtڣa $]Nf,lRya.\h3'f;Gjj >>/z'GP(p-Ÿ>SS97}U;*,FT^~X|?iv<,33k]fj^rҳI6Z(}MsD7nts8q_H"_.WZ[sr:^]]gvڪu򷖎_0 c襙dsآ7t d Ob9lZZZ|rrZS'OLMMf ˕t`0US1" OIDAT|X~#?ެ2V$I[V4J)-ml6%=)hig cHnw$.a M$k9gϞtnS Hd\ c r]42{LD/zCrK$Iee%z׷/0&rP<:ՖrjttLOaSi>_!?TPPu}rrZve5g=C9J}pӨwpANwW3I6aUWWDVWW<`9;vE"Vbcjt_--kffVP{{HXdVUo3^xpxA凕fg瑱Ϣ:->3󛺺ֵk˸mV)//'!==odc%Xr^4GtFGjj:g/;;r媵Q;w*su6n第*.~[/k cH͟0^IK6猌-}CϟMVb$ё#9͖%''ey)}_PO/1z{ĉ:|w5==t`VuuEouus? ֛aW$a ?vFfffeዄEfU>SD]{xǝ,9 ɓgx1p=Co( J۷ŋ&@ҥNLtڣa $]Nf,lRya.\h3'f;Gjj >>/z'GP(p-Ÿ>SS97}U;*,FT^~X|?iv<,33k]fj^rҳI6Z(}MsD7nts8q_H"_.WZ[sr:^]]gvڪu򷖎_0 c襙dsآ7t d Ob9lZZZ|rrZS'OLMMf ˕t`0US1" |X~#?ެ2V$I[V4J)-ml6%=)hig cHnw$.a M$k9gϞtnS Hd\ c r]42{LD/zCrK$Iee%z׷/0&rP<:ՖrjttLOaSi>_!?TPPu}rrZve5g=C9J}pӨwpANwW3I6aUWWDVWW<`9;vE"Vbcjt_--kffVP{{HXdVUo3^SS97}U;*,Fgs.VfC>O>|doZ׮/Y;qdc%ye_э?F6G0{8ף~\jmmΝܦzuu;`VV˗tdJ1OeC/'sF澡h`&+_,$}=Ob9mt---YNtrrZS'OLMM򓻞fe ˕t`0US1" |X~#?ެ2V$DiSZ^l6-..JzS&4ƐbI]"VmmH&s^Ϟ=9 'j'ܦ@ cȸ uJoid6^*zvHJo'|3_`L&C=xpKyy9:u- 'j'؟Tg.RSS:};]Cҁ'&"vz-%'jv{s ,+;%Qo8Q'ﮦglê᭮xgRzsv8}[ǎ=ZZ̬L3^54|Ȭzg ;:xk︓e5pxA:y /f ~ngeUix_==$#] N{4a ߬%y9~v[*/?;^х sLHMM13X41a<+pϿ}>_N8"(P[?}:sڽ]9o*??߫v: TXxHmm I뾾JK۫1Kf+"rӾ}冀C|T/q/23~]54xTWYT#gf~SW׺vW56~ռ!=gu獓l$+Q+nHMM,q6Exgg\\6jWtnScc휕Uoo-Ya SK3i朑Eo3j@l>0pS4:r5ҵd9L3 RO+'l=9!j@l>::&+7`H?ѣC cXEJOOWiiKn%G:~Ye6HiSZ^l6-..JzS&4ƐbI]"VmmH&s^Ϟ=9 'j'ܦ@ cȸ uJoid6^*zvHJo'|3_`L&C=xpKyy9:u- 'j'؟Tg.RSS:};]Cҁ'&"vz-%'jv{s ,+;%Qo8Q'ﮦglê᭮xgRzsv8D"6ǎ=ZZ̬L3^54|Ȭzg ;:xk︓e5pxA:y /f ~ngeUix_==$#] N{4a ߬%y9~v[*/?;^х sLHMM13X41a<+pϿ}>_N8IKKK:E8ffƽ^W_y%tf]uklں5So]rfgǴtW; ۱l"955xSч^YCjkV8Mo\]UZ^]]2Xsff{O ld>xpxA凕fg瑱Ϣ:->3󛺺ֵk˸mV)//'!==odc%Xr^4GtFGjj:g/;;r媵Q;w*su6n第*.~[/k cH͟0^IK6猌-}CϟMVb$ё#9͖%''ey>'b&v{nQPQQo߯Mjk?ҥK GVYYILA:Y2ٜggڱ]j9gNwJ3E6}|>_N8"(l-1LOxtIENDB`icinga2-2.8.1/doc/images/getting-started/vim-syntax.png000066400000000000000000001127611322762156600230240ustar00rootroot00000000000000PNG  IHDRl iCCPICC ProfileHǭw\SBB D@JM^wA@:IPBH*vdQbAQbÂE}ADee],Py||>ssϜsofPg Y\ad3>!IP( X"wDD(egyw $ߊ2+bD@NYk\n07W ᷐UP DSe%d[K}#}!@XT$yTGAٚ!Ncq wC Y 48<JgY.B]2ccJMEJr?#;DP;O 2#4qP̨[ 0@%gx-K( 0^np(' #Gy̰8+Ӹc\G!ÕOD/b +@neD}6#GJ4B~" `Y0+6K::dܴ Y_,+4`.?fTWOh"AfĨ?V 3vD5ַ3.0<`YS#dw܈h6&Ú A: _; peG^@> HrAʮ Ez7O#o˝+y!|Դ\7"s|$!n#l9gp)o6'@f^8 d6\r!H7Td `* ̆`!X@ X6m`'C(Mvp ܇kF:"Fb8#?D" H1Y 6d7RD!W.҃#O(RQUT5F'Ψ7FT4G 5=֡k-}af9cX8`Bl1Vaa>X76}ĉ8gp}18m~{A+F"X\ xB*a.PFG8Aߝ>;" ໙@L'. & ;!A I,R.ttI#} ˓uɶr"O. O;rJrFrrrrk5](SL(hJ:ee 0"卼tyR-G/PͩԙT1u zzFӼh\Z5<]J!XD\NSᥢl|2c䔌|XJʕN*u) )ӕmÕW+P\bQ)T٣r^ t6}9}/"OjZzHMuPME^-VmZ)n0f32kG&hOj ޫOTRתRXQP4ל9WBDՉn'xO 2׊ZGUkH[G;P[UCK']gi~].Ow?jLof&s sPOK/HO[MoXD?F@V `A4Å5䌜Ҍ67613^a\oD$$ߤ)4Ǵ,lY9j`f^n~pYD2?rR%2ϲƲNJajU`Uor'Lj`iTF׶lrۛv4%v v-wV84;|qtr:vw2tJr eKGWG\ףYep{>d w),L$]ݞz,J^^}^ϼͼӽzyWQ~@j@M`CAA]NSMB 8kǘƈcccgVǾ+뎟(Zf/!/qhM3f:,y{ɬy֜999ǒIqI>YɃl_f g#->KqO)MyꞺ!?3,m{3}FxFUHf\fm9+)$_=/C`!(tl,QC*괊M?{<>̍{l۵~gGgW;Kv~ugwJʲ==y{/4RůBSukkqMj8lyxw-8">I>rǍo?A?Q\ͯOnHh89ds[߬~jk*?vji#g 8zyNo^~b˗.on9sr+':_xաhsltݥcJNs7n\|ڭ[cn}s̻ACeUaGmcQ{_<=Wϛg ၢn{%|5z7Uo6E =zn}?:lϤ[}iHȈ%dIhJ %{g=/9#ٳgR  JJJT*!#H addcccH$d2H󅂂077gĈH<\rҥ !IJJ.\^zҒQ""""'GA!OII ,,,xjNNNHMM4''m۶eTּ y^^̸IDDDDfnnekK*jaDAR{6=I&QUԂ0!5DTQ'pT, A.LMhg>0(l,V5"+;&:}{~߉󗮠w:k  7g, s`Hy 9!ATϊ&&Q2cs7 [~\ZᵼwHu-#-#In#m:p=^m5յck=wyţê Uo֖:ۚv:]sA]דzV(J<ڛ=F5 9_UP? R1mip^LoظvI&=LMM5RjZsS&A.kNO?[릦ZO+J@"[ѭSLH89k˹՛ȉ|r-/#\kKO+JyJy~@۫#Rr\ݲ'2R+w32qT,ڵiV5155 (~ /@VGRV?1,f TN~"QT3Vq,[+{:a^DkkX2ec98~:I&Q=S(*V1k8WWCVĸs% 1{(qt;$$ѧzfha#_L&ʍ[ #(6{AnR3o6NնWW.^KϿ۩wa$7BSgG̙2FZ*J$ `XPdO><Ap?7je1{aĦvʷ5;\lu1d8q6o߅t8'a_@+/(y{CV*ʣD`פ ?G vCaFF9y<>[* _ AȤR̜<FFj]Nz#/>;'塃GN011WF?߄}Gt>cblm3&a0tD=JjF]ƺ^2fW \z]Σbhj(J9E ff07'kIxy`@o۱a~^r n WúHMj8|*˾WýiJc\P`ߑ(8ۡkn.pvt(Sq Ѧ'lmR_u*f6VS_b||J!/]26bQXq+]0-ВXg'^aaֿN~4_HDfO \$"WXRA&)`af]0satZ_؅ԥ@VCV#5-Fr9[O7sOCAaAS5so>f|8:6x獱; j >~ {k`aBDŜAҭA]:U^]q073EQ2 ];ch>(**0?>b~Yj:]w"J%wZ3 _u*f qS]-תb|08`[ڳ98ܹO_|oh*M07'ϜC7WUPyX,uLqwdѓp7#Ml`fb.3ݸB?dd݃j52݃%2JJJW2B,ʹ-=~zYYZ~nn6o8;i~9ވoBHxsK04uH$&ӣ[6N> _TĴ|*Ne{U*qk\a_{ss5eY###ls/ڃ~>L0ױh?o}VO2I` )0{t;t8:@{_^}(U*8;vj鸞} hnyS"7@sV*zi~\٦|!H}o8;}5uxixoL+^dffAPTTJspsj^+bVXXTa;ť ;[\O,4wkZC'asxn@?ܾ{.мnddm`ï 3 2V[jj̔w+}~wmߙ!jޮ YP jȤR[As7k߄ˉj?o߯@^A8q,?+mܹoVCۖ- m<7o!N*?5|+K pKTbW=i4bP?|Gqv xyn˯ vMluMнSQ9/ѾM+xN2T*Ŏ;sM󗯠X@.5_?UŬOT^i`H/8s_-_"7?rIe[ kFv5ym¿^ֺ-\3chS'cUcV7TMDui}pvpxkJ_i~ZjR2B;}xlΞ"(JJ֩N9EaQlڳmA]:A&?b m[@^~>}o:mُbn..C**۫68|5諹nnܺ/#l+MMӴd9@:UbSY\zΣ?i>mZw&aXW4uvZWo *4.^v[B.ks(Sgk xSwFצl~X^zpk.i?}1ztDFF Æ $zYZ>U]޻euT SSSkJ E g}֘x4sp)l ƎU066ֺ_dR%,mO~C*j&ګ;,=E]T*9Jek/ܼvAZF&%h. zz};6 ƨF "+T*$ ŋCjN[c@0դdjh C=oCDDLID5Uzq~֞kJU*JJJUdRbIDLd!I""""24dq% +DDDDdp\$""""J&W2I&1$""""&DDDDDL2I&1$""""bIDDDDL2I&jD?""=IIEIIޯJ8¿wPnU}mL=##3^QrrrW¨18`q*ܯX*wz׆WcDݻzVm#"CO.A3W,mKKHd2-t̝)ַO|JKs{7Vg7"/?ϟ+++=w Eg~I=0!))2m~۲I󺙙Y1"""&VCKumӥŸ|AԽ;p,8yйf ꜎;/?^m\6}b ?x`1"""&3p0֭Z^+))pak`56IEI GnĞ^eۓn$#`ХSZ'-A=#$S}(ƽz1.f[cQXKM]90k4l\g'Z w۶U_}O 7/N2y2w 4|F GII vl58y*ҩ>Hx}DD"Asww̜o˘3h'OH.! 7GR1! 40h ϜAFF&1?S_gl#/RBpPϿaldٚIN2K?K͟ z|ʈp"G˾Ï+V⃙#6} ,`՚Ĝ>g@Ӧ.}f͞S޽n >~"۠;yyyĕkא}/={t;f{cUɁm&HD?Z T#GAL)㹈>q/xÆ ^9K 2VVVs^tv 2 pppo˯(ViSerM /=?AAprrϑeX^]}?pǷBX&Ç>'wߣo*jY055ŬMaݪ:c[o:S&Oݴ4|k,z)f75ѓdQ̵i* o߁%_.DSO+ ڑڦRXdTsKN073C7=ݺ\99:7°gG1bP?t.]o1 m{mM?Cmܼyv Þ#ǎკQެ|Ǡaf|"ucccQm>}?Gnݻw5:TJ˦>ܧ"/011 / 1~cZ-z_>qjB{ptpMD&(+MGU6iDdxi#}*+'}{s>B… A޽Ӫոt2ѺU+aov`ooW'1H$:xV]!Ւw32pԩ*iҤ 磸`m%|{ظrbb`ov^X[ D__!w/V`ן!-ĝ=o:v6:^=ljm۴'qg!'}kL+evu#1| /xNZ\""zƴXb[xlLqm.bќCHa5nFDD <EDDDD$dQ'g0/mQJ&1$""""&DDDD@ZZ#ADDDDM2۵kHQ5O2 pOx&""""xM&IDDDD!=#011#,+ӹ?_kbNѓAn.nܼBj͛?ɜ8+<(J Pr2<=32x>C$3 ?8  L&eӖ\&ExX#ODDD+**J6,YJI#L2+[Q(Qtj`(*̍b䉈@5.j ȤQ^&b%Uxsv""""dVIDDDDT$S*&$DDDDd$DDDDd$DDDDdZ0h/#BDDDD&eI&5z弱: W2I&5~ڼ9pZf+,pM{POk E@Fq8qc^Z8J朕G(UjRƖ1gQ)Qama3{ɚ(jpj+OR3QC{%3<,ۣcڲCi!;Â痿«-?ynt,͌ dj/&ysh;XSr`gm7m4N܀b=Yc`ge*E,TȤ9cyk^וh5;qNm0~lW|nmOQ},LCZj ;#-g 1&br,L#ؠҧ=ճ]u!J0nz\]aˤk1ʙ_97" [;bxk#N /bnD>,wrզ2 )c+n=G7Ք[93Fuws;*l[oG[&X{yWDªN9{7bkXIfT̊-1",=SXNjؕ uŵ;96v֦_Bq%L~QX|I|>1EL= įb_Mbz?W3b#wÚ)+w5\dIDD3,HeR ¨P/)(VD^4~= {/i%>-f&rL{3Fۡy]l=B;c`WO(_1st?Zk̐K[YZu~-0st;aF_Md?}:!1K[6O3H.ջ_g1r+ {k3 tvG~Q IDATq&eD3c9075Ҫly)Jrg?zΫc;kSd]OXr+:/c#Ytz)jσVqGAFN!!M Ucs~&/އc,_c^psoKpGDD?ɬ ϦHLCoH%`rr/ɋc闾AЫ|xDl,L9XHb%zO`[υYpjbЩSqӯC0{ ]\tmK!m1ΜM2C:cjX8xjPgwfO&@ J_3N&$eE%̚ɠ(Qiڕ Gїa z.&ÎDld&}:]Uq/WK:Xj߸-$EP/OHEĮx-Bq )ZeG+!!) E %r 8w o-ާ׶ Ua}hS _HEA7`ᆓ5boB_6 +śc@JQ.!@%[b_b)(V0n67WUPPQ#b5=R ȼ_ǓЦm .%""jLs9~r/J-\m2]۹@"m;7VxmP{ezWe^ܠR8\OɁ)& q7UǠ` /xcP{|: hjoW f 5"$Azb;KTCxX&|A%Nwfk%Z:WfbI{3H~G;bzk,*861C/fXvozDDT/$˜1c3~5?pr~>,vDEE5r""""zr1$""""&dx<81$""""&DDDD$aL}n{9 eĉdV4gQl=xJTeYy~3DDDDL2+  L&eӖ\&ExXP̈1ɬjUL""""&՚ KN B܈Js# M֮@&ŨP/ v_0*&L*&L*&L*&L*&L*&M^4?#KDDD2DDDD$dL"""""&DDDD$d1$""""&DDDD$I&1$""""&DDDDDL2I&1$""""bIDDDDL2I&1$""""bIDDDDL2I&L""""bIDDDDL2dL""""bIDDDD$dL"""""&DDDD$dL"""""&DDDD$d1$""""&DDDD'0iJ_ AĔ!""",\&<(J Pr2*b+>b#ͺ8qV;`j,C f IX+)yp5Ǥc: 9Č ]ǠcY3WuGW{G>5dkBQBByꧻç湳22o^u5;qNm0~lUFWŌgT׶ uDOHA8"l>pI(Q Jش#z0a}⮦ /ҲӾ=(y"I_,d/n8) N^ D8{-]x~_'oh޿r9-Zu.#~NtA>{[k[qWnl;Bl!* 72>C8)3=º?R=(ZO=b.}ɋBB)d 6tD{+{S:bO| b5v.4DH>^}L]NHFMS|b'۵4f1ǠcYltGL{Ou.,&#LV߷*m<%~sKma )B~Qz_.Z.fbeP}'z\ܸqCo]U+[.22Rtg12ͨP/|e+q][ZWZ&;v1\Ƭk39[9b֘DyoM <|,؛W;n;1i?x<1}dgl{ISʭlwdR lLЧ;~ѷA#3"&F244hgCP>x+:qM18u5;1kLo EcP̱liSq.] Aooȹ;r/!~f4k;1sto s9<]kku/1T׶{W{5=}Yi8S. /l*N=JυO,7r5=]amnos3`ca kڛrmu)>prg?<;r%|[:T#ƃVqGAFN!%O5P1$ZM[y|=%~-cb9ˆ*>snRgoqD~u{gg-d6"NVHHD\VZx`Ң6 ĊYV+&l+SL{O{,KݮpuTj x4mn}[@nNĒ- vҭS"gSU~mJZ-T Ymꈉ>ӞڶY!>j)b%N>ӜO|ۧƹRԸEb߭/<6 EbpB* 7k~6p_oEB&f W 1[b0b(.QaAMchc ۉ"v> &~B}`h|y_rg,VZXLTWF+ uǑ;s=#>Ye1fc ħ}Zq.;fR861GHf4ܿBzK,vzupJp=%v֦0ԿN{u1Cm5VHa̘1c,%3S9_c0jg?5X$"*+9}8pr~>^L b/XԬ|,a=[20A~9|NL0AϋϴͱHN{; hNڀX8ADL2H?:W7*mQcDDDD$dSVdNPgWYeS1vզO5TLrn!"zZ齒9gQl=xEJ[^ƜG ڰS+^MIql1 IY> >I07V8:X"l}s])Ϳśb T7bL?oQcC~WWb|~)96}b6uO 1_DDO|97" [;bxk#N /bnD>W]_Jן$K6bƨ.nnBmM1X_'#hWog#<"6f`a{.j>pK?\K#z wC9rvxXvk+1omtVߪ;U9gKn)K`>05aᆓ"v% <,mmqN歍)z(>Ǡnx(QjG象oG~CCU1mNH܈(=|]q3>Zf־A1Cq&cd/e*I1*K~.01 &? tE6N03ñ9.ռe03ÿ#f @例2Wne J`ke>Ìz1D eݟ ZJa" H*3st:v~-0st"v%8>1'͍aom(|}U1VǤ S#a%^ɬl&(s8r2r (Q$ Ws[v֦-< Ze|[8fZ0v.p--ާK}cJbJUWd_hA{lЈƼXCsR }!籺Sd^Nǎ#`UK>1U31AQZIrwBBR5RIYhlU7>k vWI%PȤGC#6&[K7齿Z6d[ zOкV/!)-\mb]O}11mni{iڧbƪ>X}h_rEK-P @obɖJ˶uDU2)S[BhS 2QXL,}/`GT"ˇJ- ~!vOBf~0Yi:GLtidHę2A>X9 IY(,V ,۠ʢM8w=J$$eaX>G蛴U56cb<~>Zy IY(R([[xk>S1cUy̐ $FV2[b0b(.QaA eg 5"$kAŔZ ~!f8MP/ )e|5E 3,zw7UǠ6SOu UEc0fN)]0z~BJf1~E µ%QH.@S{ >:}T76114\ ˶YP +6ѵOŌU}Qc!ƌHUhFܧDDOd'\?GEE5r""""zr1$""""&DUOI&1$""""&DDDDDudfDDDDd$sʣz7*59+2DDDDT$3<,2ӖL[vraA&, $>&""""&z KN B܈(Fr}ل` dR ¨P/F """"2xIDDDD$dL"""""&DDDD$dL"""""&DDDD$d훭o`0DDW8qC[?C_J| 7#'o4H{nKW$u}1Y~3zGPT6g4+΍a?Ǹb$DU9gQl=xJTRc˘^Z_eRƔD.Úbߒ0Wkj;ql3߇D|F44'~58ř1 li-; zhjIkW?oXͤ ߫\>|Ōg]1[CTB*B.¯F^5~sw7÷L_wÇtn1TYv瑖ṗ =ZVZ/bD'B&!kl.fN 57^t7~#z4l. X-7`mE'`nDfB3GKtkTvGK&Ҟ#g`Xy[9"=\4_ #M cT6>_\ç{[\hۘa@-1",=SXNj%bl +G+zg<>_O #&a=ڭ Ƽz}_ B[w[\ykakm`? |U5~/Xѵ/GN8#; IDAT5 @KSy%ZM[y|)^UVg.05BB S:oϕ[Ig^9yZVz.|ʽ߷nj=gl$^e(s8r2r xD_ SWf}_ˊeR-Ck_0v.p--A}&v5͍q>1qzl,bmP |bcGbƆ8!fN 57Mߏ^Ǹg}qz-Ѣ 3bh(ӽ:_+.ch|G4w+ttQKxDl,L9XHb%zOݬW %0~olǗ.aH8y.Bb˝ >~ _J+G4fcڧsUrl<κGu/<~ULbii{i}Q&x`{TbmGt"VrA|mgwf7joz IZא'eEtX8VeSԫX\TLZע%$eǡZy IY(R([[xk>y6<<wdCV!b xm---ZVQ^E7]*]ԚPJl+DbK"$GDd2kd$d" ̽s{~/{35]Ã<1ĥ~ڷgX=gDyvOڛaDo_+ViuNFqQ ~j ;SC~E;"Ug 7G"&>KvVlWeb{$ݾ)b# 8[[Dd2d2^/ebwG?, Q&'T~8ۙb_XBcf&z|0Ma̸N>[E8W}~@:9>/u}1Vl8Yϼ۶H}wC&Z[ATG[K?EaҲv͌dJwoO/dyNυ Pe}:!n>>_;ښJm ׅ/32 yRX|vD`½()-kK3,Ӿ?R=>xWś]f:oVW}nX)L~))TNĢ g!z~21`dGvFB,)eS}`3_Q_?s}d9|AP~ӿP8Zaޫ>ܣ>[6Lm CVN 1izyU]2 ʌ>[TxKK#z8e# |}} jH2ہП1h=c#2!Ưsg2JJJ?rnO kˉIhmӔ "ߛhfj^JZ Qknf/a@H)o!}AL2"Z$XˉI&1$""""&yfV-ϻQc[}_DD@Γ2v}0^\A_LVYtJhj)hij`f&"""jLjt #DU.+,CU}|3 ؤфk ̙iXsafɃ0'gɔظ? ws&lHwG,)|zx0ѭL <Ƴϼ=޳\7w@QƩ+)t raDS?>d,i}goc_Xy'MޯGcdxB{D l$Gc:coL 'Ialј01QiL%`d/@3Sz:;Se㣎K_Xr a1ZpwoWo;JD$S K6cKglêY}ߛX9 ˦Tlep$>f((`+ֹt,ѽ5aц0Zk;+` Ng;SJ`fnrzœ sE*cT(G;`{$vWthm"l9rB2P-2~2㧏AGKwe:t>MSL`Dui)/G:U^&@*Sf8LZ[D͖p|^O|ڣ$khc)9Oy[;+jU ,z[m%R[{F:*'ʶ wG jCkKBбXrө٣ŵ9-qP2|]\[@W[Mt1}xNW)οmms]PR::^l`nM Luj';q? "fBꒋ²rKqIfCkK,3\-;X !t;=Ҷ">ʈOɁs2ʶ5sq8.ʶ7c|7_af%e*+`}5JýbHHZVuAKR6ׄb—`;SXEŚI@g^wu"Zu<%~]L|X|0#c7Ѳ1tkahb> #hkDWfg5JkHǗ1TGup=Gx\&~}oq׃'"hjVVvz/R{ Ĭu t5!)-Sy.'.BM6vW:֪eBٶ:4| ~< ks#8ۙ_v͌on8GoG?Pxur 6K_F0/_bIDz㏵ND&C&LԡX,bC,"HSWR0#ukDĤn&/*.ͱj%-X"Y>B)a|3K.L+G H|7n P-W{3,9?yjؾ.X=щ(."*!Uqv3Eб8I_$KX#Rz& rC@p$bDka:9J kۯw;a |P28t>N )L7;! 86LTw5/#}Ck =2yP;|1 Y9E27ĤAnaS\_/,tCVl H fw#~!Z`戎X)LSwa{yؠL&ϻvz.L0mhQf,jVvHn%3\5 ׅ/a4 yR> -ͰtJLJ[A^1o {t ,3L7S1Ў/UbX~}0#O;#!>zuŊ/DAAAK.Tҳ 0Ǔ0㋈$,?]_s7DXa> 13#t7- 1_k>æ""OL""""bIDDDDL2US Hzeg c?wVKCm!oËlT:/ :sL2>;O--aPꑖǡMıo`D6XZL4!EcӀ,kǿ0?뱸-jF_/n)SKPݧoѺ ,¤=eD"Mc/"6DU.+$Ya$|3 ؤфk ̙iXsafɃ0'zN]IѸ &:iw6%{D_~aV2%`d/@3Sz eŎ[+*Ywu){[߫%¯g`l?D'd#&>>Ya{bUPٱ8s5 6> ѳ >Y(sLj/z_)3:0#p.&"zJf?Tf1ʎWu䋱>b2pa145hޚa$b3B8TZ&xM"J˄ΨTϫ~;"Iem&|yPW( Y9g ˵&C8zPP,F- Ǥ˜* p.&]( /?W-AL$,xV()-jq}u/e*,DvP$.Fw&]E&De o|Rߕ2c!0#!%R!'_,!|TWN8үlO:W(<,, n W~>1U^bEL&< '""ŝ;w}>Q\PPw2M1@K[450 MR=RV?[tj}]-X65p1.Sx?߫% Ѷ9> [l>Oy[;+jU ,z[)= #|Nhݏ/eO 󂻣us}l?qCL֏U9N&62b_>.-F>E}̕:yo'; nc.jյ?1OA607чƺx~g0k|PO) ,bolfr\|bۡ%ӹY4sqE^RFBC=՟_i*P:ښb" և\Ù4-Q_T&:8~}yb—`;SXs !"zpniڲ Ԭ~6yWXQ(Ƙala>.ϩ_cW!P2}W&Y9 M uÇ}`camMHʬ;(5k-N׻9ʭ{HL 7;/ 1ɬZb_XB$s t=Z齪Q).gᕎU٥9 WIXδFL&@SfY2RFk릈IFvVuщ eWR>&x/Vwe"F;~SӵSe<=Qf?Te5քLadСN^ d2 nDӆv>r7/gb<EB&*U~)xSҳ SewuX.T~)1}]0ȻJ1 +EKpmit{ˏKߕ/AX%epmiSz`GTġ(yn2*^1Uf%Ỡp7H%el^lb+BD/=QPPHQIIIQ1ןYɤ@XX4:""""R7&DDDD$dL"""""&DDDD%\T8](#NDDD$Γ{RKdq>w 1ɬh)S)=w<781ɬ@QO,&*-Ҳ2jVHeX9$"""zhez*V}]0K9IDDDկ/{9IDDD$S8IDDD$S8IDDD$S8IDDD$S8IDDD$S8IDDDrӪJd#KDDD`I&1$""""&DDDDDL2IL)< H$6FD/Ԏ^iRnC-[n?9fIfCHF :H$zމ#(.ODD5K2^4AEEgk MSCDD&OMWu:>Z!SpxNK$\X q{",`|`@2ɡ6c"5D}8B,K\09j:\с#VZzVVfΜ GGGI&8p :$/#䳘-[Knn0p>vKzzj*0R$BӸѻ7.⪥%Ǝ4+Kz'B/⪥%2R$?%wzy=jU+doT(ӯ+W"tt訰 B̙vte\i7r^?O] &)/((Hxߓ X.]#O%L&&&BLLL[u[=xBY>щVaBA Q e$KK)__MJ%UP IDAT]ٳQ_]TH:$Ė&&BLIY)6NDDL2N2Uwyn%tμM\ |_a^eb2m).0q{"~sQV*~|.NiJW4͛7zn/_3g:uoooxzzݺuC׮]e[ >-E.1X1F=z }xz*,k7o{*ɠA5W+0[O~{K|& wn .7N` OO::°[ ~o@kxꇈU7m%Iz~C$2G#sth? ,7~jŘ8q"BCCqm?~ ,30Jkc Zzɜsnu?R_ձZf' 4%o#q-X3`[O?]lW`C+~jQ͓L2)D_n ]fnshd*'!&*GYXavS2M=Wu ]p  _W$SKK RZZZuzۣ94 wN믑8q2CQd0-Cuw(/?>d0IH[nVKf>aH;iiжE?Yq^ ֬A9AM CJv #ax@&@A Ͻ=Ej=%5hn`0^6 )d0^"IIIQ1ןYWxRޭ!Cdܹ??O$쌌Or 8cJDDJ`IJ>)ji¨G4%>:u ""V}5SOad0%Nm""R g2I&1$""""&/y#m&&&B```\I&5$%)_` +W ;;mۆŋs#"C@T{gΜQXn׮6m| 1Ty#WoHOAT 2^};]O#V tæ >`/{ `=;"9Bm;O"39 MүB;8t Ӡ61|P51TOnJ6[ʋ8~ O\„`H~UWVe̸cgƱ'fMw+JSGǍ7SM- ;ۡp`R~Lu :c@mhj! If0 퇖Kq|I^> 0=(MŒxoVȽVHm:a(.ПGq& f 3ӳ퇝0oa'6* Ж{iK'CK[.y#UHNު*Lߕ~a wzImh}(.,F$Rgkr=R?[oO""bN;ȟȹP/ޑ?kluZ8okq#>C V8]OOOlݺL2It;: υ|ݭk ʥNGĉKhu8oGkڲvB;pn[mmc|~TӶVp6~;L5U445 +ACW2}WVҍS)7SܶlfMYi_UJ2}2;lm=oF.Rx4ǎC.]^DDDHLj<%4$_}/_bjxQ:u@DD%1bq|Id&g֊K ebp1N6ڸiCaP^8~wS`}GF*U^Kx&F*ce漑0U|UէLױ8pB6@7װo~8 ζnqB['wF4袭+M }#FsD"3Gٳqycʕu-Һu!-L"^urWG $b gc?U܁(-)Eq1bM5ng@7[[P7kfs1d5껲̭a'v cSc[?+ 9B1 ň:M+˪U DT6=V'3BV&á? 3/+Wz̆xQ9s z-@GGڵæM믿O7o=== 0s5k@"":V.7r.@Ȇq9Fpbn?)Y0jj{@oW~ OgO'y;qI^Y=[>UӿAǐz; :hç QCU]|{xQwOOΟwcΏ:4RoA@m\1l`7T!=[q|qɗtR?̄6u <DDD 1kv|2qpMFOgdgc;a Nmy#)5s G.*$B)MϲoA {uضFq< 0~L|GOw\;d^={ > q)HK>ZI0P:TϳFHH cXXd#{U(;t`l:; BQٱ;o>jQ^匪SUT2<|q88Wqo"d|;=R67,\_iCǿoj5d,_&MT*#L@cƍ={6nݺ''']v2˖-Ú5k0gÆ Þ={@DDT L&òޗ%GIIIQ1ϾkۓI? hbni,?3Z6ńyu""""&Qw{2'"""4dIDDDh0DDDD$dL"""""&DDDD$d1$""""&DDDD$I&1$""""&DDDDDL2I&1$""""bIDDDDL2I&1$""""jI漑^ȶ^$H-7t"CW]I&,L"7LH1Ӫc.ΓL΂qS#*P&!C4j{k 6FM e_'p7% FMwtotr[E'.aq0nj~90;M,L3;z !}EqG[9;Sr3æ WNJyO#V tæ _M6'.x&M> ~-8}i(20k@Y3y+WO?A [[4=Kt)ikð[74G,J# :wFYn.R?)~~pض `d[[ߡ^ŝɓբƍ~ 4:.aaв@YN Μ+I#E*gZ/a"㫯4}:kg7;9;v($903F?H|m7 x$t[ɀ*řFuioBU;Br|º|a?NN8a*%K߿*ok'Wn*/JJRIcT2Ņb_ʶy U \N)\/v"<>իޗ?h@DD;w|| Nf23خU0P0#\׽*nfak˶ )IDATNqvOall)rJJU*S\POz =ȃT =5V]ܭt:OOe!wO,yފ_0 xr9spS'z{0MaPe99H_Giz:db1?j﷞+4MMQpz@AX4̠"/StRT=Ϛ l\SS2_O:Q p0ViZXX­kF?xw,ւD,"/THMOWG]:/ĉ( E;~i r (]OI27G == pظNtèGl eVGDD8ɴvB;p]"g*@mnp6~;L5eae@J| ,-щX~. n]KP+lsr|;-=''+|9;+up|YX/ IHK T Væ)''CiS'*. }}bhոofc+6 9ӧ^7BRT' -HK!*̫Z)7SQZRB1b.śjܖ5Fo"?@{@r|*$b Sw]qq™(.Ps1tP_)7msR\2B6h;YH=.@VXf~~27||p?0dR)J32`xxTOvA(+𚾧'rsQ]GnVZt۴v\ VVmFuŋ0~< !+*BYn.rA|߾#"Nf2uqLCAf_G?nN!r+ =UܺEvF6ӿ mmcx M̛8!Jq8ezq쌂l_A&0Uըwn  Dر(MK-}!Ə^ ֬A9AM C={*gbR0~< )a#X NqW دYķF̙ShFOtXB&CQd0-= ח """ ϣb?[;0񇈈ԏI&C֋(""""&cIDDD^<]NDDDDL2&6Ֆw!""""$/zFԓdjDxw""""RO Z=u ;""""Z%MqY#DDDDDK241P*1JDDDD$+oo4odH%ϼϷ.x][FT̙ t4xv""""RS).+omNDDDDjL2ԚdAɉH]If `ߝ$2:DDDDT#ti~# 7CDDDDI2ߛʨQDDDD$dL"""""&DDDD$d1$""""&DDDD$I&1$""""&DDDDDL2I&1$""""bIDDDDL2I&1$""""bIDDDDL2HuǎC.] D=TD"3L2H-+,_CuOBCIDDp:uAC,d5B+W#tttUV). ̄M6Յ+}$"""jdlقua֭С^ɓ'E7nܲe ̄cǎɓѬY3 4η3DDDDիftѣV^~B9[nXz5粍L27o[a]n_a]y]vELL L""""R/L$*rrrBxxº .YaݹsѮ];&DDDxnYfaٸp qyOPXXpaǔ]_5];''кuZCÄ c"-- 1~xr~)<j ǰajܮ+ӭ -""F짟~ܹsq9tؑ!D"#$_;ʴjic##rXXO6n܈ &)cc#454W!|ˉ^/_f%FՖL& s$N mHo`z!{EIENDB`icinga2-2.8.1/doc/images/icinga2-api/000077500000000000000000000000001322762156600171455ustar00rootroot00000000000000icinga2-2.8.1/doc/images/icinga2-api/icinga2_api_icinga_studio_connect.png000066400000000000000000001306711322762156600264420ustar00rootroot00000000000000PNG  IHDR < iCCPICC ProfileHTSY{; P"D!$@B !TDEdpƂ(8*u, "`>Ae,>` ;gw~|=RaY`_ZdT4 ; i@bg ܙ@|k||lF!Id1d>@jFOgu`w ,/D "|dmgvNh'bdKi ӲI#a6A8aӴE0t/d$<{2qHKͯ 2Wd)jS$̏_4)pB*&@Vr@($\h3T BPT CkP?FwayXևtCp6-|ï @P(-DQ(!jUF5:Pݨ(1j ES4 C t݂Bc(5 Db012L ss3bX{6 ]-6a;aSqA8. Wۇ;;>IxMez9~ C#8ZvBa0E%d&b9xD"iHI>I> >㾶|;0~~; 61oR9 $"Yq0c)鮥-/k A]AO o˱˙+? Ćԇ| (0L.^>Q!\>Fj/-]={Ş#111V\*UJDzbOa"㾲XլxFq'{/5Ǎ3P"94esҮQ+;U&%JL J92ڔOKkS5פ Lqcƞqa&\ٖ%49="ClOWZ#gڭk_+W+wSzU 6l,8W)e|#6w CCTppӖC?ػz뾭ߋ8E׋-ˊKdSOn~pvǽ;kKeKsJw-ղh={ٔK++.,oۧoǾ܊Mo?ys`Cꇊ}*ߪjه ? ՚oGGŵ7 c1{ok4kjRl*>NN5{'NvjH}aéGy1<){wߛvC^C=B=f##)^h{įh߫F^ ^OMo9۟=#ooߕWy͇ ӏi&>|L%ˋ_q_˿}t%dͶ(d; % jDx6~~y6i`vHf`kkGd&Z[iZ֤lz=68==:=1Ώs=LEB6`%ڮ <iTXtXML:com.adobe.xmp 428 524 [@IDATx `T@ 1.O xgC @h 0ϋr}[" ZD^hחy֢o* @ VW: Hs.-ui.uF$PD|mmc a$P' ԆPh樭iM&=i 95Dj*ڴWX*06&w#TGU>qaC'HHPP3hblIҷ9 @$@ ߡY3ln~|HV7?A;aZЃ5`*>Ҷ jʎHV0ǪYz}U)ŲcLʴ1j{/IʴL٨j{Ja*Ҿ">5կe@&PStE}ElN~U XV cUmpom: @#P?v;Ca׶J\l+w e#pUl零$@%;PƎX UIVSge ?Ͱ2۲L$@fYVU/D&-4 eE|z[eZ'*e˖6nB\\\F(șHH68W*ȑ#]s5?~. Z\d䢳&kV}zaP#?Ɓfg'uoeʪE-wln&Mv\(r8 ࠚHOA@dd$Μ9[nN8q\$W]:hI[j'uIf{MnrvvubokPAaYtZ.~19993Zht& {pı]vfPlJCnilc{rkn۪C(Yz}:Ȍ͚S>z dNM@՟V%k NJe.?CW\>@y/Ξ=y8R>6OBhXX <_=WݲЉsHT& ֩~eM[.N" 4Y}ڮxa+|յN2L]ehVpb;DM>Á.>ݺ~^a%AJ' ::xm1ѪRХ_B|h|eoԫ}qoë@T5s.#l;5ŕoս-p؄.> w`&_o+*Ν=/׬ƧEDVjN}pSur>4! /覼i\bՙeRmܵu;mkͭzuՑt@՗F%7Ň7Yg؜;wx*PKŋqٮp " rD'6ևɷ6z$E&LlĶ/p}VM+v3Ƌ/2嫨^{$18w 2'= s?Aq`?6 kv3~(ROY94j7w oVi#'csB޹HXaSQ~՟ПسÆӅ!cS >e3^uV䒴] ƾeU }:˔t9FTRh`%$ sOb妁*7on*ۢrܑooྻG tIaУ}釡NW݂/x;Hy\ƚY<WL1C3{b<8\کs܇y/Nʒ Wf'?7| DnjVDingmW @dRdve-D>ʹ}+\>f[FC!WZr_Kwy-Z(cH$uiܠAS׹{gU(j ?2 3;G_3'b#Y`Ub!N_Ǥ܏gc y_ŵ2>Dہ|D_c)x6ɏˌ?`4 ,2ЁVɥ,eV%ݒ V%`>Zf dq f wjV? nO{ d4/G+r&[iH(mn-2Kmyu/=vySc-2̙?_t/'HhY]΂0}rg1ӓqeq~tRc:xhs56D=Ni+[~'l7:A-VxH%voCvh)bq޾ƕg@*;㹹8EY8< M#JۗNF9g_\NG!:$m}{`؃bع8Q'<CoM~s9|Nt9ͦx5 rh(hAG4k Q:jLXOk:@Z+;>sYtIQـ%Kv6v2c벯N'2ܨ, \Iy\ "VO ?QS'ᡌ?q7Ķ ‹yKjķAVիbi/6<"'"uEsϽ)70 =2qJV`]g#MAYѬC73H)*c+FW5+4|ʃ2|91XƨƦַUu%uAymg]hHM%(:tl{[{b'ϝGO:Ѷ`ڱe9gq׏(?w&_NW[]js>M8w q26oiK,Oԩ:~ r>s[$,Yy+ĩs2 CjqZxՖ؅}K;(ƴGUTvq\.&M{?;C7)o[~E]N&{_G>]ٗaDk$7>YKש1;w ļ5 6jWEWx7pw{~7_S^{ OOyKqM!L6P +?9Ν ?^4u=UXSS5LleNu+%X Ne˺O[]~Eqp&-C{uÇ:]h؜SI6O[l /6\Y_o٢%Vo:S`OE2H㞈RzM^sY\Hu5w?R.$~6n'Xl<bO?q?&>Tq 2_ 8ԇ+ o(2U2xdظ__K˞ĸ>3Z$vg3??S{bۻ0PׁꐱDFw@+`ʨ'=@bliXZ2\):] -Z~XI! IPh՟*P_ЖXTmR8/հ1LJ9BuO #v|BXoOZiu/L}BѯX/J7?e3B3\u0[:syϟ_lC_tБz(Q̮evYf-K]] h_\xRuܪuYfXNp%  ,z!E`z 3q]ҁJ:tݚ.\l%ʾZ۔՚jz7|2s_eC$`m֍>gDeX8wցv_kK.];ruXM!$Ҟר},$2r-+k9U$ݧV՟EJ\ b[.mNIu_ے@Cw.u:jp9H7ֵn|:@9ֲ؊̚KYC̃1뤬[˺hJl2 @ KuפuPul+rsf*ʬek.mL" سgb" @6:gp$sZ\e/o9ڙ 2d5+rOF>v$@$P Zi^+Ťp_n.W/?t2L2I,ev"& u zh^̜{tek!Cu'ͶR6ץYs*ֵs |dK]2벶W֛r@x9JK'fۈLv23O})d" "`eK:spf_b}kvRәiGeVsqa-.r),3~X& LY2o;qZ'utYZ^ܯ@*2sr>n\1gN$@uz퓲$k.2}5u"ItZ_.ts_Xv[szi@sOIH.2W,0R$vv2ibTxdR7dvzs{)d~/PƩ`?6l؆0yh†m Q8TtCg‰ʺ꺌׮O)v5Wu[uR2In>i[o= qCGv'v] }0vT쓿\܉޽t^[>Y:ĒWPm5ډ/G X0 >T];*/%t_ &__[ ?y`"B:hKSK2ƭ ךzJPҰ4 Lf]˵jO%}M1x^ n@op2C x[O@BR܏HL#—ܳ KT_-8С~*u?*ߖrږT}F Fײ"/6oj7ɮY5?~1ҍ./ Ztrp+*U<²eQo<zʤ4EQg7=5cm-K۰Du Z&OYZ/ @RLگx }]lak|Ճ6&*(leWam؟FMG{7bIQ8 뉮M41ʑ*==~YsFr0sDE.J?v2cSFV=>b"#ڵڻW0k 36.$޸a` @-`՘{WN\܀dH Y|̪׮\uKF+ڂz tڙ'"m!r]$7t9 jm Aˉ=k_ǰdr5Ϯ K^7DZ#ze>nJ!wz?Mއq~g܄/PBMBr3.{dg̹}W7QW'MϪMǖp?_$,m~S=b/B4ݿkK!N \VكޣiBS<0-c>"Qgwv iܸ16mڗd3+&꺞ȭ2<KIy+'lu;:}+Kr8hذzd<Q@$@5@ܹsꞸXPțjckV˽mPPl 20$kk;FdZs6?s "#uO(x7lH*B@$Yd*=\772)NݵҺ\%FWfEny%|7 +Yd CsYJݗNgRun+Kʴ+7+uEh7̓>D:ʤ5`U\lRA$@J.:($sNfˆC?/㮬:WXe=Va]VZR7ZΜH hFqv\l̮]ʂB11Sr}$or3@mcL$@uݚM3Z'<uӪ733U[:V0&m!es]2ugN$@u [ aguᳯX2[eֺybt, @]!m&y[uֺ]M*;PY\َHjoYn7'kWmp Xekn:6Hj^t.CuC?_Uև[)79 \6Ͻrsj/kB*Ⱦ&C қ.éXeMM^5blM$@MM.36P;sk:`Dάe X`غj 6:-.|Z䬒 @P5O\ğ^ N=',U܅OGcAOZ;fh$r>MM[7晄, @Z *S /WfL@m+3*i]5oTETOcEySiS?D$@ PuSl/WЙu Fº5DqjV:Ւq<_f17uRf܁.R)Ypfdlt T}@8,y 3ۚj݅{ ''G{T^_:ϧ߅)_"c^6֮~gkV@y1jD~>]l޲CmSv$yX-Ro߿ ɷae"k쏉Vޟ뭗A:l I sl Rz=s;}:V~>~zv%шl4#Sѵk{#Ӹ]5d|! D ܯ+ >-o k: CʗY\F޵)*]t]9 sF']Ԗaf%I)yGո2$@@Eּ5, I~B{"Uh&FpT`u;3-nfLIMćTRKЋlRږ% (%o /F5xu[섾Á#@=8YX6n9;1f}Q1-L@wD7Q1mV!ts?yX82 !FWO!. "Bʞ5NQH|f#bRzdC1g% ƬQ"uD_LhfdRi=}3e}?qr/OSf$@@XȄl2I.\e-\b#L̜KY9r$K^S~~>""ļD>"* >Ap8]*+̞I@QQbcK>mpHU9"Ӈ\inέe!Iu-7 <6ve_2XB vJ'2 1`" N@RHHH 0`)IH$@$@@]X 7uvI9_ HH`;3! :MN^NHs.9 HH`;3! :MZӳ lRb7 ˈY!  T^Jt,%UGkUA$@@vvvx`hF$@$Pj?{' VhF$@$Pj?{' VhF$@$PB߹ 0#t0C#= @` )B*g B؋s9]7Cfo Sz# `Zc(UkF́ _ X~uk4* jPq3W 1£KHywh*ݨ6JT!V7,0"{Pz NF.S[22opbCpϰ;q/-ΒѰ@$@e 0`k/^{^s_Es'b猇p͔Րp57љXC:ЯbS)Ɵ.PNn@ s'_d^EgŽrm>(?>arpXx OcqHs 7NC`d&: @f&Ԏa.øtٳoG؛VHx/ ]R^„DUb.âmGEEEh 0*@4i|u+UN 5֮TMij) ]RK{1%8O ;A}Ss*F Z EqIeD$@OWXƼFvؼcUfN\7*#X-bpYVA,}>^z).;)#hMJT‘;K DG[zʭ忼E]}0x 7=d8,f*3 @`.gUOy쨧 Igl1BڅDXpى_. C>FLL߬Hت t'}.<1' j'UMc. 뢻2ac*3g`1=Mpe/[o<8*:wc+T阹h;j qt6 y͍8.l'qxf,Ŧ,̰ a.~Fj0^X5RpF IIm{*~:z$Lp 1*`bR Fzed_seʦ%m{!WӃq2 FSDx>@=h#Rz7<^ @ 0l2I:+""ļI~1r:jk01Qv\p8URT(CW_r7U9UjU梨= s{X~Quxx7\M.2}hY-\͹,u9$鲹冁ƮKu0j'^#cZ"U;{WgHyR:/;H\0 @` S oBSISq$@$P@r) XP ӌHHn C @` s U$@$@C+|GB$@$8T 9  X>PE$@$>\p$$@$@>0`C @` s U$@$@C+|GB$@$8T  'v|({7j~> &S OgHα _V磰vc\έH8go}=[N$@uCt'*ݻ86zTOL\lE$@DF+ #uYHGq$ፏxFD$> D?@zX,2vG|J<٫6eOcf$@$Pg 0`F61y?|uՅplB{~,^sƷGƈ.Wط3#외EH~;yr_1e;0uzl[8g*^HM4Oi1foڃ17|5w1u%zj]]c GqZb E X:dU3zoَ>I}4Ӷ"oLC'6Ȋ\˓ZTe1F$Pw 0`:CۑڳC#cv8 Z.lDݡ֞8%^QeC4x% 0${X!=)WCn:Oôw>G\l^2]W'6^9Yb 9 wV=A#]5w2 9^:7j<qKnHYaAww5#m*4VۉSk45jOvO=qPۍ˷HL,+ktYrg-k)GdZe\Mȑ#Y*!5(gQU꫁% @!P֊XO%s*iu8"ӇI$3׵\rkY˔YZ.$d.i BG@} 8__z&S*HHžV؟"HH@0`}@$@$P+0`ՊA 0`=@$@$P+0`ՊA 0`=@$@$P+0`ՊA 0`=@$@$P+0`ՊA 0`=@$@$P+O4mٲbXƄ h@FriիWi% ZO+ȧ01112+ӌmH˜ph$@$@JYD$@$ph$@$@JYD$@$ph$@$@`)m[O/@F}!} Q 0?+i!Jg>1΃_o{4AСA7vU_F_E[=s 6\7_zֶpDŽH2~'bˌ6+pG\4 s|e,U ZN+'ϐ0n(ӱ HWjąxnwRFN~f(UBiJ 1˚!Ҹr{_=PB$@uVHO9mjrY|؉$"3" Go}j'OQWS.1AÇG>rB7 B$@ul M IH@=XazQlZ`Ӽp饸GFa.hv3`HK/UÚ硃Ӂ s\HPMQ|>[_V=:-@ʀ 쒘X]%| uŢ~\ w\3{]z`;19ܵp9֯_c1aXp602vO\l $@$P'0`4F/7&whRfkI*P$^KoH fi6#{$@$ Xhʼn 387HVo}S.Ҽ){+һZ+ p`a ޸ǜ{`>=|m3\(]mH[Gwo=gNF{3qI !56l+sXДHH\V!pt^] z%Aԁû] |sl}J_vS򱭤U`)N@&Mб_vLQ(K0G<\^sOAp6_)זtu=}i\ Q߳v?>ۻ╪krRpgWoGzS])QS:u8:B4F]h9kY:-}{e2;\"H:6>F5j=Ue" "G,`x ‚B4:]FbcnvzV WOgkcK1[ֺg"؋LGr_Spxz xV!EZ CNIH x 5uY)iwC? 0%"9s(g.SL(ZwPuq8K6 O=tʎs+cF^d ΋mXKXt5ݰ粐sԁ{aL}gzāU#~1ݫ1$@$ ?Yne/K]܃O$|c%cc!ub?o_j0t-zw1z4ul #tIyS7/ś_Ž\$ 땇qu317#Uսq^pI/tg8  IWI|b'( u% % MMwd? ߥBB]+  Xz! 생p7՝ дCbNcGuQmVF , @}!Ug1s&>v_/{ iKC.G R[~ᮌyuZgPl8`L\Updiȫ); bccm{*:z8^`"FrwGte\Mȑ#Y*!UOg( NSF NY @EjS\\pUiun9"Ӈ_2uݜ[RC.ZnxlʾdZDB( DF@T d쟾IH&  { Xa8@  !}O|*E@u*.[ZœHh@n3B+JxY`s -Ap"  Xs.8  |HH |0`ϹHHH|`*  !>#! AHH‡V HH,p"  Xs.8  |HH |0`ϹHHH|`*  !s݊k~5C'rí(lܸd/u=;őqhg=Kږx}g;'Xtt3}SIL=mz3 gnGrЯc Ǿ5HQRׅ>FV p~i ^bmm>.YNTƀIn m܁*XI֧pո޽rlC~$|vT } 42em]-].P*Fyk|8T ` >G7b Ŭ94lu/%e 1!^¶cˏye4+ֶyX5+#i"KW.)%>)67Av;~*8nzӗͳR4sCg]tIx=;=1 cB c6!93]tAt,luqźUؓ狛=3 :O+d؉ 387HVAN"w`(Uμ[!yJ2^1>vo`|8 ^ES0pGʯK' Ld`X=op$c׵9n˜RѷW:*c.ư>'r&kaXgv¤a^'{^xHG]9/qj -bĠ糑l΋mn<:_5X?Yۇ㦋T8x F+ƙjsM3ЫIôw>G\l^2>mV/1]o`GQغCz8 @}'+d[,|.u|$$c[/+ omc0yXwP#-m8/t]{H6 F]J>sf&"FGe>ux繇>ənv0^m]N~.4.:}0sʕ-@Ұr00UpQ31֪@ctbS1pq郴գ~O*$nG'>%W0;̮eCeeClais)7UG#GxVfUI\p:ե\DLw3t9p"޼+թvN}+J)TXI=ᔧ=">X+b0hEu@7kWvqqq)dK:?*8gLb'b\rɭe-S*CgkDKu;5%Jj3H'2*rSTb2ZQe/x)F 3rD$@$@aO+OH$@$ >  ji IH  ji IH  ji IH  ji IH  Gjm[l)Wqv,c @='РmԫW Ke0`QJbbb՝ @$]/褹%()ڑ (IH%()ڑ (IH%()ڑ (IH%()ڑ (IH%()ڑ (Pwڥ'zr(]ӣ {7مK_F+pF]~C~mB&S &`Ҵcgnk+0wRn8w/ŀ!0ipDf߻0ף,w7bT=m<0# ZB[!=Q VF?;ǓFuT8t]wor $@$P 0`$ߎ6 n̨t 4}.rbbHRqj.X" ZAߵYfW2!uY0e-\b#L̜K:9r$K^S~~>""ļI~^;S.1MXI=жYq!?41;fH _k"EEE9ĸ WQ9"ӇIY~Iu-Z22tֺK.I:˾dZ*Y"d!bZE%=D5CxW#ѶC|YvʜHŸ\0 @` S ,HHjZq8H  >tpKHH‡V HH,p"  Xs.8  |HH |0`ϹHHH|`*  !>#! AHH‡V HH,p"  Xs.8  |;]I Vn^w|cvu wTj;Rր:v1j1r^QN3^a쿑j9FaVfAÐ6{΋ A!tܳ 3%cw>"Q⚋ZTW3'7F231}H 3c>Ja0jdJ1#&*XO5u:9s6{Z{7{=۠|xXڄw?Hm?$}N54i9ـI0 /\gͺa{(i5s^P~$AcܰW-79L'=]xΰ/|ݞ8gtuдniܿ=&7I_Qb\s WN_nsquH>: bp͵n8R&Tz|AwX+;#[k''~m89\2uZs<ѥݹ߱'Ѹ0ORmȨTia@, )Y VW.mP-.uRXw;Tyja_VX~M^83:?s/=yPw6AZV >]T g`lT΂=]tmд;v`vX1Ivhuh':A;&XVynnu0j[ ܻ}wFU&-ͰhNXQ# A!zX_YP[Za8k`Ǿ}u=rf1)mj}-p5=c .fzcS[K@x:bڶ¤mkNʐIк/4ƭA7'ݰmm}uz8[sPsB[K-xV]pW~9]Oty&A5ê hxF+4VBCð'뵵>óU(W ,~`k>Ѱ Z}~_?A v>ZUP6O-vIR]xmA.xYeM Lr,Ď4  P[ \W<͛;S]`Q)cд=j4|ƛ CobJa<w /J*_֪50{J1L~ܿڞkw&× PR kͅS6B IbH5r,7 JÔpQ2h_&[ZH!|r~jDx&|wS c8⭤#o 'NwjPw.]R __v'eqU:mtxKvN ᶦcKF+gf\*ᛛ*{:/ePwm0yd[w}>0` {,f"}|o;̇bY-N#?kx}0x^-^&¯κ|a28q2.rv. {V-+x7:Ϲz, òZxbf/{$6ƽrBml(ɵ:i6TmڞPFu [Xߚ~>ɺ'D)FfqpXLfNM'l{M. . .N~<toD3L81ιK)Hs;- EP:KMЛxqxǶUB#>r,[Tq#EkoTŻR'x|di; 50KNS".G6O%9過zlyVl(Je0:nq? %2B^RyYp, .M\Ga:HH7%zE0>ya_ހ&¯`$̫Om?\^18w{{=Lf";'${E`If8qU8|i'p 8{N~jiOIV:A|b} s 8~&f+?\ ۮ^.hk:\؍6įףz-8ZYC"gHW y.2ƻІ_`:U_wxM=O4kӾPY_49:f.}8.znva{݃ΝEcvG_{igp{p-?3-w1wY rNM5Pg?]]rH .. J뢮__4nvrwǹ5r'kj8p.ggMa!8ac:mM|)m!59).A>͔;DND~zp3yt/`A!&_68ksnX9/Zj5.8~`;

<=G5g-~y.1KO9xb6̱`9낯]r55yvC;۪W'L:KR\`ުu:l "_|{1*{?^qZX Έg ?|$^ *wCrXfYU-,/V1?ƜS㱍2/xrF/Q~X,%u7"8S3NZ,ͱWAMe > _'e`F~t$Pz!.ې%PY>-Zw?/4*|囍0~1v'*|P]tT0LkrkT@C\w*h^cʺnp J sR4_Oo[5&*[GBq$M1~8nx/D?rf2h"Uxʊe>+PMHHI%ԌzhhVBݯ{k`bӹ:X71S?65΁/8XaUԯ Z6,~ba>}VePˠjU6l)r{N}} bSAH̦3FjutgꌑbH?G`cLJc[oвg9Pxߗn=D3uj0Z_En@%5Xqfi'ݑᤊ䱻ǃwC )(,JyQG~uc?'S419XF(YYs<9zι+z?v.Đ%^z=b =߅9_}%M/t|b1ؖɦ f t?}id¡J(,TjaN*l4Zڰ¯?rti# mDoAaWEN{O4|WA=W/jg~ҿD|O’>&Ң (ʀ2 xtH; (ʀ2@ 肥A3M)te¨]X̖r9&יڽl2v2 d]ϩ܈ovoc93w67KH*meHaͶfgmSP u 8ћ8&צM<¸ doRh]e@ Vσ}#Bg3acxǏ_MӦ~)m9*`/Ayo4糡n߱rJg. m4wS ';`^S^P6YZCƔ^Q"F{VQEl2ʀ20+c#B_ ӯNi}߁m8 hlō iӻyPxz@}7ehoC=\*H)_XJ 'B'r&hƴ_Dߘ{>6Lx//lR SUe@ 肕b߈zaL0a ]aPw_Fw5\=qLЀCb[|s47cP/<5P|͵Φ&ǤF}RGzo;젹^ze}cEKBʀ20H6Tyg{g륒kSK 'boi+eXnkJ2\16[WHd)O:W\%BMi>'Nd ~[ 7qB/{ xKPp{Nu¾٤gu(as  b6"tk A|zx7LM?_6;3vn,+ƕ)6u8}`.x. tlf n1>pŠ`x*6 bgpep%Z񐯷uDoi}e@H0G:ms7b\&8z7b<VV%<\\Nr=7s*Om}:O7k+.kQ+|6ܶF(fP(ʀ2 (])*ʀ2 `u (ʀ20(kP&2 (ʀ.Xyq 2DxvZxV]rz.Op4GkD=PݲJ.HUu۰t3Nh޸WV [HW=,چM){N}}g,^#[VZSGHs|v+딊]/6?<2v&p̯)}!`YM+ 4 ^XSs-ehVlJ뭏uG{յ>WGw>U Pa\i۷](tX[]O^d1؆4ƌuӽ 63u<lcV9,:0b!쫡6쁞T(i[DlqOC??nX2.7m~`2wX9} .M-ӁW8ux,B[KŠ mI@#{) M~gКvl?x*,Ǝ>AV%xݪ64DMpRK﯅5-;'A\(uav:Ə~  5p'|ze46-n :CA10y·`~uJlX_5&f|dc1R'߷n-^8y׸ 08.(=vﺍ&(öϛ1-q> *P0A=B[]\_ŝƒdJҶior`@Y%4>t'̼4d)앫8y=8Gw˴+@Nb$BSHɢ/@x`x"E:_~U8. |WǠ&l M1$=Kw9r`ג_;)q);ǺBѮdH6ZXm$>NebW99 u`ʏ,]-}m܆gˆ_SvKe&L,NmE|7,s_u=v=;v)g~4غ[lN\oK ǓM%ıWz/g|p}Qu#ooG=с{ᅘs 5`%ȦT5 bg:a꿂 0 *WCOs;'->2]4 r} ߅AN{m3Q0Ǖ}C{ ,/":r6j0=Xt ^?996*p8rv0gVmr|A@pe(ީ`ѹg-ɳڪ-.T=cWg S;kU#pl"D*k]K"E)/P7Á]us{-}ѣ{@]0F@p/Ғg.Mh\P54Ώlanl3z,\W,+4Hlh?a]5n~\w/?<uWye"6nϯ,lN}pP޲Ɖ( g  Σ)םG.-\ڡKZqnlc}օUƏu“7&sqRR 0g|dzƳTRQ m5gkc)T%9^;wg [k߁U Cy~ )Ə~V,e9)Cw$Kᘓq??^0ZWƟ,rki.PR E29΅o$G׭ 1޲E:eyXƣ87{ڡm2bjQ ƈA#1I>Y3F!7id\b#Iyx]{Wôqcv>+**i57̃䓢;Ol$v|?3o7c9Sa{Y3ލ1=-f3Ճ6xsK[>>l>`[[S*9Q( / 7 @,֍{{eeS p)M;Fnck(zIJ DiL<4NXMj'8|lH_ Yq;R> hRLB7*v!M.PhH XS WX{C"G&"QB.HM[jqI*|top`gg#JjMeUҢu KzT/ۧN5;bMg$,wQ#捻OYqLa@ĺ:91|6spͬ"4Ɯ[pر0R)ʜFɀaš.Ș0?2ᮅB;alPR;-ʀ2 (g@ʀ2 (Ā.Xz(ʀ2 tI; (ʀ20O}_UDɺ^ʀ2 伤>O?y \e@P EsP/C|.\CAǯ 0h U}ڝ!_ s~~t}>EO/?mLPǀss\!` !/s2 C`>D2 (C]Y1*ʀ2 肕'Q (P`@puʀ2 `I!(ʀ20k(e2 (y.Xypuʀ2 t gYǨ (@0 VD2 (C]Y1*ʀ2 肕'Q (P`@puʀ2 `I!(ʀ20k(e2 (y.Xypuʀ2 t gYǨ (@0 VD2 (C]Y1*ʀ2 肕'Q (P`@puʀ2 `I!(ʀ20k(e@% IDAT2 (y.Xypuʀ2  ug裏ރ?O'|>Oðaχ .=\ԧ>?])?%1t"':I՛oLǏ|38̜#w.bgҘ1}$8oGHwVNuԩXepi'C2jQ2[S KqrX .Ҽ[_8$.?*cLgoT>y=:zuEbp!q(Qgʿ=[~V~߼um=/u _1"̯|95 .3_a~] _&_ .v v~Joc0v0υm*'q˜ 0KI+KDjg/̀0c=T/)x7' KчgFʄLDWsR7??:;n[  +?0oߙ3pφi&1˜2 FR 98CYeZr+l+`ӛ`$ZSiE5ߍgu=Y+P{׬]os׹pߟ?~ xu4sa ?Xv> G⋕~Ҝ^z-s3\qαmǃ?]b9zRHXw9{wT<[qꋍ ;ѱGߎ/VUW}n|,p^!w <ǫzf}>+My邕7R b/1׏7]l|Iuλo; M{ӿ?@yc|_ / Un‡P>aݓwO? O?v_w6f?;hOTջNPM-+Bz<?n}藰g_ВQ̀.XhaHwޅp?^ º_~^~?>4jMaO|.{rR ЇWv6]Ïao5N_ ύ.I3V߾~`ױQ \qo (zV0 [ ~_~]),h/R;!5=p_ݷ֪ | =,4L(~/O<0{)|?v,|To=pM߁6Sbl|˿:~f>K+£OߍDRE'ipگ)<(<7M+}5~tHAa%:c$?Y8c$㒷z +#9z_op|Eחoѣ+?x ߎ)ul.mI:cr|8I*"u?}%*d SOcQo<"ς e 7["o˖ Vmy .1K2|:h(-d`~XӴq(Qgʿ=[~}@z~!:" 9~}MQ1{|۳9S%Q/J|P(Y'Q#GNx m8#C2jQ2[SZQ( g3 lf,3*f6taÆq㠫 ^xgOO>ϊ1@ wy:Qd|6OfE7:,"'BtvAVf \p8k@[4K0G!\[Y'F6b7h#]ڔJڤkQe`0@s9ʱoJ\$iDi%v(uMqʀ2 VsGJΩ<e23(z_ VЀ_< tҺ>Je@P\׍4_lu8d_fMՂ7'mKRcB,Xv{ԩP (@1@sΝ;qEC 7m݉9f+}봕|P t4uqA>'uZ oNt}3)_[%+c9WO>??cE>ăެ]-R'@WG:p=Js#1?}Rn;b:ISg[CXJ~v"?VtTqs6ۦjqn#,W2 ~n#vEu)INXA}^EwT~\Aɱ:KRKIvX羳mSb>¨KKlZ;u&,$ay`GwtbiBŋ)H\Ȧ~c$"uLX9N2 x3@_1Ҷ1:Kjǜm6c$ZthbueN̛o~8Uͬ՛Nx"fݔf~ AdӉ:/B$ivYJlas B)fLJS' ֢ (}"qYR<|lsAٌrIY2}>pY2nJ3Ʊ&s`@L2^ ܬ%?`aISdIcٶ0C9ɖEI\ue@>4Oxc%!Ms YJtMu0j%\$86oɺx`qNT{ل|qH hA⺔tɖ:T?g/Ts-8/UW dm_bIy4oOꌑenbeẄ|f-Nxfn8_< oNm¨K '1TǺ1m|)@8̿;/1Sg[J湅$,u flcc%b UR" ≜s.UE`^pgꌑA1Tc>s:Tx1#t)97Iz&0*d"mSgS[P \8S]iζ3浸HuTti˼~:Vs Ht©HɱW/<-  D6N$%eN'# x4^H0*\q#vc̴2LW]P9$ݓD?qd40RbdIV1?)BqQK:a%ҤRL]Ɯ'q87I>MIR6h^6Is e,ÐiN]}aү2 ?dK&ƶ$u6ˠ8ۤٞ& w+$ ǰ Ղev:O0Kql$t't'%)/R,#?#[Kt*^R@˶Gb+@n9ĖIu$˺)źM2Fnems aTfMk赯L/IlSr I?N,/^61)-^0X7%,XlI# Ŷ)fʀ2^6X~f3ΒbtYKqzk_,XDM,M0 pMJLtrŊ0*|'Œ$űnJǶMJBmhQeIIf\L}$c;Q,O:K36kv,0OR6q$3c&e@^(cMR.\60>PMQ1}9 2fڌ8Օe bdlI86Ke%Q1Җ:& 51i.sH.XԙL~M3umN(/B$(<|p ,m8c~|T(YlCv8[]Ŕee >lq&ƶ$&R Y2vMl*TǫHW{`ɎDթr5B>?L9.H҉ɔ19@3& )c ۶S]PYΒ(*(ncHqR( KH)iT;3멭 (IxH"v+N61\:KKnOXp}9ƔωłE UaPe]qcI8tx1"IEblƩ.,%ƺR:f V2sl>֥4u0EG6]bKl~1qa%"uz%,XԨmR0aIM0[[8B’t:y@1NJYg.Ƕ~?I>*\׵^x2ƙV$n1ŋG8`c@5{a2ƦFs1*e ajI̦ƸM7}Cs릔>ř>iXM,ҖWIKvJ &g[U˃u3r6H^>TvWeXnuJIL꜃0*8U*@3 ٺ͒bY')u1.}cݶ(8akcd}QbrZ4MInX'Ikr""fL.\*#<Ĥͺ$a&c2Vue@afMm?)}lƥ-Re]bCM\.X4: K8^d IĩA9$&mN9v/ݍLʸ$2 '~sn8K-RA~[^30%VEpuSR'c$$_B'J.JfE}a}6)1S' s-k{MEe *a[l:cR&,#b..X! b)i#sp}'>iS>?)}n0eH,0l}[Iu43ԑm8p5>8F(@TNxv(2J,aa!c[֓Mյťa٘ԩl qr_mK=J2 䎁(-ļlΒFzcImmabl,d8ǒzTMTOO2 &^Ĥߔćmu%F:Z-cMi2v&Ͱylq&g% u6},bO7}60.mT*@~07>?[l:c,=ֽ-&#?Z-cMi2v6'0bLϖ>YҀYg[L7uȶ\}eԣ˺+@n:zpIF6\b27Td6 1.KBٜ 3q?[l #Rg):Q9\Ďϫ (¤?Hﭟ9|z2lY/ŶM)LI<[: s1-6+I|~uԧ (e ֫ 71igC9-iKl¨\45l\zM6W 71iF':>EgL2 'Aob~vX ِq|vlW,בҫ b2+ֆ-}R'b-ug`k+fŔe`p0eBņiKnl/'YdL_d;Wg^6zcGp{I|^+@1U/,nI[Lom[f͸MFOr9YFkXm"y~unXF (c [_/ 7lĖS2qAyv'(bm0XbP[> (zF*@ 9 Ay6Lebmbz_ĦAr=Fa0[ Qgz?/f520jdP[^-.,Fݵ0|#exYW/jA^~#l~$֫TeL|e g-&WLkz|~2j< %j2̤:Q}^^8 uAAmEɥʀ29{l cv2q}S3c3r̤:~~/NNBPnS@o&렺~~/N,mg"(Nd'L d)˺+@~1u"XwV25v _Kƪ (ʀd $[?+(;t3m;LlarE!?ʀ2]=i&.[16ߓgo[7q&aV@}zَm mo~X"6j|N_. ykbn( m9Ccibm_2IIno\+`~&3#Fo\mFz7u3= f}zPg?&޴ٛ|sJ2[hyzu2 5ZZlMYH"'w9 ʀ208"b}.r"0檏h2 (0%Wy3bz4iE_2 ( "mx0gNh3i0e@ ǂm4 Ix00WVVa }L*|Li, (@oxN:.yTWeX>T)ϭʀ20Ȼ<}Cy"c7e`p1tmcŔonԣ (e`H.HAPtr3 +q)ʀ2 (ʀ2 (ʀ2 (ʀ2 (ʀ2 (ʀ2 (ʀ2 (ʀ2 (ʀ2 (@2z0klIENDB`icinga2-2.8.1/doc/images/icinga2-api/icinga2_api_icinga_studio_overview.png000066400000000000000000004570101322762156600266560ustar00rootroot00000000000000PNG  IHDRN iCCPICC ProfileHTSY{; P"D!$@B !TDEdpƂ(8*u, "`>Ae,>` ;gw~|=RaY`_ZdT4 ; i@bg ܙ@|k||lF!Id1d>@jFOgu`w ,/D "|dmgvNh'bdKi ӲI#a6A8aӴE0t/d$<{2qHKͯ 2Wd)jS$̏_4)pB*&@Vr@($\h3T BPT CkP?FwayXևtCp6-|ï @P(-DQ(!jUF5:Pݨ(1j ES4 C t݂Bc(5 Db012L ss3bX{6 ]-6a;aSqA8. Wۇ;;>IxMez9~ C#8ZvBa0E%d&b9xD"iHI>I> >㾶|;0~~; 61oR9 $"Yq0c)鮥-/k A]AO o˱˙+? Ćԇ| (0L.^>Q!\>Fj/-]={Ş#111V\*UJDzbOa"㾲XլxFq'{/5Ǎ3P"94esҮQ+;U&%JL J92ڔOKkS5פ Lqcƞqa&\ٖ%49="ClOWZ#gڭk_+W+wSzU 6l,8W)e|#6w CCTppӖC?ػz뾭ߋ8E׋-ˊKdSOn~pvǽ;kKeKsJw-ղh={ٔK++.,oۧoǾ܊Mo?ys`Cꇊ}*ߪjه ? ՚oGGŵ7 c1{ok4kjRl*>NN5{'NvjH}aéGy1<){wߛvC^C=B=f##)^h{įh߫F^ ^OMo9۟=#ooߕWy͇ ӏi&>|L%ˋ_q_˿}t%dͶ(d; % jDx6~~y6i`vHf`kkGd&Z[iZ֤lz=68==:=1Ώs=LEB6`%ڮ <iTXtXML:com.adobe.xmp 912 681 }̾@IDATx |T@$< *A ZEjAF+%hDʣj ւT(`J'Q$ЄG ,]sln.w_yg;3gΜ=wB@! B@! B@! B@! B@! B@! B@! B@! B@! B@! 3yp46aHY! B@!`Bn"Q- qFJB@! N@OwRv.屛|D$B@! .IRq.qyU! B@! ET^:z|9! B@! EP^L4 i! B@! EL^Nׅ #M ! B@!p!8jBMߜ չi~7FoB@! w5Fuw!9E磯磍:aRY! B@N|8z磍:cC٭"B@! hk();Q ѷވڐX! B@hHǬ!l7ڑjNO}ѡB@! M@}9mMNa/:Tԭ-h}zB@! B ԗs8f]>և eNqSr^ڗԯM=ےB@! @]ԯM=۪u)8@u?e0Tlv ݐB@! hT4ۮ?k}3>QK֭o=#\_I^! B@O[όmխ1ڶKaMo{-B@! Bb#PΔ|ѫ/f$k,g6RǛN]JZ! B@E̛n]˙7fjS̎ϲն=o<׶LAT_cu%-B@! @EߓNmxԞzRzlOg6my];9TK)dЛmOuL! B@Dy];9S/f$4|95iS黓3HOefxk[+B@! .V$y]Lޟږؓ=nq o'zڦvm$B@! @ChH'tɘ;\_}Uϧ{wWf&Ef+g[o%B@! 7Diom+Un竌jLcu=Ǿ']2_dFW2cҾ)}B@! ;_(wzfrO2c<ШNh2c쏮|C:8kVfys:Qb=$_e\LWoK}S ! B@!?_'wzfrO2.rV깱<3([z7c]wfr̗<;At3ݜbOS|yWebv_#"_B@\pZ+QA|v+ؚe?"A!^HwΣ:9r3z,2_іjW aQ)TM>4ƵzrʓOxs rsl*D U6hdBF}od{8,G{˧hza6aвtK `!G/d_*?G~ oo~L.o{DC#`82܍mxJ㇪Sؾ#BʲB*BD352kx{w(nMBA)Lp[:O/<9۱oow.ka Os~5qY ׮"r_ϗֹ#Z6S_}ֶ+fXE?sɩc'M[!ѺK0ٷq=w!,$!  ^}zq :ac'sP:ܹy3k^dKG:*bJLeJb4\~2*$_[!uk\~IHЕ@ͬ]Ղ2Fz!h*ʾGHzEx-#v pު6}<:?MIu$PE7h%lvSӊt v~s ~n~o[7n-ݏ?:jD;.\Eěo_sIL2flUUE/cq: |x6ZM{㛘F\w;3ƏpÿǤT~;۫S*/hw4QKn-MRn@[u/>5&-+MKF:`q{:~7w ><jL 7V-gVJB@\[/W,3\M:T}G~H@r'kGf@@ydSNsء oGqt܍%/YylF]$u[ace.chO h8|9͵_5MPn?sݻu\`6Ġ!_Շn)5cG__3=:tޜt).=^ tm/h- w=v87,owC@f,ӛ55:KY7TlW ?гyIoQ{!mDDв_$FszвZUEʹ'z.Ez݌z9z럽ڍPj ! |$E賗XJG/5]6V=1e>)/1o3AA iuT%ylӌt[]ljNw[ vQϤ_DUXEɾ Bc_~Cb"~3vw [׾\+w?~/ѱu Nۏ_/t>ݏJtYk)}=4i|n5_mO&k-h1gBr]1a$ MR٫T_˵3^TVmF@UsTExGI88VҌ[>-Lƣq!lݏ@N8NtBt*@!F935B/}5 MWКϞ-!-]c6sjȳyy66xBhYlZ: WRz.nBycx噈5N { mP~HU~?M%G"@̞9=":,o568F'?J`=]OB>UYcKH}Q?#tՌf1?g]1;Mm?k[+вtbN/~}=}~{*)! @p"!`/T}Un̛(z:#<(c0yyXF+>=o*Tu 03^6Q_ܴ]6I8^v9ώ`؈6(-S\>ZEyBA,_|M>O=}^zs'=^;#ih >ߎi]`;t{w~y_Geט:Uċlkk󯼎+Z +OaאGqjt Ӄ4\sh>~D׈m'49wS1sqe.9&O>~ v̎{nEsBkӺ3_Lw|T*뒶=BgEǟ;a?^ë3_B/c ^yIt Fى=H!4fMG/z4ʃk# 93cΏwAf(?UJ3x9!g[9e-q0C/4g/NUZk?v^yt*ބE˒\6|1On*=s/N|cG~83SP׺,ʳ?Ƃ_ /L˖uu̪(Cފ+:]N=p}' cHceGbagoqpǭxjR p˕_----mx[ B@D@C- c}P2_bfyw2KiQm,&r/ M^}Ul ?W?F\/ȣ'܁٠P]z~-=^ޞGv. K_Z0]Bcc_Kqv<0!m"fz+7cc GF#?dU7!"ڹwcԳ pGG{PlRߎ9 <KC[ᆱ9{,bnF8x nXUe`9|AרD,dRYY!IFc3aҋ#{̞a‚6!'x!Nw`3ǩٯ`@>姴z0Δn xiòS098-ǜ浼 N"; Q?-ADs /~M|zy }?4hb?[EGPܱٳvV]z^݂?ÕaXwSb4S#ᔷq g@7 ĝ?s饘җ%2x{ԃ(& aHi|> ]WtP?+~r7ޯ6.o>w=m8{J}󹕐6tyB%!4|+aTySzlK9"4&FmHn[01\=fe,˵Uq${.Ǣǭbi5 йsvΩNq~6ջ휶x ƻCs*׷}jމ.Uogl\I?quj}Ue iy oii)u50Dkv֎j>Q$;Sgln6,-t, v+^vCy1/6&L$M2 sfONS㟚/7c\ޖvk2 sj|z6?4?xhub~za`p7iz5cŌW=@Ou9ݹ]kM8?$@SCӚ~١؀,/ۭJǙ87Ҟg_F}θY^Fmkm$L>wwBzɩTYϒB@;>}%e*2i}0u8틎yyF1(جez O~u}a*]"WUu(Y )XoJTM[u8C۪+bg/G|gNUuٻ@m=Om7gn6[E4t9Xכ=&A"E;*+nHq7ܥ# 6zf(&Yg/`V;<#s~FR~ؾ <B; ֞dyPsڐ'Pa;.єuʦ^mҿ_gF)W6>2܆ :UvZ5x(@t-sKf=C)sV`ß^‘kF/(~#-sNj}ny^viK!;ISPRn'^{;ΖYG>lv}&/skȋBa ~ *YҞbUcǺ=ԼڨU,:+9ƴ 7PhZ7va^kiNuXד-.;1Nic2a]o Clp~`z'?G4g WF~!t~o'ufӎSc=H(c͑x{vA?.I={Y8>V+'UI 448YzyY m]Op G8s)"o78v#۳SH_g9xٸ_xcd.Z>zjŴ(.;xgޫ4~Yr^yJKߥ[pO3(f~(CGH<ݘoY缿hu%!;_a\6ΞQL^^UM6H2)©p$7CM˚=lֲ5Ʀm_87G?_;#>eCsd2FOR0fpp^; &uJsl l=5E9VT_LdӪQ.r۳cnD=?>imGV0-[CtuH׵աqk8p\V۱#+mZ3q5*vfcP$@?qx=6UҞ*h-вUЅk/<~`]ouTW! @3sNj'ېHqht>>u.D3rf<~Kw]3#l؅ۭԈ4$d=6ިeVPNә4t֓>owTvn/hAʝ}6IASO8BDi+ܙ:Gy /RN cy{g Vf.Y_=-{oԖx{wǁBx1~Nqa1b!ٝ6/ppgp~l[91ϩÄgj}Mhf+h3Gu*9XƟNxxr4{ |utin0 aYH< |/ÌsH~qu haf+j7wUMtƼ ̛9dny^ǒVxa"Lt6s;l}{ءչ灻~f؟b每ROٲ\﫫sB@4 5uSyyu2r\T=duN1_t2z1yupU4:nw&x ͎CDPV6kga_` 6f^3$c)~tgSnX7OҿI8D?& g=~lkNNLk*TVZi)m ~եzDW`@c7mjNs>Crʆ4$fvVN 9q4=3O_-_ua0[笕>U䢙fle d|.gi;o[gşW ٹﻙ3O]L7Q]24yV~JwwIWǥ$ ! @ګ:hGJe*rz1ymGd,*o.rW2L_:n;?n(`ϴÏjnUA|8rvU! .|V@Bhy5PU|9WhI~j1;f[:WATWRd-ѪyUyxx˙O(9`|?u硶YV8z9,{>Ni:G7|o1m3(qo?W5P]ݐ1JV!#I3(,W2c_WJƱ;^NiQ_x7+J=LoǮﲾDO!гlЮ]9_7i%`E0z=;G\ ! Hf S@^nV2})e O[nC@Sg]uTJs^,b ! .<0*bS'^}{*B@\YƺӬ2ciUnKH}'peV*(o17 B@! NWCO ('u>rYz]T׭S>Hҗ1:Jfy|- B@! B@Aڦr>}ޘfi냧2t}:Ƹ>9ϡ<~-'7B@! B@ԕ.z%Y~-קSGדsx`3@8cLYGTY0O$/B@! +}%1a *mUy 5K繾ce(75H?QX!p >|m۶E fA?nX_߿_B@!@N;3fQ\*Uڬ^揮Ǵ긙1Oe\/קUL| E[`+pOC#FwǯF%!Шbbb}i\! D>k藱b14E.Sy}Zo˝umeXfez=~fL5Tb-2ʎل19?Lit.$tư 8 o8,㖣{Wً].ف/fa\?]B@! h|z_ĘޙɔܬJ_q^V6j!fӾz*,< 6Krʰ.m6ۑ `e"^\ A-#6uڽ%)B|M|ߥ>Ŏ;,7Qdʄc.SykTЧNqC8fR7Ƭ2%u'Sz؍..[1 VcF<%@CZlE;0s'~iܜY?Kr >is; X?gy:Y~Iذc=; <;mNX??U/`Tl.PYV'C-Ț/e`5)pU@}q|7No0X!`f;l;Ǹ||8-vr5. !p ½|JWvv3xi|w(-->iq૟32cPJt*o|9fWUe Y*iUns|ܿg'I25@;$L交m/<e3)+ +9SUbKz2֔?76DcVªvibY L9^2V> ӗbѦ,gb^B ,ưkjJ,0e2rpotk輖6QFt~44{H\dde +U''S%; C&ג hc`dl/b"1&2"s)A*PyFS<웓nIB@KoFgɗj,Qwa*bw2 kPWTXy%3K+7Qo4#/|us1o Z#iNa%7FߘcY#ۣ/F?1ec )>$ڤGߡX.B(@ZnAq5)ڌ=#{y ATfJrwso^{JaٽR4t) zVͺ7h"~NDwIFvoS2WQ_;tPDB@ ӷO_,*B@!p)8q{(S~'Q291:U+F:կi줾3^(QU*Wy.Wic^ʔFZRwܻch1#lccA)E0F\I[P^ 5rA AHH%kZʔUU1uQTN7I);:wX^[ȱAAOoD6E, y8)[&p-x4Kǣ >6/Y= ٳeC`0ԩ;'gF;%/ eʌsU昃ӪLSнuؓ7UW\YjP*f}ZaPe:FoyFMHsw2˓clyfuGt9J?OhBZ5 tISðr*,$ܑ4Im+JǥH]PY,(`;M./?M>HQA*]y;\7/C9G9mBW'>n"?Oժ?~wNs x;r!m(O^0`YpĜ#(24 _f{#e()`)ח B!?13QXκzJXo^ÁK:؎U.oܑX\'rؑs)e`K1$/mƈ 4Ft57i9fƳ9h 02aȰ {.441eYM}ˠQvv@"!pN۟L w=4}hLş=ŴGkchvOɄA Z~mҥO>cGhH! EK@pMҪc.9rr}^WU2UㆺVV+fL__ɔ|a ĀG Mg.nc(V27+* DXpwVDK:پّ 2JM|M$U- sL[QQAcC%73kVdK 5R-[c"svPoDok_yػ mB(VN&f&BmB}՚Qʋㅵ9Tt~lnܽ /KB0>|ʂfb\~,f@B@\ (ʹS2}ǫv9z(Ǩyc`]ՆюQ|}:XAyꈯzz\G,Wi_b#1 QQ`rΣ̧4mnsOІ9,LPD?k烈)䆷F4)ÇѶm[hY?o*Yβ.Lh y3ڴrj*.]|PեKMF^sȿLꫯiF|7k1Q;,:*bՐYӜ6֭P[> eGWUJF}7UK0FݚƸiӍCG;T bW%X^CRWK@mUy#2Od99ܼ1dsqH| ;_Au؞79uy6܆ۓB@! B6ܶ~6 lIVHOlS1Ŭ'A!pͽd.B@!/NtX[obD%iƺ72%Sd]:4TUL+B%p_c ! oy:_;ܴʫn=L!m2U*f]V:#1a XFmg,hԃJ! !PW;w?N/(7e/sZ1"o,;,]g\wlOMۆb9AAo>-[mPs~m+ށ9|ZEPy>ɦ"c^HRX鬅tX-+P)H_鼢9=!} "=c͡)ȳìY P"[宱hǦnXSCN. À1k d15 W(V -i@B@!` `惰LtL7sVٮ!6PNy긾LvgOXq^(yӎn`"܁X) yYr2z&,v:ؒ>[s=}ғG⎙} +/K`Ax7ny'L¢Ldf|r2͍:m/<a5+Gkwa@$T~u; ُ)ؔMKZ@(mhK?xC0hOG:.r:=+t\IGO:z\CG_:?zv1ѣv>F(/ӝ%y?þ)+ϞivT:0ǒ`O̷jϺS2#MKSY}L{>3YO36ii-ߤXٗ%Ps s2i\i )%N7t31xs2γoںݞWW@@}Al|mUuRVQy{y.eWp8%B@\xlݺ;}:a}QWa}aؗa&qa}b}#WbIOKO+bߋŔ_Ʊ8V~F?kac>OsTcʔTmF@IDATc*v_قyhgu,Z'hq[Qj ~(Ux{#:<\-({fCf |7_-(l ˝m\G[ ahnJL}$@t﭅PjGDaL2oNQ*(cu:*o2b}sTШ~5V!^gc/קU_df:~#:Ozb~_ӑ!jfd6ڡ[(+{76/HyKjQ-P([hq ( lxW5颮^/k9>~"ԝmBg$sQ.s֣*v}c:R$,r.]KB¨D]4'ZɃ?hfzaH[WN@mdE\l,b=ZKVD΄at>ռݍd{p_e֧BSi*ٍWˢ~=G)D#|~L =$ HOuM;8LW}RponV_BcjΣT ;c:gMFgZZ8zB}*B@!+/b̳o2r}n,`1 >jAZ-ཹ 77;vT_gh5H6볋`)-q<4da՘)w_*Ks&bec4#EJ6eaгi-xf)[ ͆r*QsĦ)3w=5[ht/KB>XG7Q}-GY*96=6A^5=Gn8Zg;t7jKZt#*a=0)m3h-=J i±6jE32a5@}LS՞ETXֲgD$.D::ouZ}c%=a0Bزnn5 QP#~f-PCyY>_"B@x'|_µy5M%1敼t  }yg̻k-i1Чߕ7cƲM(<9c,$vFxD4,{Y/9))X9h _iL ]wf%cd\4:tEUHR'9HX:}:COڈg"%svpۙI@$Mj"h/G c'sx\zB?aWߢml)E;Vb29#ntjcάz8+7s-T?hvK[}ZӴO9 -8q1p*&f=& я&6䝠aat>Nf#õ̠ >mΝ(.eՂIqyHI-hֱLI;( m"NՉqfZq3.om0z4gL&Gb fKT;PJe $<oVB@x#`Q8F[ʌM&TGsJW$hAO1j֔5RiF(hG::|MǕt7x5\O?ʷoAą/oVSVB_ې&vqrgVWy˹]޽MTg3ۅF)[t<2!p0>lSI꘲l)M5LF+՛ОV^&g؜mbUocMNY^;~=y*n›è6csnYxS*,h>yS1i<,396 r'~2X4%|rF.XDڄȹ鐣N 齔j j\5FٹCB@\D t8&:wtO¾ (쫰¾ 0˰OþM4\A>/>F#Dw5߉}(鰯.?3q8>J}`%oLG/3K+vT;Ӟ=!v$]n82֎^kZ>wIR#N3Yrz, KhK߂5k8wB3F<Tl(--Xn^X S^R !a.'N5zMx[h@',*eMd>jF3Uպa#崦X;Aj 3*By(EB@ ;:gHoY+o!ÜuUyM";3.;yB++J*V:~.aG.f%B@! ,僨bLʺMơeM1ܝNSI! B@7ѧ#W{MՁ_P= FʄB@!  x]ܕ5Y @ ̓2w&fHDŽB@! (EyОP|שtc;<_xӗ B@! B@x |>mV[㫞ү)8jP~]"1m^AKB@! BԗoR_v< +W8nAՏ do'uO#  ^s?>e,یw͘h !ФTCz&YB@?~ 6Xi7BlŗGbcӱXFmg,h|[G|;Fxa;! ֤B "$z$cPѮ ؘUػ4w3L[ӡ#J-Rc-yʯ1)XvCdk0l8֣y/wr C#qOCV;x_xEx<9D[.?=~tҍ|mD7V" . w$LNDb{d չƮq3$ɹ b>{CE.;1}iDR'$ z8W= j%*BXA]eo"Ke)nvuMHR!pi"7 돾7{^zpS3خ`لX㵌\gJ~~QTAeE/9/*r1tl.rԳiJwǹLMۆ [ kzV.XK9U7mpgؐ[sl_WV3;J|iJI%Ю/[1MߜH?z|1_#0k gV.ȂOg-MsºnQy } ~tkb:XSsٚC7π1 8ś8a%.َoW,ub5Ng6s,xّ@l +0XJƚLԒD6nG(󹴱m\ҺB@GBs țznTZ[nsoǢLlŌT 8vY: f 0ZUAlH^vaY ;/ Ėd,88Yy9X2 ' »V *dfh!+%G5"+g;Mǰ>јU0ªvE9t԰yJāH\]`:J$@cFR@3}QACR,kn#eʽr Fg,9MZnڡ[Ӓ -XeR e+F#[QQ[` Cִ:{?YC0ꢻPSJʽV>C+-lԄ OD~VF6w؜q\7Ά\ͨf/sS;ذo%npwsi#ݰ~ñ|VeJ7Dun {]bs٘MDGvUB@!`Bu7i.4R[D0 'O;+Yt#=& 1anvӜ{,yݒ_Uz+ӑG#)ܑAw':0k^~}{`hK#颩[ vD17Q_FFKZV9K|F+Rwtn^QKdl/XlR:+cor¨N݀ri&#~ k yWY{!H{/tDlL'w?푌%I;aVi7.#}p/Z3i!eܿü&`Nr}uM MD9q7pݕdU B@!P;WQq4Z 'tR̒3@HE_P.h4\N:L$mk bopQg@A$` i$R+FDb*ؕMۏ@Hq+ RLn`#ZIMc $[8n M QL"3=fȐy{޿{y?KT=)LBA9atס tIYyܥj>:Q@+G=2= ,,!Kuw.nQj<{7,R9!D&yZdeIFe`4F+S QgUb6qJU[3Pێg#O_z*4_ؼKq46%KhרÎݸ6F720.4yi֊:3^qjc04atRj iJ:>1&p% +zJòeb )mȯnX6ȓ|߆Pq )1XGVU{c%I17b$I u%RgAa\֦XܝF$Wea,M{2W.51&p allqL(6[imD]i}V2ݍA$CaH<&%tf::lfOx#) )cgC;td]v]d!:aI4H3&K^]T&՗L+F1׺ȵ8L[fZ/p3gߥ/1򜛻ٌS-T-rY^s WDέO22&. iL#}ghvmVX(cu`4 lj Ȇ1OeH*ާ]aR_Icm$Oo~,FKyRtz6!2YQFW 켄E.I%(΋*9p()I*u!N+ݻ%#^qT`-CC_ [}8eGa!Mg)͉YlDL!#bn,aL 0&B`&srݥцajկ_ giVMi/wљ^- ^vL 0kӧ1w\iJ֝SGՙɈWhݸn>Tɜg2G TUIC кCob;vQ3xʕR]?7!69s+Nۉ.* ~C%"Vr=w "pu;t8{b[S*mGN^i,Rcb}'vD HE>wIƎ \ty02]Uh}"dF]ܞsՎywuL1{R1`Q [F}Z=Ɔ>CDiY8ss.ft$#"Etؖ w474$q+ R=KFn߇?b'RԷܤNص^_T 3ĊHD-H%v BSF} WӻPs')yER]: :/WڒI'?>ٕ8r+{<𢤴ނTy}BWHF/#'[R*'pP]T.Z! C@6~0u a/br?o,o\O.C_iD3 :J#H ro:MoL8>{7)}Ec?fXCd='C+)^IBH`T"x$I#hrYVAqb?އ==!"r{phI)?ot8D*G`L \4ȵ*%h4ص[RR)#j"Ӎ{.SD4eGHa ԩ[Ga,ۢ%҆V*VP$ 4R 0<<67MVD?7@[IբjZ!)&mC46^U~o/)WH=4c4{E=45 BDDT?D16!'RhV׆?^7%ޭ;W*ݭ(3O fE`P֚zO\12nk@&`Wf̕fq}F#эnc?u4w%+hMP;b8@Y7a i&m4Gl"$dH)KRO~6Gl5:n’ U[Pi:$DŽO44RZOBPvSP,G" zI3t8!3pT{ "Wl&g?`V⃽'Ȋ]ht~:ZSwҌڿ|qRxiECBzabE6s$l A׆~ #wKﰬF_Ƕ!0R@ĴN|cǃ+9 o p{o:~){Y͡w.E]iO{:TgQ#l{v~_)*1Wt5nF]T8w'~[6zR9%gL 0&p yE?6cp:dkldmv+,bWZcsIZm}_ ys&Qwn-QCg~9V$F%靕j,r8Rk3`)ڨQ;ÒnC\ΦwH#wIɆ"]d*w Nv/Q{#Q]_C7iS8{|ɯērR ;oFĎ42$g@Mc=ːU؃%F#{`l9Xx]]]I h@~;mk !<±Ā~h:}&79u4Xi!vf9gxo݉)Rn^CpY6`L \b'.6̝_ g~,Lޮ~5LC~1H Sj,Ѽptt 73rz%6蹑o hN>s:Ļbk9fyʵ [Yݗx]EJBȏy FOO}Y9*mȉIRr7)޳ i1c 2ynA,WEx)C"XhڿB3ۿul*J&^ҦES Y )& >vE"i+WyRi:z%k/2YC 4j8ڳ_\C8կVåJw8#=%r4 ?^ n-H7dZ ﻉp]@i;QM)޳ ]LUŒ$!==p‘[e;, Evj"`\Iߔp5~}%F% bH.BgA6"Qkv܄eh#nW3$W(ӱ+Y$cAV2VaPi/&>#NmG3LR!XgS2&yU>.waNBnCS`i&xѵ8o*GuEV3CC^:kGJlܻQc?5#b 'mDZc\sSQYYNiZzTqw|/'JSk9v7`bDL44Ub"Ion󁏏r+a<vLf%]c}̆ Qdv- _ҁ2]1Мhv9a=)~N 6B;1r.Y{@6+i!=i8>VN0jy'8tQHE2uR`YTQ(d))]cL 0&pc` {_Nbp1,:/xxE/9/PG. Kt8ZPj@وH.WN{>H9(͊Á^+vD]:vu20 ]n>x hdtsu4mx.$Ŧ|ZAd6)"΃OӉF$- α #19Қ, 104֊*gE7̊ӆ*$E]=0tT#8lnd˒/9D2uYH-hr|nBHߥBTT gE?1~EdQ;x,geϑFU6,u\[N1喷*ޖr$Ps|XSLx1lh5`L$ f-JSbH)ٰyhSRZE #~U`@Zu dxW͐y͈ Ěp/Yi(ohM(BeU7~ Ѭ???IR}aJz|h9)^G?Hi1Od0vj`"χd?B`F#q(FzΠىFflHN!=6ۀpt.yIqu2& y?Sul˄cy&7{[f;;76]O.cX@9V@c:lfvwh4JGwÊ>y4qp aRȚ@abi>jIǿ:oRظd7pR-Yp x?Cg\&)VKEmk`C=1#&0BOIAK=g;{pF?#+. bj)9kӺu+q&N~!X5ՈpvGׁXU PAVJar 0&uK+ >;e‚x YBKI*CX7^7i6ޱd:jݗ{3Qz'*b<@{linhivm4f~ϒ=F|hFH*H 뽎u-EZV1|] wtrnRni},Ra YÈڊT\)@GE 0͋PF^JPg7~4Z^>LLlһcÒȈVgUvcl][G%zGa1x}1 ottxvmMEAqhuiC~,g@/z_cTʛoGSG|Yʼn[7HAbIBy%MY&1 +킽|GiN -ρX)6~@̽C/qlAvNcL 0&p#͸K sWY=DU_= կz4&LSôg/s_7"N8ArNBLc&|/^rQ_NLNu~1H2)vX3r?U]1MY9{O^&ʩW8~MbSߖ]|~F\DX؆"=;g 4+B8OeW=*lW؃k#zez-*VZ,GMS-m;H)m]WXׅј _ߍkb# 8 mۢ|fL 0k3رcI}\R>͛',;uO37g"VկQzp"^uZtaj9..{)S#aj8(Ag0UA^J6N ӞoXR@dMn/5^Rî񌶳"X6髛OF'U 2>1!ъ6>clp(<ŋ-<0>< ]XFz+z凙4wj8ID*3Ytt&>YӻrCJ!L 0&pCJ:|)SRb'`R8=kCdI+Ĺs$ΝPz7-ܙ0p\U.i 0&p={6> ʣ3Ms Dw~UnՊ?NAVkiL@QVf<]+דYx72cPE!9XxtUclf8S^>UV|RO%{i^~ H'G{L Jxa L p"1A D;qTWgc}l#FVcGPJO{zJ~!co[ *Adx>DћSd(/}gcQt<~wkFF߼oӚ #OwS~+4 ,Fl! Qjc:dOm+2E0&:񜍌t%v#f+iOJ p΃F4 w"!.sM?ʣzL8\mvj,ߗ^I3 UDaXyy;|K@X=稜q98r,ȋIBzz*ᄣhKb]| KFAv "sa(IFb= N`Q"t#&{8:(ݕ,1m> ғX_~ܑSW"ԠQd%#lEUz:l"5)))S<ۜ ]1U2MZ|['M8|V ѓEz/pIL 0&p`|Z{*8j6yayf=t5Eן+i*e%lG6UvK*@aS#krL㖗c\ khr%MW+8vr6TzL>8Ea\**i][LJދE֡wME w7(r7;v4t:aG=Fm86-w]'⤒,hM@JHPC}wkl#n^!m݋վ6H9$dZ^e(vSBny}g.>I)!3Q9hs+RIwwȌwW3:$N[u'tqRih+LG-ڵyBrg=;`]2+jh{vn߉6SюJb` YHĉ{ ݩ1XVd<ӯOS}!k~u욁 84z^J+3WPXP8C/;xm"lފ'TY6xɥ4#j k#~#è6dhڭZzK"u_{ca:^MT=X(C':HFMI<;$=ի)L 0&<P04`o(oPHI.*CN >gl}M:ag0In"tE.Bin#tP:#t ]HDB7:Е$t'C ]JTB:o K`>g&Ϊ'ήz։L SdtYٖؽ4|<W?̪.~x@Bshmj#FxOc9 k9mR[ʡ)LbG)ZZNO-[3Y"`g}/BxCcN'9&=v[,`<\ ?bCݥ)~wPnNd;bhE7VR\dFCH;E#рM;j1 Lxmґ4 s|R]8nu} m:1& Ho]CiEL Ey{$0 ;03}8T菬0zI.,/#F36MK~XֽSyb+i>qvUQ^\:0 ^* ̣ Y+FOvH0p!| P ǃGK:_7܉K+%L 0&@^ԛp9n5'GO,5SَLm;jB9ECf$a:Ld[™ƚEYoD,MBvx(h gfrd-)C&PG}/7} Ҏ&GY${v)RD%i ]0Tn)nDK/ytzcJ΅_ \ L֘z鈉ѣ$Ni^?^j1hjk:ih#LȨBHhhe(*AInC>`٦i*$ڃdt߆`G&}uV7-{>GQr"c}#rI/< lZ )Ez0QmIky޻&5 N4 (81R/ds BdHv&Ok8 na 9Zui'K׫~&`%shYUFntN uh/q4U yq(W6?Gnc4ܘMENqJ"zGa`o ~'ةʓ4&VkG Ⱙ *A#jvsS0>7ٕ@)ME@6I(hDޟT=Q@Ab]%mE9: ]17H,ڐ؇L?4zvR1[G$]SoX4&FN9kgD>KifB/7N}mFhFy0|[iбץ4jpė%c/m >j 4&]s2I4 :pRz?Z.)39ReU`L@&#W0t8,SF4+FcCJ6KI/eg\GvOKt߈x4]kwk UXO.@Nu'Q&TY.#QH}HnƲ[bQ`2U-js5:QM[bAm_ T).BE)D`AYUih쩆%9lrw"y/>M]O=!$&̂@mZvY{-QiKC͆^0_/ (e@jHΖ|G*!#)\Fs Dro¥tKVoN]"BPn Nĉ&,CRz=ToO/ese Ɵ/LN cccd@ } 7=1~,hh rwC@'~/1dPz?報 N}0#ghW2#t[R)S> Og&'n'KKHrrYiKƈ aMϭDqI?b22heu0RpA`L+|=M(ý)ȐF jtØ`L |^zJ~^q.8nCy|qD,I7 Ӧ7&Iڀ˗.6eQڱ3ggΌ96qAf/˵cU` oh]gNp26}6q%.^v3MMtrD>{Ym%6uQCvڶKvkmP6Qg[ <ŋM2PأJ@L/Dj7,R\rD_|z{asS-QDl\&i@_!_2icW|N]st66v2:rp(!{MrNTZ֔ @__I9V4^Ž 0&psp}k7Q7&:B1ܥцaկWTU{-Umaڳ eu!BXGgz4e>}suرcI-*=αrJoZ.wg1cl.tUM.O3C@s-# m 3|BxS|dqt xJ2>L:~_й£ S*t^h&|}52ׅx p&0S452.fZw\lt5`L' vwg}ϛ7OL9Mx$~\¯= zqAz=ŵ8Sk5\Jq.L<'AaL 0&/)Tt7I|I)t9S2<]⩤`G.՛ǩN(bė2t_ }s9S2q_Xu/`L # F1&`L 0&HH8`L 0&`L @ 0&`L 0&fDaDL 0&`L 0& $`L 0&`L`FX+F/M1&`L 0&IX,0Ə^߬Y?a:=Ymю=t7 뷞`-P&n.z?eͅһ-J~AL 0&p'pdT_Ӛ{dM2,xcu҄3ɩc+_2&Y:#$-8b~̃Q]y=}#\Cۈ/ػӞ_TVʃp~vV~H[5彅-$Cy ??2؆WmN…;SkԾOϨ-yM2!Z@eܥ29/`L 0I^N3(k,P5<2IiE\1R&|`L@:3bF^LS'y, Ev),]4)υQ5tzEKGLptQ+7aYb:H}'鱾#xKPcWJ j( 6d}TL9RS/ns/KOk{vusE.`L |X*z, ˱6`[%%`mDZc 0'|MnR[P)FyxײskCǙ5HX;I>UL \ Qux?Gl0H?Yy.rg=;`]6+#M۹}'L]TF;~+2҆ZUt=sZbY 34bvXW`(ZÝ݊M R{ϲmuל1R=fL 0& V lQ,:&?1fb54ftYq"J%faIE3z 7#EMêvQ9֏BbQlG]JF`niCKAKϢ }f$!VQxl] : =l,Aiz,a&XDkG'\:%,Fdz-G}bKo  6xL·p#uITL=%O]숡ReAm1~ETx@Ys٨b`}$*8#fTm|m◍`h0+jpDu5r"H[yϓʘ8 0&U# F?k1P?1)սyx/uOGKL47ɿ}d@E1'46#sM4£`ϫZq=iKИ6W:MHXLg&f@`p0ʗSЌQ aZWbݨ|.4"toLg7dckQ=?m3$gV4cA8Z /j|hfa] H9(͊Ii`O^OL 0& ܫ) ϭQH,j_¹hHx@Ӵ=%{عjɔbs1n|ʁabND'r:\ 礚dG+ɒ#9,݉T%FhꞚlfNJ5w.B05y#TWQG+]f%¹X@o]0bI+.HEmT<)hTR,P2t Ή^<514-vMϘ>^TSk?FJ\fzA2Rh4sKkF.dv*}[ߕ֝ICePڧ% -0Nf`L+_]?>06WcB~gnkFz׎EYEm&h'Nru?ZڬH?ef3 L{!shpvL \u'5&z^:bbh8I"?ܐJp^o9v1j!M͛:Q⣔҂MPT>/mfCIPmf%XMB)MFm FpdWGaxcO>>B [bHj?ñ~>R؋GN2"?O6\FLRq\ȈaRGi!j%G ƸW`L 0Lȫh;d[О{1hP5antoC]kGrG0hl¶8؊nU)yN6`~EqKxO eJiZ[6Ѵ\7):thAa~o6UOSK~Jz/GZVIk;օ†|lxZaZRZŘ $LҬ;K DR6܆u47^5J$b+aFzlMYW=<L 0&n=^3݀Kܗ۱Qֆވ޸ `ǏtL6;Һx`?2] 92ݰ~F$və6+.ȵҶ,ZiY6EmyR 0C@ئf8iXxc:7w|6cmY?de\xEK`(>L%Q$y OgubexjvRGIcm#<`/ڰbg6IJfdydkο`&b[Z"cuTi,fERdL 0&pU x͠vwiaj8Jg1WY=DUƩaڳ QȆ^:MeG "Ǝ 0&`L 0&G@zD `L 0&`L@`L 0&`L 0&0#@'bL 0&`L 0V ;^nsAL 0&`L X*8֗#73;PY߆a1kpmVZQIz_\qMh֔c m0`x[z5Oo5L \,~HvL 0&.z(˘;V,Cw-?ߎd!]cZI*|QAlB١VV|8EdaK׀Dr`-#DbyΝ-aI9sv=s}{1%z|M_[,y!zvjCCO0~c>ot69?ԧ0ӟ>ǾJc,.\@DK waAnZP}`L."3e9qR(Fql[H*^?o5 @Ng`oWo`=i2LE=vK.RJ}d򏰃8k>l^X]G (3v0JӐ[coGPD"'g( A%Q'f.#*.1@iÿY sPzH6qyiFd6 z op"JHA B"mX И%Gvv)E7ҼTX+pnȏ6r9SӍِht:ҥϲcCo8Y(& _}r}+jM8WQv_Lh⊵ -E45ڦ |XZlgVXV<EM:i ]cDm癉̀(DE~ }(ѱf6Q*!(0`''C* ĢMn} }H#7])p|doS@[''p"8&i;,- Ar8:`jל)A.U^C^Jn-F܃}[QMJz? DL6!u:*Cy$5d9`w9V 7 tbFq?9QB3ͥ*iGNJ[vʤ;w fO((vvdX:~MXq&(8-rWh[IR 'r0`m:OMuDӃz!+cL l:.vzJ A GcmniCґyp7f166 Ed+Fmc#ZcUmG[qZML")ܰ]%3 @\eǞhag|;4IFE@)pO[^d!aG)1Yg{Կ ,CxQ-4)i&( ըA]!4w6l]Q td *k&`w&s75mN'lL\u"F,0 c9ǰ6uOW:?6,=dk cw r};% r}p䠘׌AI Mg YXÁ 0&'Ig 7> sɟk LdcMz"1v}fܲ%ku~0m Q4XC`,?A#= ZZ斷`}^U1ܘB( )`L 0{+-ʼnŴ!dTc|vrÜ$r[-z|Rt6?x9N\((B=gю_Õ`wCz<(8lo%H)Pq(_Y5;zU8}ǬaACJ۴>МBpJH.ٷz B+ßhY/_M^Y۷]RAjHWF,}mCS'w)Q{r,suH;|VE\^yLW!iXw`L|fL 0&p`r½a=_ Km+!"i+j[b^j?Dc&c8B"]gy1aGaɟOV!#$:Mx!vL`OZlEФE=qkBRd8Os G`<ׯ{Iо[쾂c^: af(ϠvN~QRtIݪ `05҉g!Up3Ћ1FƳYzcٔS/G͇ވ4гy2]lxn4~Z@y8ks[6&{&9!eAp rb1OAC9Qa۵8`L%QIށ\ O¾B1ݓ-'%6h=R2J(zm3Nl=DT%dSvM*@@"•7Rg`97%bGzZv-Brq3a lT 0& [膯24_q5MCTճ]WY=D Mi"._vM,N&OիB^ȸp>mmNj*ϻL)Bvڀ&zC"S8iV}Nhk Mu6xJ.8"1/if[4"zjWUJ+& , o ޱcpOY,C-#~4qVqq-ԸZMe|JSNz9`L=)bՂB\r4I`pX ڄu۠-< >T-ް 0&=B@q`L 0&`L 0&.V E`L 0&`L@`0&`L 0&_X bL 0&`L 0V `L 0&`L EH0ۅ'q>&`L 0&@~"_<PRP*z0ssR}9Վ tN_593muzq"[ÆW3TXOc8Y-wς1&``r]D} !H.¥ۀw{Q}u9n.`n5 (3# )l.is?ˆiO\9iΜÓ}oS#^p@x+!௑r vmZw2ݶFVU\7tBkmu`& _+jD9{_H9qtFw 0K`h5y[+}f!U& kV qF">E&4oZoEX`L ܙX>j؂#q;=5d8r^ܪZn-$N rcZmAFy[I h8C!4lNS`Q#(:fFza-uSKzHq׻eK.Gz|,~EY_UDHE@CgPd – tk.P,]rfЭTϟL hk$F FBv25+n f6mZTikrNfRUަ5+bL 0{+\(HO[Qk:+EKE)p̂sx`GKN"*ZRweXƳfR(fESaVae(JyDQku= W xI0, +@Z9V YGd3""-ۆ,.t8ȓT{F.:?R+hfukRAY!Wdu[iF^tB YПOD}ԞK &c_HY2Fi2U1jI9@SPkFyj@۰WiRJhE{L-)%rGԶF 4tz]I`%\cY,j<Ѿ7x䖷c{@IDAT" k%b}ڶdXM }V gkK{6`EuRv[ |ze|2ʽ7OeݭqFҙ[ee 0&1^ñ@yT dZZEZTьb:I,:^āD~!щʺ›U9~"{cp/POz"ZT5@*;1{BahDcx%Xxz\G@#(x,ŊX\V TqO>N%UzD'%K{b#:: zJFw@|&=[έ+9) 0-HD0"cD1G'1Hƪ,liʹ 4MdԘ,Ȏo 6UҰs.m=&MuVTڄn+pVTCҫ@5JUbtzdBigdZ`SPJy`%FWMwtAYLz ]Cd`:_^25[u kby yٿBsWZ2G[Lo5#6Ki g*XG@Sы SEz klzz"q^i2H^!M4T8`'p{w6ޞ{NX-D ౜cOc?A^8~D^F"$oNt3=iiJ<(}^{9w4LcJ7߰ yWXT7Vz(BhIɃqx4ȒD".Hkw=U z o~-H~-IaL&$۰\S2&@2iSt`p;]&HMY7Ne*kA#J-$>x܈OdyĜswcE+Qzm(uyV40B' C8 kH.{6(~ZS۴iWG+&Y:=NE"aM@dXv!D bxVjh^;lݶ tY>5cx~}tbNY t6 *(LxnS % {X&~036t%v(D+b=m.H2J2&x#@#v2ɟE`f&2ӱ=pvyu-o5ZDc~ ."Z9a=(KF$?AI;ă=^WuXgܳ &'5LX\ R)B;NtyEh3ݞm 7HnAnE3JJ7!5qaڧtNDbŵ@& Nz3[{Td&?a 9cWehdX j/c)y=!%nGx#FO+.˻U5}| `L 0[S*`/N/&2h;==huy$6F:{#Qe/|=X0DV"|uy; "jE f0;ރ\z "^L |(3}631ogWy b*5=~wihIl4i~_% _Y2yoI7tF'FFoމW>.Xеa-';@kor7My>Z5}㝋n>ۤ85: ZN:n'_4hF{hTG%vhdm|8~us*`L 0/V ,6%74VB"w dW$ٻVHP?l-CKav#Ef7qEjSD&@uQXjIK>ꌨ'["@kR+1DuWg'"$(FSp!!!&DxbJ4+_)Jɰ_jXb ߅'i ьx 8T}+R<&dLCbI#3dģh&ž naѐHY NWa<.$1>H&i6(2`Rm#f,c<)g* q\۰fC{A<ٙ⩟&<6­ OM08zZ1Am>Roڹ5Dp`L 0UhV)ɷ@LIr|fi-M P,G#F } eŊ| :vǣ=CǝZIykmI"7=.&5PKGz~s_ >:mh( ax uV.]1(Sh|.tPZIrC$⪬/,$(5-PFFc0<ha*Χ2Wpy^2 aOb2[bX˖5y]&w7!$CR+8$L'@l揧g|02Jbb-k-`I|GCώ5]WW.N`L 0&>-24_q5MCTճ]WY=D Mi".dڵktFhh8݃sl :;=qg \z/{_|}y"ȸ -ZVv205hZ;n#w;-h +4]CN4vf[av;% CRPs3)a+z b P kT je?V[D*Fd򎍧gamFx|`Ln%7W?j7xǎt),½?84D\ik5]4ʒy˯tqAA_+MnI]F$Rr'I@/hAe(܃:jz{ Q)V(nWw`𝿚Sjs4 UO)ݫIXmu},ٚ6Z8 0& ӶAI\#߹?ڹb&L%LIÀK+]q#`L (&`L 0&``r]D\ 0&`L 0&V `L 0&`L EH0q!&`L 0&`0&`L 0&_X ӭ*dpgg۶5B؆MG`|-(.`L ܣX/ցLx]NQmXīi06qq02 `L$jG`PJ:쟿reNglZ-T#1Y p~ӊڇOK,P]/vcO!+cL ƥ-hSLJATeSdʭjǬ`%)(5FZ]I|h)EۍxD&N}[{ιߝ~ŅJeq|`ٓG jOŀ:2aH"8Fra޳!=$1toÔWQgQo@[lj[s'ҥ1-/pB^FALiԌ矠t$~ĝh@Tn#k:#Q,L~Oأ%9B^-j-۶q>fg$tſ~/o4(x_ L 0&nV oۏ&9 _ӎ}x3#0C GCA'>#4O#> +pUL+GkI@&?F6`&!]R9$0Tjz6В؊i:J*@ʧؼƈގ4pbjd,'f^C^]'\ }E0|hM\M8'UMOtm;RX>Z5}㝋n> =MXOvVYPL 0&n'V o']- F*AO1Ynr`m2|L(<ºo̪Fek3vwbVX90& Q)ʊZ0;։Ghz ۓX`aѐHgk%1x.I@*> ܃Y m#f,&p}a؞ȗ3~4Sdcj mB{(6{!*aC{AmUN)~\;:=A3 s5ϖQ:^ksI{bol E' 5!)/InS%ꋍHrFBP?Ha$11\ږIk5q`L 0UlY%]쫌6W\Mg2ոz3j8(#IS4YŖ _v U+L 0;իWqm 7\X'p[F[DK"2Z^lC[0ښhw梼Nm&Ǚ`L Mȵ\ت[)vk2)uމpԂ>8.gZ4E<9 >2SPȚܚByXW5;n.`nw;k# Ooct<0=x.2aWy8^x&@nUx<%OK ͣ[h6Q>y]l@34hA )2aK69wC`:~Z{qV*9y Ž8V &{z⸻6Ƣ]lcgP3m#gрm>dTʒ/&Ȍ^Džr[M0ɊF#g\-:t>ypcJ.M s0krNfRg7VfL 0?[@nW5Sc^oCt]C2ڇj$?a"Ķ8K1(tK!ŭSiy;eL}.WRv'Z+4wa%fD*DxyNRHT(ni+zf>Juܤ%p!K ,Yx[cL la 11 2)2DqGK^Z3SԲh*#UQJm5R)~Q`jq* ca-j੷}6;b*0,\GlDuބ0ՖN3bmm묥<t-|Fh rpC\q~bX{o95ۆ&4Rw+spߠ_N-g&`k`rM<>s+=e%""2#d㌘ QŖNO8e@2ZerZU6 GKp8#:)=14I1MܱM!>hV06%ts;Y3tGS".& \x|jLDFL;}np0z/Oh< E1&ILƵ*Q1QIv7;ӈn~jL~>MJ w(`L 0X%ޜjKs\G?qdY nF';9v~X,Mu[H70Dce_!KO=M32|8~Ԙh|[*b9^|t[s'-x2\eCj5>"EcƈO[j^s(kJ%^!x p1qT;Ưg$3c#81uZqLHʜM9IlEYN`L 0&+ˉk흦s*C6,NM{A349) pT>O9 d)RH([uILaY6Zzcnrg\*׿C-O>H1UiN w[;v7 *ʉ Vt^Ļޛ! JjD1L l2Veaq)H=g;3Uʠ# ?.10LgE%@ҌcסyTGd 6O'>/0ˇ&ĥ]фN q2A4TlVg;|5.mW? 8ڡfqx12 \(Ex»FN`L 0&! DWk#G揧ј?H 7Nz96# 12JiCa7fUIr]x&D<$]MRƕ.Uоp1{ʚ1~ ߪyGXJ%P]Ḫ@Y*|iCRd8#^4zH5;YhF)s*KqOL | Q)ʊZ0;։Ghn9{2%&fp Dx1K] #܃Y m#f,&p}a؞ȗ3ipAM& l =x(׆xhU獶Eq}5PE(TI`#lj?()oӮ(k>Ro㞅eL 0&Ƒie&j\rX9a(0_3v@x`8J;ld44yH(8 `؛xi~v' DІ 4K4 &\e}ko2]$F}: 4p"AqF8VaâC( 0O@D?#ҳi0ZJe[q:RQ I^d6`n EUH" ]1(n|.tPZIRPXI2NQj!F]OƳ4d#d8z[~\Y30 e\ÙSDÅV'͙e&{'[*{|#mI 4,}sH"\2UHEp A$#A ҶO5N]^ӥZ'Owt]A^׀YL 0&!E_-꫌6W\Mgոz3j8(#IS4Yj]Jg I6\:vƲGի6xQoA8p@m4'an+k *`{W{cGnh +tBu un'Sa+ t+va< #Mo9% b`'.E8opIW[jfzc-i9ޒ>f 6ٶ[_KdL Uj7XرC.~|Ezr".~4.jeɼj8 ՠi&~KZ~_CL{} X.̹Ҡi@h*LiHAl[n\?bL"jG`PJ:]5;ߎ5J,1J^K-/sxGjk<&` ~&OBzr,R+v#hJiuL=z[װ8{V5+v1&pTJ &'ݘR>tzD;Bfz&Pu!K ,YxGӶ5 ZdmČjWPe+F]$EԮqzWmsϡq[1dœP;lF$ 9QHTPqM\@ɂFb΁ ܣh( Q/(8gQP B҄Ɩ*Q)Č62pĤ5mI)AϔRhƍGth<c{RކYЖs;dtRtcm{ Y-L[R6A|mi4#V56`EuR:>#G*a2zoegK.u s篖vdL 0&q l!x_P\=1W*Oѱ9#m3t_tG;EtY:c7#舦a:b舥#GHKtȵk\3‚WukꢟuWIoӮ,n״c՘ Wr[6Hs:ԢW\9t0TOyFW߂rMZ)r98]}.2H+m"uU36J״[RΖJzµ^P}XC%j4ȭJƕ\]\VLQxLnrK"r]&}䊲n!cTM^?5L"{v͛?O_+>8D(#99ީ|wW\d$bWk[w5r"nD^[\5Z9rjλFX]1nkzrHp*[]dאF@ڒP־fXqYcrV!b*^CٞZFXܳZ`L&7X՞Tm7~!tD(BW:]#tF8:}$t! HHBW:v:%t)S JX%t/8z8/AIp8@}^_phK3̺I:~{]x>2h d#Gg%><sRܚ-ձb.oT79SCė(zkvۚV$?f JYU=r˿ %] yoceRoO na۩37F/F~OC[$GOGi+Swx(û܈OdʿڃhTPp,HDŅJe3>xI;{^O!C46$zɅu{φtPY?CЀ0!qԙb+q".BL9Ҫ}v!z/ &yQgYSuR3ehTלFbqWHx#^">BZ) Q 0Šb$geAxr#i(ޣ1B["?`L JBI܆(wlB,g0<,U1|fL 0&p[y[!4 OVG# N6?7?qՏ"gš]h3%&pIXόLE| E<~7)4L4Zь؋"Z35Cp,ʧ^ȋz Qd͆A@Ewam3/S|I3`[5[)7A]azP}Ѹ026L2z_yC+1A* 4$bJ@d|7r );<"qiW̸CpTfWr_gZyPf5j,;޹6NMkjg])R|ӀdAC3`L N@N>d i4hbB"QhP &̠L 1}4̋/Du%jĂ|H {y4!}B(Emk?rx*F diAo8cD8"1߈Yv~|% a.>e8F`kYT1EmBRd8Nܖqm^eI`Cԣ n$bdƆٱN-dQId{7a?$?{PTҚ 2{P\8JRdraRJarGŠ5'uk^(Bb]芩EB3/w'Ju4 ŷB1Qj!2 )UQSҤK䘊nvCަC< l%pa&J0&f:w ,'&^i|-B>IUVqIdȪYJ25(IFHK!QZ(pb-kS޾h)ZG`L G$_eij8ճ]WY=D_k6Mgq~څ c`Ù e~eo*D!- W!(~+N|z, z* ^wľ+(<dFZVvy)hZ;n?^xqϣ!6d - \4ơ%b+G|]cZr6ShSVN\vxmtj']Mk`-cE!Xz.laE``_ui|o;RXN>Y('\M^&`L 0&n V o F1نTC^z3΀^v*)@AA j͝' :ϴaxVӖs"[!9/s`N5ڌ','hj C'l40?pkU݂zcHUo-PdyrF9$FIh!1cR1چ߆ƖV|,hɢD1S݈{ZCEG FԦ@OQA"C(ӢPP)H1TTk껔c%V"2#?Q+vQ[dWh%n*G )c֕[^к(Ǧ%nBS}桗hZ J5yVPQG R{q_cs4f]2k e+ܼ 3fFflurDi @'7U? O;$ǩ RrOvwp2!ơ&|z#; ܃9#o:Gi  g4~v2VA:`;x>+踒~Ϥ*:B+q 鸖X@tqtDH:舦:6:Vб߶qaAKSːBuKƾk:-CoxRKBI4Yf֊Q]3VBy:Kˠgr(Moi [ XluďZ* 3,$Q/g9n#7m'Xچ}3$XtV,]Pj1kPmTYN Y;h,jɣr9>Jo!s-Ã-Zo88cdXJm[.18Va2nh$XZ'z-7|b6-O^zib 'OT6>j\cit6mkSSyZ-G;[-P=Zy%xR]H9]mcu hiYExFe -}=C^wV5%,4XzΉ?3Imdi0vZ+y7uZZk_ksa4w0$,² ,, ò 4,۰yXae!X6be%f2R,Sl2&o2&i&Y.$h|/¬\74XP{\A |,Tw-!.܋G&-?O6< --8l!~(릡`5, Ħ5h1il|/GkEv $П4^Vg>$ r{Փso!&W~"-``3|ru*]i Y VPFzT_T..LɮCˋ;kk5В=zuU,E+QB3N ٤k)ÓW!bQ$n1$ۨ+w`xh#dMX[cPvxV=["bޭ \ϯXѳBާ0/dn> kuq$EF 1A)I]RT-RHۇ+9j]*~;BqOZHzo]XImG.[m:47{?E},.'2"kT 0>Q`D ejh~V#vfwu|k'%]f|<   9)8p1Qi܏. d-Y5ʖ&G/ǻD_܉h9RjBy/G뇠9 ]TЌi7Qu||.f<.GU|8qmfr~kTZ*#wu \ czl?jYz7M7d%T qȞOަ,?Ny }V\.HMVDNŅMdWF3:IyF5AtR*U55]oc}3*g1kF$bbpZo|ކz,VSWhdZANk\M5E3ln`{#P? ;uc ׺J~wГcDܺ7DW=qAWnPƦ(Ő69~#H؇A"<5ޮJ=U rɄGF3ñ!T>OQ9?#O"7y763)i0Q^htV$[?,R)|ʫ mƉgǐbM;eXiGQ"MFH+>2\_I@u* B#LAڀif!W"!G%Q] 8KgbM"4" ۑLhAxQKx$iv _`}zHwB^E+6D? d }N6Zyk{?T-kla0;ғ'+ iy8YT6dF6GHl>!J\{m0}0ۊD|z<9SOG <CvLJ!Fa,A̐5ݖoo+;rT+n=ͱ`5%& p!0mT9S\KvpSZ\;=Y; w rNOhj:clv )H7.svS< {2/KKz W/7b_yQ}<x뭷,z|}f3+uIa*97u7GĚ k@U@iTJm͚[f*s#08:ƄtwM0.v::5h' A5 e+m.$& 0U=W_}5.YsJ/BvÙӴq_ZgFY*ZK3ׂsWfϔŀy8^@cH]% 䍕.٩~y ZSm޷w%{㤰>N綘ܶ)A@v    cB$A@A@A@ >A@A@A@"@ &)$   (軔A@A@A@pA@H858ԯ=1sѷ;ecnVz{5堎$pj=MD~Q9N_ ] 8no#< ;aAJ %S7Tw0>J>=5A\ 0[`lI~|2{֢k8p;@ j4TCS#E_Qi-EYv iAK ~s/OYW\xUR0ܛr-yذ"g0v(GEMڝg/gsAjL)߈sМboD> IV#u p>Yn!H?3-/CS[kmc(^M踈hrA@8?y~pz5)i亚ǜ?i*;Mvl$ jp֢wJ:wTôrfnBM2j(n;:fT]y/]uN\Z/!NîNf(xĪn*GiQz@N2O^D)i{ofT&jeIs>~.13&3 fscT?+L0uT"*ReSP.Q`I 0ֺ̊=Xa6=r^ \L@ Oǹ@N2BEq7g;Euزeh84SA@A"@zCf қDc(ihCg[ `ڥ q6FQ5XGȦzi*NmFz* 8R"PX pfxE;HDz.V`h,ʅ6^%\CQ#?> ö=] w$4Y,XS{9Wd!tPp51f6hg+Ɣ6Z2:all<\au==X>T4q؀8 ח*Q0j7}=._Z]:9h3v0dhvdC;ƣh(άxN̯ 5̙P. drRX3fixj]YcSEYǎxX5#|:!9Eu'%߱6~Bt 905['Q}-9Xd*!AA@8L#j k`e+MeW8\AǕt|&WU~C\:ők鸎t\OG87AMtDEG4KmtԄo # ZJtX,Ҷzj(c)Ac$2K B_CeX:,_F4Kkgk)Y+5VP~mS[Hf$ǐAy9LOqe9 [#-VZʱPbV`[Ʋծ%Y}[Ta,5jNc*vHi+,CFeZ2LԹ=~P Z6,m}VNNV?tڰXZkkY ol6[N>my-/Ҩq>N<;mSc=;dRe%X;{,ϴs9zZ似}RXur'XHd!咥ƆC.i4Zzڬuu3emS_Xm!Pc,֪ƳBˬt } k m}kϞ}c2u$>i- -6#r\Y 6)x́Rmk[GI4mGPÛs|QK'VøXlMPJ p#ޱg+Z:XaeQXVaeaXaeq2>,,2F,#2N,C,2V,ci^,i&i59r_ LP@xnBhW8C!a|_aF( pAlpxNKCȼ ;wͪ^JF2mviv njHxh)&g A*2k׎0D^dNnk@\0*)~.af\f\Ȱ`UUZm>!Տ;\^֌52@-E;H @ s?9+,EEdm1=ȕ[W{ce5M[!t;exr*b6{UIz܁:¹fc!rW4i#ޭۥlYɈ{Ъk?bf{Gs޽!!k'4am,i{Iр%B1-HDDWWad[W*fgm>hy 6r7\mGk#1y)nۅ|@\xv>L-rF7B' h6`cVC+ZRDNIQ$a?{1"h}ks#ٖF6   xAN XLv}RmAIdj% 8E?|ʀB2`={Y"xsA"UZM T'w"yxuF|fو uKx.qʼnv1E=A{ aN8"<å=<5bcOCU~MMxkU5quM+AA`Bd~t"-ȟg'1eQS]M $raY 4{QT_ 8ڐO<-S9RJNZ鬟\p7:qդs:iMmQ+KiLYA5^Z>*x*>?q [Y+0y`sU[|(5ڦP:"aS+$*jA*~"}]s>ZߜX WDbh؟`Yf9,_(LAAA*oƮwu#765jl,?c9!rVr-$Ki]&}vIEkѨs Gfq0*1S?Hs]hdVANRوUjXGaq,QsD%&7XSʗh]vő*߶>ԅVՖZÙqMUYJa%vI0d3&ӝТJv,#ٌt{(ݞHC1K! NZ:3ЕT}0_+KH}J٦UÓ>-ZI9  ]waiZhqPg2w59M3%<څΘ=\܅MK@<ڴԈg D{4F>_gL\* B୷U}W^ye2ǁ]DoV76_;ocF4L*ŕsqMM7fZw_PR[qx:yE  !)&GqL(OM}є 3Y5b&YYx6,z3:Xi.sg/l)i Oܝ `O;|wW_ͪK֜ҋp4r|=QuuYv>s5Xg ^U2iZiq{\KvpkBI@86;w1yȸqao. 氪\  _^ BSA@#p v_:9~s.jsLPA@A@ IA@A@A@D@1!   r     A@A@A@V?SWA@A@ Br\th÷܇$"0l5r =رr]4L]} ܖK$^.>|إߌtɔ A@A@ H-#**J^6geaFӭF ~7"OBoH3?N s;Rcv g]G ӑ:)~HGgJ p#xQ:( LMMMS׆SAΊֺ=2SIpONmg4+\(tttLyaܹ# ?7|xJA@8_[o lUt,j0j^;& !!裵}e Ϙ;9- 5]&j&NAӉ;wMEnJ?7CJ{6(&3 fscRIߞՃ Mμ`ٺ`LK)'&Ԭ¦n;OJ fkRׁR$iQ)Q`DZE #tI:aaw#rQ2iq}cH ,lAyJFG@Q$  \yegx@_x!p2`Z0)τ!*!YB(IWfdCs0u@z?HV*7b+=9:yؙ@rL"Ҟ|pg_UIOOV:[PM\Og f^TR 0 s:Mq /qI;ӋՇ3WFw?:c)|/)c=U(? pi# yR,G5R[]UH^94rBE1<" {[0^!^۾kzjŁO-;z(bbbz?jW.#44#WgiJ\>d"! c?|@^G;!vt߾ H1 ٫ݜvrt0Dw֑L.::Fb?3CLϟ*]AvrKoS:ijkP t[z؄讟՘lJ7u|n+$^9CO{}f|p/ w\w4ЋM1Q'J'EJ.|M_$ g7x)))'?9 #^£> MҲwޭ^zIYRG7u-܂kuuuַNΩS ~Ͻضm]/vAA4W_vYHO]vX?[oUy7^կTnݪ p& z]rƤYD@ȳxHM'ykwj)Z kIvŰ]w݅-~faCwcj{D&[߯Xh׾=KaKwWQQ/ Q.?!Xe+$ X`ߓ˗/q^_*SN>OlWaAPPy ?r~TXu<荗Oyep%E`̙?Qv- qg?4a8{DFFX"3D@jau61΂^*ՑKK[pE57h$maM")/(b\H":0_(͛l;`%aߥhQ{YqN,f%6^bWA4˴q8 bp4?~ Y~AMҋȍ֮LrՂw }GZ}9 E'}OO$`$Ğ6eeex'23VBs=ʳK_[[8Z?SOy27*V'&v;u<,ZdUyeL2pU-b΁ ıBaaa!8g+,c3@@ o :JltGKK ؝7ł+|P `,r+|DW yfw/~ 0x [e+++|7^-[f㙺ۉHD!CDuQByAiń`~ j~JK*!X™!Ϭ:Ф!29_-R苶_ 7>JM_7£/c8!`5 ff\8&Pv]dq֔P@c[xmXh=7tb쪪*Yz,p0w\U駟Vg\_RVSv?$`sN`!(v8=;;fin=R,@o<H(^;)ve룟[+tRRr;+b/ynX-v9 ,(;u7Q… 9_u?+cgWYƃ?A9$ L0( 6ǁ:$'<1w_uYğ=Z OYimg^Ɓ ɾV޼9 [a?͢!6&`-p֟gREqw+{ldK+ܭzB&?֪} a-W3뭬 AoTVo~j|8wlisI7hHmA@A"V,% tʥl bA ^۷OM͉;O>!*o6ed'0ɁwdWvS䐗gߕ;>S!ʆo#,l:*`k6G5E*3440Ɂ A7lg \wrr`+C\7 rVne& ОÇ~W*C Q~ Xw^=/ׂd`+;+~X-Q{4dۑc# ȱ1 SoAckI 'kq`a-IS8-(lMd닳VS͛s=&mgKވק-vUdǖ. Y=̇~CJ p׫$~El;kYe7O{PHYvԄ;;y |TdWbVK( |OCVVgCXX6l}h;:cLG _Py-H ͂Y8Sx4j6Uvc7ǘlIf,-_O>ӧ*-'?W֟˗$٬&cٝHo;2g5RwJv;֬wg^=='1#=Ze:e6':}&u$ 0gaV*? }멎F[^o KOnݴYO*zکgk/r-ڵ=|pZ*`+)+M˳oiO  p Ixd޼ .ήz\r-z4rgh;R##,'<$<2]_y|;x6u.;޺\_D@G_\XsiQA"bll9lAH  /*G{cvBޝ fijp}ք   y@NҌp|]HTl]sce;dNcF*A 6!>8UO;nnC=W `zL䋏6O [\A@0֍LO$LԽ<5RAE|M܄^5ہLL7+n(=yHDr'Z?Kִ+'A@A@A@rǀ E0;W߇8XV4hg !.a9: mNFa4 U2E0KFUa+\XξI(/Amn4ӆXXn{9‰nh>ttPd';8k,|+zRcA@A@  <i0"9&}OcƤh,XV$]#  gCDGF`{=_0r)""?9v {EXI \O'܁al_y7aB؄#$F'&ͫA<$*ZIE^#>+یS 0Z[[ _;gOZFÿofescJ/mSڨ46EbUt|fjC&P,kE, q8WdF1xֈpP'I+ASl/UFgzk{DWtºK .EckQU5LJINU.Z/W.rݭ̢E2:Rx/} mmm}%{b^u477c֭'8>L:i2،Վ  p.ƍ>|8w.yڣ hL,%(r=Ұ;uib0!g(a47PB*>YMաU;-`}ǸjtgXp,$*!>lrT]7ҪɌ0'auTEIK ˗ӗSo&鋞`sAEk_?Y)o|BeGtf)2mPލ(ώ!gO=\̟ pfwCͲETOmS`a_|;. |搝zJ;nXq`W \a8ב J6w\v֭[rN6vr뮻N,0~[R4n(?F@@NTBahb\Fo>239Q2 Ŋ MöȁtmkāU]σ4 EI l5tRۂb3wB\ݭ U %Q뉇ZE:,ZK<8s)QA@>D<~57 J/O@.^NoꫯVV|3%Zl۶ 4`_^-Wlc5׿J =Z#-- 駟Vuy_RVSo{"SY,^yhllT(\-}g'r&%W<ݼNHмCX9)nN0q9q̦ <97Rk£S~ԦCt3q֓b pI!f'.lcaR[WB[fΜQ9ǢÏ(O+'p~?d6v3.DLRHA`9,9/"zjemӶog'lcMk}۷O \&ZYHxblv}`p`]u8yyy`w+\7~3[<x7eɁ՟'o~So\4'o|D . < q`kXĂ7߬6 QHp:k veW=c®ϣx|A@?86l؀5͞=^мR~V?O;7P:cso$$|iY8yki|ŵ3[@ZphiYKs>s71V; 'AvOdkڴixWFy؅[oUqkXMb&R[7YZ橕B?O9YBU]'94Bsu_~-]/>r♭,XKKqk'O8D}3?5묔t乒Jiր6ev?svhy"];|-|2ҴsN^" #IxdjY@bktΟt֞ Ώ/A0Lڻ\ OK?A@L`aq" 9װv!s+A@.m T    0&b&3}c79#fFg+YfS 9@@[9Ʉv] m{!6{q& @|<ӫ# 1D 3w!)AׁgXmD|K6؄hr誧`!ǫ`dW`n=̃7&.d.@苋qVpC7Nϭn3> 6ظfA`g\+ xug*usCx!99k4Qj٠{`h|cqR2LNx4#v},m?Ktmoڎ8dok b\wy)DORAA@K޹ R9M@:t+1a$eb2[Ց>  2괚yψS%?o-B tÊ\@_XM6*3"]V !l:uGGc~9sϡ  {g?O4oC100lM7DFrHPTԖNObU: jYP= i)8f+3j2n17FWv`DTJ%:%ٺ@LK)nºJwzʑhܴi)(!n&4d`PtvZDdn/G~vnM n {m.R`7@9#COOúzhP 1E)6RpEv۬)rj&_kx1.Q/G-?j])rUto<n4$n*G}c|ʑA@A@ o.£ 'Np`';?EˡmEICv opBF){Qrf=aqxF 7)9Ս|^b'aV馎rBpa5:z`(&aSfRQhD_Owb cSco'ItC&0}sԧV H)9LRu /&(HH7 ö<4i,#dS=:h6`024a˩xԈ5]N~ Cx5%%Vq7V_FQ['-]+Xυ01v"5U#\GtLvK}vwH%RM< #JJdzC=6&EcQ2l5% /\8E :2sXE!"6)iaRDḊpY^ۥ=["b$ V06/Fȼfc!`l\#|OtU Wn~HoVHZ5bXS, ;YUyQԹ;C˳[щhh#)|?ڄB On]HL?#rQ$İ<βAhJ/} B{#dY|af,nEl=d2"L"#v%$3A@'~ߡGO~\{`-^U~8AbG/;_=,Xx<쳓W zqނ=a`GUՄk&9U}Y3c$ZGW8ݱ!a (PUP,d\?Yx˚{Q)_8q>cB hX/u:UDL pxW1sLDEE)rr=DE>>8L>?. IA@?ʽoIII+ODJuy!?h+KH'i0H3pa=,M`x7d/9 $4׽jE@#$ޙyΜy}g +uFE+1|pZʦ?DPP 'xBqyw  1wSO=͛7Ѷtm3Gl%*̛7zVIsr 7 55zx0p }\z{ճw^tMٳ`|;Je΂IlWXE}*Pk :Xx]$TTVwcީH\ʱ-s!")N4إk*5t:ɂMݮJ!zdV{b`x]+(@pL +\|Yk[6Y% w]X%jѐFM(G~j,VDR5&"Aר[$>&e1<< 9%)%Q1̍GHXTxdMnq^e`,BF$?+[ŋc/; }rbEI &%p< ᛕC;M BkB"`y}5BacTź`;{n>b>VKxcCn^X'1~&Q IUɛ2_J-iQ^|e(YXb-KP"naALbdR%hZ:{X~m#0s / IKrII;F4'N(~[LۼOlQem x!zɽax0l ѩ;1-Zs?NNjK8K8N>0nx;m VnF#X F.AKpL|&.DafQ7^Aa1Ea(&:j 3Da"Oﺾ^~j/Uq+k(0˷Ԡ)ianr!Zjу@ᾉЀl5ZPۡѩ86-YZ-q[Z4@ᅲkchU޽;^.&ך*D܂-…^(Ս3Fd[o{FWcg]F%9曥cCVV\b@r8wEBWW%:եL a*N< :Cѹsgh4b%ά )tGE(\=T\ }?[ίh>-yW n-'~D@n$"օwG񜾵*xy?Wa"J_p)Wbij+h4F@#h qGDypӧ"!˙um/o1ʫEjdF)9A2~*TD?Vc{&OHnȚWZZP ۵@J.k]3_&_hw:zCNuET fY\T[%u,GY.Xnm\({(1HBjRUܤPLK˜kHʲbm w22qTor J<SF`֭-Uc˿m6TIݻ?4~}:SeeeO>[RGipϝ@k!pС&zwpGZZM [ $!'X:Vs_1ilEr^!l@|B'3z ljdę K0W8Tœ#<|qQD 4\i!*N萘H>*FYn(wכ_!uXcPᇙ]-JEog+z}Il` ~[somڊE9 ZܷSd &6ǎaJhR x7Ah9!f²O$`aI9yy1GX3mP[9 1ln,mQ-C, M][Z{ ߄7sz,K1_@  [6_z6VldddO?mv**jn-ll,q@u[l}l霝<΢f}Vmg alC`" ͢8XX5F##㠔W^u*!C st1|G{L 5 Zo6aXv-IANxz⋰Mqi_&'̜&8T,X+"N5+ar!G-QS5,ˌӮ84z,ytrܪwD&z-.F 4*%|fs ~[T)5.0l$ZeĹN=n1]֌6:]&  aOf_E[b.0Xv Y6H0=F@# ?AAAr'xλ-Z{H2`2h+qi~wrgK/!,, 7|ʳ%G`` _qsAqq-rĭY/6~{ō7(w8qIg5'{̙3ѧO,XogصkJއ. IIIur 7`ʕq)|XZ}7n܈[oUgQK\wu۷/ԉ+((eܼyQ/Nk.Ǝ;S'˘ssc,7:AliF6FW.#05@y$eiNM HtX֠F1(RXt PJYOx0g``wsa@ :ZI~ rY_^sEŪ(_Y!ݯ-_=$*فb`tLaATqxݚ'zVw?\ْxh^<< ~Đb;1N&QX_]b$hlp`J+<{xxk&(**>d#++K D9% ଷ+]̨IH90w$u!\z5}衇)"H99\en!+Ƶc| @D]%U6̚5 %%%ЅtbBIΝ;oȵ6mԩSej7-/2N$8e~ZgΌƛo  Iw}'i}Ek"IO?utŊ2)߻wocvy,~$I:,Lp կĀ$d#.$lsZ;|I9BlۥSNdQF1{𝿜d%YoIojٳ՘z4>&5$0:{"4(`aX JqA3#e:IұA#ò5'E+fs (?Pv_Ch`u~OM*>`;+7@9e.D ʼntMe.C"Y]]zҢu^~   _/* Dkuq(@Pl*Q11o;-MV2B[OJaB^x4%h!)FOp,Æ g]0R_|$ rˁ+]u*L/VZ+VEK -F{]wɵ:kVy~$8\ BL.r} ud4z]tEr;tj6F:rN5& cԪ)h+ވN*C ~,ڋADŽ+&!$ V7*Fum0|I2>Sur@^w D>]yPRċc//!\l.ǧ+|剂ڤ+F-Cظw ZWoSC (D.R%6ep?QA(n>ϩwPVdž} - Ī=y$61~&պ* l( l8$w΃C"qPʋBߖnQ!p F')<qiHkM[DHgUSFH83H8pU4P /P~H J5;;+,ÍBR(iY)cǎ$y$Jڷoosa%QucZsS~'Q+SQH)(F옇Gϐ)QuS(~jePӭINEgĮgϞ6$Ub٫J-[ QQQ2$LmMasտ3ɤcƌM7d̮5N/--QYY3s8^;za #`6Zh!^iYwQG 6qԝ\-ƹFyc^y%H'f7O 0şa{zêܭhd\i znGI]nBIVQau:)STFq5QP+^!TVyxKԏ8(jD}T`@^G f@Y<` bzLwg,%mqCD F|!mϢ6Sk`bQ#hn9Ƞ!gH+Mh'nnnՔnStqkH!w4USRH q%_@111r--brfBW-0`>sp#qU?zi,++h~GEa~2FRHgϞ**--VsP.'{JS=wLn|\Ƶθp&HBZJZ~ $#]+|^8Bz5HkڡbLE#X~G5JZ9 {kWk9r L#g L<fU&tȒuq=%ۻK=hMFhkyrA# -i Ў5ק@"@δp]]9iq%$lݺuč$1H 6GXn H <$>$$}"""d5y${H:͞=&M]u|A*HǙC,ɞN>MkjuoL7dtOY&&::t8a[{!3㹶}ܜIvi5K+I/N+9*߱I!!k!'6u0?hY`=Тh aߢ8ךȉ5bSix8(1ѹ Q}]# Q}-QaŒGwB1{!wMZ4(8=zti#rq ΰ@+؋r"I glѭĊ -]}[usp˙ܙr MbgX]\e.>@Z3U.uŏkEY]Տne>ߩvMk,IHKx+ʖb~>o1zyT_kgT= +k"9aneeazOwD{ccFgsQzTY -'ًa>0Qi薨xTƣ9s i SqzlCB9xtAgNsuK5g7<g޽te4bJ#H*QsW;]ȣv77i.S˦P䱩:փl{Cjj}$:;7 _uVzG&kjwZ5SOPh4FLGkhNe蒭v<ۡ=@=ƺF@#h4'5ά'uu4&'v]F@#8PFNd+3Ңgt4l:f:F@#8&:'zMSklrS68E8AD= tI@5Ż%h4F@#h4'm\h> /NREMgmX"A)ki5mWX'B9~ItX:=tDNi4//r8pVݻ|mۆ]N~7vͿtVNs46"GQ:VWWarA`Gm>;x,_ /7cJ`OfFbWU+us RԈ,("T3]*>`~~SPZeh9& Ŷ snڹ˲נŝ?ʹ.CR.Ur} ޚgiF2y^m(@8}.RXm2_JT zknl˺F@#p!ꫯ>;u2W_UQ۱c^yVӫeddO?Ur"wp1B׿^ [/Q''Ǖ8+Ugqt={O>i(Y 88AAAMuy;j(M .R_W,s'H Nck%KyG0zhxx衇ĩr1{ /[n0L裏lq?Ə/*$lqGz]tz-(}}8_97Wj0*hg{ڎ 'a %{5grc|8#oyJ_-EߛW`|&$! cq_ٻw*6/}L sG"r^$0c`1֯>0/īskI@HNj:/߀"Ҝݖ-̡>lB~=7lmJs遰g2Ph._/lL9ތ=<On&-F@#pz i&\}խ֘PJKKѿ9'x]{'uhh(O~#G<@Z{Z_oSN4}W0`@pub I>In݊~vY&99~܉Ԟs!""7pR)˗/n:|{l^{ Æ e%Z$FqСC$7o,*k998އç_LѳN]Lغi a^.H^&P&i#JZ$YTLl\㏀SP|9o-6ų9^>Czj?EH 6rr1ct Gcɡ ECQqaH"QLυnk0'\7CF ZU?lY#)30 %i:tzy RwѦaB{1I0cRZ2&h](f`UiD 4O<Ŋ@*AТEp뭷_|.zT:V\)1wqv4˙{L -V_=hQRq|ATUY~iU뮻dFk*HIx:'|TqFyyy{C aF}%'''O>s%7 V&&&srP>y{ث@IDATd{ڴiőpN Q=U֙/GOЍp„ }yŲ'ʴΞF]V֙2Dy\_ds(ETT|V/# ۭNJJ/3YINNĆoA57_MIhql/tO>v&1o ]Jׯ_/㘀vjKs{G&*1-t =z5-\p>^t6Kq df{._~OT $e"gI;$LUa3GԷVi |pl@TV[%} +9{1i$pz8(P5c ,[&&4/ Fk)+/:tP[?md.yyyذa;҂觞zJNҵOYyH:s5;GT ~ߜ9N&"IË/(ˤFY&zݻK9Qp',5 )%p=" ZJ6Ν;W;^p@ FKENOL>ceYfI]tqdHxlb匰+A'Z[Zi3~5.rP&'H/5oTEN<ƌ#'8p K )S$Zzһwot$iż+lᴀ~fgg2֛\J^Qg2qŽ˼t3@rH7tN:M:.@ţMWe8FAZZi%,7$tFJZk8'Phya~RV@+fs uC ___90iEL?*E iUz9{,;\D#XLKZII;u$ K'8Grw5'N$nM  Hut򒖬9y1G+Y=GR>; "pS2n8tYc]f`پ2\y2DEΒ'‰c^f|^3'sh!z5a/.,Ol/k߾$O|nHh&H (1e1B(I(?jR.<2t(=<*#Q3~8Ԑxwq‰t?rߤdە[/"!-wPRH8vu!$$_|Q7Z1 '?nӑUUGNl8NqBte2 Y%|69)Gq?eee*>6M X̌(:BnSzJ0!s lxTbSQ\Vҍ.$,w"n#\4"1s*Tqn<ɫWQ,l`k@\n?Ԉ*A<^a1**Áb,,,Fy:b-3+1U$HoISJA0S MaU\VQ(`a 3ğ[,53D;qˁ>yd(t* I )݋8hTBzԀ3F+Z-Mj#p(#ѲKI^Ysbg COJ^O׮t|_~ζ\xCM7gykCrճ5O_Տām$ qQb"٦[?I~C~N0='$--=HDnݜi8]}L(@pjSeTF]2uOPA剕#00iwɦI$~Fň|}b>q(3M>KMXc~ zu+FtBĀʥk8xa8XA(ZjZ[hUm(JҐ a[<:;*rF "*$jMDb=crq\Mgؠ*ƒdsPO -Uj'JZ'wG&qpokx6TOZH@md='tтN˶E]HZH8Wnʡ0_ G 8p>olcaaxэ( .я>lh(|}{ʉ Ve!f2N>)}$J3} #vjx( 2]w-:,֏GT;cB{ҕ DI%̣;=62FĕK)%퓧ěSl9~Lg[7ϴ:;˯Ý#SVG `<*:KU0yuzwQ Fz]̆ΞN\c'J(p4ODݏd@t6Eay'1ȭ ,|Ay0;[+RiֈX،6ԿS^FHCa_*~mY,'Co0,lüFtNLK3"ڔFCV nsUWɍ>|}}Eq8PZn+]f]-ЅSK !2Jhq z< -qMC ]WSzyFY iQf/rPM+3[Ber8qK=)#7: ?F'1Vsqtd>GtJ >-e|נ*뜊WG/}n2EwEJ6JȺ:Lr{U7kgw^{ҥK%c"O0 gP JiQd$׹wq6OfϞ-ݞJOWOy/k(\JrWVU:[Ԓxp"ϟ/L_AYCznGZ  e$Ɯxzo2WW >5GiaUâԹ:jxT9U:0P̎d\ UEIFԩPs]GF5 Q;Iu3Y^IS,_\?T&[*wk 9Uz;YQɊ}xG\dtsLm(K$ę>cZe)q4e2J33i\e*6.@\=όsUO snuNL˫Us9:2uBr<'OIPs։8 KZ#97UrC59'%5!}lo+čHبP7>77Q_%*iHg\mo7K2:*K6(o'RGLVFߋab^~aX Q]懢΍*\&qt*LWس{jh4"jGmMYWGe7MB~<^odsϘ`YۓG*:rJ7:58U錈$ q}Zu<0p~Ow4 ulγ@\̵|GkYkG֧!}lWS#u'9g>&&UƼkZʋ9X]Qcsƣu"ڟ0ea4^s*sf<@kh` hKu)-jSyJ6 ~ƕj d-:j\m>h4F@#bТȪv5CW8 Kq)S&̭h4'jDN'NC -xƹ# d1948[ uQ[t9'vZKgZjh4F@#h4@h D:A["P-v4Ӣh4F@#hy\S5e!3+ YOn68ڒJEQfB{&:~[qjBSZRHE;HJ7buus@2W梬 -˂xܲ:D#h4F@#8ޒlY<c>"]碴$_L_rfakjTW/qu"M)epfю`0$RN =Yȩkqj[W >|T_~[[_k4_|g[nEMM-8* KOqUWm8@59,*<(kHrhb&"!QRwCS7kJwl.ccD?2|Вh('#X KF@#p!*gbs[Ir2c /'ImZ^r1{o=eowy^_ n?w\[ 7uT;\s ,Ybå^juYeLm6ꫯҳ.HNcc =ol\>CUχzH捉՛ql/,#]Y\% _& `ėQd4㋀&zut3W&S;*v&#Xjd ňǸ~(ؚ Ot&vHv]~.Bgg .,#t& .F !"R{mHϖ>bn&dpw_IGv lBk}#`/+3[tKAu`-yN_p5 A`rCCC1}:|KDDnzETVV'DTTT8̚5 `+VD룏>ַ~vY&ww ZO1`\r%?.Is!DFFJ ~ 8`#ڪ%I-))gQ˖-ꫯes`ZB a),7sV ybQ16 U~>Y&Xn'>) ذG1m@H'Zz!p3, o_+&pr UkYaBU|N 7-HۀqaaƏ!ljdę K0׫A<_@AA}b޼y iӦIT~7tM8x2^ lCZ 'xBxtX\: bKC7É' &HwEZn>$'[~S9a9b"??_=0Lr^bc{o,m[/ƭފױ}嗸dk׮B6=# d%--MbE7KixNK3 ($ѣ-alajMy:Yj\g|p5$'l[@N&DK3h|욗>=Q<P)$ͱFSt)-k[Y;k;m/*Yç -ElTABrRf?j!̴GQ>"gWD==z B bV'+bz0lƖ_+,PCt&ҭ ѐ>gpFD$Γ5k֠9 -RO>9_(NFbGbIRǗXs`AGIc>}凤4sRG'::#G}\;G=2JrjObfőVqҞ=-򸪋6Rhg}6^z%,)kg5(0\VsRZ_9] pDL^/*Z-LSѲ|O'ZZ%YVرΌr" o< v;y$t )? r2#v|2x~bHV#36ÿ[nb*ikiӐx DrfG7\q0\xZv*9!ukj(Ђ$gV%!HP8'kN$&(a=XW IWd3,[GSBku$A0,t_>q 4- 8G6ҥdn$F^pZ:H9Аdҽt]fc(اhT *}VQh>"8Ӹ.@b@K+R{̦}X-/`wD\I/@6 J 4F3P!~s{_)i yͦcF(G~j, &g!~#*Ul:5kErg2ߪ~k7Q4"sj-ĀD)qc:.6(L&a_}lP[Z ұ"[[ZGRtF@#p"@kg{%J慖'Fe4-LKPZNtU:*ꦵ6BKvmLIBe4EHkX_TyއQՔOtLJ_ߞCa!u댌L\vY/GbxEnfic[99@ g[_x^z\ r'WZ\ M뇫/X?0]e2-utI[Νf9Y$6(qU]\G@K?ܠεPG-)Cm8Z-kY]FMh2 l4.m+X,m,n>F'`bda%̖YpNjy>9"$ւD +F-CpJơ1{FOpɇtI4RhYq7t*!AW8 ݬ~{w[*7*FBd+<Ƽh}h\h5Z)MN& p͙ÇK TH9+"ws*I|}}m3p=!pP)i^A4 ]HzS.l1ٳ;DK.̖+%jCJ~qS~|6I/2>VE .k]yE ٔ88!qI$$M*tZ,әrLT$taf?\EFatUe,Wk1PQ].dz^_k<?19:Wa<KQjsƣ0 Ϲ\ 3y)>}Ak,ڐSFEbw*L'Bxn᪯p:,"ߥUIZ&kN,pϐ?~7`NMHw5^;yXܴTWknM6F*HBf/CwV)0\H>nx$F{491}S}V_5ؾ>)};-WqC WϹ:P}oV64VqUWmhl:F@!ВgH? JJ/r$"E"E-4b߭sX Q]懢΍*\&qt*L9(}rpk TDpN>w-,ԅTyZ&k4.$h%l#p'* t|1 O!pBAx#?2yoO[_u--;"*}.55mlqUWm0F)m]3E}ԙrNF@#\z'at4F@# A5 F@#h4F@#hml"@#hPFÏ dz\]։A@~{bJץj4mxƹ3# d19479Nצ*g> h'Au48Q8'C4dE#h4F@#h4 " dF@#h4F@#@4@#`EZGF@#h4F@#M cF1GQ1 I3=SsQHRД֩Wu1&wT7\xUJΪ(j8i)벐,g]67GoZr, :`fnYFEQQ+^kH+?3bJMM 8T͡C5aF0 ݘxi;g~vmWYYi\_k4@相-ezGN9?bpF8֪p UGj6B#rjexDO؈`tb\)1yS%). ćO5wjLvF#C矷ٳ|-O֬Y6mV#F[O[o?Oxw}ܹsmqԩS1vX\s5Xd-OSBYeq۶m2W_g]t }3 ŧ~ڨ|՘9s&y}VχzȦe&MA߷mڴ Æ ĉ1zh؏p=olqڱ~zٶ[nEuFNmF֭[Ć}SˉC@}u #9`}k.FaҪL2 ߀p% ;;?$2⽈? .Cpz)PvC [6 &HwEΌ0NC+V``  nρ? \޸q#nVI9  }ʔ)J?1nի$ʄk׮5*=# dZxύ&+q7&4 I=zґlҢxNk}w#)"w}'///6JOiq;b}^ęy'2u] RKq֎#GHjc@@ˌK#_.D1W_}[{gg}V^sbw|ίjܹSz?.ZȖG4M [ry]&`Np'L¶RTT!`8 ̬#ao֗CHO jc{/Nſiq1=$Ʋ6y}k6K5gN RY#p/ QRñ nk܏?s*.VM.13H/I>g랒 \`D;?Xf^GX*ҶH|l6oO% 'K-!x]D/[~yH3 1V`@ kyp7p|p=ގBD,Db2w?֛ǜXO4XF@#p< Q3gp!x}`-]TΝ;KQݥ$Q'..|rMBٻ6&өիkヒ޽{KZE+/̔/AR/K;vȉAOg^z ,XM ʕ+i+}j?yf/ zu_~$ ʄqvILZhDo(1cп90eQHhSi䄮Qu 6%+-<+-8 d:W=\'.}qٲ sBСC .,Bw ſoCHH$L:\y啶ENq>swy'Uh4 ՚iFa23>|6 p2I$'BH6\Ȧcւ0o%F!?vd*`/9#m",4#NNXrhZM) Aa\bGIJikr΁5-ZBZKIV8묇/kH:jHKا:` [仹ٮOODѺHI"mHiYNǏ8P-[&I+ 9)ANh<9rmի_W\!-#$d:8:HwxIpIr)dsҁ'wخ3foB)I"oR9&YVY;lJ ^v]-"pg3. Xc|V\N7P|NcҶ9zaʼTyUcK6}<*3('5ܕnfQ[WWAJxuWuֿeF%@ZBuSUcKʩբΪeuL[̎W:u?k.W h|:i%{P٧7>*>s6JX aX]q }?[b,£:]:u4ܘE٪'} S--hCcj}"EBKR׮]9 $pt; "`4Qh*E4 _cw$1E ֟q88Wa# -E$$ $*;7k.LFq.cSiqS GKn={"Ƶ$t%٢[3QdY*MoT]7cҒIWc:;g}VQh*] N5?$vm`-smi,瞓t֢h)tU~ %8c{]XYؒrXcկ*~Eqֺz7^*}L-܊^)-p^eSr:pPE5EZ;\gʄ4c,E}9T_1A8+_LVF@#p5[Z;HZ.Vk^hy"a$ pvG]^N[lM PJ  ,$YFS|pEҡw-pU#AߚϴXI/Sk V7D{HZRI*v{`2+BiݤM%)hPos9Eq-~={kf>Z3$Ԭjk$]9݉|KZ@@@0Ie˖kn:DfaȑLO= jJ 0%g>xI&YJZ5ʹk+YI7]l)7g ϴT<WkK=۷o7Aa?Hxit嫺kueNDDjZ9É \hf6(?wWRkTLęů?[HE"l]\%<~>2S1w2&ct[A%`e7P,\#qx\.2mmG֥.E7XyƗĶfoڴA <8gaǣ6GR;M< 7ę4g=2LJV=Ȗv౾%'m "#5y3m ׮EYkqWP&C&) /\yz[Z`Vn]p& Te--,̿;bJ#◡q8|LUqk+8S/H_Zn'DկXH@][ f$.B`*$ bbcB@ˍ^a~/_ZEdaWwl)ӯy 2OS4tjMC0Sc46b/!4#Q=~* UrZ@ dJ CX=A8*] *ޕ0GMO,pǐ?~ff`Hٰ?u7Wy+ @+{9[SE".񝀎B=YO$AfH>nt$źntU溛3cYӎSHXm)]G\iv=aM**gm kn⹶uB#- ?g3t]ñn9!P8w|;?4[g^dr҅|XGQߥq*7)Tnwr<2|LMzt  [MPY]I~"@(8gaǣP #Ich=7$њfGOII@^n^NfEEʕGU݄Unb/eݫԂI2V/QmӨpU=* l/כ:u\oX8 lX׷ ׺ t).":AD;P# .ULJ   pF" iA@A@A@Ȫc&%A@A@A@8#yF^v ߷.@y/ >kmm}Q7;5B.=CRSm۶믿7瞳HKK͛+,k.{ G`ݺu _[nyyy/,9AF?6nX[yofhӢI-ٿԲ^Q'@jj*  .fg+qчu]O?E||馛kΝ;1a\s5Baa!>#cΜ9={0\ve9snïIII5jL?Ϊ}W^yE9:NGȑ#X`uB߾}uLNkZ[oqqq'ɓ1}Y} +p%h/H91o<{ T^[~8@IDATFg¢9_vh-γM҇!ɤuҥHII$]tז'%%%Xp& 4,N]տK\~{ω?#j|]P`3ӝxϴI$ '˜dd g,R=Y=ܪW0~?4kڵ_So4R< Q ʑShg>~UɝwTjD㦾3o~ݩ(ZSo*^6򂧧WdT_QSrvmԴ :+xlߞ߁vL/T:K)A@{4kL3\~~~XvnܹsOhj.-tdgY,M9es׺uk:t?n)Sm_7Pb_[AWis? vWVG7E@) p @U#*-V56&-۷OrfQ.JͶi>i55bWVr|ɒ%vWO׿G{L ><>J+G><YNf~U/}++`O?'E&;xB6MKu]zgnٳZ&PΥ`"Zg/"Fx6VvJ1K"IZڳ'uSu-^B*" gi:EZ#p ]Mi{wM Gs%,G> *8p@NuAL6M-[xkڴ)k?ӧ5"t{{.\[I̝ae ;lVdg@9r",'Nׯmԩ^xZޥ&>S aeԼO#sf9^8{8D9^r m쥬$xǰ,Xۮ#h[& 7Ŕ,)5*7>>Q\Twdg۪$QS///iH ch>0me&M0U?0QcW Ǯ=e~pn[?܉ХGٵ%P'Y ס;ڞ?_~U |U\1vgmG hy^>\v2Pq<:??fDmӥm3*DcD5 .UfS)A$ YcH7~(.$xJFź󧫼E.p&nMtݻJbH!\G(,3c^W\k=SZN @D&<+юl}-7k+H`Em3N>jԭC,0l=2l>&?&Gsn=:yń&^g(,.Τ;%PF{D$+\瞳ײm6| jMݕUj*q`?)ޫwG##((~;믿SX׈% 2dƎqxwugr E@[x"YV!nZa~dE=x~ _Q aZT͌C; ':A$#[o:f~7ȰFI$ C{mڴ Ç##´p HLL>3f=(|F[ Y VEEڢ1>h,bDu˦3) Y;,/kVh+fǠq|)3 EG(UKANHIIAѣG뉉AffP=yꩧV5{ĉ1o<\p:t(~g]wkfO⫯G}x=={=]uIBB^1cꫯ0M<tdAeŒZjM2#-ƍCrrr9ռg'Oluȑ#^{-h[ znn.O?TN(q+p%h}A׿z-b[oe|M9sd=ܣg.+(SmϤ|^ 4ظqNo g3b1k,Ăψ.$Vz;wl*q饗8Zח-[B{ذaF3Œ%K6 +z0Jqe]gǁ8g9xZ DNzަMrش=鴮%RGWD6ۢE MX+G< $vF ~]㏣RuRo7|3/^lُ+VИr`!g}ZnI"i>!)$ivQ2e yy:|Y@!958VnGo݅ j~aom椄yvgׁKX:IJBk"޽GcѨQ#}g/|k'Hܵxvø‘ݼ9@7ʉkD)p& 7oy]ާl3lg7mݦT[MS$!z>j{݈䕈Jr03C%i()EX5-#a\[fISq3U0~qÚQvgbCvj"!>12KxŹ@؋KqKֺ%ע,CƦ,"[!J碙Z4&J^΄ս$q!Ab ||?D%R_ia,{Ah%[eqƁڵkqرuZF䀀<m7nVrbr`l>,ţun\#VY!Q 80֕0 -cur]*I6 *'`>=ЧD.ueZHv 1|TWHJ}H"}jjd#O@*I 16:yHZiuozZy]iK.^xzm/pJݴ3OudڴiӃvoSnJjz?{& ivlۈbPSQ% 20tz-2lFؤj&]ZGa8zB&E˰nF:7aۖ?B|r n #U:Rl#G 2xX$w+mSKDv/%em 84q{`:2khL^둤P:Dt륣K*]̵p櫈pMENZH.HsiD|x;2C2K4k>ޫ9z^%V˼o/2&#ɣkxmV?|ŏQ\#-iʼncQnew%ĕm#4S#$A4}1b:{vbXYZ+MGBGk;2K{N>rJˮw8 Yw׈\So>{k'KJ^9w&Y{?;y [ |ݸGFݍ4Un賂[gb"uy~T jPQ&ĕk0eTt6s>ۢ\T>jGqヱS6g@V?ƅ(kc8lZ҆L8E`Kt\9|:5ESG^WbNF R|SoṪ"VbQխ/n^GDcǁ#gԍuN׾Z88[ ք,tQpd]D˃#_!@wTk 9eqުU+ .Օ5ZV︹OeāJ:"۳gO}ZMSN44p'K#l#&ҺܺSգ!U-GEׇkH ͤ7!.޽[cL?i&Z}ЕQDq[[Ѫ:˯cʜ fYZAy݈UH^ʼKuv}f+7?VGkְkkBB͵质g|EaOX_d_.I]ʦjWhso7L>ϡ w|w!B-MJzu/j,rNGjI*g:.O>#zEB/i`&FR;~Ryx/5ȈFGtn'mIJз]<18b2zUDdVK *WK>砇-gUNUV]⒒CPhk8 :/GV3wq裏X17:GH8(Ł>71B?>c&ZuO?7+'d9gV#Zi:>UxOpZk$DLmYw!aH~n@Sa=t|7fx2Bd,p&r2pp c[yo`kii4|>sºcgPs'' +)zuEn͎B"ELK' +7ᵠU[v|qRHw8:k]#&\YU0w!mm峘bşn͇}}X㜅MZLiu 8͇ynd3i&zd #ڪ2u?*<֧elnv/, ‚Mb |lƕʣUZXP _B$aʗ2űe(p!;[H On(h Fu(-%~g?"γT8{6 )M6àUw  sj"ǧ\ZK:[&œta BtY"$!^WiS{Oꑄ JTm5\7D8 +}Ý>Ÿ qvYZ@qȍj*$Pܩj6B.ǍT-gnN=P,t'k\`팼XKЊā+1>'CNv}-$yA=ܬVL 'B^xUc;~9~6nv[ug:zzl-[Q{@"e;+㪏g̰t5c5,}7ǶUt{,<|p^*q59N>q=?81i!7qOk!Ɩ$ޥ-hRe/Uh} j3,Tn$˥JOzbs4J F`e"0|66);m8Oič ۘX@N[Ac 7P.eA(U -Пj{AՈ T-W_Č!eRёs8Jf,ۄڢ kEDh%/Aym *^/A@8V$X㜅MzLϲęȰܸxM)ªT*%ꖇbE[+T_v i>z./Q. ^g]V%zuY*=/OToy.C{y*GRVJoo@JT_;j5]K6k,=UMS ;:XŅ |YOPҼ;N]%r\KO2QeT-ZL%Έ)沟jCu6S [n"g`@E>ܜG:fRmpyMR TnS[|T:ܩ@}Y'NM4U@C :B 8 xr)"  \C("   T !   D@ |xff&"*|1lDPKC@da+A@NCHrw}$ Uӱt sUG2 PW]vx [E@V0~ PRTS9A@h lݺ=z>Z;͞ >B3 p"_"00om!' k*MBT4OXވ+ۊ5˗cժU5HIZ7$k,Gzef4.-B KrV+goy^|—T, @!'Ny .СC?!}ʕ+u<~qea0a>S\{wuסK.scYƱ̒%Kt=7|36o_W>hypWcȐ!x7tyxt{'7x#J5eOؗ'|Rcضm=u?^cpw ''GtMb~Zgcbb0h cƍvA.XbfϞ,8p^ ֭~]qqq?c ٳvٲexWz$Pu@VH[4Efe}~Q,eABo~z(JGU.\?Fظq;vl' C{'d>,΍ T%j8$|ˮ cT܌ R)BUM#017|UlAf<<#m( 4nA\gyF>W_}T#G* m݆?\  G}+:/I/ϩW_EDD{DM?O*H.W҅mٲ9k~۞xM:UcA]m{_r%X~=.\X  Ppn>w8)gy睇B;wgϸnOɼҊ͍NBXzOIop2ՂGUoW-ӫ5 I1~ڵDzP$06H}I]R$fD\՛Q2 $D jdQMǒr. kXF3ǎi$rɚ0R ;$Gfȑ#5䀇GٳG?_yNKu\y~PUs u]P~:!z{{skHTI\K#& I[n6 x뭷@ILH"JVZ@:CIA㏵tu۷z+<=|qY͛#;ciGɼ.^w}cyT?F"#&H>lY2kGs΄{LCJ/DW T@?x'(W,Vel]N[涮]_82PJIU}GMǶqe)K.lUyv{Xwa|\| {$u52KdG ݳ`||DcV~$S[}zObax`|͂[᦭$:ӧk p#AI!t-жm[еkWޤ 'М ˒8C᳏aS%3bs_~vԩngiv=zhA_&9k/ɨ{L[B5kVZJ2i*  PEu]xꩧwYq=k F! zUo; b1m*ef!}#t ,2L]M[0"kf#,f1e`׎MCG%@Y񦭋혺lc$|Y *k_1g70Msyi)4;rvD`nޮaIȟv`݋! 59UkBl!DLlFLU$S s^ljcSߞ1$lܴcZ[_ U[!U-]~}-ƒ1w+,7*k`D.'vOEi]:e2w؁\s5g]a9dI؋/XlWXEZ1KiE2fn"'MI\UE+;IZ]X׬YGyDGG1WZ_Y7;p;fsA@j>222*]9zJw:p. B [5Ku/!qDDEp`w+Yx*٢s/{^h&;ZbLm/MSf) AjIЫWElI|xaOSr6<}:b̜w<&O,f9&k񌿢[\6r\)@xv\޼>+y }/%YbG\lsC8Beu=zeW)z -*z =v7.Qw#Iq̥iו>D i7:B3nҧOt @(ڑ _]K{ \ܡrkkjMxe`:Ðfu4A4C×_~Yҝ]O]HÌka>MI>_z%{ n`Z:+FUv9u39ZB!?MZERn~coA#y5j^i]O4Jl0P9s0 7Bsnch[U=kxVXHrr8J쵘93tWSOQO!QM?bc@fs"˰KY!`ڢ0īl::hVsꍁh=va}bČ ‡u.60WY--BEnxFm4vUoH17 B [JqԹs'attҳf^Vʠت֩idRlA dC׹"};*ΡDTcvjHXXo[  Apqb^(LеK/asWu#T/ 9kCMupkwA@A[gz&}ܠQԆeTo{ɑqchέG0 yřj{a TOP7l⑬٬QTХxz YUqvV;[aQVZ)(4h>Eꣳ܁T@>3D㜰:   " B$   )   @Y)$ @CC7nQ݋l擖G֨l9tP\+_NarU 4l@6+A@pÇq=H\tzz:.]Za'[*۾ݮڪ/''G,|w߉sNp3g QF/ǂ i=zyg4j:L{Ywv0vXc׮]J۶mpr2]w݅;x벓'ODZo\щ-?3zxlެ^%"?SF8 ~WDšZ+5   7""cƌ9 LObD뻓`{AŋkcǎkzO?dVݑ#GsիIp7N.sHMM nrr2ܥދE+ė]_M$[l%*usW*ct:U[s+*9 B5g}vtHG@,hA@'^y=v#>,z˗/78o<=^Pm `>##CsNbҥK >,;#^{M?sOg͚U \k֪n[n%ܵQ~N|};w.z!w9&2ԑYq sݺuh)!҃?\9as?`sժU,q$=zhaYd$đ#G $n(L_@o7|3h=k:Nݻ/w^3ٳ#K#1B,LJ {/bxyyաC_^_&P/CwiwĔBk_]ꌥكӧ[nѮfraԩbʸU[Jxz^x)3޳_|rX[g\XX`6?3=DOg&'f堬*CViƠUKZ6݇Ia?PWԤ;CA^MHYA@ Zq=p2e^?CBIW6m_o:,F "D7)Z'͠I&Z\Ѳ駟jD5nWE{4kL[V\ ׮]TEEyvepÆ ZGM!Q$IISO=tF-ʥ(G ${PZ>dM3aN<<6lpv'QSGkiq34%ɥ*7HHi=+SVabi&&@uhܸ1]2iҤrtGAs|_z$H5Ǯ%17: azʕ|lT(|zÿ>1e.0UW^;%ρhlnzrpKG+iuuNK"I"I'_Ǣ"{#ur޽nDFJDCOXjZ?̷,o]!/Krz|!XZ%Bl:kh|*eÚQ3Sd:sU=-dZ Ln̵(Qd|[zE% g8~Gq۵ՐpI|Rh1;h3״8r#뢫)-$q#,뾸ib: >r;sR7u5:ܵiGZ@@@i޼&(òeѵk7FbtCиndWS{Mx@q!r'Wu$Ut]Z53kYn6a^$7kx7oГJbÏweh;}:1O"@+;'~8BEkwLUW<bhS>r#]=ÐL ٸ]E;j6NW{ftYkCxsӧ7|SOHk.mO? lJ4k Z#={qR#{Mšb[tۻC1u&ĎD oO^f&/p"r)ca? J”($ cg#']va(+ 6 ܱō>7G׊;TRWۂ4#\C7h ՗)2uD/71z~yqOu/۔˵B  8ch,f]Lpp :TtMe˜|&S@IDAT2zAsU\Fh\EiZu6^PPr劐1oL.NܵES:Pl,'U.~{.כuB=yvޭ48qv^2H P]jw̯L[o11+o9ݚuqJoS>J?|o#cCnx4֣cPLznu^;T$ŎMճ5nXI(".\F;qؘ8 ߇synU(%Fpx2b.'aZrG(_E_sz賃I3P^_\8&ں]MY/xy(bSlިJZ] p#@Rf~00*eGƻ"L<2a#e\ qUTLO:šGb{y(כmgqeB:e"@}!__9O$!P3g& K*OQO!qDu:kłTEl⍁hB]X1caTqHUIJleb %_?,l9zKU}S|jI91|<)2RA[OWČ]9Nsݲ%$@B.|S$A$]A@8Ey/besNg窗 (OD*ت%-.EzEӤqKĐeM3Ն8>hތ.hִl+)hGdrrs1n)0;Rj)HW o3TҖ9[OVw褧oU\=Q?t2Vg!7' AP1G tdD#LmAm3ʴiqit`Mf |ZZmV~\K   P?ճpژH-dd<}KsO ,ƌI!+g$c'4lrzrF9jgXA0o͸ReT2|&G UvN)M2䇍C4-:qs"B16{iZ,^8p dtCqVL|1}#m7b}B}C>9p 4\;5TW0pRG /7dͳLS'ҍntR g@Qu2Ϸor4=wru-"jRQSmcMA /7 WQ qG|^v2 RRQx3tdSq=*H+(Λ& pR&:5|'N֦*7<5`&9Ss2T k1hf<:tp E[1z[@,uŊli(G9؎Ia? q{ +!"/ qnk|pY8xcf4J:k~P<9   @#`ޘ3-qdlw8y ;6D7E.X< CŮ ~ sbWj]zU^'   PM4k˳5~խxsLP}1ꖾ.V$  )A! p(Vݸqcݻw/*OZZkSCʵҜ?MBt@w_3Ç{Qӱt uw}ݶl{Y۵k{rqINN;ngu>v nBDFFbԨQ˱`{Z=py?5BvvN^u{~ݮ];; Fܥu]ر29[nW_}5va+ATE|D_hh(mv6hY:) Аx'E~ك5k`ȑ=FDD`̘1'XI֟|IL^`D|AqjdŚ%&&رckj^O?lՙ{Xz5448qw)w&'']˓hnٲEټE٦]_M0aKy_|ǘ3g_ATGD9O1 s 4|^y=v#>,z/˗/78o<\xᅸ59`$ݴN^p+W"1ҥ 5YwyW_MbZYʑ禛nҮ^{$(&& Bxx}ӳOw}7.2:TN#|:}ܹx衇ЪU+$]V>^W8=Z_{[NGki%$Dq wDUqu`X#j*j{nmhP㩎9眃[oqqq'4ɓ᳞K.͛A߾}gHY3jtQAA K;SNMh;)]WXR$|YYYzO7>as? *`ZJwN:i+$=uzk,Yo ~~A9r~΀!{$qGg?_~G{ c…JԻn 4y1pVǾ;{ xffL; ٳ#Ku!$#F Z-,@￯:/bxyy1hZx-"M^;އҘӧkWS\3᪯,cUYҝD~SS/Vtkc3.,TJ/Gs†ς>LO&I ˖-I. W qa^5ʝO2o;Q+u>c15i*t]XP \][FLGXL_*% "@2A?SLgH(ئM㭷G! ׆=3zFnc䠃VO?T'5e\VYѬY3mb*]VG㘏}zz!ξs ޙ"0 [h.3>::-Z1"@'74>޵J8 Z 6 l4Zr{_tIv9Q+˾e3.EjJo IʴBHH^_r^z^m۶2j$\?d!gS"E.u$,A=fl6.CCL"=ίQ;c ͑A@j$O|򉶼qph%2Yך18ђHgH/mTiju;t>2#so.v:J㘏xE2IwG#M413H0-f6int+k4Edz#kcaw}R;rr܀טmJZ/ZZGuo3]Yd_N* p: pe>i4rhyD5r"5CWfzt%; =YMCxPa_=-b70JTU>C)XԘiX|Ϫ%)*\A@$$S,s۵ՐԸΘ1þ8sM#7RBrHK:RՅun@aµH*HJ\7I&?In&96mԾ5# t\?͛7dfٲڵN#c!4LRHxc<@e+ZNj}.8yn͛3{E]]jGH ypȿZ9Aq -\hf4iT!t4CֿLDyj$|"=ْґH^:llhԽMЖ|uk,y6ĜEkN C^mӒ&.%M_=g]xYlSHNJ W_l7L۞lo{=_$]wl-m>+.F_Nӏݓ+[l?L uOoI +Nl+u'ƦVy2웗;b|Igxĸy1qH㉭c@#3goD7`-[S{]:θ֎",u\6ɖ+fxpkj:lygڸA[5g3vYa;$suwjo\oO?*k>nõ4p{H_X֘rÆ^DhflZ-okiiaEC\;O_:>|OKJ;׶?N[O=3[pMDSI=]4v{4S" " " " " } >tbK}A٧05 /adw\oc:& 'm:yvm\eM͋[ҥDsc>)Glƾy<6";kY L[HOBOCsw<#&" q~oژ=SF}iⵝדoj+;GNz ]gɛX.αLғkIngMLٓ6¥鸢jyޜ=f:[jK^=/yےMzUxNO?wbrԺfP@OcZvr-}1>Hn:%ޤ-V}>/귰F#Zkfmɕ#"MغZ΃[WvSL7J^ܥ{2$]I"0p^ _6<o[XC::o?"[ m}˸J jjt%}\8LƮ(E;!" " " " 䩉@Y* "R@o%۸n[u@#R@Hk ]Qh^N`6e>gzmٲנ E@C/K~ӧOzOFPٽ5@K Z4`Jj(\y'뮻 n~{C" K/җdoFNr ţ@_"pM7:}'ڪUҥr)K/վ 裏3g%K>`[|y_B[o=}}1z'~kE` u] _]r%]vs9?ۑGi'lݺu6o޼gW\GJu|Buè,͛7۲em۶ٍ7hӦM;>~t '8`gq#_PΘ1vyQ͞u_ajW]u]xᅢ#",\0Ui;ٶmK縝_с+WL|ov͝;}jPY7n#p,S+=zkvEW!ϟ>??~9~+~2CG?Q=M<9L/^l{M4WE@M`Ȑ!KN>"gwI'٠AЉ1cT ,p:(~)#ol f+{>3“bY}']ӫ}Ea>(&p\u5jTzT_}C!A?WE@I#}_o|Hg{#O6* kWav_lۂ~l|߳__UWԐ~!"V"[XQp nڴ;94tYg٬Y E믿^ye-w\]v٥S%pw4+W{vu]D~;[vm:>ow?t+ 8 m2ypבwN<4*#0|pG?^ 2l2bj%{1ܶk_Zz*x/Sx! ;vl;B}gċy~d)=J_6'x΄ 3LI4~8lx???rH6@kArPDArC:cy }X5{@pkiۗjObOiw|?Ѷ? xvR%SlDb>->gRGl.ҷlٚglb+W?>w/_nSL=ÊPAH#59{{⿚?&O`7ҷԾ No^&" .b=O'ڥ^.5\Sv~j;؋);OP" " =C`v?<:9g[on]wݕJzG^|Ӝ{.:u-Z(tM6}U N#8N?t{mӦM6w\ҿ?_WXa3fHx7_tAvG/x_|&" "Й{[+brJ{}0a}ӟn-;߱իW?WX٥O{g)PY.%4 QFuvVaD\O}~'> [v]uUx4g۶m}.rۼy-[~ӟwaO>:… JE̵}ݷmVhE~7ԏ&Q,&" "Е iZq}L%gwy yF>O=T )D@d!LJ.xϫ[ N Pн7puQ8:+SOM>zh{좋.J N;Pvڈmظ5jƍwɉ9P@_ٿӿ#W$'M&@N<9sR6,!C a^ m NC\Aĉ բ_O ս˰ۿ[{Wj" " hucJ33/o_}=tKH" "%uРA8gڴiKk4=vYg٬Y۠5ŠbNH_̀gMN߶7fÇۋ/>餓1;LE@><ַޖ>g ϵ?3>r>B:* Vev_lۂl|߳f홶ߤf[|6|vy6iH/WcCD`` sfϞ✐N{o;ۘ`W^yh{lmM8g'O~;Um%ij_M!" "@Ag:~g*^6|M7<?.#"^ժ#SnArT)Q:}ܐ}^Bl{˷&2Ȟm-v!#mW-vvG-\mOZ`sA}ό ,v|ƥκND@j 7rxwY_Ғ,0^Rk(~RJEnEA[W%q7-δOwGoӎcZٍl=f-m6{ڡtevԁmUTD@D@D@D@Dȫd%^|5i/oe_~5o=4is-Kϵz4'/&7X0ã:tMlvs7Rm|ioʎ8wټvWW'y魩˛Beg `-ϴn޸>ڈf[`GSmjwr5]>&7V_sL?ˬy?6'qk;} f̳og_9a=n.^v@^s_{Cq4ǵC\o/<ц;g2kxa:5!p!ĚUD@D@D菧sm65)"/o_hWcq@t1}ٖ0yR[%9I+ 6ᆤLZK4Mc>OsNnS'bW^aNvw?to}S2.)" " " " " &:A# 1FQ@. im m&" " " " " D5HXˋq' H B(/ɶ7\t 剀@jI"YuJ5ÇRhW3fU}z,>ud98homذQvFh=Jgɩ/XAܺ* v&y ~c>vZ@s= O0ARD@D@D@D@D@M5ʕ+$㲀>6}mɲ s}jz<1P+y^GAmJkkÇ5j.C D@D@D@D@D@DbXlٲnuo'.f*$ 9ڒP{ :/ٯ)}7Dg7x,tƼ|G2i8̣AI|dlCDsNP&zLza\5( "=й?uH(wɶMoM$sC/١Ckgv(&cfcq%z6,DŽ9b~ >#Pbs GhSzuH4yfe8$E@D@D@D@D7z^ ގOEX̦܆"#%9p{זG^sez, ;ˆz(C|88YBļ>?mΜ2aal5hpkOйArØbI?%}\ @16%D>lt^熱Sf"6vؘK;C_VgNytpޞ|:%@q8Ag}|BG󾒧'9oUDQ@r:>\~ ,o̫F DŸuhe?3~4JV~" " " " "Зucq'pϘ<=ƾban,dYyzdxN^2=/7Z;+9>FpP\A,6G_.2IFmH~" " " " " u|y<-, Cncݯy>z# H,ρ?fg8^V! D|)1t Fڔy1Dcc1ND <vL21;}tЗeK }y6cvܺF,; +AF$2hxE#b17|G 7>Kܩq4Ĩ6丱|" " " " "Wcq u^Bs}H):spY9Ѧ״FA_xYǂ]?D,Z!>Jkf>l6¦y']D@D@D@D@rui{# !iSzuW'ä} =3Jyf^ղdbXSϝf_CAFcA1^bp/ܸ6'jsBh^O&8_.|їvLz Q̣D,/kYXnMj H.BƏuC9hCRG>,0Cyzm~m̅tʑ_D@D@D@D@z;.0ۡNKE6#/ޗ5dgcl1EƱ*[mYDA,8V;+&1$q,ڡ>6t/96d_OR1`mP/-" " " " ͋4u6t^O_V)yz-m6tѼd.},GFz؁"M<þޗeÏBymCbXPBOt4>G_he/]D@D@D@D@z#-ɳyG%cq>O?Q~ގ/O VOѼ׳a(r(},΄cOdž9iCy#ކι \ޗt6t4旬gE@D@D@D@D` G;O" cQ Aڔp O!5P˯(ި2\q/C1)9l3 1lmhYDKK}E@D@D@D@D9}l˜$|0.PzL҇^~?יmʒ`Q}vWY=RC<dLKz(N$4^i䜐ܐG=avLz_fj" " " " "0 >1>/l!}QڌAz]Tbߐ[C}Su]@b,~FRxއȢc F%}1>nڮÇKm̥/̋<" " " " ">/a,˦2c6 B6%siS>4m3>7yW-k- Z a;BvL′( %a_SZ HJu,B q敓8,C`-1;و>'Ўt(x>7yzDƥNE"1>J/"1>^·\4H;*i)}>}'Oܰ? % 4IDAT( ,p^tcP}3~8p,!Ѽ1=fӏ)^Gd@'szy>eގDZ$)G~ujE HL+r*P+\4#F #!^GSLBivxD }KVg# D֔iI kN+eQdN8E HL΁bK^}я1$b>Jǁbш8cc |csKv=sb:|h<_s$E@D@D@D@Dy|lb1sP+Py=//ymyY9=OXq:0XsS/}a_qo@hDC.Nļ>.yK@$~ڔȥu1+8BϜ,YIn]* LNx %QD*~_4F($16 Gn}ަ'Ca|Nϕ." " " " }@x>O,hI2V4"}X|lCxCe# HPz;O0EA(}|ޏ>otg̎O&" " " " @^Mctęsd\<6?\|^91XL_= H,21"1+p|+W4bNnKkXLz_Fx%+Y$'S^{r/el*-y8Cݯ3W^bqrclXUTrnnh>:ߏ3/֑%MD@D@D@D@0mE$r|m/A+-E hSO$v$Vџ%QdȩŊJ0>%Oh^" " " " "з=Ǐy_LKl|>^1¾%oE exZ H,6|yI}-c,y6B=fÇ< d~ot ~y1;y?uH|.1c>^26!+B?PbL0obއzיZ939*KD@D@D@D@rdOcKѼ:}%+&Ƙmve$W 8;}96EƼ|^G PY>4?W|刀@o$j[ovL Y6~ ̃SIzd :XǝE?0]y%+qM:^rA>1']D@D@D@D@D`S"E0vQf>mJ)g_]d H,TXt;G?$ɾ̢͵eOce>%O"9]{#" " " " ˵0'~1~اp~9cO,U@Yv(,˓||hΟ̧KFIEcduc9 e8V-" " " " ϵk,/yz%zhc~orI8n*ErxLxБs>h>V}e8Y@_'PMqM̨d99ϥ/&/OG 㖬g.=k-NCc:}y2>>C_`%OjU" " " " "; TS>o \I 僟]XZ }ގϋdþa<.g<&9w,&77Y}Bcz1HXXPY>}z^kqR,/y:%vz5>~΢zQ" " " " "TZCW"+ xُ}1=7WBY9u,6eQ!c9Y>JV3qWIL'lN ԋr9|8',Q#l(+E<=FJVr= rP,]Ng >I+Xc1>Jz!1KVW;Pcv="ce<ǨSbSC6)}f}+}@%Piᓕ{6e#}~lh~ޘ&E2 ,Xl1O}Eu1J>>.]D@D@D@D@Dr劣XƱ~"6)eѼ_';VuJ(:^V^ϳb_/XeO/b" " " " " T[dC1p0C ]?uxQ3+/}ޮEa,fgg')" " " " "劥X>tb\2)7d̬ܘ?>uX̮ćX '" " " " "P@%R,/ױboga^ _CnT1SɸY1Ů/ϒYe/" " " " @QV0^DZՎcMLV⥒rcWo1 /˟ׇ}ʼ9<U卓C_mpL b>8anaхJ%bE|!xAJF[+" " " " &PITZʍC_hc]/c9Y>bc"]?+;¤b1_,*oV?)sz[c'аBOҦ++^+c܍s4ջtrY񘿨by~6ϩVoծID@D@D@D@DQV$ .2vVN%XnY~-geWHvWqRvr3?s4." " " " "P_VEraQ_ޘXO;[OZb|tE\nq)7F^5}bdTE+ Uxƫdn劀@#P"xE;fEƎW2Ѿ a?" " " " " O«hz#ַ&_o(~j]C%+Jk:sO UD@D@D@D@z@OJ[I~%Pkؘ}Pu-[k?t!PkVMjxcUeZV{zbjת~" " " " "zeZu=X5Zk]m:4@ 6Nݠիۂ@X[#96@c^/=Zcƭ(YD@D@D@D@DOhTרq/Qݱ.Nt(cՂ's|5@!=QĜ`d%//1߇" " " " "􅢬/1zSqӟ%zlע?vE@D@D@D@D@z7~Q4z(鏭t% @.dTF1*bTJ>fw@,wPU$#Ty\L+g" " " " "(*EV㊀@#[#P]IENDB`icinga2-2.8.1/doc/scroll.js000066400000000000000000000005511322762156600154520ustar00rootroot00000000000000$(document).ready(function() { $('a[href^="#"]').on('click',function (e) { e.preventDefault(); var target = this.hash; var $target = $(target); $('html, body').stop().animate({ 'scrollTop': $target.offset().top }, 900, 'swing', function () { window.location.hash = target; }); }); }); icinga2-2.8.1/doc/update-links.py000077500000000000000000000035021322762156600165720ustar00rootroot00000000000000#!/usr/bin/env python # Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. import os import sys import re if len(sys.argv) < 2: print "Syntax: %s " % sys.argv[0] print "" print "Updates inter-chapter links in the specified Markdown files." sys.exit(1) anchors = {} for file in sys.argv[1:]: text = open(file).read() for match in re.finditer(r".*?)\">", text): id = match.group("id") if id in anchors: print "Error: Anchor '%s' is used multiple times: in %s and %s" % (id, file, anchors[id]) anchors[match.group("id")] = file def update_anchor(match): id = match.group("id") try: file = os.path.basename(anchors[id]) except KeyError: print "Error: Unmatched anchor: %s" % (id) file = "" return "[%s](%s#%s)" % (match.group("text"), file, id) for file in sys.argv[1:]: text = open(file).read() print "> Processing file '%s'..." % (file) new_text = re.sub(r"\[(?P.*?)\]\((?P[0-9-a-z\.]+)?#(?P[^#\)]+)\)", update_anchor, text) open(file, "w").write(new_text) icinga2-2.8.1/etc/000077500000000000000000000000001322762156600136235ustar00rootroot00000000000000icinga2-2.8.1/etc/CMakeLists.txt000066400000000000000000000111231322762156600163610ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. configure_file(icinga2/init.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf @ONLY) if(NOT WIN32) configure_file(icinga2/constants.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf @ONLY) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") configure_file(logrotate.d/icinga2.cmake ${CMAKE_CURRENT_BINARY_DIR}/logrotate.d/icinga2 @ONLY) endif() install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) if(NOT WIN32) install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) install_if_not_exists(icinga2/icinga2.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) else() install_if_not_exists(${CMAKE_CURRENT_SOURCE_DIR}/icinga2/win32/constants.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) install_if_not_exists(icinga2/win32/icinga2.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) endif() install_if_not_exists(icinga2/zones.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) install_if_not_exists(icinga2/conf.d/app.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/commands.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/downtimes.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/groups.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) if(NOT WIN32) install_if_not_exists(icinga2/conf.d/hosts.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/services.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) else() install_if_not_exists(icinga2/conf.d/win32/hosts.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/win32/services.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) endif() install_if_not_exists(icinga2/conf.d/notifications.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/templates.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/timeperiods.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/conf.d/users.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/conf.d) install_if_not_exists(icinga2/features-available/api.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available) install_if_not_exists(icinga2/features-available/debuglog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available) install_if_not_exists(icinga2/features-available/mainlog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available) if(NOT WIN32) install_if_not_exists(icinga2/features-available/syslog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available) endif() install_if_not_exists(icinga2/scripts/mail-host-notification.sh ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/scripts) install_if_not_exists(icinga2/scripts/mail-service-notification.sh ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/scripts) install_if_not_exists(icinga2/zones.d/README ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/zones.d) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/logrotate.d/icinga2 ${CMAKE_INSTALL_SYSCONFDIR}/logrotate.d) endif() if(NOT WIN32) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")") install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/mainlog.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/mainlog.conf\")") install( FILES bash_completion.d/icinga2 DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/bash_completion.d ) else() install_if_not_exists(icinga2/features-enabled/mainlog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "(Linux|Solaris|SunOS)") add_subdirectory(initsystem) endif() set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/etc/bash_completion.d/000077500000000000000000000000001322762156600172135ustar00rootroot00000000000000icinga2-2.8.1/etc/bash_completion.d/icinga2000066400000000000000000000004411322762156600204510ustar00rootroot00000000000000_icinga2() { local cur opts opts="${COMP_WORDS[*]}" cur="${COMP_WORDS[COMP_CWORD]}" COMPREPLY=($(icinga2 --autocomplete $COMP_CWORD ${COMP_WORDS[*]} < /dev/null)) case $COMPREPLY in */|*=) compopt -o nospace ;; esac return 0 } complete -F _icinga2 icinga2 icinga2-2.8.1/etc/icinga2/000077500000000000000000000000001322762156600151375ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/conf.d/000077500000000000000000000000001322762156600163065ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/conf.d/app.conf000066400000000000000000000000431322762156600177320ustar00rootroot00000000000000object IcingaApplication "app" { } icinga2-2.8.1/etc/icinga2/conf.d/commands.conf000066400000000000000000000123251322762156600207610ustar00rootroot00000000000000/* Command objects */ /* Notification Commands * * Please check the documentation for all required and * optional parameters. */ object NotificationCommand "mail-host-notification" { command = [ SysconfDir + "/icinga2/scripts/mail-host-notification.sh" ] arguments += { "-4" = "$notification_address$" "-6" = "$notification_address6$" "-b" = "$notification_author$" "-c" = "$notification_comment$" "-d" = { required = true value = "$notification_date$" } "-f" = { value = "$notification_from$" description = "Set from address. Requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)" } "-i" = "$notification_icingaweb2url$" "-l" = { required = true value = "$notification_hostname$" } "-n" = { required = true value = "$notification_hostdisplayname$" } "-o" = { required = true value = "$notification_hostoutput$" } "-r" = { required = true value = "$notification_useremail$" } "-s" = { required = true value = "$notification_hoststate$" } "-t" = { required = true value = "$notification_type$" } "-v" = "$notification_logtosyslog$" } vars += { notification_address = "$address$" notification_address6 = "$address6$" notification_author = "$notification.author$" notification_comment = "$notification.comment$" notification_type = "$notification.type$" notification_date = "$icinga.long_date_time$" notification_hostname = "$host.name$" notification_hostdisplayname = "$host.display_name$" notification_hostoutput = "$host.output$" notification_hoststate = "$host.state$" notification_useremail = "$user.email$" } } object NotificationCommand "mail-service-notification" { command = [ SysconfDir + "/icinga2/scripts/mail-service-notification.sh" ] arguments += { "-4" = "$notification_address$" "-6" = "$notification_address6$" "-b" = "$notification_author$" "-c" = "$notification_comment$" "-d" = { required = true value = "$notification_date$" } "-e" = { required = true value = "$notification_servicename$" } "-f" = { value = "$notification_from$" description = "Set from address. Requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)" } "-i" = "$notification_icingaweb2url$" "-l" = { required = true value = "$notification_hostname$" } "-n" = { required = true value = "$notification_hostdisplayname$" } "-o" = { required = true value = "$notification_serviceoutput$" } "-r" = { required = true value = "$notification_useremail$" } "-s" = { required = true value = "$notification_servicestate$" } "-t" = { required = true value = "$notification_type$" } "-u" = { required = true value = "$notification_servicedisplayname$" } "-v" = "$notification_logtosyslog$" } vars += { notification_address = "$address$" notification_address6 = "$address6$" notification_author = "$notification.author$" notification_comment = "$notification.comment$" notification_type = "$notification.type$" notification_date = "$icinga.long_date_time$" notification_hostname = "$host.name$" notification_hostdisplayname = "$host.display_name$" notification_servicename = "$service.name$" notification_serviceoutput = "$service.output$" notification_servicestate = "$service.state$" notification_useremail = "$user.email$" notification_servicedisplayname = "$service.display_name$" } } /* * If you prefer to use the notification scripts with environment * variables instead of command line parameters, you can use * the following commands. They have been updated from < 2.7 * to support the new notification scripts and should help * with an upgrade. * Remove the comment blocks and comment the notification commands above. */ /* object NotificationCommand "mail-host-notification" { command = [ SysconfDir + "/icinga2/scripts/mail-host-notification.sh" ] env = { NOTIFICATIONTYPE = "$notification.type$" HOSTDISPLAYNAME = "$host.display_name$" HOSTNAME = "$host.name$" HOSTADDRESS = "$address$" HOSTSTATE = "$host.state$" LONGDATETIME = "$icinga.long_date_time$" HOSTOUTPUT = "$host.output$" NOTIFICATIONAUTHORNAME = "$notification.author$" NOTIFICATIONCOMMENT = "$notification.comment$" HOSTDISPLAYNAME = "$host.display_name$" USEREMAIL = "$user.email$" } } object NotificationCommand "mail-service-notification" { command = [ SysconfDir + "/icinga2/scripts/mail-service-notification.sh" ] env = { NOTIFICATIONTYPE = "$notification.type$" SERVICENAME = "$service.name$" HOSTNAME = "$host.name$" HOSTDISPLAYNAME = "$host.display_name$" HOSTADDRESS = "$address$" SERVICESTATE = "$service.state$" LONGDATETIME = "$icinga.long_date_time$" SERVICEOUTPUT = "$service.output$" NOTIFICATIONAUTHORNAME = "$notification.author$" NOTIFICATIONCOMMENT = "$notification.comment$" HOSTDISPLAYNAME = "$host.display_name$" SERVICEDISPLAYNAME = "$service.display_name$" USEREMAIL = "$user.email$" } } */ icinga2-2.8.1/etc/icinga2/conf.d/downtimes.conf000066400000000000000000000010361322762156600211660ustar00rootroot00000000000000/** * The example downtime apply rule. */ apply ScheduledDowntime "backup-downtime" to Service { author = "icingaadmin" comment = "Scheduled downtime for backup" ranges = { monday = service.vars.backup_downtime tuesday = service.vars.backup_downtime wednesday = service.vars.backup_downtime thursday = service.vars.backup_downtime friday = service.vars.backup_downtime saturday = service.vars.backup_downtime sunday = service.vars.backup_downtime } assign where service.vars.backup_downtime != "" } icinga2-2.8.1/etc/icinga2/conf.d/groups.conf000066400000000000000000000011761322762156600205010ustar00rootroot00000000000000/** * Host group examples. */ object HostGroup "linux-servers" { display_name = "Linux Servers" assign where host.vars.os == "Linux" } object HostGroup "windows-servers" { display_name = "Windows Servers" assign where host.vars.os == "Windows" } /** * Service group examples. */ object ServiceGroup "ping" { display_name = "Ping Checks" assign where match("ping*", service.name) } object ServiceGroup "http" { display_name = "HTTP Checks" assign where match("http*", service.check_command) } object ServiceGroup "disk" { display_name = "Disk Checks" assign where match("disk*", service.check_command) } icinga2-2.8.1/etc/icinga2/conf.d/hosts.conf000066400000000000000000000027351322762156600203240ustar00rootroot00000000000000/* * Host definitions with object attributes * used for apply rules for Service, Notification, * Dependency and ScheduledDowntime objects. * * Tip: Use `icinga2 object list --type Host` to * list all host objects after running * configuration validation (`icinga2 daemon -C`). */ /* * This is an example host based on your * local host's FQDN. Specify the NodeName * constant in `constants.conf` or use your * own description, e.g. "db-host-1". */ object Host NodeName { /* Import the default host template defined in `templates.conf`. */ import "generic-host" /* Specify the address attributes for checks e.g. `ssh` or `http`. */ address = "127.0.0.1" address6 = "::1" /* Set custom attribute `os` for hostgroup assignment in `groups.conf`. */ vars.os = "Linux" /* Define http vhost attributes for service apply rules in `services.conf`. */ vars.http_vhosts["http"] = { http_uri = "/" } /* Uncomment if you've sucessfully installed Icinga Web 2. */ //vars.http_vhosts["Icinga Web 2"] = { // http_uri = "/icingaweb2" //} /* Define disks and attributes for service apply rules in `services.conf`. */ vars.disks["disk"] = { /* No parameters. */ } vars.disks["disk /"] = { disk_partitions = "/" } /* Define notification mail attributes for notification apply rules in `notifications.conf`. */ vars.notification["mail"] = { /* The UserGroup `icingaadmins` is defined in `users.conf`. */ groups = [ "icingaadmins" ] } } icinga2-2.8.1/etc/icinga2/conf.d/notifications.conf000066400000000000000000000014321322762156600220260ustar00rootroot00000000000000/** * The example notification apply rules. * * Only applied if host/service objects have * the custom attribute `notification` defined * and containing `mail` as key. * * Check `hosts.conf` for an example. */ apply Notification "mail-icingaadmin" to Host { import "mail-host-notification" user_groups = host.vars.notification.mail.groups users = host.vars.notification.mail.users //interval = 2h //vars.notification_logtosyslog = true assign where host.vars.notification.mail } apply Notification "mail-icingaadmin" to Service { import "mail-service-notification" user_groups = host.vars.notification.mail.groups users = host.vars.notification.mail.users //interval = 2h //vars.notification_logtosyslog = true assign where host.vars.notification.mail } icinga2-2.8.1/etc/icinga2/conf.d/services.conf000066400000000000000000000041241322762156600210010ustar00rootroot00000000000000/* * Service apply rules. * * The CheckCommand objects `ping4`, `ping6`, etc * are provided by the plugin check command templates. * Check the documentation for details. * * Tip: Use `icinga2 object list --type Service` to * list all service objects after running * configuration validation (`icinga2 daemon -C`). */ /* * This is an example host based on your * local host's FQDN. Specify the NodeName * constant in `constants.conf` or use your * own description, e.g. "db-host-1". */ /* * These are generic `ping4` and `ping6` * checks applied to all hosts having the * `address` resp. `address6` attribute * defined. */ apply Service "ping4" { import "generic-service" check_command = "ping4" assign where host.address } apply Service "ping6" { import "generic-service" check_command = "ping6" assign where host.address6 } /* * Apply the `ssh` service to all hosts * with the `address` attribute defined and * the custom attribute `os` set to `Linux`. */ apply Service "ssh" { import "generic-service" check_command = "ssh" assign where (host.address || host.address6) && host.vars.os == "Linux" } apply Service for (http_vhost => config in host.vars.http_vhosts) { import "generic-service" check_command = "http" vars += config } apply Service for (disk => config in host.vars.disks) { import "generic-service" check_command = "disk" vars += config } apply Service "icinga" { import "generic-service" check_command = "icinga" assign where host.name == NodeName } apply Service "load" { import "generic-service" check_command = "load" /* Used by the ScheduledDowntime apply rule in `downtimes.conf`. */ vars.backup_downtime = "02:00-03:00" assign where host.name == NodeName } apply Service "procs" { import "generic-service" check_command = "procs" assign where host.name == NodeName } apply Service "swap" { import "generic-service" check_command = "swap" assign where host.name == NodeName } apply Service "users" { import "generic-service" check_command = "users" assign where host.name == NodeName } icinga2-2.8.1/etc/icinga2/conf.d/templates.conf000066400000000000000000000040141322762156600211520ustar00rootroot00000000000000/* * Generic template examples. */ /** * Provides default settings for hosts. By convention * all hosts should import this template. * * The CheckCommand object `hostalive` is provided by * the plugin check command templates. * Check the documentation for details. */ template Host "generic-host" { max_check_attempts = 3 check_interval = 1m retry_interval = 30s check_command = "hostalive" } /** * Provides default settings for services. By convention * all services should import this template. */ template Service "generic-service" { max_check_attempts = 5 check_interval = 1m retry_interval = 30s } /** * Provides default settings for users. By convention * all users should inherit from this template. */ template User "generic-user" { } /** * Provides default settings for host notifications. * By convention all host notifications should import * this template. */ template Notification "mail-host-notification" { command = "mail-host-notification" states = [ Up, Down ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] vars += { // notification_icingaweb2url = "https://www.example.com/icingaweb2" // notification_from = "Icinga 2 Host Monitoring " notification_logtosyslog = false } period = "24x7" } /** * Provides default settings for service notifications. * By convention all service notifications should import * this template. */ template Notification "mail-service-notification" { command = "mail-service-notification" states = [ OK, Warning, Critical, Unknown ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] vars += { // notification_icingaweb2url = "https://www.example.com/icingaweb2" // notification_from = "Icinga 2 Service Monitoring " notification_logtosyslog = false } period = "24x7" } icinga2-2.8.1/etc/icinga2/conf.d/timeperiods.conf000066400000000000000000000013341322762156600215020ustar00rootroot00000000000000/** * Sample timeperiods for Icinga 2. * Check the documentation for details. */ object TimePeriod "24x7" { display_name = "Icinga 2 24x7 TimePeriod" ranges = { "monday" = "00:00-24:00" "tuesday" = "00:00-24:00" "wednesday" = "00:00-24:00" "thursday" = "00:00-24:00" "friday" = "00:00-24:00" "saturday" = "00:00-24:00" "sunday" = "00:00-24:00" } } object TimePeriod "9to5" { display_name = "Icinga 2 9to5 TimePeriod" ranges = { "monday" = "09:00-17:00" "tuesday" = "09:00-17:00" "wednesday" = "09:00-17:00" "thursday" = "09:00-17:00" "friday" = "09:00-17:00" } } object TimePeriod "never" { display_name = "Icinga 2 never TimePeriod" ranges = { } } icinga2-2.8.1/etc/icinga2/conf.d/users.conf000066400000000000000000000004661322762156600203240ustar00rootroot00000000000000/** * The example user 'icingaadmin' and the example * group 'icingaadmins'. */ object User "icingaadmin" { import "generic-user" display_name = "Icinga 2 Admin" groups = [ "icingaadmins" ] email = "icinga@localhost" } object UserGroup "icingaadmins" { display_name = "Icinga 2 Admin Group" } icinga2-2.8.1/etc/icinga2/conf.d/win32/000077500000000000000000000000001322762156600172505ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/conf.d/win32/hosts.conf000066400000000000000000000023111322762156600212540ustar00rootroot00000000000000/* * Host definitions with object attributes * used for apply rules for Service, Notification, * Dependency and ScheduledDowntime objects. * * Tip: Use `icinga2 object list --type Host` to * list all host objects after running * configuration validation (`icinga2 daemon -C`). */ /* * This is an example host based on your * local host's FQDN. Specify the NodeName * constant in `constants.conf` or use your * own description, e.g. "db-host-1". */ object Host NodeName { /* Import the default host template defined in `templates.conf`. */ import "generic-host" /* Specify the address attributes for checks e.g. `ssh` or `http`. */ address = "127.0.0.1" address6 = "::1" /* Set custom attribute `os` for hostgroup assignment in `groups.conf`. */ vars.os = "Windows" /* Define disks and attributes for service apply rules in `services.conf`. */ vars.disks["disk"] = { /* No parameters. */ } vars.disks["disk C:"] = { disk_win_path = "C:" } /* Define notification mail attributes for notification apply rules in `notifications.conf`. */ vars.notification["mail"] = { /* The UserGroup `icingaadmins` is defined in `users.conf`. */ groups = [ "icingaadmins" ] } } icinga2-2.8.1/etc/icinga2/conf.d/win32/services.conf000066400000000000000000000033321322762156600217430ustar00rootroot00000000000000/* * Service apply rules. * * The CheckCommand objects `ping4`, `ping6`, etc * are provided by the plugin check command templates. * Check the documentation for details. * * Tip: Use `icinga2 object list --type Service` to * list all service objects after running * configuration validation (`icinga2 daemon -C`). */ /* * This is an example host based on your * local host's FQDN. Specify the NodeName * constant in `constants.conf` or use your * own description, e.g. "db-host-1". */ /* * These are generic `ping4` and `ping6` * checks applied to all hosts having the * `address` resp. `address6` attribute * defined. */ apply Service "ping4" { import "generic-service" check_command = "ping4-windows" assign where host.address } apply Service "ping6" { import "generic-service" check_command = "ping6-windows" assign where host.address6 } apply Service for (disk => config in host.vars.disks) { import "generic-service" check_command = "disk-windows" vars += config } apply Service "icinga" { import "generic-service" check_command = "icinga" assign where host.name == NodeName } apply Service "load" { import "generic-service" check_command = "load-windows" /* Used by the ScheduledDowntime apply rule in `downtimes.conf`. */ vars.backup_downtime = "02:00-03:00" assign where host.name == NodeName } apply Service "procs" { import "generic-service" check_command = "procs-windows" assign where host.name == NodeName } apply Service "swap" { import "generic-service" check_command = "swap-windows" assign where host.name == NodeName } apply Service "users" { import "generic-service" check_command = "users-windows" assign where host.name == NodeName } icinga2-2.8.1/etc/icinga2/constants.conf.cmake000066400000000000000000000017321322762156600211040ustar00rootroot00000000000000/** * This file defines global constants which can be used in * the other configuration files. */ /* The directory which contains the plugins from the Monitoring Plugins project. */ const PluginDir = "@ICINGA2_PLUGINDIR@" /* The directory which contains the Manubulon plugins. * Check the documentation, chapter "SNMP Manubulon Plugin Check Commands", for details. */ const ManubulonPluginDir = "@ICINGA2_PLUGINDIR@" /* The directory which you use to store additional plugins which ITL provides user contributed command definitions for. * Check the documentation, chapter "Plugins Contribution", for details. */ const PluginContribDir = "@ICINGA2_PLUGINDIR@" /* Our local instance name. By default this is the server's hostname as returned by `hostname --fqdn`. * This should be the common name from the API certificate. */ //const NodeName = "localhost" /* Our local zone name. */ const ZoneName = NodeName /* Secret key for remote node tickets */ const TicketSalt = "" icinga2-2.8.1/etc/icinga2/features-available/000077500000000000000000000000001322762156600206735ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/features-available/api.conf000066400000000000000000000002671322762156600223200ustar00rootroot00000000000000/** * The API listener is used for distributed monitoring setups. */ object ApiListener "api" { //accept_config = false //accept_commands = false ticket_salt = TicketSalt } icinga2-2.8.1/etc/icinga2/features-available/checker.conf000066400000000000000000000002031322762156600231410ustar00rootroot00000000000000/** * The checker component takes care of executing service checks. */ library "checker" object CheckerComponent "checker" { } icinga2-2.8.1/etc/icinga2/features-available/command.conf000066400000000000000000000002361322762156600231610ustar00rootroot00000000000000/** * The ExternalCommandListener implements support for the external * commands pipe. */ library "compat" object ExternalCommandListener "command" { } icinga2-2.8.1/etc/icinga2/features-available/compatlog.conf000066400000000000000000000002611322762156600235260ustar00rootroot00000000000000/** * The CompatLogger type is responsible for writing log files in a format * that is compatible with Icinga 1.x. */ library "compat" object CompatLogger "compatlog" { } icinga2-2.8.1/etc/icinga2/features-available/debuglog.conf000066400000000000000000000003771322762156600233410ustar00rootroot00000000000000/** * The FileLogger type writes log information to a log file. * Unlike the mainlog feature this sets up a logger * with severity "debug". */ object FileLogger "debug-file" { severity = "debug" path = LocalStateDir + "/log/icinga2/debug.log" } icinga2-2.8.1/etc/icinga2/features-available/elasticsearch.conf000066400000000000000000000003251322762156600243540ustar00rootroot00000000000000library "perfdata" object ElasticsearchWriter "elasticsearch" { //host = "127.0.0.1" //port = 9200 //index = "icinga2" //enable_send_perfdata = false //flush_threshold = 1024 //flush_interval = 10s } icinga2-2.8.1/etc/icinga2/features-available/gelf.conf000066400000000000000000000003421322762156600224560ustar00rootroot00000000000000/** * The GelfWriter type writes event log entries * to a GELF tcp socket provided by Graylog, * Logstash or any other receiver. */ library "perfdata" object GelfWriter "gelf" { //host = "127.0.0.1" //port = 12201 } icinga2-2.8.1/etc/icinga2/features-available/graphite.conf000066400000000000000000000003221322762156600233420ustar00rootroot00000000000000/** * The GraphiteWriter type writes check result metrics and * performance data to a graphite tcp socket. */ library "perfdata" object GraphiteWriter "graphite" { //host = "127.0.0.1" //port = 2003 } icinga2-2.8.1/etc/icinga2/features-available/ido-mysql.conf000066400000000000000000000003551322762156600234630ustar00rootroot00000000000000/** * The db_ido_mysql library implements IDO functionality * for MySQL. */ library "db_ido_mysql" object IdoMysqlConnection "ido-mysql" { //user = "icinga" //password = "icinga" //host = "localhost" //database = "icinga" } icinga2-2.8.1/etc/icinga2/features-available/ido-pgsql.conf000066400000000000000000000003621322762156600234420ustar00rootroot00000000000000/** * The db_ido_pgsql library implements IDO functionality * for PostgreSQL. */ library "db_ido_pgsql" object IdoPgsqlConnection "ido-pgsql" { //user = "icinga" //password = "icinga" //host = "localhost" //database = "icinga" } icinga2-2.8.1/etc/icinga2/features-available/influxdb.conf000066400000000000000000000011041322762156600233510ustar00rootroot00000000000000/** * The InfluxdbWriter type writes check result metrics and * performance data to an InfluxDB HTTP API */ library "perfdata" object InfluxdbWriter "influxdb" { //host = "127.0.0.1" //port = 8086 //database = "icinga2" //flush_threshold = 1024 //flush_interval = 10s //host_template = { // measurement = "$host.check_command$" // tags = { // hostname = "$host.name$" // } //} //service_template = { // measurement = "$service.check_command$" // tags = { // hostname = "$host.name$" // service = "$service.name$" // } //} } icinga2-2.8.1/etc/icinga2/features-available/livestatus.conf000066400000000000000000000002201322762156600237370ustar00rootroot00000000000000/** * The livestatus library implements the livestatus query protocol. */ library "livestatus" object LivestatusListener "livestatus" { } icinga2-2.8.1/etc/icinga2/features-available/mainlog.conf000066400000000000000000000002631322762156600231710ustar00rootroot00000000000000/** * The FileLogger type writes log information to a file. */ object FileLogger "main-log" { severity = "information" path = LocalStateDir + "/log/icinga2/icinga2.log" } icinga2-2.8.1/etc/icinga2/features-available/notification.conf000066400000000000000000000002271322762156600242310ustar00rootroot00000000000000/** * The notification component takes care of executing service checks. */ library "notification" object NotificationComponent "notification" { } icinga2-2.8.1/etc/icinga2/features-available/opentsdb.conf000066400000000000000000000003221322762156600233550ustar00rootroot00000000000000/** * The OpenTsdbWriter type writes check result metrics and * performance data to a OpenTSDB tcp socket. */ library "perfdata" object OpenTsdbWriter "opentsdb" { //host = "127.0.0.1" //port = 4242 } icinga2-2.8.1/etc/icinga2/features-available/perfdata.conf000066400000000000000000000002461322762156600233320ustar00rootroot00000000000000/** * The PerfdataWriter type writes performance data files and rotates * them in a regular interval. */ library "perfdata" object PerfdataWriter "perfdata" { } icinga2-2.8.1/etc/icinga2/features-available/statusdata.conf000066400000000000000000000003631322762156600237210ustar00rootroot00000000000000/** * The StatusDataWriter type periodically updates the status.dat and objects.cache * files. These are used by the Icinga 1.x CGIs to display the state of * hosts and services. */ library "compat" object StatusDataWriter "status" { } icinga2-2.8.1/etc/icinga2/features-available/syslog.conf000066400000000000000000000001771322762156600230670ustar00rootroot00000000000000/** * The SyslogLogger type writes log information to syslog. */ object SyslogLogger "syslog" { severity = "warning" } icinga2-2.8.1/etc/icinga2/features-enabled/000077500000000000000000000000001322762156600203455ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/features-enabled/checker.conf000066400000000000000000000000551322762156600226200ustar00rootroot00000000000000include "../features-available/checker.conf" icinga2-2.8.1/etc/icinga2/features-enabled/mainlog.conf000066400000000000000000000000551322762156600226420ustar00rootroot00000000000000include "../features-available/mainlog.conf" icinga2-2.8.1/etc/icinga2/features-enabled/notification.conf000066400000000000000000000000621322762156600237000ustar00rootroot00000000000000include "../features-available/notification.conf" icinga2-2.8.1/etc/icinga2/icinga2.conf000066400000000000000000000032711322762156600173250ustar00rootroot00000000000000/** * Icinga 2 configuration file * - this is where you define settings for the Icinga application including * which hosts/services to check. * * For an overview of all available configuration options please refer * to the documentation that is distributed as part of Icinga 2. */ /** * The constants.conf defines global constants. */ include "constants.conf" /** * The zones.conf defines zones for a cluster setup. * Not required for single instance setups. */ include "zones.conf" /** * The Icinga Template Library (ITL) provides a number of useful templates * and command definitions. * Common monitoring plugin command definitions are included separately. */ include include include include /** * This includes the Icinga 2 Windows plugins. These command definitions * are required on a master node when a client is used as command endpoint. */ include /** * This includes the NSClient++ check commands. These command definitions * are required on a master node when a client is used as command endpoint. */ include /** * The features-available directory contains a number of configuration * files for features which can be enabled and disabled using the * icinga2 feature enable / icinga2 feature disable CLI commands. * These commands work by creating and removing symbolic links in * the features-enabled directory. */ include "features-enabled/*.conf" /** * Although in theory you could define all your objects in this file * the preferred way is to create separate directories and files in the conf.d * directory. Each of these files must have the file extension ".conf". */ include_recursive "conf.d" icinga2-2.8.1/etc/icinga2/init.conf.cmake000066400000000000000000000002651322762156600200330ustar00rootroot00000000000000/** * This file is read by Icinga 2 before the main * configuration file (icinga2.conf) is processed. */ const RunAsUser = "@ICINGA2_USER@" const RunAsGroup = "@ICINGA2_GROUP@" icinga2-2.8.1/etc/icinga2/scripts/000077500000000000000000000000001322762156600166265ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/scripts/mail-host-notification.sh000077500000000000000000000100511322762156600235430ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) PROG="`basename $0`" ICINGA2HOST="`hostname`" MAILBIN="mail" if [ -z "`which $MAILBIN`" ] ; then echo "$MAILBIN not found in \$PATH. Consider installing it." exit 1 fi ## Function helpers Usage() { cat << EOF Required parameters: -d LONGDATETIME (\$icinga.long_date_time\$) -l HOSTNAME (\$host.name\$) -n HOSTDISPLAYNAME (\$host.display_name\$) -o HOSTOUTPUT (\$host.output\$) -r USEREMAIL (\$user.email\$) -s HOSTSTATE (\$host.state\$) -t NOTIFICATIONTYPE (\$notification.type\$) Optional parameters: -4 HOSTADDRESS (\$address\$) -6 HOSTADDRESS6 (\$address6\$) -b NOTIFICATIONAUTHORNAME (\$notification.author\$) -c NOTIFICATIONCOMMENT (\$notification.comment\$) -i ICINGAWEB2URL (\$notification_icingaweb2url\$, Default: unset) -f MAILFROM (\$notification_mailfrom\$, requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)) -v (\$notification_sendtosyslog\$, Default: false) EOF } Help() { Usage; exit 0; } Error() { if [ "$1" ]; then echo $1 fi Usage; exit 1; } ## Main while getopts 4:6::b:c:d:f:hi:l:n:o:r:s:t:v: opt do case "$opt" in 4) HOSTADDRESS=$OPTARG ;; 6) HOSTADDRESS6=$OPTARG ;; b) NOTIFICATIONAUTHORNAME=$OPTARG ;; c) NOTIFICATIONCOMMENT=$OPTARG ;; d) LONGDATETIME=$OPTARG ;; # required f) MAILFROM=$OPTARG ;; h) Help ;; i) ICINGAWEB2URL=$OPTARG ;; l) HOSTNAME=$OPTARG ;; # required n) HOSTDISPLAYNAME=$OPTARG ;; # required o) HOSTOUTPUT=$OPTARG ;; # required r) USEREMAIL=$OPTARG ;; # required s) HOSTSTATE=$OPTARG ;; # required t) NOTIFICATIONTYPE=$OPTARG ;; # required v) VERBOSE=$OPTARG ;; \?) echo "ERROR: Invalid option -$OPTARG" >&2 Error ;; :) echo "Missing option argument for -$OPTARG" >&2 Error ;; *) echo "Unimplemented option: -$OPTARG" >&2 Error ;; esac done shift $((OPTIND - 1)) ## Check required parameters (TODO: better error message) ## Keep formatting in sync with mail-service-notification.sh if [ ! "$LONGDATETIME" ] \ || [ ! "$HOSTNAME" ] || [ ! "$HOSTDISPLAYNAME" ] \ || [ ! "$HOSTOUTPUT" ] || [ ! "$HOSTSTATE" ] \ || [ ! "$USEREMAIL" ] || [ ! "$NOTIFICATIONTYPE" ]; then Error "Requirement parameters are missing." fi ## Build the message's subject SUBJECT="[$NOTIFICATIONTYPE] Host $HOSTDISPLAYNAME is $HOSTSTATE!" ## Build the notification message NOTIFICATION_MESSAGE=`cat << EOF ***** Host Monitoring on $ICINGA2HOST ***** $HOSTDISPLAYNAME is $HOSTSTATE! Info: $HOSTOUTPUT When: $LONGDATETIME Host: $HOSTNAME EOF ` ## Check whether IPv4 was specified. if [ -n "$HOSTADDRESS" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE IPv4: $HOSTADDRESS" fi ## Check whether IPv6 was specified. if [ -n "$HOSTADDRESS6" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE IPv6: $HOSTADDRESS6" fi ## Check whether author and comment was specified. if [ -n "$NOTIFICATIONCOMMENT" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE Comment by $NOTIFICATIONAUTHORNAME: $NOTIFICATIONCOMMENT" fi ## Check whether Icinga Web 2 URL was specified. if [ -n "$ICINGAWEB2URL" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE $ICINGAWEB2URL/monitoring/host/show?host=$HOSTNAME" fi ## Check whether verbose mode was enabled and log to syslog. if [ "$VERBOSE" == "true" ] ; then logger "$PROG sends $SUBJECT => $USEREMAIL" fi ## Send the mail using the $MAILBIN command. ## If an explicit sender was specified, try to set it. if [ -n "$MAILFROM" ] ; then ## Modify this for your own needs! ## Debian/Ubuntu use mailutils which requires `-a` to append the header if [ -f /etc/debian_version ]; then /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" | $MAILBIN -a "From: $MAILFROM" -s "$SUBJECT" $USEREMAIL ## Other distributions (RHEL/SUSE/etc.) prefer mailx which sets a sender address with `-r` else /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" | $MAILBIN -r "$MAILFROM" -s "$SUBJECT" $USEREMAIL fi else /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" \ | $MAILBIN -s "$SUBJECT" $USEREMAIL fi icinga2-2.8.1/etc/icinga2/scripts/mail-service-notification.sh000077500000000000000000000106221322762156600242320ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) PROG="`basename $0`" ICINGA2HOST="`hostname`" MAILBIN="mail" if [ -z "`which $MAILBIN`" ] ; then echo "$MAILBIN not found in \$PATH. Consider installing it." exit 1 fi ## Function helpers Usage() { cat << EOF Required parameters: -d LONGDATETIME (\$icinga.long_date_time\$) -e SERVICENAME (\$service.name\$) -l HOSTNAME (\$host.name\$) -n HOSTDISPLAYNAME (\$host.display_name\$) -o SERVICEOUTPUT (\$service.output\$) -r USEREMAIL (\$user.email\$) -s SERVICESTATE (\$service.state\$) -t NOTIFICATIONTYPE (\$notification.type\$) -u SERVICEDISPLAYNAME (\$service.display_name\$) Optional parameters: -4 HOSTADDRESS (\$address\$) -6 HOSTADDRESS6 (\$address6\$) -b NOTIFICATIONAUTHORNAME (\$notification.author\$) -c NOTIFICATIONCOMMENT (\$notification.comment\$) -i ICINGAWEB2URL (\$notification_icingaweb2url\$, Default: unset) -f MAILFROM (\$notification_mailfrom\$, requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)) -v (\$notification_sendtosyslog\$, Default: false) EOF } Help() { Usage; exit 0; } Error() { if [ "$1" ]; then echo $1 fi Usage; exit 1; } ## Main while getopts 4:6:b:c:d:e:f:hi:l:n:o:r:s:t:u:v: opt do case "$opt" in 4) HOSTADDRESS=$OPTARG ;; 6) HOSTADDRESS6=$OPTARG ;; b) NOTIFICATIONAUTHORNAME=$OPTARG ;; c) NOTIFICATIONCOMMENT=$OPTARG ;; d) LONGDATETIME=$OPTARG ;; # required e) SERVICENAME=$OPTARG ;; # required f) MAILFROM=$OPTARG ;; h) Usage ;; i) ICINGAWEB2URL=$OPTARG ;; l) HOSTNAME=$OPTARG ;; # required n) HOSTDISPLAYNAME=$OPTARG ;; # required o) SERVICEOUTPUT=$OPTARG ;; # required r) USEREMAIL=$OPTARG ;; # required s) SERVICESTATE=$OPTARG ;; # required t) NOTIFICATIONTYPE=$OPTARG ;; # required u) SERVICEDISPLAYNAME=$OPTARG ;; # required v) VERBOSE=$OPTARG ;; \?) echo "ERROR: Invalid option -$OPTARG" >&2 Usage ;; :) echo "Missing option argument for -$OPTARG" >&2 Usage ;; *) echo "Unimplemented option: -$OPTARG" >&2 Usage ;; esac done shift $((OPTIND - 1)) ## Check required parameters (TODO: better error message) ## Keep formatting in sync with mail-host-notification.sh if [ ! "$LONGDATETIME" ] \ || [ ! "$HOSTNAME" ] || [ ! "$HOSTDISPLAYNAME" ] \ || [ ! "$SERVICENAME" ] || [ ! "$SERVICEDISPLAYNAME" ] \ || [ ! "$SERVICEOUTPUT" ] || [ ! "$SERVICESTATE" ] \ || [ ! "$USEREMAIL" ] || [ ! "$NOTIFICATIONTYPE" ]; then Error "Requirement parameters are missing." fi ## Build the message's subject SUBJECT="[$NOTIFICATIONTYPE] $SERVICEDISPLAYNAME on $HOSTDISPLAYNAME is $SERVICESTATE!" ## Build the notification message NOTIFICATION_MESSAGE=`cat << EOF ***** Service Monitoring on $ICINGA2HOST ***** $SERVICEDISPLAYNAME on $HOSTDISPLAYNAME is $SERVICESTATE! Info: $SERVICEOUTPUT When: $LONGDATETIME Service: $SERVICENAME Host: $HOSTNAME EOF ` ## Check whether IPv4 was specified. if [ -n "$HOSTADDRESS" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE IPv4: $HOSTADDRESS" fi ## Check whether IPv6 was specified. if [ -n "$HOSTADDRESS6" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE IPv6: $HOSTADDRESS6" fi ## Check whether author and comment was specified. if [ -n "$NOTIFICATIONCOMMENT" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE Comment by $NOTIFICATIONAUTHORNAME: $NOTIFICATIONCOMMENT" fi ## Check whether Icinga Web 2 URL was specified. if [ -n "$ICINGAWEB2URL" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE $ICINGAWEB2URL/monitoring/service/show?host=$HOSTNAME&service=$SERVICENAME" fi ## Check whether verbose mode was enabled and log to syslog. if [ "$VERBOSE" == "true" ] ; then logger "$PROG sends $SUBJECT => $USEREMAIL" fi ## Send the mail using the $MAILBIN command. ## If an explicit sender was specified, try to set it. if [ -n "$MAILFROM" ] ; then ## Modify this for your own needs! ## Debian/Ubuntu use mailutils which requires `-a` to append the header if [ -f /etc/debian_version ]; then /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" | $MAILBIN -a "From: $MAILFROM" -s "$SUBJECT" $USEREMAIL ## Other distributions (RHEL/SUSE/etc.) prefer mailx which sets a sender address with `-r` else /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" | $MAILBIN -r "$MAILFROM" -s "$SUBJECT" $USEREMAIL fi else /usr/bin/printf "%b" "$NOTIFICATION_MESSAGE" \ | $MAILBIN -s "$SUBJECT" $USEREMAIL fi icinga2-2.8.1/etc/icinga2/win32/000077500000000000000000000000001322762156600161015ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/win32/constants.conf000066400000000000000000000017241322762156600207700ustar00rootroot00000000000000/** * This file defines global constants which can be used in * the other configuration files. */ /* The directory which contains the plugins from the Monitoring Plugins project. */ const PluginDir = PrefixDir + "/sbin" /* The directory which contains the Manubulon plugins. * Check the documentation, chapter "SNMP Manubulon Plugin Check Commands", for details. */ const ManubulonPluginDir = PrefixDir + "/sbin" /* The directory which you use to store additional plugins which ITL provides user contributed command definitions for. * Check the documentation, chapter "Plugins Contribution", for details. */ const PluginContribDir = PrefixDir + "/sbin" /* Our local instance name. By default this is the server's hostname as returned by `hostname --fqdn`. * This should be the common name from the API certificate. */ //const NodeName = "localhost" /* Our local zone name. */ const ZoneName = NodeName /* Secret key for remote node tickets */ const TicketSalt = "" icinga2-2.8.1/etc/icinga2/win32/icinga2.conf000066400000000000000000000027551322762156600202750ustar00rootroot00000000000000/** * Icinga 2 configuration file * - this is where you define settings for the Icinga application including * which hosts/services to check. * * For an overview of all available configuration options please refer * to the documentation that is distributed as part of Icinga 2. */ /** * The constants.conf defines global constants. */ include "constants.conf" /** * The zones.conf defines zones for a cluster setup. * Not required for single instance setups. */ include "zones.conf" /** * The Icinga Template Library (ITL) provides a number of useful templates * and command definitions. * Common monitoring plugin command definitions are included separately. */ include include include include /** * This includes the Icinga 2 Windows plugins. */ include /** * This includes the NSClient++ check commands. */ include /** * The features-available directory contains a number of configuration * files for features which can be enabled and disabled using the * icinga2 feature enable / icinga2 feature disable CLI commands. * These commands work by creating and removing symbolic links in * the features-enabled directory. */ include "features-enabled/*.conf" /** * Although in theory you could define all your objects in this file * the preferred way is to create separate directories and files in the conf.d * directory. Each of these files must have the file extension ".conf". */ include_recursive "conf.d" icinga2-2.8.1/etc/icinga2/zones.conf000066400000000000000000000024661322762156600171540ustar00rootroot00000000000000/* * Endpoint and Zone configuration for a cluster setup * This local example requires `NodeName` defined in * constants.conf. */ object Endpoint NodeName { host = NodeName } object Zone ZoneName { endpoints = [ NodeName ] } /* * Defines a global zone for distributed setups with masters, * satellites and clients. * This is required to sync configuration commands, * templates, apply rules, etc. to satellite and clients. * All nodes require the same configuration and must * have `accept_config` enabled in the `api` feature. */ object Zone "global-templates" { global = true } /* * Defines a global zone for the Icinga Director. * This is required to sync configuration commands, * templates, apply rules, etc. to satellite and clients. * All nodes require the same configuration and must * have `accept_config` enabled in the `api` feature. */ object Zone "director-global" { global = true } /* * Read the documentation on how to configure * a cluster setup with multiple zones. */ /* object Endpoint "master.example.org" { host = "master.example.org" } object Endpoint "satellite.example.org" { host = "satellite.example.org" } object Zone "master" { endpoints = [ "master.example.org" ] } object Zone "satellite" { parent = "master" endpoints = [ "satellite.example.org" ] } */ icinga2-2.8.1/etc/icinga2/zones.d/000077500000000000000000000000001322762156600165175ustar00rootroot00000000000000icinga2-2.8.1/etc/icinga2/zones.d/README000066400000000000000000000002051322762156600173740ustar00rootroot00000000000000This directory contains configuration files for cluster zones. If you're not running a cluster you can safely ignore this directory. icinga2-2.8.1/etc/initsystem/000077500000000000000000000000001322762156600160335ustar00rootroot00000000000000icinga2-2.8.1/etc/initsystem/CMakeLists.txt000066400000000000000000000055321322762156600206000ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. if(NOT WIN32) set(ICINGA2_SYSCONFIGFILE "${CMAKE_INSTALL_FULL_SYSCONFDIR}/sysconfig/icinga2" CACHE PATH "where to store configuation for the init system, defaults to /etc/sysconfig/icinga2") configure_file(icinga2.sysconfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2.sysconfig @ONLY) get_filename_component(ICINGA2_SYSCONFIGFILE_NAME ${ICINGA2_SYSCONFIGFILE} NAME) get_filename_component(ICINGA2_SYSCONFIGFILE_DIR ${ICINGA2_SYSCONFIGFILE} PATH) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2.sysconfig DESTINATION ${ICINGA2_SYSCONFIGFILE_DIR} RENAME ${ICINGA2_SYSCONFIGFILE_NAME} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) install( FILES prepare-dirs safe-reload DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/icinga2 PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) option (USE_SYSTEMD "Configure icinga as native systemd service instead of a SysV initscript" OFF) # required for packaging on Gentoo, see Bug #6498 option (INSTALL_SYSTEMD_SERVICE_AND_INITSCRIPT "Force install both the systemd service definition file and the SysV initscript in parallel, regardless of how USE_SYSTEMD is set. Only use this for special packaging purposes and if you know what you are doing" OFF) if (NOT USE_SYSTEMD OR INSTALL_SYSTEMD_SERVICE_AND_INITSCRIPT) configure_file(icinga2.init.d.cmake ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2 DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/init.d PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() if (USE_SYSTEMD OR INSTALL_SYSTEMD_SERVICE_AND_INITSCRIPT) configure_file(icinga2.service.cmake ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2.service @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/initsystem/icinga2.service DESTINATION ${DESTDIR}/usr/lib/systemd/system PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) endif() endif() icinga2-2.8.1/etc/initsystem/icinga2.init.d.cmake000066400000000000000000000106511322762156600215400ustar00rootroot00000000000000#!/bin/sh # # chkconfig: 35 90 12 # description: Icinga 2 # ### BEGIN INIT INFO # Provides: icinga2 # Required-Start: $remote_fs $syslog $network # Required-Stop: $remote_fs $syslog $network # Should-Start: mysql postgresql # Should-Stop: mysql postgresql # Default-Start: 2 3 5 # Default-Stop: 0 1 6 # Short-Description: icinga2 host/service/network monitoring and management system # Description: Icinga 2 is a monitoring and management system for hosts, services and networks. ### END INIT INFO # load system specific defines SYSCONFIGFILE=@ICINGA2_SYSCONFIGFILE@ if [ -f $SYSCONFIGFILE ]; then . $SYSCONFIGFILE else echo "Can't load system specific defines from $SYSCONFIGFILE." exit 6 fi test -x $DAEMON || exit 5 if [ ! -e $ICINGA2_CONFIG_FILE ]; then echo "Config file '$ICINGA2_CONFIG_FILE' does not exist." exit 6 fi ICINGA2_USER=`$DAEMON variable get --current RunAsUser` if [ $? != 0 ]; then echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." exit 6 fi ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` if [ $? != 0 ]; then echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) getent group $ICINGA2_GROUP >/dev/null 2>&1 || (echo "Icinga group '$ICINGA2_GROUP' does not exist. Exiting." && exit 6) getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command group '$ICINGA2_COMMAND_GROUP' does not exist. Exiting." && exit 6) # Get function from functions library if [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then . /etc/init.d/functions fi # Load extra environment variables if [ -f /etc/default/icinga2 ]; then . /etc/default/icinga2 fi # Start Icinga 2 start() { printf "Starting Icinga 2: " @CMAKE_INSTALL_PREFIX@/lib/icinga2/prepare-dirs $SYSCONFIGFILE if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG > $ICINGA2_STARTUP_LOG 2>&1; then echo "Error starting Icinga. Check '$ICINGA2_STARTUP_LOG' for details." exit 1 else echo "Done" fi } # Restart Icinga 2 stop() { printf "Stopping Icinga 2: " if [ ! -e $ICINGA2_PID_FILE ]; then echo "The PID file '$ICINGA2_PID_FILE' does not exist." if [ "x$1" = "xnofail" ]; then return else exit 7 fi fi pid=`cat $ICINGA2_PID_FILE` if kill -INT $pid >/dev/null 2>&1; then for i in 1 2 3 4 5 6 7 8 9 10; do if ! kill -CHLD $pid >/dev/null 2>&1; then break fi printf '.' sleep 3 done fi if kill -CHLD $pid >/dev/null 2>&1; then kill -KILL $pid fi echo "Done" } # Reload Icinga 2 reload() { exec @CMAKE_INSTALL_PREFIX@/lib/icinga2/safe-reload $SYSCONFIGFILE } # Check the Icinga 2 configuration checkconfig() { printf "Checking configuration: " if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C > $ICINGA2_STARTUP_LOG 2>&1; then if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG echo "Icinga 2 detected configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." exit 1 else echo "Not "$1"ing Icinga 2 due to configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." if [ "x$2" = "xfail" ]; then exit 1 fi fi fi echo "Done" # no arguments requires full output if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG fi } # Print status for Icinga 2 status() { printf "Icinga 2 status: " if [ ! -e $ICINGA2_PID_FILE ]; then echo "Not running" exit 7 fi pid=`cat $ICINGA2_PID_FILE` if kill -CHLD $pid >/dev/null 2>&1; then echo "Running" else echo "Not running" exit 7 fi } ### main logic ### case "$1" in start) checkconfig start fail start ;; stop) stop ;; status) status ;; restart) checkconfig restart fail stop nofail start ;; condrestart) status > /dev/null 2>&1 || exit 0 checkconfig restart fail stop nofail start ;; reload) reload ;; checkconfig) checkconfig ;; *) echo "Usage: $0 {start|stop|restart|reload|checkconfig|status}" exit 3 esac exit 0 icinga2-2.8.1/etc/initsystem/icinga2.service.cmake000066400000000000000000000020001322762156600220000ustar00rootroot00000000000000[Unit] Description=Icinga host/service/network monitoring system After=syslog.target network-online.target postgresql.service mariadb.service carbon-cache.service carbon-relay.service [Service] Type=forking EnvironmentFile=@ICINGA2_SYSCONFIGFILE@ ExecStartPre=@CMAKE_INSTALL_PREFIX@/lib/icinga2/prepare-dirs @ICINGA2_SYSCONFIGFILE@ ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/icinga2 daemon -d -e ${ICINGA2_ERROR_LOG} PIDFile=@ICINGA2_RUNDIR@/icinga2/icinga2.pid ExecReload=@CMAKE_INSTALL_PREFIX@/lib/icinga2/safe-reload @ICINGA2_SYSCONFIGFILE@ TimeoutStartSec=30m # Systemd >228 enforces a lower process number for services. # Depending on the distribution and Systemd version, this must # be explicitly raised. Packages will set the needed values # into /etc/systemd/system/icinga2.service.d/limits.conf # # Please check the troubleshooting documentation for further details. # The values below can be used as examples for customized service files. #TasksMax=infinity #LimitNPROC=62883 [Install] WantedBy=multi-user.target icinga2-2.8.1/etc/initsystem/icinga2.service.limits.conf000066400000000000000000000003541322762156600231570ustar00rootroot00000000000000# Icinga 2 sets Systemd default values to extend OS defaults. # # Please check the troubleshooting documentation for further details. [Service] TasksMax=infinity # Uncomment this setting in case of further problems. #LimitNPROC=62883 icinga2-2.8.1/etc/initsystem/icinga2.sysconfig.cmake000066400000000000000000000011751322762156600223600ustar00rootroot00000000000000DAEMON=@CMAKE_INSTALL_FULL_SBINDIR@/icinga2 ICINGA2_CONFIG_FILE=@CMAKE_INSTALL_FULL_SYSCONFDIR@/icinga2/icinga2.conf ICINGA2_RUN_DIR=@ICINGA2_RUNDIR@ ICINGA2_STATE_DIR=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@ ICINGA2_PID_FILE=$ICINGA2_RUN_DIR/icinga2/icinga2.pid ICINGA2_ERROR_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/error.log ICINGA2_STARTUP_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/startup.log ICINGA2_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/icinga2.log ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 ICINGA2_USER=@ICINGA2_USER@ ICINGA2_GROUP=@ICINGA2_GROUP@ ICINGA2_COMMAND_GROUP=@ICINGA2_COMMAND_GROUP@ icinga2-2.8.1/etc/initsystem/prepare-dirs000066400000000000000000000041101322762156600203470ustar00rootroot00000000000000#!/bin/sh # # This script prepares directories and files needed for running Icinga2 # # load system specific defines SYSCONFIGFILE=$1 if [ -f "$SYSCONFIGFILE" ]; then . $SYSCONFIGFILE else echo "Error: You need to supply the path to the Icinga2 sysconfig file as parameter." exit 1 fi ICINGA2_USER=`$DAEMON variable get --current RunAsUser` if [ $? != 0 ]; then echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." exit 6 fi ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` if [ $? != 0 ]; then echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) getent group $ICINGA2_GROUP >/dev/null 2>&1 || (echo "Icinga group '$ICINGA2_GROUP' does not exist. Exiting." && exit 6) getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command group '$ICINGA2_COMMAND_GROUP' does not exist. Exiting." && exit 6) mkdir -p $(dirname -- $ICINGA2_PID_FILE) chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_PID_FILE) if [ -f $ICINGA2_PID_FILE ]; then chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_PID_FILE fi mkdir -p $(dirname -- $ICINGA2_ERROR_LOG) chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_ERROR_LOG) chmod 750 $(dirname -- $ICINGA2_ERROR_LOG) if [ -f $ICINGA2_ERROR_LOG ]; then chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_ERROR_LOG fi if [ -f $ICINGA2_LOG ]; then chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_LOG fi mkdir -p $ICINGA2_RUN_DIR/icinga2/cmd chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_RUN_DIR/icinga2/cmd if type restorecon >/dev/null 2>&1; then restorecon -R $ICINGA2_RUN_DIR/icinga2/ fi chmod 2750 $ICINGA2_RUN_DIR/icinga2/cmd # Add a fallback if the user did not specify this directory in the sysconfig file if [ -z "$ICINGA2_CACHE_DIR" ]; then ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 fi mkdir -p $ICINGA2_CACHE_DIR chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_CACHE_DIR chmod 750 $ICINGA2_CACHE_DIR icinga2-2.8.1/etc/initsystem/safe-reload000066400000000000000000000014001322762156600201330ustar00rootroot00000000000000#!/bin/sh # load system specific defines SYSCONFIGFILE=$1 if [ ! -f "$SYSCONFIGFILE" ]; then echo "Error: You need to supply the path to the Icinga2 sysconfig file as a parameter." exit 1 fi . $SYSCONFIGFILE printf "Validating config files: " OUTPUTFILE=`mktemp` if type selinuxenabled >/dev/null 2>&1; then if selinuxenabled; then chcon -t icinga2_tmp_t $OUTPUTFILE >/dev/null 2>&1 fi fi if ! $DAEMON daemon --validate --color > $OUTPUTFILE; then echo "Failed" cat $OUTPUTFILE rm -f $OUTPUTFILE exit 1 fi echo "Done" rm -f $OUTPUTFILE printf "Reloading Icinga 2: " if [ ! -e $ICINGA2_PID_FILE ]; then exit 7 fi pid=`cat $ICINGA2_PID_FILE` if ! kill -HUP $pid >/dev/null 2>&1; then echo "Error: Icinga not running" exit 7 fi echo "Done" exit 0 icinga2-2.8.1/etc/logrotate.d/000077500000000000000000000000001322762156600160455ustar00rootroot00000000000000icinga2-2.8.1/etc/logrotate.d/icinga2.cmake000066400000000000000000000011521322762156600203620ustar00rootroot00000000000000@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/icinga2.log @CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/debug.log { daily rotate 7@LOGROTATE_USE_SU@ compress delaycompress missingok notifempty create 644 @ICINGA2_USER@ @ICINGA2_GROUP@ postrotate /bin/kill -USR1 $(cat @ICINGA2_RUNDIR@/icinga2/icinga2.pid 2> /dev/null) 2> /dev/null || true endscript } @CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/error.log { daily rotate 90@LOGROTATE_USE_SU@ compress delaycompress missingok notifempty create 644 @ICINGA2_USER@ @ICINGA2_GROUP@ # TODO: figure out how to get Icinga to re-open this log file } icinga2-2.8.1/icinga-app/000077500000000000000000000000001322762156600150605ustar00rootroot00000000000000icinga2-2.8.1/icinga-app/CMakeLists.txt000066400000000000000000000036341322762156600176260ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. if(MSVC) set(WindowsSources icinga.rc) else() set(WindowsSources "") endif() add_executable(icinga-app icinga.cpp ${WindowsSources}) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(icinga-app ${Boost_LIBRARIES} base config cli) set_target_properties ( icinga-app PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 FOLDER Bin OUTPUT_NAME icinga2 ) if(WIN32) set(InstallPath "${CMAKE_INSTALL_SBINDIR}") else() configure_file(icinga2.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2 @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/icinga2 DESTINATION ${CMAKE_INSTALL_SBINDIR} PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) set(InstallPath "${CMAKE_INSTALL_LIBDIR}/icinga2/sbin") endif() install( TARGETS icinga-app RUNTIME DESTINATION ${InstallPath} ) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/icinga2\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ICINGA2_RUNDIR}/icinga2\")") icinga2-2.8.1/icinga-app/icinga.cpp000066400000000000000000000615671322762156600170350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/clicommand.hpp" #include "config/configcompilercontext.hpp" #include "config/configcompiler.hpp" #include "config/configitembuilder.hpp" #include "base/application.hpp" #include "base/logger.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include "base/loader.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/scriptglobal.hpp" #include "base/context.hpp" #include "base/console.hpp" #include "base/process.hpp" #include "config.h" #include #include #ifndef _WIN32 # include # include # include #else # include # include # include # include #endif /* _WIN32 */ using namespace icinga; namespace po = boost::program_options; #ifdef _WIN32 static SERVICE_STATUS l_SvcStatus; static SERVICE_STATUS_HANDLE l_SvcStatusHandle; static HANDLE l_Job; #endif /* _WIN32 */ static std::vector GetLogLevelCompletionSuggestions(const String& arg) { std::vector result; String debugLevel = "debug"; if (debugLevel.Find(arg) == 0) result.push_back(debugLevel); String noticeLevel = "notice"; if (noticeLevel.Find(arg) == 0) result.push_back(noticeLevel); String informationLevel = "information"; if (informationLevel.Find(arg) == 0) result.push_back(informationLevel); String warningLevel = "warning"; if (warningLevel.Find(arg) == 0) result.push_back(warningLevel); String criticalLevel = "critical"; if (criticalLevel.Find(arg) == 0) result.push_back(criticalLevel); return result; } static std::vector GlobalArgumentCompletion(const String& argument, const String& word) { if (argument == "include") return GetBashCompletionSuggestions("directory", word); else if (argument == "log-level") return GetLogLevelCompletionSuggestions(word); else return std::vector(); } int Main(void) { int argc = Application::GetArgC(); char **argv = Application::GetArgV(); bool autocomplete = false; int autoindex = 0; if (argc >= 4 && strcmp(argv[1], "--autocomplete") == 0) { autocomplete = true; try { autoindex = Convert::ToLong(argv[2]); } catch (const std::invalid_argument& ex) { Log(LogCritical, "icinga-app") << "Invalid index for --autocomplete: " << argv[2]; return EXIT_FAILURE; } argc -= 3; argv += 3; } Application::SetStartTime(Utility::GetTime()); /* Set thread title. */ Utility::SetThreadName("Main Thread", false); /* Install exception handlers to make debugging easier. */ Application::InstallExceptionHandlers(); #ifdef _WIN32 bool builtinPaths = true; String binaryPrefix = Utility::GetIcingaInstallPath(); String dataPrefix = Utility::GetIcingaDataPath(); if (!binaryPrefix.IsEmpty() && !dataPrefix.IsEmpty()) { Application::DeclarePrefixDir(binaryPrefix); Application::DeclareSysconfDir(dataPrefix + "\\etc"); Application::DeclareRunDir(dataPrefix + "\\var\\run"); Application::DeclareLocalStateDir(dataPrefix + "\\var"); Application::DeclarePkgDataDir(binaryPrefix + "\\share\\icinga2"); Application::DeclareIncludeConfDir(binaryPrefix + "\\share\\icinga2\\include"); } else { Log(LogWarning, "icinga-app", "Registry key could not be read. Falling back to built-in paths."); #endif /* _WIN32 */ Application::DeclarePrefixDir(ICINGA_PREFIX); Application::DeclareSysconfDir(ICINGA_SYSCONFDIR); Application::DeclareRunDir(ICINGA_RUNDIR); Application::DeclareLocalStateDir(ICINGA_LOCALSTATEDIR); Application::DeclarePkgDataDir(ICINGA_PKGDATADIR); Application::DeclareIncludeConfDir(ICINGA_INCLUDECONFDIR); #ifdef _WIN32 } #endif /* _WIN32 */ Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d"); Application::DeclareRunAsUser(ICINGA_USER); Application::DeclareRunAsGroup(ICINGA_GROUP); #ifdef __linux__ Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); Application::DeclareRLimitStack(Application::GetDefaultRLimitStack()); #endif /* __linux__ */ Application::DeclareConcurrency(boost::thread::hardware_concurrency()); ScriptGlobal::Set("AttachDebugger", false); ScriptGlobal::Set("PlatformKernel", Utility::GetPlatformKernel()); ScriptGlobal::Set("PlatformKernelVersion", Utility::GetPlatformKernelVersion()); ScriptGlobal::Set("PlatformName", Utility::GetPlatformName()); ScriptGlobal::Set("PlatformVersion", Utility::GetPlatformVersion()); ScriptGlobal::Set("PlatformArchitecture", Utility::GetPlatformArchitecture()); ScriptGlobal::Set("BuildHostName", ICINGA_BUILD_HOST_NAME); ScriptGlobal::Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME); ScriptGlobal::Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION); String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf"; if (Utility::PathExists(initconfig)) { Expression *expression; try { expression = ConfigCompiler::CompileFile(initconfig); ScriptFrame frame; expression->Evaluate(frame); } catch (const std::exception& ex) { delete expression; Log(LogCritical, "config", DiagnosticInformation(ex)); return EXIT_FAILURE; } delete expression; } if (!autocomplete) Application::SetResourceLimits(); LogSeverity logLevel = Logger::GetConsoleLogSeverity(); Logger::SetConsoleLogSeverity(LogWarning); Loader::LoadExtensionLibrary("cli"); po::options_description visibleDesc("Global options"); visibleDesc.add_options() ("help,h", "show this help message") ("version,V", "show version information") #ifndef _WIN32 ("color", "use VT100 color codes even when stdout is not a terminal") #endif /* _WIN32 */ ("define,D", po::value >(), "define a constant") ("app,a", po::value(), "application library name (default: icinga)") ("library,l", po::value >(), "load a library") ("include,I", po::value >(), "add include search directory") ("log-level,x", po::value(), "specify the log level for the console log.\n" "The valid value is either debug, notice, information (default), warning, or critical") ("script-debugger,X", "whether to enable the script debugger"); po::options_description hiddenDesc("Hidden options"); hiddenDesc.add_options() ("no-stack-rlimit", "used internally, do not specify manually") ("arg", po::value >(), "positional argument"); po::positional_options_description positionalDesc; positionalDesc.add("arg", -1); String cmdname; CLICommand::Ptr command; po::variables_map vm; try { CLICommand::ParseCommand(argc, argv, visibleDesc, hiddenDesc, positionalDesc, vm, cmdname, command, autocomplete); } catch (const std::exception& ex) { Log(LogCritical, "icinga-app") << "Error while parsing command-line options: " << ex.what(); return EXIT_FAILURE; } #ifdef _WIN32 char username[UNLEN + 1]; DWORD usernameLen = UNLEN + 1; GetUserName(username, &usernameLen); std::ifstream userFile; userFile.open(Application::GetSysconfDir() + "/icinga2/user"); if (userFile && command && !Application::IsProcessElevated()) { std::string userLine; if (std::getline(userFile, userLine)) { userFile.close(); std::vector strs; boost::split(strs, userLine, boost::is_any_of("\\")); if (username != strs[1] && command->GetImpersonationLevel() == ImpersonationLevel::ImpersonateIcinga || command->GetImpersonationLevel() == ImpersonationLevel::ImpersonateRoot) { TCHAR szPath[MAX_PATH]; if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) { SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.lpVerb = _T("runas"); sei.lpFile = "cmd.exe"; sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; sei.nShow = SW_SHOW; std::stringstream parameters; parameters << "/C " << "\"" << szPath << "\"" << " "; for (int i = 1; i < argc; i++) { if (i != 1) parameters << " "; parameters << argv[i]; } parameters << " & SET exitcode=%errorlevel%"; parameters << " & pause"; parameters << " & EXIT /B %exitcode%"; std::string str = parameters.str(); LPCSTR cstr = str.c_str(); sei.lpParameters = cstr; if (!ShellExecuteEx(&sei)) { DWORD dwError = GetLastError(); if (dwError == ERROR_CANCELLED) Application::Exit(0); } else { WaitForSingleObject(sei.hProcess, INFINITE); DWORD exitCode; GetExitCodeProcess(sei.hProcess, &exitCode); CloseHandle(sei.hProcess); Application::Exit(exitCode); } } } } else { userFile.close(); } } #endif /* _WIN32 */ #ifndef _WIN32 if (vm.count("color")) { Console::SetType(std::cout, Console_VT100); Console::SetType(std::cerr, Console_VT100); } #endif /* _WIN32 */ if (vm.count("define")) { for (const String& define : vm["define"].as >()) { String key, value; size_t pos = define.FindFirstOf('='); if (pos != String::NPos) { key = define.SubStr(0, pos); value = define.SubStr(pos + 1); } else { key = define; value = "1"; } ScriptGlobal::Set(key, value); } } if (vm.count("script-debugger")) Application::SetScriptDebuggerEnabled(true); Application::DeclareStatePath(Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state"); Application::DeclareModAttrPath(Application::GetLocalStateDir() + "/lib/icinga2/modified-attributes.conf"); Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.debug"); Application::DeclareVarsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.vars"); Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid"); ConfigCompiler::AddIncludeSearchDir(Application::GetIncludeConfDir()); if (!autocomplete && vm.count("include")) { for (const String& includePath : vm["include"].as >()) { ConfigCompiler::AddIncludeSearchDir(includePath); } } if (!autocomplete) { Logger::SetConsoleLogSeverity(logLevel); if (vm.count("log-level")) { String severity = vm["log-level"].as(); LogSeverity logLevel = LogInformation; try { logLevel = Logger::StringToSeverity(severity); } catch (std::exception&) { /* Inform user and exit */ Log(LogCritical, "icinga-app", "Invalid log level set. Default is 'information'."); return EXIT_FAILURE; } Logger::SetConsoleLogSeverity(logLevel); } if (vm.count("library")) { for (const String& libraryName : vm["library"].as >()) { try { (void) Loader::LoadExtensionLibrary(libraryName); } catch (const std::exception& ex) { Log(LogCritical, "icinga-app") << "Could not load library \"" << libraryName << "\": " << DiagnosticInformation(ex); return EXIT_FAILURE; } } } if (!command || vm.count("help") || vm.count("version")) { String appName; try { appName = Utility::BaseName(Application::GetArgV()[0]); } catch (const std::bad_alloc&) { Log(LogCritical, "icinga-app", "Allocation failed."); return EXIT_FAILURE; } if (appName.GetLength() > 3 && appName.SubStr(0, 3) == "lt-") appName = appName.SubStr(3, appName.GetLength() - 3); std::cout << appName << " " << "- The Icinga 2 network monitoring daemon (version: " << ConsoleColorTag(vm.count("version") ? Console_ForegroundRed : Console_Normal) << Application::GetAppVersion() #ifdef I2_DEBUG << "; debug" #endif /* I2_DEBUG */ << ConsoleColorTag(Console_Normal) << ")" << std::endl << std::endl; if ((!command || vm.count("help")) && !vm.count("version")) { std::cout << "Usage:" << std::endl << " " << Utility::BaseName(argv[0]) << " "; if (cmdname.IsEmpty()) std::cout << ""; else std::cout << cmdname; std::cout << " []" << std::endl; if (command) { std::cout << std::endl << command->GetDescription() << std::endl; } } if (vm.count("version")) { std::cout << "Copyright (c) 2012-2017 Icinga Development Team (https://www.icinga.com/)" << std::endl << "License GPLv2+: GNU GPL version 2 or later " << std::endl << "This is free software: you are free to change and redistribute it." << std::endl << "There is NO WARRANTY, to the extent permitted by law."; } std::cout << std::endl; if (vm.count("version")) { std::cout << std::endl; Application::DisplayInfoMessage(std::cout, true); return EXIT_SUCCESS; } } if (!command || vm.count("help")) { if (!command) CLICommand::ShowCommands(argc, argv, NULL); std::cout << visibleDesc << std::endl << "Report bugs at " << std::endl << "Icinga home page: " << std::endl; return EXIT_SUCCESS; } } int rc = 1; if (autocomplete) { CLICommand::ShowCommands(argc, argv, &visibleDesc, &hiddenDesc, &GlobalArgumentCompletion, true, autoindex); rc = 0; } else if (command) { Logger::DisableTimestamp(true); #ifndef _WIN32 if (command->GetImpersonationLevel() == ImpersonateRoot) { if (getuid() != 0) { Log(LogCritical, "cli", "This command must be run as root."); return 0; } } else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) { String group = Application::GetRunAsGroup(); String user = Application::GetRunAsUser(); errno = 0; struct group *gr = getgrnam(group.CStr()); if (!gr) { if (errno == 0) { Log(LogCritical, "cli") << "Invalid group specified: " << group; return EXIT_FAILURE; } else { Log(LogCritical, "cli") << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return EXIT_FAILURE; } } if (getgid() != gr->gr_gid) { if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) { Log(LogCritical, "cli") << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; Log(LogCritical, "cli") << "Please re-run this command as a privileged user or using the \"" << user << "\" account."; return EXIT_FAILURE; } if (setgid(gr->gr_gid) < 0) { Log(LogCritical, "cli") << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return EXIT_FAILURE; } } errno = 0; struct passwd *pw = getpwnam(user.CStr()); if (!pw) { if (errno == 0) { Log(LogCritical, "cli") << "Invalid user specified: " << user; return EXIT_FAILURE; } else { Log(LogCritical, "cli") << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return EXIT_FAILURE; } } // also activate the additional groups the configured user is member of if (getuid() != pw->pw_uid) { if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) { Log(LogCritical, "cli") << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; Log(LogCritical, "cli") << "Please re-run this command as a privileged user or using the \"" << user << "\" account."; return EXIT_FAILURE; } if (setuid(pw->pw_uid) < 0) { Log(LogCritical, "cli") << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; Log(LogCritical, "cli") << "Please re-run this command as a privileged user or using the \"" << user << "\" account."; return EXIT_FAILURE; } } } Process::InitializeSpawnHelper(); #endif /* _WIN32 */ std::vector args; if (vm.count("arg")) args = vm["arg"].as >(); if (static_cast(args.size()) < command->GetMinArguments()) { Log(LogCritical, "cli") << "Too few arguments. Command needs at least " << command->GetMinArguments() << " argument" << (command->GetMinArguments() != 1 ? "s" : "") << "."; return EXIT_FAILURE; } if (command->GetMaxArguments() >= 0 && static_cast(args.size()) > command->GetMaxArguments()) { Log(LogCritical, "cli") << "Too many arguments. At most " << command->GetMaxArguments() << " argument" << (command->GetMaxArguments() != 1 ? "s" : "") << " may be specified."; return EXIT_FAILURE; } LogSeverity logLevel = Logger::GetConsoleLogSeverity(); Logger::SetConsoleLogSeverity(LogWarning); if (vm.count("app")) Loader::LoadExtensionLibrary(vm["app"].as()); else Loader::LoadExtensionLibrary("icinga"); Logger::SetConsoleLogSeverity(logLevel); rc = command->Run(vm, args); } return rc; } #ifdef _WIN32 static int SetupService(bool install, int argc, char **argv) { SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (NULL == schSCManager) { printf("OpenSCManager failed (%d)\n", GetLastError()); return 1; } TCHAR szPath[MAX_PATH]; if (!GetModuleFileName(NULL, szPath, MAX_PATH)) { printf("Cannot install service (%d)\n", GetLastError()); return 1; } String szArgs; szArgs = Utility::EscapeShellArg(szPath) + " --scm"; std::string scmUser = "NT AUTHORITY\\NetworkService"; std::ifstream initf(Utility::GetIcingaDataPath() + "\\etc\\icinga2\\user"); if (initf.good()) { std::getline(initf, scmUser); } initf.close(); for (int i = 0; i < argc; i++) { if (!strcmp(argv[i], "--scm-user") && i + 1 < argc) { scmUser = argv[i + 1]; i++; } else szArgs += " " + Utility::EscapeShellArg(argv[i]); } SC_HANDLE schService = OpenService(schSCManager, "icinga2", SERVICE_ALL_ACCESS); if (schService != NULL) { SERVICE_STATUS status; ControlService(schService, SERVICE_CONTROL_STOP, &status); double start = Utility::GetTime(); while (status.dwCurrentState != SERVICE_STOPPED) { double end = Utility::GetTime(); if (end - start > 30) { printf("Could not stop the service.\n"); break; } Utility::Sleep(5); if (!QueryServiceStatus(schService, &status)) { printf("QueryServiceStatus failed (%d)\n", GetLastError()); return 1; } } } else if (install) { schService = CreateService( schSCManager, "icinga2", "Icinga 2", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szArgs.CStr(), NULL, NULL, NULL, scmUser.c_str(), NULL); if (schService == NULL) { printf("CreateService failed (%d)\n", GetLastError()); CloseServiceHandle(schSCManager); return 1; } } else { printf("Service isn't installed.\n"); CloseServiceHandle(schSCManager); return 0; } if (!install) { if (!DeleteService(schService)) { printf("DeleteService failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return 1; } printf("Service uninstalled successfully\n"); } else { if (!ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, szArgs.CStr(), NULL, NULL, NULL, scmUser.c_str(), NULL, NULL)) { printf("ChangeServiceConfig failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return 1; } SERVICE_DESCRIPTION sdDescription = { "The Icinga 2 monitoring application" }; if(!ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription)) { printf("ChangeServiceConfig2 failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return 1; } if (!StartService(schService, 0, NULL)) { printf("StartService failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return 1; } printf("Service successfully installed for user '%s'\n", scmUser); std::ofstream fuser(Utility::GetIcingaDataPath() + "\\etc\\icinga2\\user", std::ios::out | std::ios::trunc); if (fuser) fuser << scmUser; else printf("Could not write user to %s\\etc\\icinga2\\user", Utility::GetIcingaDataPath()); fuser.close(); } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return 0; } VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; l_SvcStatus.dwCurrentState = dwCurrentState; l_SvcStatus.dwWin32ExitCode = dwWin32ExitCode; l_SvcStatus.dwWaitHint = dwWaitHint; if (dwCurrentState == SERVICE_START_PENDING) l_SvcStatus.dwControlsAccepted = 0; else l_SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) l_SvcStatus.dwCheckPoint = 0; else l_SvcStatus.dwCheckPoint = dwCheckPoint++; SetServiceStatus(l_SvcStatusHandle, &l_SvcStatus); } VOID WINAPI ServiceControlHandler(DWORD dwCtrl) { if (dwCtrl == SERVICE_CONTROL_STOP) { ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); TerminateJobObject(l_Job, 0); } } VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv) { l_SvcStatusHandle = RegisterServiceCtrlHandler( "icinga2", ServiceControlHandler); l_SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; l_SvcStatus.dwServiceSpecificExitCode = 0; ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); l_Job = CreateJobObject(NULL, NULL); for (;;) { LPSTR arg = argv[0]; String args; int uargc = Application::GetArgC(); char **uargv = Application::GetArgV(); args += Utility::EscapeShellArg(Application::GetExePath(uargv[0])); for (int i = 2; i < uargc && uargv[i]; i++) { if (args != "") args += " "; args += Utility::EscapeShellArg(uargv[i]); } STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; char *uargs = strdup(args.CStr()); BOOL res = CreateProcess(NULL, uargs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); free(uargs); if (!res) break; CloseHandle(pi.hThread); AssignProcessToJobObject(l_Job, pi.hProcess); if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) break; DWORD exitStatus; if (!GetExitCodeProcess(pi.hProcess, &exitStatus)) break; if (exitStatus != 7) break; } TerminateJobObject(l_Job, 0); CloseHandle(l_Job); ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); Application::Exit(0); } #endif /* _WIN32 */ /** * Entry point for the Icinga application. * * @params argc Number of command line arguments. * @params argv Command line arguments. * @returns The application's exit status. */ int main(int argc, char **argv) { #ifndef _WIN32 if (!getenv("ICINGA2_KEEP_FDS")) { rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { rlim_t maxfds = rl.rlim_max; if (maxfds == RLIM_INFINITY) maxfds = 65536; for (rlim_t i = 3; i < maxfds; i++) { int rc = close(i); #ifdef I2_DEBUG if (rc >= 0) std::cerr << "Closed FD " << i << " which we inherited from our parent process." << std::endl; #endif /* I2_DEBUG */ } } } #endif /* _WIN32 */ /* must be called before using any other libbase functions */ Application::InitializeBase(); /* Set command-line arguments. */ Application::SetArgC(argc); Application::SetArgV(argv); #ifdef _WIN32 if (argc > 1 && strcmp(argv[1], "--scm-install") == 0) { return SetupService(true, argc - 2, &argv[2]); } if (argc > 1 && strcmp(argv[1], "--scm-uninstall") == 0) { return SetupService(false, argc - 2, &argv[2]); } if (argc > 1 && strcmp(argv[1], "--scm") == 0) { SERVICE_TABLE_ENTRY dispatchTable[] = { { "icinga2", ServiceMain }, { NULL, NULL } }; StartServiceCtrlDispatcher(dispatchTable); Application::Exit(EXIT_FAILURE); } #endif /* _WIN32 */ int rc = Main(); Application::Exit(rc); } icinga2-2.8.1/icinga-app/icinga.ico000066400000000000000000000013761322762156600170150ustar00rootroot00000000000000 ( @ppwpppppwwpwwxpwxxwppppwpicinga2-2.8.1/icinga-app/icinga.rc000066400000000000000000000013311322762156600166360ustar00rootroot00000000000000#include #include "icinga-version.h" LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 100 ICON "icinga.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "Icinga Development Team" VALUE "FileDescription", "Icinga 2" VALUE "FileVersion", VERSION VALUE "InternalName", "icinga2.exe" VALUE "LegalCopyright", " Icinga Development Team" VALUE "OriginalFilename", "icinga2.exe" VALUE "ProductName", "Icinga 2" VALUE "ProductVersion", VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 0x04E4 END ENDicinga2-2.8.1/icinga-app/icinga2.cmake000066400000000000000000000015121322762156600173750ustar00rootroot00000000000000#!/bin/sh ICINGA2_BIN=@CMAKE_INSTALL_FULL_LIBDIR@/icinga2/sbin/icinga2 if test "x`uname -s`" = "xLinux" -a "x$1" = "xconsole"; then libedit_line=`ldd $ICINGA2_BIN 2>&1 | grep libedit` if test $? -eq 0; then libedit_path=`echo $libedit_line | cut -f3 -d' '` if test -n "$libedit_path"; then libdir=`dirname -- $libedit_path` found=0 for libreadline_path in `ls -1r -- $libdir/libreadline.so.* 2>/dev/null`; do found=1 break done if test $found -eq 0; then libdir2=/`echo $libdir | cut -f3- -d/` for libreadline_path in `ls -1r -- $libdir2/libreadline.so.* 2>/dev/null`; do found=1 break done fi if test $found -gt 0; then export LD_PRELOAD="$libreadline_path:$LD_PRELOAD" fi fi fi fi exec $ICINGA2_BIN "$@" icinga2-2.8.1/icinga-installer/000077500000000000000000000000001322762156600162755ustar00rootroot00000000000000icinga2-2.8.1/icinga-installer/CMakeLists.txt000066400000000000000000000036661322762156600210500ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif(${flag_var} MATCHES "/MD") endforeach(flag_var) add_executable(icinga-installer icinga-installer.cpp) set_target_properties( icinga-installer PROPERTIES FOLDER Bin OUTPUT_NAME icinga2-installer LINK_FLAGS "/SUBSYSTEM:WINDOWS" ) target_link_libraries(icinga-installer shlwapi) install(CODE " execute_process(COMMAND \${CMAKE_COMMAND} -E copy \"${CMAKE_CURRENT_BINARY_DIR}/icinga2.wixpatch.\${BUILD_TYPE}\" \"${CMAKE_CURRENT_BINARY_DIR}/icinga2.wixpatch\" RESULT_VARIABLE copy_result ERROR_VARIABLE error_output) if(copy_result) message(FATAL_ERROR \${error_output}) endif() ") file( GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/icinga2.wixpatch.$" INPUT "${CMAKE_CURRENT_SOURCE_DIR}/icinga2.wixpatch.cmake" ) set(InstallPath "${CMAKE_INSTALL_SBINDIR}") install( TARGETS icinga-installer RUNTIME DESTINATION ${InstallPath} ) icinga2-2.8.1/icinga-installer/bannrbmp.bmp000066400000000000000000000723321322762156600206030ustar00rootroot00000000000000BMtzl:`pBGRsʦ @ ` @@ @@@`@@@@`` `@`````` @` @` @` @`@@ @@@`@@@@@ @ @ @@ `@ @ @ @ @@@@ @@@@@`@@@@@@@@@`@` @`@@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@ @` @ ` @@ @@@`@@@@`` `@`````` @` @` @` @` @` @ ` @@ @@@`@@@@`` `@`````` @` @` @`                        icinga2-2.8.1/icinga-installer/dlgbmp.bmp000066400000000000000000004602661322762156600202600ustar00rootroot00000000000000BM`6(8\ʦ @ ` @@ @@@`@@@@`` `@`````` @` @` @` @`@@ @@@`@@@@@ @ @ @@ `@ @ @ @ @@@@ @@@@@`@@@@@@@@@`@` @`@@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@ @` @ ` @@ @@@`@@@@`` `@`````` @` @` @` @` @` @ ` @@ @@@`@@@@`` `@`````` @` @` @` icinga2-2.8.1/icinga-installer/icinga-installer.cpp000066400000000000000000000201611322762156600222260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include static std::string GetIcingaInstallPath(void) { char szFileName[MAX_PATH]; if (!GetModuleFileName(NULL, szFileName, sizeof(szFileName))) return ""; if (!PathRemoveFileSpec(szFileName)) return ""; if (!PathRemoveFileSpec(szFileName)) return ""; return szFileName; } static bool ExecuteCommand(const std::string& app, const std::string& arguments) { SHELLEXECUTEINFO sei = {}; sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.lpFile = app.c_str(); sei.lpParameters = arguments.c_str(); sei.nShow = SW_HIDE; if (!ShellExecuteEx(&sei)) return false; if (!sei.hProcess) return false; WaitForSingleObject(sei.hProcess, INFINITE); DWORD exitCode; BOOL res = GetExitCodeProcess(sei.hProcess, &exitCode); CloseHandle(sei.hProcess); if (!res) return false; return exitCode == 0; } static bool ExecuteIcingaCommand(const std::string& arguments) { return ExecuteCommand(GetIcingaInstallPath() + "\\sbin\\icinga2.exe", arguments); } static std::string DirName(const std::string& path) { char *spath = strdup(path.c_str()); if (!PathRemoveFileSpec(spath)) { free(spath); throw std::runtime_error("PathRemoveFileSpec failed"); } std::string result = spath; free(spath); return result; } static bool PathExists(const std::string& path) { struct _stat statbuf; return (_stat(path.c_str(), &statbuf) >= 0); } static std::string GetIcingaDataPath(void) { char path[MAX_PATH]; if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path))) throw std::runtime_error("SHGetFolderPath failed"); return std::string(path) + "\\icinga2"; } static void MkDir(const std::string& path) { if (mkdir(path.c_str()) < 0 && errno != EEXIST) throw std::runtime_error("mkdir failed"); } static void MkDirP(const std::string& path) { size_t pos = 0; while (pos != std::string::npos) { pos = path.find_first_of("/\\", pos + 1); std::string spath = path.substr(0, pos + 1); struct _stat statbuf; if (_stat(spath.c_str(), &statbuf) < 0 && errno == ENOENT) MkDir(path.substr(0, pos)); } } static std::string GetNSISInstallPath(void) { HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Icinga Development Team\\ICINGA2", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { BYTE pvData[MAX_PATH]; DWORD cbData = sizeof(pvData) - 1; DWORD lType; if (RegQueryValueEx(hKey, NULL, NULL, &lType, pvData, &cbData) == ERROR_SUCCESS && lType == REG_SZ) { pvData[cbData] = '\0'; return (char *)pvData; } RegCloseKey(hKey); } return ""; } static bool CopyDirectory(const std::string& source, const std::string& destination) { // SHFileOperation requires file names to be terminated with two \0s std::string tmpSource = source + std::string(1, '\0'); std::string tmpDestination = destination + std::string(1, '\0'); SHFILEOPSTRUCT fop; fop.wFunc = FO_COPY; fop.pFrom = tmpSource.c_str(); fop.pTo = tmpDestination.c_str(); fop.fFlags = FOF_NO_UI; return (SHFileOperation(&fop) == 0); } static bool DeleteDirectory(const std::string& dir) { // SHFileOperation requires file names to be terminated with two \0s std::string tmpDir = dir + std::string(1, '\0'); SHFILEOPSTRUCT fop; fop.wFunc = FO_DELETE; fop.pFrom = tmpDir.c_str(); fop.fFlags = FOF_NO_UI; return (SHFileOperation(&fop) == 0); } static int UpgradeNSIS(void) { std::string installPath = GetNSISInstallPath(); if (installPath.empty()) return 0; std::string uninstallerPath = installPath + "\\uninstall.exe"; if (!PathExists(uninstallerPath)) return 0; std::string dataPath = GetIcingaDataPath(); if (dataPath.empty()) return 1; bool moveUserData = !PathExists(dataPath); /* perform open heart surgery on the user's data dirs - yay */ if (moveUserData) { MkDir(dataPath.c_str()); std::string oldNameEtc = installPath + "\\etc"; std::string newNameEtc = dataPath + "\\etc"; if (!CopyDirectory(oldNameEtc, newNameEtc)) return 1; std::string oldNameVar = installPath + "\\var"; std::string newNameVar = dataPath + "\\var"; if (!CopyDirectory(oldNameVar, newNameVar)) return 1; } ExecuteCommand(uninstallerPath, "/S _?=" + installPath); _unlink(uninstallerPath.c_str()); if (moveUserData) { std::string oldNameEtc = installPath + "\\etc"; if (!DeleteDirectory(oldNameEtc)) return 1; std::string oldNameVar = installPath + "\\var"; if (!DeleteDirectory(oldNameVar)) return 1; _rmdir(installPath.c_str()); } return 0; } static int InstallIcinga(void) { std::string installDir = GetIcingaInstallPath(); std::string dataDir = GetIcingaDataPath(); if (!PathExists(dataDir)) { std::string sourceDir = installDir + "\\share\\skel" + std::string(1, '\0'); std::string destinationDir = dataDir + std::string(1, '\0'); SHFILEOPSTRUCT fop; fop.wFunc = FO_COPY; fop.pFrom = sourceDir.c_str(); fop.pTo = destinationDir.c_str(); fop.fFlags = FOF_NO_UI | FOF_NOCOPYSECURITYATTRIBS; if (SHFileOperation(&fop) != 0) return 1; MkDirP(dataDir + "/etc/icinga2/pki"); MkDirP(dataDir + "/var/cache/icinga2"); MkDirP(dataDir + "/var/lib/icinga2/certs"); MkDirP(dataDir + "/var/lib/icinga2/certificate-requests"); MkDirP(dataDir + "/var/lib/icinga2/agent/inventory"); MkDirP(dataDir + "/var/lib/icinga2/api/config"); MkDirP(dataDir + "/var/lib/icinga2/api/log"); MkDirP(dataDir + "/var/lib/icinga2/api/zones"); MkDirP(dataDir + "/var/log/icinga2/compat/archive"); MkDirP(dataDir + "/var/log/icinga2/crash"); MkDirP(dataDir + "/var/run/icinga2/cmd"); MkDirP(dataDir + "/var/spool/icinga2/perfdata"); MkDirP(dataDir + "/var/spool/icinga2/tmp"); } ExecuteCommand("icacls", "\"" + dataDir + "\" /grant *S-1-5-20:(oi)(ci)m"); ExecuteCommand("icacls", "\"" + dataDir + "\\etc\" /inheritance:r /grant:r *S-1-5-20:(oi)(ci)m *S-1-5-32-544:(oi)(ci)f"); ExecuteIcingaCommand("--scm-install daemon"); return 0; } static int UninstallIcinga(void) { ExecuteIcingaCommand("--scm-uninstall"); return 0; } /** * Entry point for the installer application. */ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); //AllocConsole(); int rc; if (strcmp(lpCmdLine, "install") == 0) { rc = InstallIcinga(); } else if (strcmp(lpCmdLine, "uninstall") == 0) { rc = UninstallIcinga(); } else if (strcmp(lpCmdLine, "upgrade-nsis") == 0) { rc = UpgradeNSIS(); } else { MessageBox(NULL, "This application should only be run by the MSI installer package.", "Icinga 2 Installer", MB_ICONWARNING); rc = 1; } //::Sleep(3000s); return rc; } icinga2-2.8.1/icinga-installer/icinga2.wixpatch.cmake000066400000000000000000000031301322762156600224360ustar00rootroot00000000000000 1 Disable $CM_CP_sbin.icinga2_installer.exe>2 $CM_CP_sbin.icinga2_installer.exe>2 $CM_CP_sbin.icinga2_installer.exe=2 WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed icinga2-2.8.1/icinga-spec-version.h.cmake000066400000000000000000000000471322762156600201460ustar00rootroot00000000000000#define SPEC_VERSION "${SPEC_VERSION}" icinga2-2.8.1/icinga-studio/000077500000000000000000000000001322762156600156075ustar00rootroot00000000000000icinga2-2.8.1/icinga-studio/CMakeLists.txt000066400000000000000000000042231322762156600203500ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. set(wxWidgets_CONFIGURATION mswu) find_package(wxWidgets COMPONENTS core base propgrid adv REQUIRED) include(${wxWidgets_USE_FILE}) if(MSVC) set(WindowsSources icinga.rc) else() set(WindowsSources "") endif() add_executable(icinga-studio MACOSX_BUNDLE WIN32 icinga-studio.cpp forms.cpp aboutform.cpp connectform.cpp mainform.cpp icinga.icns ${WindowsSources}) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(icinga-studio ${Boost_LIBRARIES} ${wxWidgets_LIBRARIES} base remote) if(APPLE) set_source_files_properties(icinga.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) endif() set_target_properties ( icinga-studio PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 FOLDER Bin OUTPUT_NAME icinga-studio MACOSX_BUNDLE_INFO_STRING "Icinga Studio" MACOSX_BUNDLE_BUNDLE_NAME "Icinga Studio" MACOSX_BUNDLE_GUI_IDENTIFIER "Icinga Studio" MACOSX_BUNDLE_ICON_FILE icinga.icns MACOSX_BUNDLE_SHORT_VERSION_STRING "${GIT_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "${GIT_VERSION}" MACOSX_BUNDLE_COPYRIGHT "(c) Icinga Development Team" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in" ) if(WIN32) set(InstallPath "${CMAKE_INSTALL_SBINDIR}") else() set(InstallPath "${CMAKE_INSTALL_BINDIR}") endif() install( TARGETS icinga-studio RUNTIME DESTINATION ${InstallPath} BUNDLE DESTINATION ${InstallPath} ) icinga2-2.8.1/icinga-studio/IcingaStudio.fbp000066400000000000000000004362451322762156600207000ustar00rootroot00000000000000 C++ 1 source_name 0 0 res UTF-8 connect forms 1000 none 0 IcingaStudio . 1 1 1 1 UI 1 0 0 wxAUI_MGR_DEFAULT wxBOTH 1 1 impl_virtual 0 wxID_ANY 800,569 MainFormBase 800,569 wxDEFAULT_FRAME_STYLE Icinga Studio wxTAB_TRAVERSAL 1 1 1 0 wxID_ANY MyMenuBar m_MenuBar protected &File m_FileMenu none 0 1 wxID_EXIT wxITEM_NORMAL &Quit m_QuitMenuItem none OnQuitClicked &Help m_HelpMenu none 0 1 wxID_ABOUT wxITEM_NORMAL &About Icinga Studio... m_AboutMenuItem none OnAboutClicked m_DialogSizer wxVERTICAL none 5 wxEXPAND 1 m_ConnectionDetailsSizer wxHORIZONTAL none 2 wxALL|wxEXPAND 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_TypesTree 1 protected 1 Resizable 1 315,-1 wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT 0 OnTypeSelected 5 wxEXPAND 1 m_ObjectDetailsSizer wxVERTICAL none 2 wxALL|wxEXPAND 1 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_ObjectsList 1 protected 1 Resizable 1 wxLC_REPORT 0 wxFILTER_NONE wxDefaultValidator OnObjectSelected 5 wxALL|wxEXPAND 1 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 1 0 0 1 m_PropertyGrid 1 protected 1 Resizable 1 wxPG_DEFAULT_STYLE 0 1 1 1 0 wxID_ANY m_StatusBar protected wxST_SIZEGRIP 0 wxAUI_MGR_DEFAULT wxBOTH 1 1 impl_virtual 0 wxID_ANY ConnectFormBase -1,-1 wxDEFAULT_DIALOG_STYLE Icinga Studio - Connect m_DialogSizer wxVERTICAL none 5 wxEXPAND | wxALL 1 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_ConnectionDetailsPanel 1 none 1 Resizable 1 0 wxTAB_TRAVERSAL wxID_ANY Connection Details m_DetailsSizer wxVERTICAL none 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY Host: 0 0 1 m_HostLabel 1 none 1 Resizable 1 0 -1 5 wxALL|wxEXPAND 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_OK 0 0 1 m_HostText 1 protected 1 Resizable 1 0 wxFILTER_NONE wxDefaultValidator 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY Port: 0 0 1 m_PortLabel 1 none 1 Resizable 1 0 -1 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_PortText 1 protected 1 Resizable 1 0 wxFILTER_NONE wxDefaultValidator 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY API User: 0 0 1 m_UserLabel 1 none 1 Resizable 1 0 -1 5 wxALL|wxEXPAND 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_UserText 1 protected 1 Resizable 1 0 wxFILTER_NONE wxDefaultValidator 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY API Password: 0 0 1 m_PasswordLabel 1 none 1 Resizable 1 0 -1 5 wxALL|wxEXPAND 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_PasswordText 1 protected 1 Resizable 1 wxTE_PASSWORD 0 wxFILTER_NONE wxDefaultValidator 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY You can find the username and password for the default user in /etc/icinga2/conf.d/api-users.conf. 0 0 1 m_InfoLabel 1 none 1 Resizable 1 0 270 5 wxEXPAND | wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_ButtonsPanel 1 none 1 Resizable 1 0 wxTAB_TRAVERSAL m_ButtonsSizer wxHORIZONTAL none 5 wxEXPAND 1 0 1 0 0 0 1 0 0 m_Buttons protected 0 wxAUI_MGR_DEFAULT wxBOTH 1 1 impl_virtual 0 wxID_ANY AboutFormBase -1,-1 wxDEFAULT_DIALOG_STYLE About Icinga Studio m_DialogSizer wxVERTICAL none 5 wxEXPAND 1 m_InfoSizer wxHORIZONTAL none 5 wxALL 0 1 1 1 1 Load From Embedded File; icinga.xpm 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_ProductIcon 1 none 1 Resizable 1 0 5 wxEXPAND 1 m_AboutInfoSizer wxVERTICAL none 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY Icinga Studio 0 0 1 m_ProductNameLabel 1 none 1 Resizable 1 0 -1 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY Version 0 0 1 m_VersionLabel 1 protected 1 Resizable 1 0 -1 5 wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY Copyright (c) 2015 Icinga Development Team 0 0 1 m_CopyrightLabel 1 none 1 Resizable 1 0 -1 5 wxEXPAND | wxALL 0 1 1 1 1 1 0 1 1 0 Dock 0 Left 1 1 0 0 wxID_ANY 0 0 1 m_ButtonsPanel 1 none 1 Resizable 1 0 wxTAB_TRAVERSAL m_ButtonsSizer wxVERTICAL none 5 wxEXPAND 0 0 0 0 0 0 1 0 0 m_Buttons none icinga2-2.8.1/icinga-studio/MacOSXBundleInfo.plist.in000066400000000000000000000024221322762156600223310ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleGetInfoString ${MACOSX_BUNDLE_INFO_STRING} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType APPL CFBundleShortVersionString ${MACOSX_BUNDLE_SHORT_VERSION_STRING} CFBundleSignature ???? CFBundleVersion ${MACOSX_BUNDLE_BUNDLE_VERSION} CSResourcesFileMapped LSRequiresCarbon NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} NSHighResolutionCapable icinga2-2.8.1/icinga-studio/aboutform.cpp000066400000000000000000000032611322762156600203130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" #include "icinga-studio/aboutform.hpp" using namespace icinga; AboutForm::AboutForm(wxWindow *parent) : AboutFormBase(parent) { std::string version = "Version " + Application::GetAppVersion(); m_VersionLabel->SetLabelText(version); } icinga2-2.8.1/icinga-studio/aboutform.hpp000066400000000000000000000031601322762156600203160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ABOUTFORM_H #define ABOUTFORM_H #include "icinga-studio/forms.h" namespace icinga { class AboutForm : public AboutFormBase { public: AboutForm(wxWindow *parent); }; } #endif /* ABOUTFORM_H */ icinga2-2.8.1/icinga-studio/connectform.cpp000066400000000000000000000051711322762156600206340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga-studio/connectform.hpp" #include #include using namespace icinga; ConnectForm::ConnectForm(wxWindow *parent, const Url::Ptr& url) : ConnectFormBase(parent) { #ifdef _WIN32 SetIcon(wxICON(icinga)); #endif /* _WIN32 */ std::string authority = url->GetAuthority(); std::vector tokens; boost::algorithm::split(tokens, authority, boost::is_any_of("@")); if (tokens.size() > 1) { std::vector userinfo; boost::algorithm::split(userinfo, tokens[0], boost::is_any_of(":")); m_UserText->SetValue(userinfo[0]); m_PasswordText->SetValue(userinfo[1]); } std::vector hostport; boost::algorithm::split(hostport, tokens.size() > 1 ? tokens[1] : tokens[0], boost::is_any_of(":")); m_HostText->SetValue(hostport[0]); if (hostport.size() > 1) m_PortText->SetValue(hostport[1]); else m_PortText->SetValue("5665"); SetDefaultItem(m_ButtonsOK); } Url::Ptr ConnectForm::GetUrl(void) const { wxString url = "https://" + m_UserText->GetValue() + ":" + m_PasswordText->GetValue() + "@" + m_HostText->GetValue() + ":" + m_PortText->GetValue() + "/"; return new Url(url.ToStdString()); } icinga2-2.8.1/icinga-studio/connectform.hpp000066400000000000000000000033121322762156600206340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONNECTFORM_H #define CONNECTFORM_H #include "remote/url.hpp" #include "icinga-studio/forms.h" namespace icinga { class ConnectForm : public ConnectFormBase { public: ConnectForm(wxWindow *parent, const Url::Ptr& url); Url::Ptr GetUrl(void) const; }; } #endif /* CONNECTFORM_H */ icinga2-2.8.1/icinga-studio/forms.cpp000066400000000000000000000225341322762156600174470ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////// // C++ code generated with wxFormBuilder (version Jun 17 2015) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #include "forms.h" #include "icinga.xpm" /////////////////////////////////////////////////////////////////////////// MainFormBase::MainFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) { this->SetSizeHints( wxSize( 800,569 ), wxDefaultSize ); m_MenuBar = new wxMenuBar( 0 ); wxMenu* m_FileMenu; m_FileMenu = new wxMenu(); wxMenuItem* m_QuitMenuItem; m_QuitMenuItem = new wxMenuItem( m_FileMenu, wxID_EXIT, wxString( wxT("&Quit") ) , wxEmptyString, wxITEM_NORMAL ); m_FileMenu->Append( m_QuitMenuItem ); m_MenuBar->Append( m_FileMenu, wxT("&File") ); wxMenu* m_HelpMenu; m_HelpMenu = new wxMenu(); wxMenuItem* m_AboutMenuItem; m_AboutMenuItem = new wxMenuItem( m_HelpMenu, wxID_ABOUT, wxString( wxT("&About Icinga Studio...") ) , wxEmptyString, wxITEM_NORMAL ); m_HelpMenu->Append( m_AboutMenuItem ); m_MenuBar->Append( m_HelpMenu, wxT("&Help") ); this->SetMenuBar( m_MenuBar ); wxBoxSizer* m_DialogSizer; m_DialogSizer = new wxBoxSizer( wxVERTICAL ); wxBoxSizer* m_ConnectionDetailsSizer; m_ConnectionDetailsSizer = new wxBoxSizer( wxHORIZONTAL ); m_TypesTree = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( 315,-1 ), wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT ); m_ConnectionDetailsSizer->Add( m_TypesTree, 0, wxALL|wxEXPAND, 2 ); wxBoxSizer* m_ObjectDetailsSizer; m_ObjectDetailsSizer = new wxBoxSizer( wxVERTICAL ); m_ObjectsList = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT ); m_ObjectDetailsSizer->Add( m_ObjectsList, 1, wxALL|wxEXPAND, 2 ); m_PropertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE); m_ObjectDetailsSizer->Add( m_PropertyGrid, 1, wxALL|wxEXPAND, 5 ); m_ConnectionDetailsSizer->Add( m_ObjectDetailsSizer, 1, wxEXPAND, 5 ); m_DialogSizer->Add( m_ConnectionDetailsSizer, 1, wxEXPAND, 5 ); this->SetSizer( m_DialogSizer ); this->Layout(); m_StatusBar = this->CreateStatusBar( 1, wxST_SIZEGRIP, wxID_ANY ); this->Centre( wxBOTH ); // Connect Events this->Connect( m_QuitMenuItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnQuitClicked ) ); this->Connect( m_AboutMenuItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnAboutClicked ) ); m_TypesTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( MainFormBase::OnTypeSelected ), NULL, this ); m_ObjectsList->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFormBase::OnObjectSelected ), NULL, this ); } MainFormBase::~MainFormBase() { // Disconnect Events this->Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnQuitClicked ) ); this->Disconnect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnAboutClicked ) ); m_TypesTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( MainFormBase::OnTypeSelected ), NULL, this ); m_ObjectsList->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFormBase::OnObjectSelected ), NULL, this ); } ConnectFormBase::ConnectFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); wxBoxSizer* m_DialogSizer; m_DialogSizer = new wxBoxSizer( wxVERTICAL ); wxPanel* m_ConnectionDetailsPanel; m_ConnectionDetailsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxStaticBoxSizer* m_DetailsSizer; m_DetailsSizer = new wxStaticBoxSizer( new wxStaticBox( m_ConnectionDetailsPanel, wxID_ANY, wxT("Connection Details") ), wxVERTICAL ); wxStaticText* m_HostLabel; m_HostLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("Host:"), wxDefaultPosition, wxDefaultSize, 0 ); m_HostLabel->Wrap( -1 ); m_DetailsSizer->Add( m_HostLabel, 0, wxALL, 5 ); m_HostText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_OK, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_DetailsSizer->Add( m_HostText, 0, wxALL|wxEXPAND, 5 ); wxStaticText* m_PortLabel; m_PortLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("Port:"), wxDefaultPosition, wxDefaultSize, 0 ); m_PortLabel->Wrap( -1 ); m_DetailsSizer->Add( m_PortLabel, 0, wxALL, 5 ); m_PortText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_DetailsSizer->Add( m_PortText, 0, wxALL, 5 ); wxStaticText* m_UserLabel; m_UserLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("API User:"), wxDefaultPosition, wxDefaultSize, 0 ); m_UserLabel->Wrap( -1 ); m_DetailsSizer->Add( m_UserLabel, 0, wxALL, 5 ); m_UserText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_DetailsSizer->Add( m_UserText, 0, wxALL|wxEXPAND, 5 ); wxStaticText* m_PasswordLabel; m_PasswordLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("API Password:"), wxDefaultPosition, wxDefaultSize, 0 ); m_PasswordLabel->Wrap( -1 ); m_DetailsSizer->Add( m_PasswordLabel, 0, wxALL, 5 ); m_PasswordText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD ); m_DetailsSizer->Add( m_PasswordText, 0, wxALL|wxEXPAND, 5 ); wxStaticText* m_InfoLabel; m_InfoLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("You can find the username and password for the default user in /etc/icinga2/conf.d/api-users.conf."), wxDefaultPosition, wxDefaultSize, 0 ); m_InfoLabel->Wrap( 270 ); m_DetailsSizer->Add( m_InfoLabel, 0, wxALL, 5 ); m_ConnectionDetailsPanel->SetSizer( m_DetailsSizer ); m_ConnectionDetailsPanel->Layout(); m_DetailsSizer->Fit( m_ConnectionDetailsPanel ); m_DialogSizer->Add( m_ConnectionDetailsPanel, 1, wxEXPAND | wxALL, 5 ); wxPanel* m_ButtonsPanel; m_ButtonsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* m_ButtonsSizer; m_ButtonsSizer = new wxBoxSizer( wxHORIZONTAL ); m_Buttons = new wxStdDialogButtonSizer(); m_ButtonsOK = new wxButton( m_ButtonsPanel, wxID_OK ); m_Buttons->AddButton( m_ButtonsOK ); m_ButtonsCancel = new wxButton( m_ButtonsPanel, wxID_CANCEL ); m_Buttons->AddButton( m_ButtonsCancel ); m_Buttons->Realize(); m_ButtonsSizer->Add( m_Buttons, 1, wxEXPAND, 5 ); m_ButtonsPanel->SetSizer( m_ButtonsSizer ); m_ButtonsPanel->Layout(); m_ButtonsSizer->Fit( m_ButtonsPanel ); m_DialogSizer->Add( m_ButtonsPanel, 0, wxEXPAND | wxALL, 5 ); this->SetSizer( m_DialogSizer ); this->Layout(); m_DialogSizer->Fit( this ); this->Centre( wxBOTH ); } ConnectFormBase::~ConnectFormBase() { } AboutFormBase::AboutFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); wxBoxSizer* m_DialogSizer; m_DialogSizer = new wxBoxSizer( wxVERTICAL ); wxBoxSizer* m_InfoSizer; m_InfoSizer = new wxBoxSizer( wxHORIZONTAL ); wxStaticBitmap* m_ProductIcon; m_ProductIcon = new wxStaticBitmap( this, wxID_ANY, wxBitmap( icinga_xpm ), wxDefaultPosition, wxDefaultSize, 0 ); m_InfoSizer->Add( m_ProductIcon, 0, wxALL, 5 ); wxBoxSizer* m_AboutInfoSizer; m_AboutInfoSizer = new wxBoxSizer( wxVERTICAL ); wxStaticText* m_ProductNameLabel; m_ProductNameLabel = new wxStaticText( this, wxID_ANY, wxT("Icinga Studio"), wxDefaultPosition, wxDefaultSize, 0 ); m_ProductNameLabel->Wrap( -1 ); m_AboutInfoSizer->Add( m_ProductNameLabel, 0, wxALL, 5 ); m_VersionLabel = new wxStaticText( this, wxID_ANY, wxT("Version"), wxDefaultPosition, wxDefaultSize, 0 ); m_VersionLabel->Wrap( -1 ); m_AboutInfoSizer->Add( m_VersionLabel, 0, wxALL, 5 ); wxStaticText* m_CopyrightLabel; m_CopyrightLabel = new wxStaticText( this, wxID_ANY, wxT("Copyright (c) 2015 Icinga Development Team"), wxDefaultPosition, wxDefaultSize, 0 ); m_CopyrightLabel->Wrap( -1 ); m_AboutInfoSizer->Add( m_CopyrightLabel, 0, wxALL, 5 ); m_InfoSizer->Add( m_AboutInfoSizer, 1, wxEXPAND, 5 ); m_DialogSizer->Add( m_InfoSizer, 1, wxEXPAND, 5 ); wxPanel* m_ButtonsPanel; m_ButtonsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* m_ButtonsSizer; m_ButtonsSizer = new wxBoxSizer( wxVERTICAL ); wxStdDialogButtonSizer* m_Buttons; wxButton* m_ButtonsOK; m_Buttons = new wxStdDialogButtonSizer(); m_ButtonsOK = new wxButton( m_ButtonsPanel, wxID_OK ); m_Buttons->AddButton( m_ButtonsOK ); m_Buttons->Realize(); m_ButtonsSizer->Add( m_Buttons, 0, wxEXPAND, 5 ); m_ButtonsPanel->SetSizer( m_ButtonsSizer ); m_ButtonsPanel->Layout(); m_ButtonsSizer->Fit( m_ButtonsPanel ); m_DialogSizer->Add( m_ButtonsPanel, 0, wxEXPAND | wxALL, 5 ); this->SetSizer( m_DialogSizer ); this->Layout(); m_DialogSizer->Fit( this ); this->Centre( wxBOTH ); } AboutFormBase::~AboutFormBase() { } icinga2-2.8.1/icinga-studio/forms.h000066400000000000000000000064171322762156600171160ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////// // C++ code generated with wxFormBuilder (version Jun 17 2015) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #ifndef __FORMS_H__ #define __FORMS_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /// Class MainFormBase /////////////////////////////////////////////////////////////////////////////// class MainFormBase : public wxFrame { private: protected: wxMenuBar* m_MenuBar; wxTreeCtrl* m_TypesTree; wxListCtrl* m_ObjectsList; wxPropertyGrid* m_PropertyGrid; wxStatusBar* m_StatusBar; // Virtual event handlers, overide them in your derived class virtual void OnQuitClicked( wxCommandEvent& event ) { event.Skip(); } virtual void OnAboutClicked( wxCommandEvent& event ) { event.Skip(); } virtual void OnTypeSelected( wxTreeEvent& event ) { event.Skip(); } virtual void OnObjectSelected( wxListEvent& event ) { event.Skip(); } public: MainFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Icinga Studio"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 800,569 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); ~MainFormBase(); }; /////////////////////////////////////////////////////////////////////////////// /// Class ConnectFormBase /////////////////////////////////////////////////////////////////////////////// class ConnectFormBase : public wxDialog { private: protected: wxTextCtrl* m_HostText; wxTextCtrl* m_PortText; wxTextCtrl* m_UserText; wxTextCtrl* m_PasswordText; wxStdDialogButtonSizer* m_Buttons; wxButton* m_ButtonsOK; wxButton* m_ButtonsCancel; public: ConnectFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Icinga Studio - Connect"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); ~ConnectFormBase(); }; /////////////////////////////////////////////////////////////////////////////// /// Class AboutFormBase /////////////////////////////////////////////////////////////////////////////// class AboutFormBase : public wxDialog { private: protected: wxStaticText* m_VersionLabel; public: AboutFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("About Icinga Studio"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); ~AboutFormBase(); }; #endif //__FORMS_H__ icinga2-2.8.1/icinga-studio/icinga-studio.cpp000066400000000000000000000044251322762156600210570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga-studio/connectform.hpp" #include "icinga-studio/mainform.hpp" #include "base/application.hpp" #include #include #include using namespace icinga; class IcingaStudio : public wxApp { public: virtual bool OnInit(void) override { Application::InitializeBase(); Url::Ptr pUrl; if (argc < 2) { wxConfig config("IcingaStudio"); wxString wUrl; if (!config.Read("url", &wUrl)) wUrl = "https://localhost:5665/"; std::string url = wUrl.ToStdString(); ConnectForm f(NULL, new Url(url)); if (f.ShowModal() != wxID_OK) return false; pUrl = f.GetUrl(); url = pUrl->Format(false, true); wUrl = url; config.Write("url", wUrl); } else { pUrl = new Url(argv[1].ToStdString()); } MainForm *m = new MainForm(NULL, pUrl); m->Show(); return true; } }; wxIMPLEMENT_APP(IcingaStudio); icinga2-2.8.1/icinga-studio/icinga.icns000066400000000000000000006445561322762156600177430ustar00rootroot00000000000000icnsInic08RPNG  IHDR\rfsRGB pHYs  @IDATx˒]u&*$  [!=IO=+<~AO ~aG8%Q@6/&6νN:{u;sS;;u t t t t t t t t t t t t t  s'wv~_lƍ,Fk`40_;.g0w 竎G_(ŋ};[õ]׮]_{}+"8#wG||jBuw+ܹwsbGZw]۪6αy?۷/\GoD*q/~ ?O/>}ܹHBovΝ;"Br.k`{5z@Oa0#Wy]* }T)g9ҕ׿?JM 5T6:s_t ls`0wjb&?Y1~ݮ)Oֽ(%e7^/!J;^ClO?2Ҷ w@^0 {owmwټ';$ZBRZ="SO_)ܩ1ו%O̟*+_Su/ X/TT9umJ<(?yͫy`y@|\w -,.`G }T7lc9(`:҉ 􋵑sϽO86{U^ o_ؽ&j+ _=QN,XDp:Üf P辻ӡ[ zO/4ܟ;`N"}c”ϣ_y|J_c pW"bbsՑGJ+OT $PPA#] 30>i=\ _h^~Y1rkg}{Ulky\&D|a +VOKG)hs^>x{k08'@˺yppΟK⥅%{`:[XV؞0jyϬ-?{@ͳCe7[G'na lrwJ廸 ?φD{S صÞjŁj "c)ˏ2,mv$x|h p--y3ϲ`RPV=^셡7SÉ=8 S ›_51 ~a7wOH~ͣ p_]A;Wv矨<׊_ሯ5P#4:Ry^zm`d ؁Lֳ_f Ɯ:!hE^~c2;K$3t,сxOtyt[Pش_x=W^yvan'D/uwxz^M@po jwrz}'p K<3lnbĩK2@ɶ;zp߀oLϗ^.X._)%{U+~> = |ܹµj/#5HJᘏ༎ !/@ 03:"ʎ^h[ 'ҀuQ` \[B] =+1~g7J'tŗv{]؄{=?'P]t9OTD(@Usp_=UoB+Stulh ?h4D^r{0'^!N2&F~M& 87| Tyyu?=`IWl=Y=mxNj\u̶͈nx<yPysn_>yMiݷG9> IğP' TGE~#.L#ձH &PW%e {Ydc XU6xPYԑ:#Ӿ\Q^6 g]=2 ,#q̘c Jmd5'0n4` f`3fnAY>Vu[%mMgd~IɵYqomtyNS?8wkqKt=M$@` NCAvh{hur[\€Ѹ[ۡ}5$[Tiٍ"P`k 6!œS0-rg`G:SoJɫP\)?@IdPk=5` ?`CBvzh&!vŠ,΀p@fF_lΣ4e͖`Oa3!1^_nܸ12"uAAs<[c [YGyQq1*E])+dLEuzn@3^ ȓ8mA+CBcHa{&0 (5׉ ; *;)^`c ).N˂?e#JS{DpO^G \gwJ%TD'?M%UvkXd64@l+֧6:;D'2l`>\ޤq&^>zBD1I{@E8oA'MG"K[v~dc<ΊkI`>э"<]]N5]jz[( tبt W֫ZFiF Gk`^}ֺ6J6j8+'L|Μ+wE4~mKS_ږ~< :/}y}Ƌ6w]D;O|ZI6O]'?KBXިK[xMH(*zOKC-Nԗ|R2`0w}/ݷz]!ρO^q#ߩ@'PI6m_!{ @>|qδ-{38y睝O>dt;['^F 1{yg}v@G>mi|fKհq[F'uj{γ=y.Rv(xLN6-C()1uĪpb?l[YMr]YxD&.yp]mS;i4K!^||fY]- v$!Ywirj;d@C0Bu,ⴙ>$H[L@'z9ЛH+y~)x'â2:<39}V)+ qX?!5`~; L;^[UCmY T(;<`ԿH@yjwaFeV %e6wH<P6\So'iZ_=꒙Ɂ/;ܴ*g9y,L, `um}ɐ@+ H%|}ڌ uh3^bWl2$vIȾ3اqON3v@ufF"=4vwkT@f|V2|6K 1^@8B7?q GO ѣӥ|ut~2g_ݩF@ ,:F([0(Ĩ=fsKE1n1h÷-$>ٞf_cAxOKp3:ؖp# )41DD{n(<;GY@ϰ|)4>"CtHӕ<FRr3l]Ґm y江$Y!c }w^ya&ϐg9eTv/` 7if3Xo@Ϫnn zB4JWF٬#> @[3E QjY?v۬[]$ĊdPg Ub#"̜#@HWɍ%if?!`NgԌ qBqA57Ч= '>zv-/7&瑁0.&#h*C2׹/nc怜k/\CdUiJK ϵ= O?t[ ݕؚ0'Im6ZNB5$@_C:x^n_ ˆ3v+Y'oi X ȳli 3.-.z*tlO<[2cŵq@tE7Vq&h-4fM1N\o"_xa@ &, (r?88i_9a v8ѧ|v0ޜS_[^@t ȕi_ܢ ;Da8Eb `cp\`f`JP1 f1+M;@~K6B10fm~@P<1Pe#aq}v^z饃陮BlJ>zЀ,;)`sҢ?y'mY `2@SYm(:L ~p(^E1Sg0(-AHkI` E!ZϨS1DmK2:/ܼys1ҁ~2@:*w+G#:4MN%QIcg&IA>qF H?03c[]rN<0$%xYB0Y!1\+b [ 駾!dTH>mHpVېFGT0NƋMH@9@cO8z׿KW&;DWqFZ34KS:dp >kX-?pxmhSBqJ+wi4ѝg}+8-HLJ艏86F6$L@F^m&Ӣ7't>ḃIJfKp eySK[ x2 WiMy8c1H_K^zV\􄤍q3F|N8cwVYt%2k 9q Gl/C6kgaO euKyŽ6136rd Rnjg\!!:[=GI]+it8QN/2-LӉ|gIluc9;-~$cZ˳8)f,JT?ekSgW`ah@>+d0E- %ƣ\eɭ{RGG62Az~r=kt%f'm˸^i#+rtrm 0*x‍|S A ,7\թ)ўg=qBYN>䵉Ԟɋ'}U<"cU4W GOƄzǷr\ɯ= .[\l˴ђ\kNME am P[o ^lB:-N}} F.ȳQ=fwNQ}%1nɣ>FGnVm YR(gR^9duRR Fx8dRr`ʯQ[a: {IouuHάp!DŽ$˷g[k ٌ#@ qJn?ok<2M&6ڕ꼶o3Λ[bK@ MJ7qʻ6iVAIW֝X$=2_96 CG:0(AHa\e#(2<Ʊb̸.R m76a^*n@'NZǣ!(x|P3X`Q2æhuR>ɵrvJxe0m#kʤ'8^Qe\{m>Qt!lIsyD]vB5|ZwfH@>>@ `qy*3;X zT!y5@(@7fP.rTd=7N?La3} ;I gLE+"ru˦@޽姫Eڝ֧Il.6J{5{0L@kAJ0xf t61l K?%ǀD7G i$qviy2{Lb3wԗSmqi2/7od}+iHAUmEewŘ(ՠƈwxc|ݥh1H@8w|G(CF,GFybci2xZ{6 )?E蛧oIC3.ʬPRVf3>\ׇX;N49{` OTrxO! @e9I$?52…۬6{gY 93XYF1,>.<pc  Kok _3vFgY1X#"3yHȁ쮼4y?=%-jN̼2|=ob@k+,Y<R6"_{'[o?CO}Xui-h%Y&X[D`TV c$m9b|@4c>,'I!+D8|CYV+"~ 'WdND$RWZ =,Bd!uȟ~}dlN6ki`V]@&N C\d&^Ktӣ!9#G@A.H K^ւ(edV"dP^?}Y )ŇHC볒Q|dO\+Ǣםhʠ@g e dJs*:`Ā[MTS"]} 0y2\m^8S03|!"zI]8>rXde2&_du6),N` +Bi؄۪n!#n12!pMmiK 7.kA^})B!ԵJl7r 'Ǔ%"Wdϫ6L'IZq iX7g،5PqOI=!!Li#qh2K =_ Ȥt@@g !ZѤMEHzS8J{SO \~q "9Ȇ(ZFEvXTS=߁BB2l5`qf _(?P"0q砱хr7o;nf҂_UIFVaG-}8K;O<!]'olv@徝.3pf@2nl%?6θNO O[4ȓ͓z"pZ)O0ם^v,pf< 3vȏ +?Q3 al݂.zN|H@(_: ^%=NuSfhЀ/ϩ8l(χqm 16D%VK_wX\W= X3 s3;Kn%Y eCʄXٮz5?@7{&3;;3<@GY$}u yeE:D=\Xu7;g?yX'zrHrz} ftl]zZ>NԱ pS.eE d_k@751d0&jk@pY4rs?-NuS&h K|yns4p~~st%s|f!H Qni `KfxL/jJ yOlzw@6CgXNgxWz;ݑ;л Vp:޺Bswͻ?[-P܂A\w@HGc=yL tqxZ0ƝN(3Vf9#u<@H8jd 2[-L2 ƈg[qq~ G<Inx3ĵ80eljyUǨݟc#}d?G!+)'N#3nF˸#.`?o`i~g%0j+oDꏞڝ%Bn4 `˜di ϰ  )-p< Y}T`^ `4Yފ61f_pO{3 NmwOB?~?+ d/YiNFŀ8 n),Y2GbdK:2?NS!{ `fApg6}n[-D)'N3?x= 0ևrBGs!m\~}_A{qM@'gE?6۸nF׿<קS]<@'%- x<2{\DK6 /+Xk@@vA{@'T@c#̻WcMh?v3+ϱ_Cvw4 `b #0{,^j_vڰ<%[{{= ]VuWpÒ5^Ji$M;{f${ BN|wgK<o-n x,8N{C' q, t8̏pΞc5Qohӊ9uw4 ;Y 2*D{' yjMN@' JYW"oAo?oog4 `ʘI,·>[:'Nh-/qMz\-FAG2[ǧ)kis'CFihxמP\f@d©۷Ah;r5OfV.}@~KʋOZHal:?>aW\02y̌5s@ׄNx 28Avqھ'^yS 턣;L3,?ofLz)@ȦZo{i 92TA #g.>rݩ7qCg4 `p0C0x@Y5v `t!&?nGnkeO.Bn,Ȯ/YQH:^>;|{ynf3l Qvi d'.n\>./9I=d֢N#5Ljtf1]f56w\n18@@1Xn|ڎCZї'g .zC>lαtW:=W'F]:LtK@<//.n޼9π?@pirlc|$HH0:L dG?mL`_]2Lm62 rg{@Wxෳ#qgY˸eƺ睮#!§~zc4qeVfQ#jT' ;/>2 v|woI@KӇb{R2>"gםNn7`_y啝W_}uy6g0 uʈ6Tuxfp3\m!ת@{ҕQ^7j7IYx~]o, xژmIo"Яx,Λ]ÛC1:.8u1XADwM?o< +0gΘҁz&OYF@k@YB㌆H82`_]fhbCLjYExGf{KWBgsƐ~鍋.UOvw2H xd8Ǩ%=ZҴ߽xN,|@Z2ϊ r/>y; u@2Ff] @('\3E )mxNY@M/@nNf(Umt7:fCVފI+zUoO; -\fc/3p@A1OSW Mēv)/pCmsё*ۓ6! eU=u*Ikzq8Ͻ@hK]ϫp Dc'`C-ϙX }>ͅ4sHt>ө:g;8 \>̟v$ ; 7u5\ D8! d٪|3dߖY{~X?mt,]Y'$H:>խސCH`P|6 Ȭ ~r9k6gs?^X >K yQiX}򙁄X(-̊G %SGG&kVjGw@/^'u;zUU"7XfV }8> N=ʎI@1@ f*.hc2G!R39"4= ?@c}eUԶp6){4Q@3uf.:ĻC!Cw!`F!ɱ"?ȣe>3N˯-kp9FQU -$2cX'ɟ$}-B!2=i#K-;-85!7Q*WcvHOxLy"_9j]1XQ jw+5IDAT* #{ %g.Ig6C , }Wiٶ|'F|nXi1M1.*<ҏIwZ@΀߳;re-߶,6")ț: 2F>m(^\Cpo 0pA@>8jcaKߑ/%UNɈxFO:;nk|^``tS`iNwθs;fwHf$f,2n~ 2~Tww!*`LYXJg9Gݐ@d1^yXd$zJOK;>p`Q2m/un4pb <:i'}ö y!=6,qҡ>myaK !+ׯ#t5ІImܺCP%y@IH )w}YVg~"wzY9z  2&lg}׭O\7I[>. |=z]]N;4]@'qok`c5 `c 5pp:-t l:lt__ǽ@'ƹ8eo ky&eVh86 lċ@ֻc8`n`7@t!cW5:,Iś5 #Cv5Ihdp}{3aqs9 E֦NK,?ywx h `IeǮN+ 8K+T/5pz=!@|-\5pz:`i@>KbSXi`* Y~ЂǨ#x˯ >g8m{qs!sMVNY8Gj Xh䋽O?^cr&R0׉wW˒@T=N̯$nH\ß3[95՛8`>s\:{Tc7l ;*lׂWoP{/Lv/j8{Ff9oI`γ`Vǿ;/5ܸqc__@`[k7{ofL4<)dž7oY_v6F vlR||Y~f>ɿH+_/5ߤ2^IxM\kқQZȁ׬̐=υstd@̣:r.9O>qq!@i4q>` $܌'In*0h 4@s:XdBYSs9:xYX '#ot![olkL0gOi ĵOIn*T=Z}fczYYx\1#G9Y?׆䓷uj`nwFb<,-SiB3z3YY>i:u LG!e=䣇';X79Uz=S0[Hc \req'%yUWx𶺪<8/U#($?zyN ,-ljKIg,2ku]o) Iukw @lY9/{ ou[sԽ= n"e,۾o@E+0 AHƠk`g d뽲{+ߧUNٟ{~Y&? *x_ЇRW\M3}'+rŚ#jGs@t"hIȀEsO?=gz`SBIӿVMj9go+kI[+ׅ!><͒_򗿴`zh Í7yG58?.GT#W?^/@J+Ր{8\I̤o;:) /0|!) ~̃ %l^||rӿc?`ltr_>>-wQ-~Yv{pQė7cȪ`w>?W 008W/P̦|Uup% Ctʱb~ΫCIy[PYfo!p9y>Dʴi]4~7{6 +}Y0*ZQV_x>??fZHʪ޽5ޮnjhs*[,y4V  +m&#6TVt!yڜȇ%U"@d$2[צo뮁U4=g9|ްGW?UgE ~aڿl"6$T*[ݭ=YK/D@~WX|m\=y%8@SuZG ęں'<=XD<v`Ϥ2?W?-P?Oٙ/~gFg*q^^n=fE9P?~3 XF7L[xī@., vly03W>`B'q3]٪}ӿ˿VSpL,XGkgKjpGE`mWsC&@ r߆͌?32V%w]Gfx+W>vVfr,HY>Wn% 3'`ThOz~u[-2VCYlY P,|e?*ӺJa淬^Wd0Sc=GyE,}R08U|%@ ]g LoTOwu6.`{rZB_,?F/<#Hq9= ",@ߞ#qڟUwOɳW;9~X e}Uy*PTެ;+m=]N(Zo~mm|fݏ ܗȕZBR->^#8_~xO'@^QfpVaQ1˥:^YGEڟUwOL`{~ﳸ/0[){’sv][);[U7xKU`nI_~vw~ӟ~Q ( %պ^햀fYW mrPs ԁUVZKzQiu6_3_VHʤxkV{*Vɀ+)߮_[e\J~(rB~xOx~Gu"S̢NY.uց<#ۢ2|]jyc};} ?rK_o=qf:<=z~P{_WgՉ@u.ZfR>t5. `Cyy;6 >Up/yr_G+/C [GՖ(R~YDBݧL`9,k4 Ȓ ]J{K>9WƍCƋJ`#c1;]8+˵f Wq@>n?L%QGN^A,jַSIWG:!WbM>s!zL }Q#':m ZQ5qxߺ},xl? ?G;>#'sLXG=z8} x5lo5o]ۤ6}P]߫8un8 VRGN%|AW"Q$PEuF[v|:e$0R q@> 0߇@0^_ֻ6|a(}?A:WDwHt6}44J;3(CcYlܹ(~Oa huwzqoc"ܸqNٽ4DQgS.p@@@@@@@@@@@@@4+b$IENDB`ic09GPNG  IHDRxsRGB pHYs  @IDATx[\y)F8&yC[MX['b^ֈ,Q%QdKJtWwݫH $s]K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z;jFggg7?n}{b?ҿW_2=t掴Z-J@ ˿K??^#]^{g?O?=|{&.h{ wu3 Ǐo?}ѣGxWJ}vcŋ~!_~I쏖@K%8. ޻Ѱ'a?&;% {O# ᷃N?ntgboΝ;?*[YO~Ǔtof͗h Z-=H>"/%h VuͧS؇w0^1lɋ{'9< +Po$y(d|RO1wpyӠ`#4 !M/ Ү%h _h;lvi`^ `/3'xp?CyQEDZ#λ˜ߍc?Ġ(iPMZ@K%8< zx@`\) g{tn|gP7a0{o<b_ )? ;>r (~ ̣4t!2h Z* 5_Фbz'_.`Dމ4iqؤ|aAl?_D/`?|?n@a11aԃvz 4-@K%pX;-ww}mo"xً3l ӗŝ$h 3 ?È; ?Cyؽ1@"Φ\?D?:iS(m@K%8 Ե79&-_l@t}:VK/OAgw~0 1@|H46 l t?<.cK%h \Z/[ HZScywx06-"x+l'ȴo 6 -ˮ 7! .M{ yx<ΰ$.[-@K8$0kTzؑ_ Ai]SlTTGas͍_+aU;,  /cqN Qo`q>ȕ僴QJr[-@K$z_,M$pA ;f?D[ûi8fQ޾BKB֧!` "L6)-w$v%h Bˮa?`G vG{stl??ˏ0^E@n>OAg:2DYs,Mo Z-=2Mdד΍2tt[o?kw) u>66^Lٴ@K%񚝀;K{GW';d;ϭnBh/U/wJ';SWx$k7x>ۏ-z/~[6#̘x33c%@VJZ-U$1^zX_!!ܮ9>baJ`\ωk¶$ Dѿ)~c{xߛjE7A0 oS?7gjয়~z? 2={UQ+bnlB8 @ߝ~?5b1 <Gy%Ӹ;U/_cK%= [ Zu }qhՓ@lM^(6 ɽ{ X".|B{!y[,vM_/zǏĮQO>ae( o6[~W=lqrz%]>qUZE+E_aAJԻk@uN\t6/MD[7ge_,&^; 0 an+_"- ? F"7pBYEܫ4AAf0lqkl '+Ntc`\\E"@w;aJ:WўAW#.;/m#$F޴q{1%vP, _8嚣~)0B[y~)d[{"'fd9:qu',=%؃.T ۔@@NI\q~3S|b{'14!]ĉDϛ}*&tكbd~<?E~?#kmğ{Ǡ= 5%7 ?`߼{ѹ1)"90hnFyc_Q7 ۈ6s+Fh+z1bA$BFHR0c9771 $'װO!I>%ؘbn"UsyN=E= W`8jB?9& }eq-gC7mԈaBlYC63l<4I}~~_=>&1܍Q]r ` HnË DU$t1%Xb*ceNXнXB\v~C;F:4|㒀:`@pU 6ecL8+h`G7LMC xͤ-v[A9|nB^O atPҰGH?OQwA3?Z-HzM=t«:<.U'aVgy5i"=S_PX~{oXq6Ènme?= N\DDg"h/*|/|؍񼟷|yZTv%XMEk9Vo<oMzܹQ#r1C7^M4'unk&ۧEY>@yQ07ˍL78/fl&[ I Џ7crrwZ-sZtS B'c}S\@'aC!xSOzE8v-O{}䮴Ë?wov^?ƿ|_kxq;ߗ|oy^˟ &C^l/ᜬ+k2@xG 菖@K`e ,eI s ߛ9m '߫>OX@hk zB:m$Th<=A'f?Z:S:;]̛j /Þ= 7aOzEvK`}Y*`O?+ {ugJ)F0_e|=]~Ąze ?'"'zh lVͅ|s3VfPG9O_LB~_;7e GPzh9%XU/'}Onr9 |\ձ&@v~ԵA^s ⫓oWg1Vg}Rg2i"*G:Ɲgb̏5i?TH{s,~ <~i$lr R^UL[j0y_"M?aD?FQ71nѡ0v|C;(|wA`K3/vJ؉μh &%N5O"iȧ'zw}7;Y6tVZx`&~P/k|X[pQ]e8X 8ƌ?˸? p> [@H譠ɟ BQYqCc3|xxaVnm`-o>ۏ PwvtK~/n'Aȓ7ޝQ_N^G+qRoh lF1w`!Bu0uA$qȧˁ5:@ 8鴇AyZBu4<i+NH{P^@t}H 0/‡b8Ĺ&.6'{~E죏>4|bf^OshuCXT/o|mbߵ2[^ɟ'Ou]t~A .ā<iwB>( mA>9|b 7Ϣ 4G1Oi^~;aQȗJ9/ @BGK oFH@t*“( /'/xr2)x<9k $X$< 8:|  ?tbE 1} P>Y ]5Ov~Џk __㒀c0=AǠAンa SG@3 eJܰcQ;< xs @(n=~8J=9'~Ex ƞ54n8k}ع !ލpD|97tMBF@:|۵Zח X\Xc i_5=L$$j5g2K}--<'h3}D֗x9 ?a5מ!Ƒ1E/qqˍ e߿b1܊= =|+ǟ?#Nż,GӨ[{?D"(Zn ~{JοU?ϟ{y (k48f -9'|$ FnL<2[N@Fth(;'خ%Xwz=<_O,z6ߍ7ЩcbMp=A*ƜuW>Cqlw\ж+g̡O:p艛 ~t6nG?^q6)/b6Fap /#?aoGgx+ ^Gрw#vs=xB/ʺ;p6;c @gf1OA;qeh VsXpǂs[o%PrB"$4T~qGf5kv^8Dn ^N}<:)Op㑀qwl ㈣'S-<}W̓:K[?1wQl)goFρ(E~#R`On^qQ89M@4kY@:}nDęDvFWN!4NΗY2?Ŝ"NL-%S=FXcE3n>6ЍbFV`бNЎxHOt#BO>i'톯zj<> T;844BGnc& 9GD_"ay` —6%?6znm9 v(6 Lf)5E8 /Ƹ)Iy;>Ap=l|!Ф?Z-$>gcʯH> &S7>2pL] "a&OM4]SG#oy{{Ø3:8i G|,=\x¤qVBg|/ L#f oV{#/0QM@qQ_0p44󑖂S 08_/O0/"fydo"}iO>ɝr2r ??[w#ȕ?? ȩϋ~0o">:;MmS>;lc;!)7GmZK%p5 c{NxNĠ'zoxFN>&n{8o īunڍ+$NppK0i^ z,' 鏣0":P]tn ~3t-@KD|: ÷jsRQk7;E#mT Ly&]K%?Pdq,DsR~x,dq5^wM_\G[Ñ1FzT07 څJy4= T;-/sGNW'.aO55Tyw%#: yb9Ype-0iU=-4.TMk[ktmqz;@8K 8#fbW}u?oꚨN Fw7TĜe`H;?7Zۓs7]pUB78N4\. #+:,,>Ug#tx%0gk_>F=Į\l$16ݡx@;;Z˼J'% sBoGz!R>ơË'ߖuo MGЉf12`]u:uO7x`<6GuHB^\pYw X KtcCi|xӦ-v$][O-++Gma9#\.u}*Z%)(MDǪύu$ ~8݊;y( q F$'8՛ʲvt,-p^jH]HIoos-ވ'x}cq) >\gW|cmQ-tk|"ʃ µ|q}-fuU;< 0x2<{#N9=LQ.aX-UOl'D3 /*  仪[j%+TNXn*OtjL;Bg\Mo  ʓt'uǓ'_ŏ4 4wLwY o}C[Xm'UyO|DʮA3 돣a44Q:(mY\j gTn#TpjƆ6F`,x@K`5 0' /S<艴S%n>K:H>h9xmE|NN&A:k'r! H&Gm8 8v1cM'mDr*q⤃<_-+[im#%ؼX,t #6pcOMGOp#n6Ǎ kgc7ZחFԠsOSos[鄩Enn(:ӔEiG$O<"zlto(8yIW:e^1nD¹7ȇ]]i0V2W1_[-K2q_7^^~3}Stʛ2si)9;9G,ߘ/ޢWZ-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZKh N={v_~9u@AۙW>9D9͵> OD~ޟ9|g\{Xz.Iv9-"KvSerY6ʯ{ `c-h l\q8w ZGOi'q_=Azҭj l\)rdU.z'h lR)NZqP ,'7x`"'{%w9MQ6κ2rǓ:sGȏ?2駟R"r oMuZ@o6-.%gF0MNcA,n}0FT^rk l[ضĻ%i9y>'VNy>aNwfG9|Gۛ a(НyrTɓ'_uӧ1" f>S&#^Cךhoc-%Q0Սi8lɏCL _Gx6«~ ;VwP8A.068 a ;'P ;8Mä=z]nY|g<~8_@ N;FA#_wc%=nZK`Da w6n0'eP> ;&b?1V1hEe&Z&خ%M `Z; C8ixiԷxG ?@ݼ%a 4 4o~qaL$GK` յ- j*b%5 `kZ- `ux4Qw\xt-]H7z8@ h9rN|K3q0g9&`"L~яK/;ہ XmK7ۖx8 !qÑ6PLU-]I7|8 h0=s%s2 :nFCO]v7ˆ\9S7uo-r׮% P%c `̪1  FA18ۑk~P>ƞ>|UN׬&lM]QK0%Qa5|FN`o.֠:_:uUU\G~mҡF`պ;K` %L5z|A\ X9fC@|xQ[uSov-C@oe-K@Cc 54MyΝ}ul08 gC-_$^znhtTE9]ؚz5QwE-㒀"\G)g=Z܊aWu#ֺlj]%m `Z. C3Oq!&ENᴁSh1W7qz *uޖ6%mJj 4]rU$|]7WO_صz[* _N۸97ғxϗio ROm B؅ԻΖ@K`% htGPh3r͏1~b;[K`/$-CGnڸ0rzÍt뮿;. .o덋Gz8'N?4Ool zҿ zҕqǩo'gCkSWi l[ضć\LE W?6]E.ɑn"e[7|EO?N#W_ey7@g@8v-C@o: HkV~TEƸ: Nn 0œ1O> 7˲ @m;v#@8ڏ.% DžTdA=i\$Wi&(U<W< 7 ҁO4Lݼy g+|PN\ Ut֖N$-.cNB^{n(E .1i mQ$]J@=QoУѫމU}$zBrH8>Kufu# 묻j lB؄T,Ӆ2\Y6Uuf섖$Puj S 4E³.Q=WM#^o zg3UYTNfk;WO==t?uC0J7;jt«6rqk][JnP^]%p FPTғ=ד>aENRo,2.!̷8)mR/* ep(_co$."3]S':yɏ.}{9> >'q7P@K`^ͥ).vsh.E˹.No-T^h8 xXpD8! zh_ףnwM@oDхғ  |[Ўj9Aa9fOv6E8ѓ?H p0V: 'CpM[1P>|Yh@'zO> k @o,#Mfa+|,o!B*jاʓgfv-K`jiSW Sά_fo  BIiѓV:ov[o&^Iݓ˜jn|/JűoWz=d3~x>T wI^ gC_O'}t4/ [rTXwcK%0-LRj=`+S6FE_J߅D']yn%X 4縂ȃ[޲VD",o~mX@9q=<'k>o&lȉru.w#/?>77h?0q^P=3xtɓ}-sZK75 $BəT5 8pM|k "SC3VO^.B ,VEȂ2ljZ]Ik[ 0FƚtE~ggЫngߏ>(7G٦;O:Ƒ;=BwAB_?Ī'锏/#h J7y=ŴzC<_]5!$飗N=%WP >Pp}ЕZ{pl@Ke<s ?n7?|Sa#|G^ p@K`y ` YбXf!r=Y`DOP 4M`Y$˅}=BX_C.9eP[7-Pq.x3jDI@IDAT38ɟ2GUi/7 v7y)0r8©%?Z-Y `V4'Љ,C'>w*\]ܒS)߅4O} ]DA ^9v-Ǫ#B/qH#ly ލGلqh ,-,-udttI'}(4xmpLDNj3'q=DzFzC=sWAx! ΰN.%@o4Eutcf]E8LMs 1 WNWxз˼kG4%zˆIo"yn_lpE{ Wtb=۸Nظݪz gr@Nx@^yG77I8'2I-%sa F,'dh  ['V$|kV區q#G}rL!YEgc 5ۅr ]/*Zs: )Lb|lIQܨ~9I9x/twI?xs7ab=`:^omAsl$>O/q+tvd>鷥])[UMɌo 3F8x2AJE,.)GhhƖEmn>}HcL 1'';bM]db9aX6q┇|94; w8A?ÇsTGDnp>Gpy)gq%Y֚Q_aH?֨iPy 77` Xv(=~sBaD8x#8KRW~ @Ɠ̊PwEφ}Negy |76c B]I@~hx1'NFxyI۠DſTדĎ>xN:|8C_@ZH5E['$7YdžcR/+n@4x8ҁ][D1Vw0$0#;zx|.,,n qxH0Ժ^|7nhk?qu2wٯ]]I~8tҝ$T>81q)3pL$'貲Jܲ#>Ǐ} f xn@{=i8<`U%.nj/ {E7J0>' v, ɏvYse7}7`?_b\ xs:Ґ;֠ƞ; Ɲqb|Ϙד'+ maK@ݪy(Go >'zD*B|Uo)Ro 3XØ;r_vݪ#mӮ7$u" Nӷ#εcsvAmU"x\{zIoQY%lSey1L,h6 8x,:yו7;Aصzd'o֒W:q8 F F*m:AEOD.hEEvI3>tAwĚMb&,>HQa5< ;`_Fbd9Q5؉~ܑstǮgGC9-2iE8lj%V‡~xdC'h~QWhYi7th;s~q3xOs6W7=" H^ow{!t =7KF@>+ {w 5%DH GRNTW)|^Of~xpc|`3r=Rdx&FCD(1'ƒ'OM߶ hEw# ]? mp'vN[YO! yYP?tQ=In_pg+o"N~Ł<?SG[7a*=cgr#eK6`?N:vL?OsGM}C= :p_uH܉2N늎h? Eg~tOc>YȎ>h71IdX>裼Yrq`,s=^Axj7%XpWUk~7h5yo@xÿ mHH`r@< egbB*<4$%&?ŀ< ~~ckEyG^ߓwe~&3`rBnXH8IFH V }yqu }Lsb|wNP=~8/t(F@}%?^"|AY? B>y jItX^N񻎁z7ߤރuN~Fv>ݴ{uo.%@'J1P`x@[Y?EBRxm:(,U4^I}T&eóYCgqs)eeB9?QHu$;*?U7xЈܑH-Q/e aKfGo,Cš(0;τ ݅ trIn}I\Ç G?0~o;NY Q GxvO ^eU˘;W>ҪSDN=.M7dNU$uyC@GzMiY]*lEO+b;.¹~偟6.j*d[6<8Qz͔>J7үIrpnK4xH&_}k]Dpꄨ;rv0QՊvti-s"%^'|@U=ui?N#=s <8'N5|:JG{Sg1x?w`,{;u3MO'?]U$V^Ici#?"mevOu~<Ě\*jEXyp2clT*!a^iTl*mdȯRv=^ :ב^ w;Ooh]ܭC)}DSɋ42 ?''y]bC3]6@HA,!eGgvy2Mw]T2iѓh@6Wu|(8k]"4~kyXb0H 2@J!q >QK4BۡY M>=O*a=~$h,qaq~+/d/N4rt̼h'BqHN|c8r#zxe;uLkܮt]@omtB>=w[n?-_~Yh֧^*1˳|C7ߛ/ҡ;c;"46 :1/,4\ eHx18Q$d  b|Pn9:\-i/HwBڜS ~މDRFk4Se_F}8щDIWӾ*/yU6Ok OW4zuIWZFw++~΀@=7IPWE5,I)Q6׶&WoM{p" i(Np #}̟V]L:aM<{3pgqG~mc0ql (t|#csuc]%l߅EG~k9']>*m$8Sw aNrlڐcɆ D$/Q C#Ϻ~)e39Ș^0A: :>(F/Y==!<7̷*Si;7:K{3tEL'?-:mn\WrlDf|0(n._&^CY #~"Wie'2bFVm[,%nWmLy #yVmGߍq4xHX/283퓫]ҧЇ,1 :Y5MoW'|7IS;rmmvG p_?mze@;4]Dc96t7k6RH"OC*T|Ǝ _M~KY jǯȳ߽-#: /SGlF،\ѐ ű;g-'1<Ag.;#ᛟ?aEjP?gM=A '~@kȜqS^I63ok'~z 'LyU6YIw=t*Ze y`R:F#[Aq`̆Ek8H 8GdSrڤHƍH^48:W z: `7rI[ '0~pri<:H:thaZ ]H}TAd 㜠+?3[v)ƙEYЦty3 Pvtވ剎(]-C/͡IǷۭz[ovw`vLDpvI('J\N NQ"R Xsj#1V9yCg|9 AG}Iǁ?kE~_''R ~  yn>:d@Ac~xF~q&#ZnK>8v3C_|gu0l|ՠߜ9٣5zi7?C3?4+hG$mRƔK}^Ջ7cI`&(YNMnmqmW4&xYٽLBG>hL4荀 'VJei<;y9'8teeCcp,:cA8;n,N8)D~ "LAN֤WCS6|\='v;/=eGo' (2Þ|&AO{S7u`}o3zu{!x39]iq&%Nt)]ɗć''Gx^[ 8w<1舆~u;/놃)~惇|v[9ֶ8$|S+m .Q6 9:&&$x/)vL~N@xv8N heZV%8,:ƈ1ũ_44tz@ˡ>뤌Cw/9U[)WP.>Q:8V7/(4u&Gx:oǔ,i ۪<7ފ[өtҪ7~x_vUu70 nh`mVG E9Pp" MmbG 0q'MH'CpxIQCbSe:UO?w|S/TN M@7vx١k_7.׽&-Bqewe :S~#!\5j_ZO#mVm߬zYUL|)ƥ 8p9=y""ߘ2_-cϢyorsmR(ۓ7 7,x5os%yWYPh[5zM8l9T^|c:o##aғ^j*'ۮMbo6)RoD}ʛxs%^h@Ag|Sҩ::Oh1|Yey֙ѢL2:e!uk6he`U ހN4 7'z3@#/ވ.:1 )p rriyR/9vuXu?7~q\grYi>A8ro3@G828R'_h:^髢uc}cDH'{d鿢7 | qxo{7ېMHSݻDs:X5OXC%f_)+N[| rU&1Jʷ.zvuI9Y1#L>E _k6؆''O83_1xɇk[7!qeDk~I'*[oxF΅R큆˗?(VbʣOUG7~>ˍq[7>Iӓ:g$6ڏ+<*?hwJ~ӂo2=y$u p'nS7" \.-7$Dщ$NxϕC=E:C ^R4']uHA'ƙ:gvَ* )>h o~ʙW2vI*߶vpEl|HJC Si}Խ+]IuX8q٧7D> QuS'$xb ~G8]qrbDXpN=tCpIeX.Hz7@vn@ hH@oL@Sf[E|l~gj?/*{494 G_z._ő{->u`}%;nmlCGVɥgvsH7?=2Quw;O,ٯDpz:O$A,^?y␅8q VRH%|Բ<2*mw4M=tO:4P1C O/04.\ov!ӉB>Hd Й 2碲D}teǗ!@s#BʂH::`#7S|lj m|"2i,?{$qk .eH)3ѣb [ =Q&3b @ _L @fwuWUO]03<-zy'vGSԭ<8U஘>vg3O`4!# 5i:!2k;nB.u']o5\>DyphOTN9zġtOl,^p=36H;KkE p^z2Sd ~dėxY30,+v<)O<)9]DX= :t;2O:!C9+n,"?½7o,qC+EO_T"HuCbr/1X-uWUuN?3&MǸ|wYN- >WѝN8Fb3\=lKt%''lBq[vM"m5޶}q~Іr@˹=)lʘ?m}Hs?fM\&1t?gdrds"3GȂ>?b\E ,"[kxE>O9/ 't]o_'E0z"rE 并ӽ> ro AToF3"MQGu]gzDž =\psݣO~C{ȸ?ɧބx7S%㻚 ^]^$__M1ߚMw䚨P.ڷ^bԵgŞxYQ.6'8^;rgQ^I`Y_< =p]#P/}=»(XZ E=R59yW[{^{_QyΘq1V$zG.FOw=,ݵ,fnxdh7d`_(-ް[RzC`6szR"eys7ISϾm`T3k4l[62a ܊s<7=;=nMB_7Wr,zzxn#؟%ڎ\Imv/S`y?޿qrȻ%aN?!G^?(N/'ߖ95$z)KFfp#2MqpD"y\k:r㚞r1zճme 4ݑ>=ѹ*E? dg<5\,f 6i\/5>;ƛ/_+>ٞri=ROةW=^<`s{2 }B~gcN<ySG?M )wL=O_@;`^Cܶ h; r@0ݎYzףr1[~oS95Tvό}\k^nqJle&ҏ0p 0,44|Y jº\!?-g?6xihmv퇞wNx}k@Ns>X~.|%a~~z'O>Q#Qǫ,2 d>\}t%dp,3~e@C+{Nk̿ R 6$X7wIE7ݰּQ~rtG/=xRз{Ed@D2Ǝ;nw=;lwǮ`׌0^`YB' :,Q2堲r >oڥ/<'x 2oP9 RYNIyxF3gD\;c[\ż!ΧCc,aȂB>LYP{˩7hQk5"`8| dݐ6:aAL7W/zAy`{)2C?/w}8@ϵƯH97\?Ɛ 1Zj 2N*\5|.dzE0 u[/~ͳwd|cߛv\ ~gYN^O/?[>BI׬?|/M&lE7 1B-4HT&v 8oRK[\i{0@]VϲEˋkշαu9}T_TOtuϵzeqtv-s)pA.iڹRh (,Z..=rt4Hx{>G}4q PO\j<7Ke/:ιk,+KtNyd%aqn⬤Oa X[ŻGi5`9a:^/i\/EDR/S*\\+G~#fp>#fύڐz>,uz\)5x"eĵ6ӎ/ybK3O|_> vxޤ\u}Zsf4_\l/a 4\gܦCe`\EGmo_Û2t 6nו?lNi630pD `oh3,hosvaS<~3 zMuiKv꫁@_|N涒/婅lNmF30pf 0 n&f܆Υvn"ۦ 1 u %? 0 U 5S{xxmOѥ|,U߮˳"Ȉx]2 |wRQ9B>LG[=иEu)v@6;30pBWIZ9=- ^:4WL:Eu9@y"o!3fPMX1ܘa` `4{0 =wwcwH\w[>[Vba`' dSI1#h`gO|]E>?QWO?tԉ n^oYTşޞ]O}@߸E)6b hRf@CFƵQXa%#F: 3-}vL>V d})u `;g=rz oC0 9ezO\jv k>y'! 웁lpg΀Ƭ#Dv P1l@5lsZW=X-vA#Hw@6wx gƀMC!P>ykG~HgCa\}OO}|U6zE܈ 'M)6a MXN{a#ku$51O|} ;5篞mO=& m'MঌE? [1aXhޢǸ <<OF=Q']Bt72wg3ynDSEl'a 5@*^d\qηܶ8^oFʇ0 mXK0bçPs',z>'@d 2>N Fw l#[kǍ8mfʆM`1..uz6sz.dRG b= 1/k~ ZGcטTTg6 g{- f܊ a`Sg#~2=kzMoڿ腁sesx@a 9~^z>'tD4 "2@܌h0G44{l>Ub  6 <4zxD>ˏ $?<ʘ\[4`Ο0e k)B` sF]/[ @60cx ` tr<{ ok#9#k<'g{^F1s[k<'>OY=߲0f I /iUhGX68-^;i@Dž'l >uK'XFШ=72@،l6)Z E_ cgtq5TOoNJ~@IDAT[`~hz_uwTeHa` dWzOrZ 6 2煑/ wygAdxtWݨCONBCa?qo=|pu% G}@^B3 EcbEE,=37,̠ 8[u&a_ľ>o@trǽQlvI6/1xp 8 ܿ\h~/ Sv05r9<Ǐ_" %G?a 2 *5ɸZ=yh9bnr3a>ϵu,: 3 9M`oQ]!o76K\@?pGs ?x%(I;6sG`#q$yǷAʒG^>a 쏁lmj1=h5b1VQY7w@g F F#o|i曗2S *e>n?dOO4|z '7e(O<,7*͟0@6{615 y@N wǀ9!#\Woʟ0lmH`s;y̯͓ϯbEN?)A= P|ȯ? 9ꇎ'n@洟 (G~͏{Í>0@6kDS@xA6l@ :e }4P#3f@>A!s:|k[w>0@6$cW cYY#Gȷb8z뭡/#-r2O]l( iH> 1y}c ̭ԁϼ駣.N~O{a КJ7a/^S#=65&Eg d:=^06e MޭX5}fC<|"e x>CN`Ό!|õoQM#M a 엁loj߀{Թӿ 7:*w@?Qٌ a \xU/ϯ?3O)2t4*2 |0x'o[n{@Xc 5f"3\;854o(KeM_jxdH\w=9!Dי M=%d F@lr=ypsu7@g@6g:F"@88>߁kzd*!:~zcgM ̞;~Sˑ1 iF41+c1 27T%7cq z 4aF dp#| `Ј<<~=1gMw޹9x7GM^>a &fT0Ia :hC1W?sa 셁lBk*=$<cI>ǏCm<6>0NlN{~3 17U?ut. 3 )N€ϓ<_NNq?8; 986c qnd\0Λl{rD'~?x $)3ca`s؜h0pq1;1,kj\1*\w8/cWYȼ PDn=0fBGyӳ^O˫Ha%Dy7^BMa dp{Φ - 7Aoԕ'7С =QrH =L==yǯH~<|3nܩ'|oCoʹ2C& >"h?wnW}p0%\>QcF:#HG;֫aGhp0? _)ӑHc<ĹcK˗sƸqFW=98kx%s~#m`MҜ dp%=ɄXXz;/bNx)X{<^aDDw}?̏} yףap}'ꩃ=~dS?as@z : a 3 :7YaE``DD @GʒH=z =r1_V'=_Oah0@(,g}NJp'\1^-3..t9~%?pIiE9)CWH=WN]W壇NG&-' 3 );,. 6%^;3cQFޥNGuD=?(à' =ЯzF#G/7Ҍ<4r&-k'q;AOoAU}qGЧ]rM a`lVIƦ .EdKqMqs$I[8n5\*iE(OGb=2H^: mgdOb \t]xzD<6IStGQ$yӃGI>iG}Ѿ'z{'0lS`Ewߑ]mw C9kx!܄YN['rc tduKa dp{Φd_t"̞x|k'C A=^O,'; +/^:c r| g>O7Ѐ>Og9򭛲/ }` dK̀b[Ѓ'GN2pygq1Vy@OADANy'}(>Iz)h #3 3 O ]\?U\RZm ,EtR.F%D@_`Ƌ3Փl5^z i@_$__sq2֥Wt-7 LO]lm[D'<N`ZGo:NlNmF_xXHo׺ȂkDXp]d37׵֧S d>;*rn{Op#}"m~OsM93 9cj,xnD-Rz`2@7k \rz"=$Rm7(cd<2f iH9_&H P< i=k>!6A@AS[/12' (ŰX{d7"clD"N~GIY,=b0k8)c]`oSW)k!OK] iBGs# "'d7 \Sqӟ0p dp~1kj"  zKO/z_}X?ӱ'Ë裏Fʻ =h|1 |>F}PP1/y$z:3ߍ|c|=ۃ?i" :\_S`0C;-|;P2]YB8e8X"O@hE H9aF^Hq (x m}X;|8ԧuXmP{x?pzr t@ːo} ygȍ'sa s-ɢIdś3hy۷щ g@6g4BJ('ϩezz.SY,DO>uZr׎cq8w3W9D2g/f20@6˼,J]7+}9ܜ.$q$T*bq4^Pmic-1upϓoN'+u!H\@6 2%==q݃r뱜򮻏n`v==\:D":.k}ztճ_~>?XeKc0zO(`J d9W} y\//ձX=6W>׍!gLtMtbe$}r tAd{Y(?g|4$x=' !l0.:}F\=&(K@NЈL?M5 2 6yc37 l PϷ5춃!'#h۷ͷM|=y).Xǀ"?DooO0B}}eԥ>elg(O8a8,z~L 4#˳\=6ō jY V!HYHx@~B}@s@C;ec{G:r^Cz\'sc  f\cO: ?Pz qа*WrtJ"aE *iY΍󧯿/F5!O8С/ǏwẈ`_\= zpOȽA>+aw @67# ^/k~P]ᚠh/D8 m/TH?\PA ?o\xA9Q C"!( Gׅ|ʩo=a1IG%Dfyʈ dp5?#łyƍq#'13F5QzQ%Rc 8=h?DIzգl39/=@|67܇rop<:(Gϑȟ0p dp Qk7 (a0:v=ݢ/a ]E. z~uo=KQ7Y]#]nuO{Q#qIWPΟ0p dP`0r{<^ x=aNא[G<r 6*N -}jn3><P>1e 7ƳN>ai[@A_TPʟa ' }f>|"G77zϝ yHX` R6X,$k.>6Uz}A=@!v=[D&~َ-"',ej#y$a zldaz; (OO@DHӿq@r x ^RӧFiʀ5 dp AWep3v| ."p :~.}]{\cC` ח0pj dj0F<<]f&^:~  uy"tO #bxiOH~ON,cWt@ ?'x' 1|D{b9=Gzi.Pi3*by> {u.:12pV <"\= z>Y?/XBB~-*uda$\#{ o}PH9KzT?GÀ9Ԇ{wKW@>9%"imW"=Rߏ>Pܗ;6j0Oa4qֽm}H׌po7 K0o|d@ӵ]{fp&h{^.:12p]cNd'yNy# D"=cϿq6/x'e":zX30p 8O[O{Ol;"'S?w>٫R>'ROO(QYf,6a2Ш2٠c8Kv{ϾhrMhzr} sF Qk8: Œs9϶L0pl @Z'sI7!<YzDۙ7s7m=ڗYXI@@9(K@kp.[6я>P=6 z.o"$g Y H1 ςìo Y|Y]đ,εC`Θw~ÁO9|/tTý=G7b֟Ӗ>IyB;LYlD## #!$k} #>2\/R~r \. ȂgM4NOSvNRDIC30W̷s /^(xm3ـciA铨>y}NS}n:I;ma8  #è٣F@t# zR|0Pz7!} Aڍr,-Z[cc ,~\A|=$R9u=/-s?+ɜ0x='=r'a4g$qy I=o_mNA$XYQƀ!Gr rt4Zh V箱q/g}ewHP>*mG,~ʹ^ QZ#W<3d,.ޖ Z?`>9a> pϻaf~JCz"p?m}OleEGF" 3pcEk-Gu/vRP.. c1||= /;*{(Qz#3 3ps[/vnaTX.EƷ CT2 6w~:Yl4v*ɟa9vN?mуOh4''#e)2pScmj@0 wEzyY~i1 g $gvi 7ȓyCS'&< +gwk=[u(3{=ce΋h>xxj ?k'%f6v 3Zq^i: iO<mK0pN  fEs%*dgcjanz 0=!pD uB7c6 *1TdCWqˇ>r~$ 7>eAyIS-C9oLaܚyy c'mM<=`~m|8unb@,ZKQNhyѺO/qw~n)c /͏Xؑk5< ϴx1 4~R4.ESG8tf"E18x|/C5߿,Djȣ>ʂ2g?]`y 2Yӟo_kOx"I-l$ -\s/?z3oEAdnW'|8ub#&э7e.z.|=m;9dLŖkx5<"wdo gCaiv%ȹ9$z.GݤAcvfYmX|Ǐ ωFACO\=O!8O^5ĀocLjpCzGN?0x ~{}n΀K-O^6׶/:; D0YlF"I<^sn(91 ,)k>,0΀*zocm;93pV FCC%z*C7d\w4Rq+w6y F{v|bI9z)0G䃔?\ߞn9a?<ؾh?lw[kda |Ym R\֎tf`mWq.?gݹ/I 팻nyNﺽ΅tׂxU\z=k:(0鵱H<}.A;~ih}vfw? *gЈMo;.O~bON="x@{ wbj a` <z-0@a$ a 0?i! 01 MI:@a` dBa c t( 0`0@@67%Pa 3 9N a 0lnJҡ0@g s@a ܔCa 0@68-0@888)I@a 쟁lqZa 0pp dppS0@?㴰g^U\i"0@Xaya`g FӧEO?q30N`'4MHwԀcOz uxi?@8w8;Ưqpk_}x__/SQy-0! 0`영n#NGʁn" '.Յ0p dpzXXc5z='|2Çq$}O)O]_|ml`!! 0@6˼D0='xyK~ X^*@'@6'77 :FÎ/Gc3~ DQapplzҽuuݫ<Ѱwu ha` dS h5vuNI<~O \{0y3 yK5t`'53 a `syK0s ~v\)cqv>^뮟0)3f\K/s0#x]rekw@=K5DO $HRw|ITTO(|D]ճ7/}D9@F#,{Ĵa 6A~3]!z;ki{Ox |Sb_5"'@w@MӦѶiߗ5dAd?#SHOٶχTq/n7}^S^)RG.\[uRrԑ@8vFQ>yvDD=qm{}d6Lagcg&xO#C6#9U N AMhkt\3 _>prCZnQ9ngOYO>|8r < VBaXvM~`EΠ!\(k>`?a 5`Ym>0@9^~kڰMm8zzL q@%rM>uD5od@x pQ!P2Ms@$(==`P&p㺫:4ʝ?=?Ctgφ>'l<p3`{w5@`0N{o c73`V.:Y3i2\ȿF;HGh vhwA)cYY+;׵4mF?4t},g]9>^9EDG:Y9p10p `cؓ1;.1,(U7?O|ޠ52ьHR\ϴq(59?>$w'Ξӏ0m'F ȉ22l+:8"ka)5}rlu>o6,UF' V:A%fFӑ>f,>s K< %\?G20Η% cdDɵAj6x ;Ѕ4I;O]G٩pzv=YWvQBrEDOwC1֙?c^!p=sP1aоOƮh_@䬣 ʬ2MÍ6s4Qys\_{ٻ!Zӹ>J{k|T~(I?@wuvQԟ^v)SF Pm`C~=(CP]wpEw(r\z@::>P:o8?WCyхs n 1 gvs>~ߡCv_hTgXv$oU'I/‹S~}iA/5nQA#2a蚦^k@H,5Mdk<ɭqӑk?#D^_ a  ktc7HO:ݨAC6tZb ߊ6}QZGjpUWQ+_^t=f{ 嵪ڭV{c@aDyrq(_AfnCuD@=[;yC9hr2 "ʛ\m׃gmOۣ@/eu[T._[ϰew)7=ȃǵ>~S۪㻲=Oku_̺IHo{sg 'q2N,Ty@3.Fd5SbgDDQX 5r(5JԭM H\/2H^wy;#G㢟͒#ה_בh[03:}è GDb<(q}?6l,5Dn/Y=xZxR c5%V؍E+j _|6W k(TQU}zSJi yGf7Kt@>E.pg,G9ׁtf!⏼$Ϩ/'|!mM0cn~oʮaᥗQN1`-}ϰ\<7pe'RqP(Wo y}Zk3l5߱Ix@eenCQQxPXME<es pKF_X{60QF9X&Nׅ,5F6D<@ԁ!#`cyS@=ڹ u]7#?rcqg=ƉtAN:͈Nf0Q{Б].mhC&ᯔ0 :_:%aѯ0ls]_oKɰ?{xrax  g4Wt6o~t8 (*?(#F}2$/.#W TKJ>Y\y{Aӓ'Q9H5!Ljs >↸|Gw'[Q|/*WO8=O2(ߖ]6 K,r0vk?kiyK_T}aϿoFK]}Ti'56 %x?<\Gn~YycxrabKvmhP_VGS /}SׯUt(Av5*zPY^OU+>)",= 8 J j@FCy^n>M?eYCE UFY #&Q8R eGQ9 6v/b;v^ir!u0~hX4r#}1bܩ# 0 \]YYK~xy+~W}5(ϟ0<5˪Z?k6ud<~ͮr׆6_n:xTzV'ޮ}Dkxl 0\zuzyVc*P={ '0 ۑYNTVNzia~-a `+\u[zZl IDAT 1'Ͽ?aī?UqPb G,qrfSrN4 r̞Tfx=l/?~6Cgx}8&8hb|dXT =/3`߬͊ Er|z ꅗ 0DF\#r#}dˣ(熭|֧mɣ6yag֗Q>Z/'tDO5GLa ͮ۬ۜfc@x08xMw9QtS!t_ᗵfb;௵{|n>gU+q[F2(|jȥ_תSs`+w+ޫξu: Oq,x`h8<6D4<\ j _߉CFcGgr+c/*WOoGD v+>qAGrG=w rrճ a DXϱ\cY{oCu :G_T|TO~\J(B6?Ǝwj]N*;wOoa|N,OOw|i5ƫ*8Pzr[XN0`ukH]Kk> D|hGz#: 0ph Fk`i@号K6>Xl0TǣZ?1'41eaFa }V֓/ZR~ppdүo B/]Zs H'0"z*?&]0tLuE DKs .\Mc DO綨A9 =/H@=vgz@Wr,Ǹ ճ|0 0`v}wwfwcfMGc0Y}/Z +T3~tyُ*_^ Ęw<#~QJtBqO.^Zr=XQɇ%c$x[r\ſFz7E" %#,2 c'#vsl@=בkڟrhkth`z =0q0#iHJع9|7kI-^G. CU2^_?6\t|N@=xR;:jʎ <|ų_Yo ~T%>`+s` tP\9!5k04q$_c A\ē Q~./1.㸯sn㪴m9U=PrsEvn-'*- a LX{dwq]b'4kY+xnj aJ1|]?){'eG׺=ZO_OO{r`~߂|v޻G~aP;' dzAP LZAidM~Œ7[~'4G8z8%̰`4S@¯YFٗ'<7+9^ xyBHS൨:'#8v'8z@{d#n~ʇ0plvI$Z1¾y V=_Mz\> _fnvy ͪ^." *8X>9w/Yy$Ss]sz>d#1mS툽Mm#@kms<}s]cĹXj{$.u׵lxU6m_iѿp'231p¯ BV#I_FF]EBd9^@op 0T:KqGekƯ [5^#0(u:xlݯkm[Ư%xc#PouoIp'y E8/3^K*}7<3@wtBrCpa4! c&RQ{7u\n>zhGܶa Di/l+qz V_/ṖDtFG=?WwdP_V0~33`:/A+vD|m0?*7 @U06 KE-opv}{o|? |aPp ]c@rz NG_8ǯ^-㸿.g c9 'ޥߕc3Pz|=p'Q/E, Q|I =x>S\}eUwxO W.sn7O3ޥGNz߁6l5ȹ/l6}>mDFLa 2F >k_z%0hO9-@8o­a~ҹp'>Pw6|a9/.ro|<>6W \^o߫M' 1r /=ʸE}=r?O[5=m$O& }޶a LX \c*r=>N '}W9X#ÉF x?_k9=4gw|F>m+{ w෉kIfPvDCzc a~!Zʽ*51^1JARxd.X؟nk<|p`> ݹ >nfʇ0Q#k,h2Ƙo+}?_U|l 1&kMEΦcoXil\-&2|6{w`3v9|Q]})"߼0oW1|dcPٯ kn:$ƀKUW =v0pz=>\nl@Loޫ{]~O@mpܢS1^>^7{Ba`,{qro|BM9}e앇1?Hfŏ r_]Yr2< |&w8MK pOç+0r#㚸@-/8Pf@omc; Юm3@kkيq  8ʯqq? 9Q/=ˍ@]c8A?z_VZ)B&~ԇ||p:?i~+ 7E*HC8/xۅU|9EwǕ QW'~0xџ*7S E4pA;|H 76$`E7}ު)@xI rs{c-~!C$B%R6{Q};9W12z*+耋q0^+=6 )x;+ &)l:sQC\W;ckRF`mbxm\_7RGa`}5c.e{%<20>Vu~[*FIٷo+-sSjO_`K6W*0[հYgPAOqG|2J/)2Rx\Q^r^ە8`3#dXo]m^>sgI$ *mz@۴I/q+"wR* 0p8 Y9 =$=dxó|^^?O}K]RK~I@j_-J;9owOJ8>X X{CL]҅X d5LCT0lsZy?&XTﮱ:=5  )ߢ a "98 kN}vƷ//qP /4tWI~;@x~9UoIƳ"w8$SB)sZI&fbCq91?/߹. O]CT.@x x?kt@Mck8~U'§s0~͏OV&a_^'^]`;L? D_: b+h|n@h]c{>:]OBDq_}7@΀D.Bl1,~ҷ}/s|O?}_JN7w1* o8x1qPF쭊(* /cGt)3]I7@a` 9i{@pŚF>0NNN|U0e u#}tQ|3+g33]#u03}Q]{3Yx775|#]W3 '0(_$ 05^yl *9G12I&aƗ`QlgM]Ů_7e,[#{PyV_w_y{*;n P3]f" 0tr:L&wd#-Guy%cy9|6ćb_Jme5?XO|<_fG^+1~` Ѽ*y0@8XY{pxVľ7Vlb$ Ͽ&O󭁯`T/~ $PeOa @,1@DW~G;ƣ ڰ$wݓ@޺Mt`t;crNa g=ຏ h/F.Ep#0>W'WyO篽!sx췿-煾{sv'<i7# a e@z=>xR0ѣ˗9߾!ܖM_V'IPgP_ۓdv @ @ @ @ @ @ @ @ @UJw1IENDB`ic10PNG  IHDR+sRGB pHYs%%IR$@IDATxݎǕmzdD2!906|^|O904EG4/5j6YUG*#d;wG @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @SsZǟ㿼9?Իߨ/U.,~eg @Go~loxyosËz=/~7U!\dG;v%@ @NX >8F @nJ  @8a束PO{hWY<{<Ol95͚_Eϟ~_yo[Rll_7ޞAlƳ @>@?{~A~e2[zqzqzArvtLb{fRҞg,kbG @ @8cp @ @fG @ @XOz'>-ge,o_d˙S\gk;K{[gS9={qsٶ  @8/~ow}X2vIjy]]ij}[7*X.ZOU @ @8e @ @n\W~ @ @3 o95$;|&sw*\6ͶL @8`2B//9۶yvYs9=`o]  @ @ ~%Z<4TnwS @ ?o\\L9oXo^xSO~~~&@ @g!7wjEnNK(8 @`Orﲽag;_7P  @ @8Cd @ @xC- @ @h؛){&@s-s}g @LIZnwL^WmO| @  @877/ @@  @87YOfϟ?św^oԺ9/9|mPk @\[>/?oHozWoiKX] @ @3p ! @ @p}O @@yg0o~e`_oYaٹsS92' _b,L @1Ny뛋gl㾨ѿ˿,:m7nQ5' @ 7"$@ @Q xT͉ @D>)\nv|ws'פK/b/^ _^rxɁƷ-^r`ߛ}˗/OK=`3^6  @4'cq7^v>`w7lH>Yw?Xz\l]<m/G}rw v=*8w\\=|ޣG ?Km|mۋos @ @WpJL* @ @p༏ @ @+ 4J;b-f9,ٳ&*͖S,/9]o%eoNfS6gqs|M?J pJQm2ƭ/![Sj.&@x=?{>|A:mr˂ϖ\m/O7G_rmnׁmτ~ǥ6mv<_ҙp  @ @+ pE( @ @9 pG  @ @+s3?&2$j˩Yӿl/Sh⥿߶r98i7=`9Co, @GhN~s˯;[5>Ҵn߸۞KGs^tBկor}U^_rYpu{r}t[6%ު>?rߨ7\Yl{&VͮgU  @WsR @g}  @\M`Ӹ.YkXt,9'[ǒs3gL<\o/.m97w/۷g,qs߽իemr|r~?^R^~&c38@soY~im=}o{1P z>|#>t9޿wo7;\lвzk_. \FEk?Lg\H? @ @6'?w puh<]@+JΔSe/zJ @|l˶_ rƱ}#` %z^zA'@ @W5ڹ,9%e7]پܾx;Jx__ m~eygoKg p$}G-GuIu~i8+~>}@']_o-/ wӒilo]7|m?3 |Iw^ontX;k;$gek|j5@ƽ{Oz\m7[n<[`^3a^e|zח蹗pG  @ @* @ @8#h @ @ [ɒC?qw]OeMNkˉ^~oo;[lm77nNsӜ_LNA )wcgƭ:7g/\vwEӬLo/gM{[\nm3}v}k].JKſ?|ޣG.?aM*j @ @ p @ @ psZ"@ @'+мktXr..={69SeۖSܬrfr6ñxl/m r4nKs`#GINI9o.}o{9꫅krާ7n{ƏgԧOxڙy9Oigʶ :mr/pk~l9K/~nso{&Ek?]?/,mo  @ @p&0  @ @>z%@ @g"EϘf˙M.3%Gc{qS]-l_-4sK[mfIsPӧovg{o/qsfRY@$М7ƭ~syiUkƭtm|[߶O˂=dprk[SzA7<"[/پL^]*v* @ @!y'$@ @%{ٙ @'>Cr%buXr.y3ޖsrw*\n}[{s-eիWx<~|L7g p,7G9)[5ϗw{ۛO#wrt&wo?wZmoq=X*w=Ԝ^t}ɖTi/{>fk@mۺ[[CR.Ek?Lg\H? @ @`W`k[QɟZƳߕLۿ~o4L9U⩧$@$0?~W-U;z3)g|{S @.~/?o\ke7(xo+h @ p7 mmkɡ߶/9[ol?Iw88vG7e<e<[ٌM|La張793#mL@$9[7nN~/ro}gm7>,j=Z5~~r+"&p>>Ko nK/V>zo[ϗmoKK۶ Wa/ @ @8dx @ @& Em @ @X&sж%boσxyJ△gQYƳx.k?^.2{92͙it& @GS}&@s.3ꫯx/G?)ẁ׸ީ?'w-hNms^gbýĿկ*^thw=x[?-^6޻p֯pƻlӜ!ow|w<htU~ @ @pøj @'u8  @|\-glrzs}5aM s9geM׏n޸3_϶^srmw{ozvzr}? @ pnq1* @ pn( @ @i 4ڣo~x,9[goVr6}79)3͑߱\*  @'"x79Q3w~s?͸'m~*;3|E~>zT}k9׳wӮ߸_7=mX?k|Mas׷؆yQo+m2^_`}$C @NX >8F @nJ  @8a{eAkGsB4qsӶ75h +;cݸw͙{?[9ߟŶiw١#q;~*OaڝxƳߔeq?5U p|w׏^q5ӶOM7nJR; @ @8ch @ @)I @ @gt/^X^jFs6Ѹ9ͩƔBvCظ9nmqsv#w{9ݾ7]303ο>l{{ǫK?5vf|7niwʶ?+ 8@Ϟ={}ΨwqӮ{M} % @nkj @ @` % @7 ? ׯ97CO>]g4'Cw\S/bqs/\ꫯK|xݻo6O{qMs+;ο>o}99~>k}@kwmq뷽w||=_{>|agq}vh dN @n`  @L dN @n=??`4G5x4nǏ^w> p$7H~s7G9~ߣG.}.^w{3eP't|;?Xϳgϖ?o~k[u>`|T=_{>|`tl~7z~h dN @n}  pEšjm7ô3OS){CO;Sy]I ً @}7{9!iw@s؜ON=}oܜ x9eE2W֟z_a>u{?Lݜi=;}CsOKWRy |t[>ۻv=m|R]TpS!@ @', C#@ @7%MIj @=2ͽ ^HsFZ5A[9QlNcseLn_s -e>z4u/u߼sM75?^~tgN˥~e3SzJ/ok{=P߻F@ @>X @ @n @ͱzߙ49m7Gq7nb p }ٜSo=>{|68~z}lKm'@x=7x#=nϾp\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(n|f @ @ p\ @ @"Ga  @8; @(( ߗvo[]~i_|Ŀ/x/h?Oo׿WǧqG_xLf\$@ 9&@ @p @ @\8#g @ @8KU pYnss#ηwmz^Ӯ4zz|O?kof\]I&툚 @xoA @mnܶ#j> @ @-/ @shrsOsկݻl?:oi\pt9_O/Xl_Kc{z}= G # @ @!P @8G>'@ @C3>> @ ׋̡ 3ڡwes70Ǽ$@#U @ @8a0 @ @a\J @NJ3Np ]L9ߋN |w[ Lq‹/gi\@-M @ pn12B @ n7 @ @ x##$@g#Мx7'91{IYt_o{ɓe>}l}LcOmpێ @ @/ @ @&m;C @"pZto @hx3rܛ#2OW^-C{A/!|g?O$@  @8I7N @Y7nSk @ @$<$A @)09SV8}&@o<l˞0Ja}N @NB 8 A @>W @ @$<$Aܴ}izq7vOlNeƭTm\S~gˠ]f&^`*o|h/鋲5^*!hgԿ0E] @V WAjj&C @#$@ @X [|pM @g&t&Ѹ9om{9cƭyn @`^:7^u=;4yL~6qs3߸ױʎqxX/no#k^ @ @ 7# @n#k^ @ @ 5 ~$pNK:cӉC_̦q뷽KcGCٸ9;Ӎ[}O⋝onmsb^ @2']o>e׮O{ׯS[МW&=c`/ۗO h~z7n'0EC @Y Y>'@ @WpjNj @ @p @ @ x՜:q6nhsJ#;ԧӜίO|d>o#59og4{˗/ges/ @`G7vl&@ @A ṕ @d3 @ p ar;ghٸOS6'9no|el[6}7Tjjxrڝ9[MJY`ֵu/Ǿ޴;Nj򫯾Z?LiחFt}hdr7gq۟gJߌk7ו @:p5 @ @3p @ @p5 @ @3 3;`:l6nNis~k_O;mnoSXc_sP'rKߜw<)^zJƭue?{M]~64ŋKW[q۟юo5ە @&|&5E @NT =0E @nR  @8Q8snjNhs83ޜƭ7'}7 3Rfc1mjsz={v15mNk_sӧOƭTނb@ÞӸ^_/?|p{u~Kc[0ؼޜz7uy4uQz9/>|~(^5n4u3Ω$@#g_ @ p&nɁ2L @ >n}  @ @xSfs4ߜ7n׸9ݿw ԉǹ^Uzjz/urp'mjw}q=X@sS?0=zh~(~k|޽/r%f[ۂ79?hbֿ?_Fw~\G7f @ pfpfp.04[gmZǔ3x)  @88ce @ @pm:;)is/'9o7nx}9w;~kܿ'MslF@s>v=z~iÇKHy?4^4͑o}s?iɓ'K?,qo7ҹ(N @Q sqgs;|rܶל辰-hmwk{۾,qϯ[w3?Ty}7nN_S履~.ʮ_xo0;ƭxU @uC @L 3;`K @#uC @L`M>4G>`/ۯ8}F@?hnsrZ't59[iw6^<ۛ;OI;=?zgߟ]/ʶ?[:}G9Mg4;b898Cb@ @ @yS- @ @p @ @ 7")xre/Xœey y?|y?qM>s3Ly?XI tjq7W׳ƳN;[ @|n|,  @ @ O `S`rkgvMl^˥Jsʚ֜/ x@ϟ_=z~޽{wi hOל~aiK7}&@s`s3g~J>=Yf]vlq3)w~ӎ|༏ @ @+ p%& @ @y p  @ @<JL*8opMvmY>lir߷iGI? ^Էɱ_zٟJnŞ7kSmCgwʶ;]y y?'@ @WpJL* @ @p༏ @ @+ xT"p&k]s9k'pS}{oJ\U`ѩ߸_s_|tr7v-} @\I +1D @[ >~FO @$WbRC3I\{-WKܜLO~ۛvN5nƇλߧV˔{oCy}iAϏ=|z2mF:lo<+ 8=_q뷽θ9/]f=v'J{_=]_]_eߴ?O<Zvq7>t9=z~7=?ǞwϏ?s>OooG7JNW`ֱaׯoMƭ_s_>O;]̧}l(̘,t=3 ZgYNO޲׸s}\q @ @p=J @E s9RI @C3Ϯ@sΚCA\.mYs߸9O>]kK-h׳q6n[7nc{Zs>͸w{~Mqcr㉛C9gO<.gϞ-ϗk?O#_?JNGSׯo ~ko~{][w[8L5;M<~ۛ~7n{q뷽?87/ @@  @877/ @g\.{9qͱ{EK~ioY3ٜ׷q뷽qƭ/ w99&gsF{~O;S6G9ͱ|Ůsk/n$@]~u}oF޸^?|(MN<~k]w}kOPo^W;7$@ @X7n55 @>K~h<]<]nה}/z 7 @8 8dN[9x֜]&%ߡo/7hqoY?vܜ7Ǿ9 AlNbo[5>WntC;D|m'O,?x:o{K*]73>|8.>cqs=hi׸Sg]~kK}o{mo9[pƾpGθ  @ @n* @8W77 @8@3R L.ljN<9wa~4}Q6~ٲ'|ٸ l`cߡGs{<׫ h߸^;oNh㯾jy߼9)ٯ9_2M_>L{ZM?J/0،7㷿l(~U~q׳w[53w^pxCg"շj{9&@ @p @ @\8#g @ @8KU.ƗM.YsKs3scm⎷9myGs3mݿ9ͱlNc5{'g)<,nN霿_^ @ @-nK @ @ pێ @ @x[PDajNe9x[793ׯ_Ϗo-uϴ{*e׸i\=߸9mq79q88O=x2:1y=9:.}]~u}o$`Ss;͸'tn{o;Vv}u~7~z irڝ=ex^?7? @W@R @~ @\A3ʾ@sn_:-倾oϧ\'O,qkNSsO 7q7?9SǷ~[v͙79i߃Nj7^*!q7CNj9k7qsq}er`=olΫic?q/GtڝQo<* g4nC׏/gڝxڝi⮟wm-y7uoϛ޸O3o^o#l~ @ @`pۀ @|n|  @ @gx|ƛctgs>}:C( e4h7qs#ո^d5=ώ&gp3z|}}63 :>5GsZq{>c΃uoߜ}?xsYO֟vl(eXz0q뷽]Yoً;ޮ{7Z댿5g?_v{o<_6wݶ7n5 @ 7ނ% @ pmG| @ @[<-(^:\`ryfP6Dz9ɟvAoд;esU6qƭx7;sw~|EѣKc{Ͼ;ovBݿ/z4gϏ?s^\^k̊whso{3KLS?VL{ꫯɬ73g4x62#8]7;h} iwʶ?m_o<{~ @\A + B @] s?O @ W@Re_97͡lǏhssh [X:ηqyO_wur׾_z5]D7[5n]o[5>pAԣq=)߼&wϤh?}F̏?Tٸs4nw`>14{S׳7ϸfֵn l{oͯ8APuy&eS39Tmd|,U  @ @ 9^Nxոw.g;lǧMx>=?}2{/zJ[`o~ޡOigʾ~Y<+ o}  @ @Sfs"3ٜʽ 5qv{ۛoqn7MćjɁq7n׸^3o{NZ֧G}Z5и~o{}qק=&ԛ-[5ߜ]gϖ.?lg,;oA?Wu1OY?Gs7=5yL2޴jew~`ߜo]ߧql~^A'@ @Wp H @ @sp܏ @ @+xT\ٜ4'rprrMԛxSoZyeH*lv~[5qo۟y}ie^xlלos7Os<|rbeLzw~;wz~?|oߗ_~߸-;%g^׼⥎ì|e @ @-/.0Ik\߿ݿݜT5n5xxv?-0-߽շNG_s>ԛZnoڛ@ϟ_=z~C~ox+{֙`ԡ߸O3o^o#l~ @ @`pۀ @|n|  @ @gx|7{)'п{ݜ~{9e9f.4}sr{e:Ƴ_u3Ω[J-G< @ @;xM @ @p[y @ @wx;pl"pYjSsPߜɱZ9u{k{gS|'9boiGI? y5[c9vl=_?:ix5?oms*e׸k;Ϟey&g4n{Ɨ3O=f_q۟g<3?7>#m @ I I~'@ @OE OH' @|I~-ajSs^xLӧKܠ9t߸'xZ5n|r(7,w#T&wSg׷]/?|ٯi͎G?omsov~[5o.[^=\)T`թpѩ^z5M]{gߌkp ) @ @ P1 @nƒjJ @ @P13hSscwr/Gn/g9~kܿ<939xڟ>%z>5-6z?8^}Iw]ԛ\ώ;3z|zz|km:o׸^>s9x[qw|gutzN @(WR) 4g9y39t́kw~k9_r?K<9ۿ-RY@@w6 'ONjq ~?49Vϖ!4xq뷽oL>^=>W}?~}t=z|>o~˅xq۟gqNRm9A @!;pl"@ @E r$̓ @C3ށcshRs㴗՜ɕ޸7nϔ79ans^~=M_\6 |s C8V|z~q^ڟvO޽LAs;ߎkm5'ݻ<|q뷽4W}?Lk?ܸ|z՜?ǯqpG  @ @* @ @8#h @ @ p$U^RsrPh_s׿ ;9a3=߽NSjܜ9?y}+#gOn<zz|{h|V|/!WKm5n~ko%01)/]Aw<:W~^݋2,o[툚 @xoA @mnܶ#j> @ @-/8w@|r}@ S9=_wln!{ 5ne}4nsi6mqno?ikf?i :;ϟzsrόcO OH' @|n|҇  @ @SpS9I @g|҇ |7'q7vl`s699^ӏzFڜY&9͉nisJs)ǧ幌[eei Z^a׷VqD=wY=^z%n084~yl94.+_xl:4ߋ^~i_ߏ},qg|  @\U JG @X 3>xN @*WRKrښƭ~s2OL`voQ p|9g$==z6'9͑~Og^׼~鸺7~ǻxi-fy}⽲=mソ9z;Oz4n{ƭ߸7'c}4什w% r$̓ @C wD @nH @xg&&5ggq뷽;{9ߌ{w5 ]=93ևΦ9^LRvϬwSoO~jeo93G͏~ĭ/;oOԛSoj=ݿշ5;Ѹhmq/{S뷽]/?~x(^7~?tKcgt7]iw[5qO=ލ[5!hmq۸23| @ @ U#@@ECǎ/3)e/nMUjWCx>4崳O= ٛ @oa2H-М5ǭ9onsz߻woy_ :[: pT}@s>_u˗/gzxoko{0ˮύwomq}_߸^(79э[5^y^;&ԛV|h[o{~hSo[5Ss'9_ߏ~n{[8Ͻ s?O @ T!@ @.A'@ @W + BwYߴҜ=x`^w}gL?g瞃|bsϴ#ۜY&ÇEիW#]:Χko{S^oi׸9{9෠9n{{~ko{5ij߼>}||:zsɓeH_79; qk߸W߸so4~ @ p7  @8w7? @g\Ih_sܚMmqv|$@tz6ngtohxֳq׿]/o{O oq7~h?l^{;-h{9o˽Nu{χwk֩3qo~oN}x/G'yM ||3^s^7:Yߦ_ŦgmM?jY_2&xov.[Cktߍo{\sCsCoLx/G9o<|0/  @ @Y p͠  @ @an6 @8K8f @u&v7nNu|siunglpszRv޸w͉nܜ'O,M<}t[=͙~ϗ^_vg1TxQֻyǿ]_:=<|T* @rֵ6`ٲ~-++u*{%^r3Ny*%"Et>pa& 4Og @ ܵ3r @ S)H @+];#'@F2=.Xm63r^kUW8gvD;>|Ȳ|7_r|iA~2G?ϗdz\3R2eO N @ @ pz'@ @"0 @ܭwܭ  @= d~gNm]JϜ,9Z9Uj'W:<^72|3zdl/<2Fq^qMq~oY>xl}\~=˸56y_V,_xnx^q2ܷ>G5Ǿ'g{zdq2g}qv7O6 @XX&$@ @  @ @`e2H @`̑͜ʹ\<^7K̉lʭx3g6S9XM?;;kMg|ttԎgO?Ԏgl/V`\ESgg7=.T"8?gu\s3gy ʉ_Zϟ?8s3>>nU޽{o߶8g{gN~Y>8g{A8`u`ʺ$@N؉Oe @ 7NFI @vp`'>  @ @2`d @9]9Uj:g{Ug3mY>8Ǘq'g峽d fs- @ @<p} @"_S'O_嫝uq%@x`5u @ @<3\ @?/虳9ݙ'>|OOO3᧓}ŕ_vY>˸m7_Y>ۻy$C @f, @ @ؗv @ @`Ƌch @4QΜawd~;5>~؎gP#,q;m/_gY>ۛ˼ x`[9 @ @Xb* @V m#@ @ - @2;s3?s3?nw d\wƕ9gSu~EPԡq[vl~_q @`'O @H ZLS!@ @X'c? @8 84 @zm;ֽFyzzZ?c9S @? @ @}p>9 @ @pޟ @ @>x}Xes$@*P5{9SWYm  @.EO] @ 7PI @vp`=u  @ @B`! e @t̡ڟ9kW5GŶ @&<p&@ @3p`& a @ @&I]m @ @xL0 @2>s+ʝNZWӧq~ոZ 'O R3 @ @`nyu @I =Aj @Y;:F\+9S9_[g8۫R/_ @`O좧. @X Y($@ @ @ @`!2L @2G>s3Ǿr^NZ8==m38-EK @"B0  @ @.n좧. @Xw,d ȏ8s+eNg$W~[ 'QS @,L - @ @mFM @ 0X؂. ^ s3qq8s⬟q_8ŵߖCP @3_ #@ @p` @ @3/ @ d}z<ۯkF5m  @M x&uM @f"L0 @ @M p&@ @3,aX@f9C{~~ަvv⯾cA*g<ֿܞ@~>3w}\~?OƟ>}jg5qk-FۨC @&p  @ @6nl @Xw,l 2g5s\36sd36~_r|cWO ?ɜ|~_r9W%@>5E @f*Lư @ @>ا @ @L` cX$9Ӛ9C{|||t?~܎gٳv- Ǘܩ@~>W9::j999ii3?lFr|9g%@x`=u  @ @BXB& @E ]%@ @ ,a@fNk漾{<}U~ʿx9ׯ_;r|Y> po~r߼yƟq2^5dz~ί @m<: @ @`an,l  @l#6j @ @ څ p @fkVn>g_{wjgP{@ʈ ,O`u駟Q?|?^\@& ߪ'VV @XX'$@ @;  @ @`u2J\dfNXkW~qWjǻvr|^ίڵ%@|CM2W;U(|W @m<: @ @`an,l  @l#6j @ @ xp Q`,G5sZr^+7q'O-_'֘;gȸ!nn8Ǔqϸڵ%@x`5u @ @X؂. @F m!@ @ -X@f9)dVh M}\~?`8G^@ @A H @^ { @ @ a͑=\bW۱ θ5vEPC_{:^+%dSC@IDAT;@j5_6?PN @% x`f @ @`'@ @Kp`f @ @`wLS dNogpgq'O\97rWYq[sW*no~wo8'@KV  @ @n: @XKX%c$@ @; x p#9ę9mGGG- OzW?Y>۫zUޖ] a_c~^Wsk޵ז,QK\5c&@ @8 @XK\5c&@ @`"O s38s~߽{&͛gŋ+ß9^Z\,eUϖ]l\<5?mq~k  @<3\ @ 'QSY Կ$֠6_ަlzYکm-9cǧ!ۛZW;oK( %1 @ @8Μ'2G8?Mٳg-~q3v6W3_🟟W6vo߾mq}_!?9֘,Lo [0%@ @: @ @`an,l  @l#ۨC*9[99Μϟ?WӫY&R*elUyۻO\*YdlUy[ @`9XZ) @Z T$@ @p`9ke @ @`kؚNEC s3?s߽{xW\EÇ(2?s_z*_W#Y>- 0O @, 5@ɯQLަlzKֱ5 @̈  @ @dOL&S57oԏqϯA <~/ rڿ,U՗rM @&0KQ @ T7rM @&x,E  0G|kwdQٵq;(u'O>3nӧOm/<j @<2X @ ۹E @%`  @ @vZ@lgNw|dVYp9\\}~\m]<gcq:ܹ@/Ssw5|ʯ;犫^~vxƿkZm3 0Q> @ @2X:% @I T&@ @eQ@ 3o_=gl/٭ϺYw|]/ǏW6A]ڟ6s3g<v=f7l/?cw}ǶN8s#,_6ۯ @`Ol  @X _@'@ @2 @ @`=w1|F sp3?s|rn|qg^j0׸+Bg{_֯~j9ڵ^3~]5N[[+gl/ϟ?*>vd{!|X\ߊ/s3g{gl]%@S<0EKY @ P7pM @0EKY @ PX69 dN~gof峽3'?g?ÊPqfl/vmd28ll]d峽[c[3<峽wIƗeN~y>WN^9gl?,;jܶ @`Ol  @X'O/S㩆Ik7+_Ƿ׶کm_~yL]*o_lm~S:>W9[ DO,qՌ @LD0 o]/ZkI8s3?,e(_kGU6ё|qmWY>q;Aw9)&&@]< @ @`!n,d  @".z @ @xB0 Y s s_|٦9gpƙc<52Μn"iPq -l/zw#0yQ,Wq_Ύjg6l/3w峽qwgS#&@x`5u @ @X؂. @F m!@ @ -X@fNk漎flێsF9<;srk\gNszۊkyR*W9~k/ @), @X ]8&@ @S, @Xw,t 2g5q̑ߌ37o88ϵG"os;9S/׷uy~y_󑟯x8jsc*Wm|~_~?Kq%@x`5u @ @X؂. @F m!@ @ -X@fÇ۴2Gv8믭Iq3Ԝ~/9 \ '\\U׫mY>/Ǜ۸Ody+2^{x'@y x`ct @ @`/nQ# @ @`n{} @E;¨[`9/_lϟ?6356dz3?o߶&߼y~Y>8sv3{dz~ʂ; %Dx^~*_9,k Ԝ993'?{].}OY?8g{c#&@y x`^a4 @ @F<p#%@6_6_ 5۟ZW;oK\sei,WԶUΖl# m!@ @ p Q jjNn ;28Xk'˜?.2Pg{_f99ߌ|'s\\\߱?>G9/^#ǟqͷʏm|yk2v55;==mMf9[GGG[ȸکJgu7,U?KgR{_vj[T_Nj7OSg\k[ Xf{U6vp3~  @`YXz- @J T"@ @p`Ye @ @`+؊M%di>|59cq ȜߌϭX\r3gw,T?_Y>jvc;sw9|gGuW|2vm:7}R_wfxow\gK2ͨ  @ @$7&q)L @)2ͨ  @ @$ĥ0W dX98sXӔ}<J8|'@Dg9ԙqcK@gq>=fSKmzT\Lܦ 6r 0OOs] @U rj @S yQ @ @ x^95V385;g{϶j/۶z#mŋVomgZ\9?9}jY*2? 0_5['Pk57ewcWƗr p8u4  @ p8H @C XG @ @ x<n*9s9w3^9aUNeU}[5Y*WUٳgmWh_z5?g\F3'6q׼޽{WMuvf/s3?QM->??oq_lBj0O7=y򤚺rW;U8-,S\7&@ @ĥ0 @X\7&@ @`2'?s3׭|q(fNcsVӳr?s|Uӫm'y㏭~Y?3͛7jdz~U p=V_OwNmuh>zs~Uϖ) eQ @ @Iĥ\_(SO/ISۭyԶXlozYکm- @% x`Ie @ @`KOl ZӟZ}gg9sq2n s398g{W9gl/d`,G?K3g峽9N CC9_OR]Ϝ|GKg꿄|z LO,s݌ @Lp` @ @`n,s݌ @LI\ ̑Ϝy̜?񏭫oϟ?oq0fw_|g峽5vAfx6ʌ|ejƹ^^j峽3g~l}2'6 6ɸryүZ?8g{qfN}}?F1?y<ۯ -Ǘr p8u4  @ p8H @C XG @ @ x<n*9gc$>{u9cq4f9峽[;23!V.j2NͿCe<2U䤊?~lq3HϜ݌| @s_66,q_W9oK) \W"@ @M ! @ @)aY @ @&C@fa fw߁wߍ32sοTk,eۺ^搏Wim~7ӳޱPy>LKO{@kL@A XMr,﯌\,?Wxxճ%@e x`f @ @`&@ @p`f @ @`wLZN˜]sS"s3g?sr3|lSG:?j;w d\׭KuMOs^gggVzHuqSONN|;K|Izzc_' - @ @nL7S @,N - @ @0l52G:s3;zY>2)NԿ ?@P5wUf{cjs9U3Zrn^ ?cIwdN|CgYc99ß,^zc_ƛ(Es\WƸ @ @# @ @\ @أw.Μ/^f峽={˜?WVqgY?z@589Wr3ce:v<!Μ/s K~Q3mǙq} 1,e G/1&# @L @X[3#&@ @L @Xw,oͮqDgNwؿ~q2ο˜9_+W=^9g{dz~?m/ǟ|2g7sz38sg3qfc;"g>S~޽{׸޼y Ggێ3>f峽q7|'m+ zj @R\ *Evj8aY>۫q @2<u3j @ 0I I\  @ @e u3j @ 0I;&qͷpR s?VS~|Q;qU+9Y>˸5vE>#_+ms9<^7wfX;Y>sPx9c9^3skظ'@ @~VVyAw|n d6o߮ގgl/jI׌|W @2<u3j @ 0I I\  @ @e u3j @ 0I;&qͷpR3{'@]+l}ϜϬqWl-nZij5<^6ݎl7sL|ƙ3_Ϳ9.1Tj>9^ܶNW'''m9}8Z!vkaY>۫vm  @`X5 @$$.  @ @2X5 @$[8s$+ǻF<ϟ?mŋx9ɓU; F0*P0@zUU.sPo:׉S 9*z;5z'@ϸ @M<2 @ @`n,|  @l"&J @ @ xpWem3G|GPouv|uwFW9[ @KVX  @ @nn_,`w]rl:*99*![9@Ϝ*n_+_w?^V8w~k|xIy<y<$㻶g<]W lO,{ @l$FL  @ @e 3z @ wlĴBSs?~&9S=cuY2rr}+Ƿrxl3Y+q;8)*Yl A ?9c9c>9<'g{sXsc @ x`kg @ @`c76R @,W 宝 @ @`ce̜̱|a`$ŭA'TUd5:*5WMy~>zUx,?߁Ql^ Ɵxˣk#srxsn qzd3o @'Ƅ'@ @ ,) @ @17Ƅ'@ @ Lr*ko3u@wU"s3^ʭW?`_N5[7)ƙ~c6 <=D @ @ 8e5) @ " @ pn䲚 @nt @8H7rYM @t7 @&E @CD @R \V"@ @] !"@ @)A.I @ @.@ @ @p դ @ @@p{ @ @A pjR @ @ =D @ @ 8e5) @ " @ pn䲚 @nt @8H7rYM @t7 @&E @CD @R \V"@ @] !"@ @)A.I @ @.@ @ @p դ @ @@p{ @ @A pjR @ @ =D @ @ 8e5) @ " @ pL{%7__Vq;??oή?}tWHU3 @x` @ @`n,t  @Lp` @ @`Ѕ3l d|W~Ϝ|~_3ո- @}x` @ @3p` dx @ @`nCQ @ @`02<2g>s3rq'''->==mqgWH/_ @6j @ @ 3\ @ ۨC @& [0%@2g>s3ݻwF*͛7ь3Ǐ|s3~?~:::jZg<6_Z @ x`C( @ @X; @P #@ @K% ?$2g>s+kW;U(|W @" )Z @ @ Ѕ3l @ 0E )Z @ @ xBΰ @g9s_ٵqCT+OY>jז @OLR @,T .a @ @)nLR @,T;pMz̙Ȝ׏ @|H @ @ pc&@ @p`>ka$ @ @nO>렿^C3Μ|EԿ'5vET+be W_qͲW<1<- @<!8g}9 \I1 @8@7pQM @)"&@ @(wo<΁h_dgqgl?u|3G:s3ɓ'N1sb2ouU,_6=\yVu38'z#,e|ӳ|Yn'S @,H - @ @mVN= @ [{Xf3qfpY>ۻLxs>9Q32'&sh2ӧ&^O^[<6=^yf{Ufky~_kK p7y= y=gl/}:瓱w[\{ @ @ @(7J– @??i,g7sx[-8s~߽{z8g{99o'͛kGŋv<C96^Zܖ,eUn={ <_|h_ίu. @u논덌|j'Uѝ؉Oe @ =(_RkymW;rcqz:loj*_6k- @% x`Ie @ @`K=̡qrv~~qC0sw2g:W9@Hgϟ)>{ŏ?6wC0s90Y_|۞5 @X X$C$@ @  @ @`{{?ܦٳqGX9fǐcQs_rB*^;䄴Cpko)8߉q8g9ҙs9*X|zzڊ|GG};c98Y?̱8g? ?<2s}=>|k{o] @ @,2 @Y7nW @ @`-}]9cʁgHdť[İ'sFW=zTjC;[{CHr9~k߹gq g嫝fy<2G:sfgoU]m3x(߮?3kן\UZa>3g/b3? COlM" @XY8 bIDAT+#%@ @[ 5 @ @`9-}agD4dÏ#=i9O.v|i 9?V~WV~yn q{@Lg9u|9gl/ߛqdz/,eo;!;!g{Sl/8O/g{S-n  @"'-߷3vCs祜ոC{v׏wV6agƭUmm~Qw[өH @#'՝Ik/jxֿWՍF.TԶJUvȷo븕ߦW7]Mom]ֶ- @^;> .?MTXUox"w+-rn= @ @`{{-Gan9 -ax"/>hLJC-~X;0-assXv9]_Z ׇr<\?_^\>>|x Z06_::Wq[7" @ 0g7:F @$ 5C @,w疤@{'k[o9XrlfŐ;QVr6^^Ǿ9CUg!393S90޶+s3y,yl[*Id*Ws;]xh33=8ۻ8Ϸڐ2~jdz|q<U.<\Sq82^kKy_Ovƃ{^a|n[}m/Zsb2gfo?(gNXsxx֯^xl9EW&ܟ=jqyʷ;2G?Ϝ߷Qg{_+|E^Y+۬qqxx'@@O^~gy֮!nׇ?a%~?hFG @"^5B @-w4Y2i_VaqoICorzW9 öxvʹȜq̑|2n3&+s3g(}?~wzzAj`zd}9?|І2n @/gO^W[^ߝ}3sUnضaG̜/.gO,i @l)p @ @% 2V @ `l]nu={QȥJ-dr@'_V~1i7[_rL*^57ĴU;s3wd3}87# řS9M o9_3! @\W3Μ|ƗZ9K.o~\g~X+?lUK뷼w~m~n;.Egb @ @Z78@ @G YK3!@ @kZR 8pEd*2G$sH.]rD=-Jr`ޣG*^rhZloievƙ9gM3!Ǘf|紲<~q7_?}6 @`q9۷!grAY>8s] 7kh:w+?l qիyq^MwۼH]d  @Z ]%@ @%A- @ @2R؛9"C9bZo"ECL*6ļ*YW3?n 9ܭ8s?}glon99o'{|)B 9MmGq/>闾w0E] @\ȜOŃ|P]ep}.8uګx5a>3..Mˏ |y}}/6b  @ @nln$ @X]:'@ @ ͫͲddNG|82Wq'9RYocY?}o{~#@WWAY>x] qpo\`h]\Nצ7̸7*Y/.6b  @ @TS?99i/-Esv#ۨՅV @ @ƮWƎOo^mW'Vm bx"w+-rKz`+h @ @`y-G͛7-cx"x Opq@!~Ç-~:e;>|xԿiſ?/ņY, @ @y 01: @ 7¨ @ 0o>^??- o[YN!׹ @zKvdz 9+//pIic_~Μ|*m~Yg ʜ)rpYŃWOgNXx#}|װ @.}9;k`^a|f[}r0 m37חDzE'b @ @z78B @F YJ!@ @2}}ərJZȐrRֽ`2LrfܕCu? kr=i91x6̜=QϜKH8g< @ } o^K׮]e3|p]xUׯ_e0lԠ].uM @\/> @ @p $ @ @9Q&8<-_* 9-~ȱn9.CN*fVN9'9>9B_O ƙ>) @y}qK^ߜ}3sUnضaG̜/ysOln$ @X]:'@ @  @ @`^uٳr`.Uj903=)R1soO} @ p ~?Ϝ~zjB;wt>\=q{wN|* @ @eu2J @ ;L @!{Z+rxsi_dͥ[LwWtk @fy^d7yGq\+ 4 @ @ppL @ @Z78@ @G;-geh6sZ2]t& _Ď㰐 @7&9M^Q^?ՍM>5 J @V {&N @I J @V;9-Hׯӑ8  @ pcyOy}ucO {> @ @NNNZ/_]6jmZO9 @L?ZsˑzU7||ynOm @ Oi^~rT޼yrX'ZD_@;>ʜV_yGnj\ @ pxSO\R!^]Կ߮o*n) -T#@ @Kp`Ie;VqzХN\"A1:𶨍mD9 @ @` p @ @3 3%>ZiYL8 z^blfMδqoŽ4 @S {BU JTE;^6@ WLd( @ 0 q @ @a64 @WE6.fyw&hG&m\vv<ϯ8[ ŗ%ŵ#y @'PϧiJ_Ok}z(nIPk}-,Wu}>Td( @ @`t?! @ @lh  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @|G?UeGIENDB`ic11/PNG  IHDR szzsRGB pHYs%%IR$IDATX V n0 ?m=DNb]ZB8c{9n'%<G}-GDm:뺾h׼j @x& qw_U5P> )c.skqj&o5O_[]Mcn>4Mw]RnX2b&,u >j0M2<,p#)aGz9.a$f~c ȵo ^QŇ"YR7/KE$;GBMGkcbhc3v?%wv~;$IENDB`ic12 PNG  IHDR@@iqsRGB pHYs%%IR$ IDATxoY0d0# ,#AH 'nfr$gn\8-IhMWq3=gkKjgWzSM6ez*c̙3ncǎ5eeecǎ K,ᾄ+W,sq{'OTOÁ0Y_~-khhH@dddPcca~^g+< dzꌗ/_..\(xb޽cEI?ڵk?~|`Ȑ!Du/^0<-^~k%cYSL^^^D406d꯬;uC1JH<++ӧ֭[;wY'-`>4y qAϗ< AK.f…f̙fڴifذafO> JN '`- eX͛bALFӞ&!$w̚5۷[nzǏ|³g DŽ >}4e˖2E@T&U$iF:T%)X6FlXիF4fϞ=@y'%#GTQ500@(OҥK Ad?h2u}\8_ uK52V;wc۷Ϝ8q³>bGn2999vh˗/G_ &ᑔU  H^&`8!ydª)_ s5yz~4BhxVjaa1bNFcu`,0^)(NΝ5kӦ_ A+M1BGI5scak-Hl˖-zg$9K.ձI/AhZӤIt-T?$*ׯ_WIZ0¤H&jժ $L|;@19]X< B=wAZЂ7aτôHQ-Y%#!իJF!/n|i͐3>#LiHBXg4<xYDkת$Ff̘#p#Ij NU$'钫 9͐fQi/^EpH-(f.8?D"e_@+va,hڢ핰e֪`ssPq"(MsMM!,)t.Gصkt ii1)&cJõA|F/4HF6f;~_` $nJCC[``o Tש֨?Zu#tcvDhyݻw2D|{ Ô_V(*=[N.jTDH+`*dӏ$Q4BPyԟ JlWoa+Ywn_Lt1͋w vޭa%jY-9Ommg0h_AE"TsIbb!$OZݏP,s{|QI6sH͸lBs5 D(q>FkP"/@.A*KZk hݵ+*hQ K -zyy nݪٝG4uTo@ 5C6#ѤsHZ0԰4`<" H&8O7Ck4:UٳU,LnÆ `P?u$SN"}06 Ler4dHv9N ;~iQQGzѶxX4=!DdRL9sl8)7ax1IYF|(S0%g &Dߎ늚Ҫ`5ۅx晏1/FXԿ"͹sjۚ׶+V7ɑk0~a۶mWv@"xfk@ rrb‡h@BPTD@6 7eg;w4ߝG`Ls ޭ^pgwz F aDS bTg11{xt9@ɢuy5C|[o?HANfnr&g|]=юx( X`_voAHą aJ$tRu6V-_X?-0+U]q(h[æQgW{I Z3FH"KxBZ<`ۏr5"ѕWϜ qdΎ;tmqEIG_:W-Vϒe 5e0hmGw{!y?֞;w^'4ɱސF2VRɟ [6YxC&i7Y; 6y vQu~Z֬ sdY3f'ioXIENDB`ic13RPNG  IHDR\rfsRGB pHYs%%IR$@IDATx˒]u&*$  [!=IO=+<~AO ~aG8%Q@6/&6νN:{u;sS;;u t t t t t t t t t t t t t  s'wv~_lƍ,Fk`40_;.g0w 竎G_(ŋ};[õ]׮]_{}+"8#wG||jBuw+ܹwsbGZw]۪6αy?۷/\GoD*q/~ ?O/>}ܹHBovΝ;"Br.k`{5z@Oa0#Wy]* }T)g9ҕ׿?JM 5T6:s_t ls`0wjb&?Y1~ݮ)Oֽ(%e7^/!J;^ClO?2Ҷ w@^0 {owmwټ';$ZBRZ="SO_)ܩ1ו%O̟*+_Su/ X/TT9umJ<(?yͫy`y@|\w -,.`G }T7lc9(`:҉ 􋵑sϽO86{U^ o_ؽ&j+ _=QN,XDp:Üf P辻ӡ[ zO/4ܟ;`N"}c”ϣ_y|J_c pW"bbsՑGJ+OT $PPA#] 30>i=\ _h^~Y1rkg}{Ulky\&D|a +VOKG)hs^>x{k08'@˺yppΟK⥅%{`:[XV؞0jyϬ-?{@ͳCe7[G'na lrwJ廸 ?φD{S صÞjŁj "c)ˏ2,mv$x|h p--y3ϲ`RPV=^셡7SÉ=8 S ›_51 ~a7wOH~ͣ p_]A;Wv矨<׊_ሯ5P#4:Ry^zm`d ؁Lֳ_f Ɯ:!hE^~c2;K$3t,сxOtyt[Pش_x=W^yvan'D/uwxz^M@po jwrz}'p K<3lnbĩK2@ɶ;zp߀oLϗ^.X._)%{U+~> = |ܹµj/#5HJᘏ༎ !/@ 03:"ʎ^h[ 'ҀuQ` \[B] =+1~g7J'tŗv{]؄{=?'P]t9OTD(@Usp_=UoB+Stulh ?h4D^r{0'^!N2&F~M& 87| Tyyu?=`IWl=Y=mxNj\u̶͈nx<yPysn_>yMiݷG9> IğP' TGE~#.L#ձH &PW%e {Ydc XU6xPYԑ:#Ӿ\Q^6 g]=2 ,#q̘c Jmd5'0n4` f`3fnAY>Vu[%mMgd~IɵYqomtyNS?8wkqKt=M$@` NCAvh{hur[\€Ѹ[ۡ}5$[Tiٍ"P`k 6!œS0-rg`G:SoJɫP\)?@IdPk=5` ?`CBvzh&!vŠ,΀p@fF_lΣ4e͖`Oa3!1^_nܸ12"uAAs<[c [YGyQq1*E])+dLEuzn@3^ ȓ8mA+CBcHa{&0 (5׉ ; *;)^`c ).N˂?e#JS{DpO^G \gwJ%TD'?M%UvkXd64@l+֧6:;D'2l`>\ޤq&^>zBD1I{@E8oA'MG"K[v~dc<ΊkI`>э"<]]N5]jz[( tبt W֫ZFiF Gk`^}ֺ6J6j8+'L|Μ+wE4~mKS_ږ~< :/}y}Ƌ6w]D;O|ZI6O]'?KBXިK[xMH(*zOKC-Nԗ|R2`0w}/ݷz]!ρO^q#ߩ@'PI6m_!{ @>|qδ-{38y睝O>dt;['^F 1{yg}v@G>mi|fKհq[F'uj{γ=y.Rv(xLN6-C()1uĪpb?l[YMr]YxD&.yp]mS;i4K!^||fY]- v$!Ywirj;d@C0Bu,ⴙ>$H[L@'z9ЛH+y~)x'â2:<39}V)+ qX?!5`~; L;^[UCmY T(;<`ԿH@yjwaFeV %e6wH<P6\So'iZ_=꒙Ɂ/;ܴ*g9y,L, `um}ɐ@+ H%|}ڌ uh3^bWl2$vIȾ3اqON3v@ufF"=4vwkT@f|V2|6K 1^@8B7?q GO ѣӥ|ut~2g_ݩF@ ,:F([0(Ĩ=fsKE1n1h÷-$>ٞf_cAxOKp3:ؖp# )41DD{n(<;GY@ϰ|)4>"CtHӕ<FRr3l]Ґm y江$Y!c }w^ya&ϐg9eTv/` 7if3Xo@Ϫnn zB4JWF٬#> @[3E QjY?v۬[]$ĊdPg Ub#"̜#@HWɍ%if?!`NgԌ qBqA57Ч= '>zv-/7&瑁0.&#h*C2׹/nc怜k/\CdUiJK ϵ= O?t[ ݕؚ0'Im6ZNB5$@_C:x^n_ ˆ3v+Y'oi X ȳli 3.-.z*tlO<[2cŵq@tE7Vq&h-4fM1N\o"_xa@ &, (r?88i_9a v8ѧ|v0ޜS_[^@t ȕi_ܢ ;Da8Eb `cp\`f`JP1 f1+M;@~K6B10fm~@P<1Pe#aq}v^z饃陮BlJ>zЀ,;)`sҢ?y'mY `2@SYm(:L ~p(^E1Sg0(-AHkI` E!ZϨS1DmK2:/ܼys1ҁ~2@:*w+G#:4MN%QIcg&IA>qF H?03c[]rN<0$%xYB0Y!1\+b [ 駾!dTH>mHpVېFGT0NƋMH@9@cO8z׿KW&;DWqFZ34KS:dp >kX-?pxmhSBqJ+wi4ѝg}+8-HLJ艏86F6$L@F^m&Ӣ7't>ḃIJfKp eySK[ x2 WiMy8c1H_K^zV\􄤍q3F|N8cwVYt%2k 9q Gl/C6kgaO euKyŽ6136rd Rnjg\!!:[=GI]+it8QN/2-LӉ|gIluc9;-~$cZ˳8)f,JT?ekSgW`ah@>+d0E- %ƣ\eɭ{RGG62Az~r=kt%f'm˸^i#+rtrm 0*x‍|S A ,7\թ)ўg=qBYN>䵉Ԟɋ'}U<"cU4W GOƄzǷr\ɯ= .[\l˴ђ\kNME am P[o ^lB:-N}} F.ȳQ=fwNQ}%1nɣ>FGnVm YR(gR^9duRR Fx8dRr`ʯQ[a: {IouuHάp!DŽ$˷g[k ٌ#@ qJn?ok<2M&6ڕ꼶o3Λ[bK@ MJ7qʻ6iVAIW֝X$=2_96 CG:0(AHa\e#(2<Ʊb̸.R m76a^*n@'NZǣ!(x|P3X`Q2æhuR>ɵrvJxe0m#kʤ'8^Qe\{m>Qt!lIsyD]vB5|ZwfH@>>@ `qy*3;X zT!y5@(@7fP.rTd=7N?La3} ;I gLE+"ru˦@޽姫Eڝ֧Il.6J{5{0L@kAJ0xf t61l K?%ǀD7G i$qviy2{Lb3wԗSmqi2/7od}+iHAUmEewŘ(ՠƈwxc|ݥh1H@8w|G(CF,GFybci2xZ{6 )?E蛧oIC3.ʬPRVf3>\ׇX;N49{` OTrxO! @e9I$?52…۬6{gY 93XYF1,>.<pc  Kok _3vFgY1X#"3yHȁ쮼4y?=%-jN̼2|=ob@k+,Y<R6"_{'[o?CO}Xui-h%Y&X[D`TV c$m9b|@4c>,'I!+D8|CYV+"~ 'WdND$RWZ =,Bd!uȟ~}dlN6ki`V]@&N C\d&^Ktӣ!9#G@A.H K^ւ(edV"dP^?}Y )ŇHC볒Q|dO\+Ǣםhʠ@g e dJs*:`Ā[MTS"]} 0y2\m^8S03|!"zI]8>rXde2&_du6),N` +Bi؄۪n!#n12!pMmiK 7.kA^})B!ԵJl7r 'Ǔ%"Wdϫ6L'IZq iX7g،5PqOI=!!Li#qh2K =_ Ȥt@@g !ZѤMEHzS8J{SO \~q "9Ȇ(ZFEvXTS=߁BB2l5`qf _(?P"0q砱хr7o;nf҂_UIFVaG-}8K;O<!]'olv@徝.3pf@2nl%?6θNO O[4ȓ͓z"pZ)O0ם^v,pf< 3vȏ +?Q3 al݂.zN|H@(_: ^%=NuSfhЀ/ϩ8l(χqm 16D%VK_wX\W= X3 s3;Kn%Y eCʄXٮz5?@7{&3;;3<@GY$}u yeE:D=\Xu7;g?yX'zrHrz} ftl]zZ>NԱ pS.eE d_k@751d0&jk@pY4rs?-NuS&h K|yns4p~~st%s|f!H Qni `KfxL/jJ yOlzw@6CgXNgxWz;ݑ;л Vp:޺Bswͻ?[-P܂A\w@HGc=yL tqxZ0ƝN(3Vf9#u<@H8jd 2[-L2 ƈg[qq~ G<Inx3ĵ80eljyUǨݟc#}d?G!+)'N#3nF˸#.`?o`i~g%0j+oDꏞڝ%Bn4 `˜di ϰ  )-p< Y}T`^ `4Yފ61f_pO{3 NmwOB?~?+ d/YiNFŀ8 n),Y2GbdK:2?NS!{ `fApg6}n[-D)'N3?x= 0ևrBGs!m\~}_A{qM@'gE?6۸nF׿<קS]<@'%- x<2{\DK6 /+Xk@@vA{@'T@c#̻WcMh?v3+ϱ_Cvw4 `b #0{,^j_vڰ<%[{{= ]VuWpÒ5^Ji$M;{f${ BN|wgK<o-n x,8N{C' q, t8̏pΞc5Qohӊ9uw4 ;Y 2*D{' yjMN@' JYW"oAo?oog4 `ʘI,·>[:'Nh-/qMz\-FAG2[ǧ)kis'CFihxמP\f@d©۷Ah;r5OfV.}@~KʋOZHal:?>aW\02y̌5s@ׄNx 28Avqھ'^yS 턣;L3,?ofLz)@ȦZo{i 92TA #g.>rݩ7qCg4 `p0C0x@Y5v `t!&?nGnkeO.Bn,Ȯ/YQH:^>;|{ynf3l Qvi d'.n\>./9I=d֢N#5Ljtf1]f56w\n18@@1Xn|ڎCZї'g .zC>lαtW:=W'F]:LtK@<//.n޼9π?@pirlc|$HH0:L dG?mL`_]2Lm62 rg{@Wxෳ#qgY˸eƺ睮#!§~zc4qeVfQ#jT' ;/>2 v|woI@KӇb{R2>"gםNn7`_y啝W_}uy6g0 uʈ6Tuxfp3\m!ת@{ҕQ^7j7IYx~]o, xژmIo"Яx,Λ]ÛC1:.8u1XADwM?o< +0gΘҁz&OYF@k@YB㌆H82`_]fhbCLjYExGf{KWBgsƐ~鍋.UOvw2H xd8Ǩ%=ZҴ߽xN,|@Z2ϊ r/>y; u@2Ff] @('\3E )mxNY@M/@nNf(Umt7:fCVފI+zUoO; -\fc/3p@A1OSW Mēv)/pCmsё*ۓ6! eU=u*Ikzq8Ͻ@hK]ϫp Dc'`C-ϙX }>ͅ4sHt>ө:g;8 \>̟v$ ; 7u5\ D8! d٪|3dߖY{~X?mt,]Y'$H:>խސCH`P|6 Ȭ ~r9k6gs?^X >K yQiX}򙁄X(-̊G %SGG&kVjGw@/^'u;zUU"7XfV }8> N=ʎI@1@ f*.hc2G!R39"4= ?@c}eUԶp6){4Q@3uf.:ĻC!Cw!`F!ɱ"?ȣe>3N˯-kp9FQU -$2cX'ɟ$}-B!2=i#K-;-85!7Q*WcvHOxLy"_9j]1XQ jw+5IDAT* #{ %g.Ig6C , }Wiٶ|'F|nXi1M1.*<ҏIwZ@΀߳;re-߶,6")ț: 2F>m(^\Cpo 0pA@>8jcaKߑ/%UNɈxFO:;nk|^``tS`iNwθs;fwHf$f,2n~ 2~Tww!*`LYXJg9Gݐ@d1^yXd$zJOK;>p`Q2m/un4pb <:i'}ö y!=6,qҡ>myaK !+ׯ#t5ІImܺCP%y@IH )w}YVg~"wzY9z  2&lg}׭O\7I[>. |=z]]N;4]@'qok`c5 `c 5pp:-t l:lt__ǽ@'ƹ8eo ky&eVh86 lċ@ֻc8`n`7@t!cW5:,Iś5 #Cv5Ihdp}{3aqs9 E֦NK,?ywx h `IeǮN+ 8K+T/5pz=!@|-\5pz:`i@>KbSXi`* Y~ЂǨ#x˯ >g8m{qs!sMVNY8Gj Xh䋽O?^cr&R0׉wW˒@T=N̯$nH\ß3[95՛8`>s\:{Tc7l ;*lׂWoP{/Lv/j8{Ff9oI`γ`Vǿ;/5ܸqc__@`[k7{ofL4<)dž7oY_v6F vlR||Y~f>ɿH+_/5ߤ2^IxM\kқQZȁ׬̐=υstd@̣:r.9O>qq!@i4q>` $܌'In*0h 4@s:XdBYSs9:xYX '#ot![olkL0gOi ĵOIn*T=Z}fczYYx\1#G9Y?׆䓷uj`nwFb<,-SiB3z3YY>i:u LG!e=䣇';X79Uz=S0[Hc \req'%yUWx𶺪<8/U#($?zyN ,-ljKIg,2ku]o) Iukw @lY9/{ ou[sԽ= n"e,۾o@E+0 AHƠk`g d뽲{+ߧUNٟ{~Y&? *x_ЇRW\M3}'+rŚ#jGs@t"hIȀEsO?=gz`SBIӿVMj9go+kI[+ׅ!><͒_򗿴`zh Í7yG58?.GT#W?^/@J+Ր{8\I̤o;:) /0|!) ~̃ %l^||rӿc?`ltr_>>-wQ-~Yv{pQė7cȪ`w>?W 008W/P̦|Uup% Ctʱb~ΫCIy[PYfo!p9y>Dʴi]4~7{6 +}Y0*ZQV_x>??fZHʪ޽5ޮnjhs*[,y4V  +m&#6TVt!yڜȇ%U"@d$2[צo뮁U4=g9|ްGW?UgE ~aڿl"6$T*[ݭ=YK/D@~WX|m\=y%8@SuZG ęں'<=XD<v`Ϥ2?W?-P?Oٙ/~gFg*q^^n=fE9P?~3 XF7L[xī@., vly03W>`B'q3]٪}ӿ˿VSpL,XGkgKjpGE`mWsC&@ r߆͌?32V%w]Gfx+W>vVfr,HY>Wn% 3'`ThOz~u[-2VCYlY P,|e?*ӺJa淬^Wd0Sc=GyE,}R08U|%@ ]g LoTOwu6.`{rZB_,?F/<#Hq9= ",@ߞ#qڟUwOɳW;9~X e}Uy*PTެ;+m=]N(Zo~mm|fݏ ܗȕZBR->^#8_~xO'@^QfpVaQ1˥:^YGEڟUwOL`{~ﳸ/0[){’sv][);[U7xKU`nI_~vw~ӟ~Q ( %պ^햀fYW mrPs ԁUVZKzQiu6_3_VHʤxkV{*Vɀ+)߮_[e\J~(rB~xOx~Gu"S̢NY.uց<#ۢ2|]jyc};} ?rK_o=qf:<=z~P{_WgՉ@u.ZfR>t5. `Cyy;6 >Up/yr_G+/C [GՖ(R~YDBݧL`9,k4 Ȓ ]J{K>9WƍCƋJ`#c1;]8+˵f Wq@>n?L%QGN^A,jַSIWG:!WbM>s!zL }Q#':m ZQ5qxߺ},xl? ?G;>#'sLXG=z8} x5lo5o]ۤ6}P]߫8un8 VRGN%|AW"Q$PEuF[v|:e$0R q@> 0߇@0^_ֻ6|a(}?A:WDwHt6}44J;3(CcYlܹ(~Oa huwzqoc"ܸqNٽ4DQgS.p@@@@@@@@@@@@@4+b$IENDB`ic14GPNG  IHDRxsRGB pHYs%%IR$@IDATx[\y)F8&yC[MX['b^ֈ,Q%QdKJtWwݫH $s]K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z-@K%h Z;jFggg7?n}{b?ҿW_2=t掴Z-J@ ˿K??^#]^{g?O?=|{&.h{ wu3 Ǐo?}ѣGxWJ}vcŋ~!_~I쏖@K%8. ޻Ѱ'a?&;% {O# ᷃N?ntgboΝ;?*[YO~Ǔtof͗h Z-=H>"/%h VuͧS؇w0^1lɋ{'9< +Po$y(d|RO1wpyӠ`#4 !M/ Ү%h _h;lvi`^ `/3'xp?CyQEDZ#λ˜ߍc?Ġ(iPMZ@K%8< zx@`\) g{tn|gP7a0{o<b_ )? ;>r (~ ̣4t!2h Z* 5_Фbz'_.`Dމ4iqؤ|aAl?_D/`?|?n@a11aԃvz 4-@K%pX;-ww}mo"xً3l ӗŝ$h 3 ?È; ?Cyؽ1@"Φ\?D?:iS(m@K%8 Ե79&-_l@t}:VK/OAgw~0 1@|H46 l t?<.cK%h \Z/[ HZScywx06-"x+l'ȴo 6 -ˮ 7! .M{ yx<ΰ$.[-@K8$0kTzؑ_ Ai]SlTTGas͍_+aU;,  /cqN Qo`q>ȕ僴QJr[-@K$z_,M$pA ;f?D[ûi8fQ޾BKB֧!` "L6)-w$v%h Bˮa?`G vG{stl??ˏ0^E@n>OAg:2DYs,Mo Z-=2Mdד΍2tt[o?kw) u>66^Lٴ@K%񚝀;K{GW';d;ϭnBh/U/wJ';SWx$k7x>ۏ-z/~[6#̘x33c%@VJZ-U$1^zX_!!ܮ9>baJ`\ωk¶$ Dѿ)~c{xߛjE7A0 oS?7gjয়~z? 2={UQ+bnlB8 @ߝ~?5b1 <Gy%Ӹ;U/_cK%= [ Zu }qhՓ@lM^(6 ɽ{ X".|B{!y[,vM_/zǏĮQO>ae( o6[~W=lqrz%]>qUZE+E_aAJԻk@uN\t6/MD[7ge_,&^; 0 an+_"- ? F"7pBYEܫ4AAf0lqkl '+Ntc`\\E"@w;aJ:WўAW#.;/m#$F޴q{1%vP, _8嚣~)0B[y~)d[{"'fd9:qu',=%؃.T ۔@@NI\q~3S|b{'14!]ĉDϛ}*&tكbd~<?E~?#kmğ{Ǡ= 5%7 ?`߼{ѹ1)"90hnFyc_Q7 ۈ6s+Fh+z1bA$BFHR0c9771 $'װO!I>%ؘbn"UsyN=E= W`8jB?9& }eq-gC7mԈaBlYC63l<4I}~~_=>&1܍Q]r ` HnË DU$t1%Xb*ceNXнXB\v~C;F:4|㒀:`@pU 6ecL8+h`G7LMC xͤ-v[A9|nB^O atPҰGH?OQwA3?Z-HzM=t«:<.U'aVgy5i"=S_PX~{oXq6Ènme?= N\DDg"h/*|/|؍񼟷|yZTv%XMEk9Vo<oMzܹQ#r1C7^M4'unk&ۧEY>@yQ07ˍL78/fl&[ I Џ7crrwZ-sZtS B'c}S\@'aC!xSOzE8v-O{}䮴Ë?wov^?ƿ|_kxq;ߗ|oy^˟ &C^l/ᜬ+k2@xG 菖@K`e ,eI s ߛ9m '߫>OX@hk zB:m$Th<=A'f?Z:S:;]̛j /Þ= 7aOzEvK`}Y*`O?+ {ugJ)F0_e|=]~Ąze ?'"'zh lVͅ|s3VfPG9O_LB~_;7e GPzh9%XU/'}Onr9 |\ձ&@v~ԵA^s ⫓oWg1Vg}Rg2i"*G:Ɲgb̏5i?TH{s,~ <~i$lr R^UL[j0y_"M?aD?FQ71nѡ0v|C;(|wA`K3/vJ؉μh &%N5O"iȧ'zw}7;Y6tVZx`&~P/k|X[pQ]e8X 8ƌ?˸? p> [@H譠ɟ BQYqCc3|xxaVnm`-o>ۏ PwvtK~/n'Aȓ7ޝQ_N^G+qRoh lF1w`!Bu0uA$qȧˁ5:@ 8鴇AyZBu4<i+NH{P^@t}H 0/‡b8Ĺ&.6'{~E죏>4|bf^OshuCXT/o|mbߵ2[^ɟ'Ou]t~A .ā<iwB>( mA>9|b 7Ϣ 4G1Oi^~;aQȗJ9/ @BGK oFH@t*“( /'/xr2)x<9k $X$< 8:|  ?tbE 1} P>Y ]5Ov~Џk __㒀c0=AǠAンa SG@3 eJܰcQ;< xs @(n=~8J=9'~Ex ƞ54n8k}ع !ލpD|97tMBF@:|۵Zח X\Xc i_5=L$$j5g2K}--<'h3}D֗x9 ?a5מ!Ƒ1E/qqˍ e߿b1܊= =|+ǟ?#Nż,GӨ[{?D"(Zn ~{JοU?ϟ{y (k48f -9'|$ FnL<2[N@Fth(;'خ%Xwz=<_O,z6ߍ7ЩcbMp=A*ƜuW>Cqlw\ж+g̡O:p艛 ~t6nG?^q6)/b6Fap /#?aoGgx+ ^Gрw#vs=xB/ʺ;p6;c @gf1OA;qeh VsXpǂs[o%PrB"$4T~qGf5kv^8Dn ^N}<:)Op㑀qwl ㈣'S-<}W̓:K[?1wQl)goFρ(E~#R`On^qQ89M@4kY@:}nDęDvFWN!4NΗY2?Ŝ"NL-%S=FXcE3n>6ЍbFV`бNЎxHOt#BO>i'톯zj<> T;844BGnc& 9GD_"ay` —6%?6znm9 v(6 Lf)5E8 /Ƹ)Iy;>Ap=l|!Ф?Z-$>gcʯH> &S7>2pL] "a&OM4]SG#oy{{Ø3:8i G|,=\x¤qVBg|/ L#f oV{#/0QM@qQ_0p44󑖂S 08_/O0/"fydo"}iO>ɝr2r ??[w#ȕ?? ȩϋ~0o">:;MmS>;lc;!)7GmZK%p5 c{NxNĠ'zoxFN>&n{8o īunڍ+$NppK0i^ z,' 鏣0":P]tn ~3t-@KD|: ÷jsRQk7;E#mT Ly&]K%?Pdq,DsR~x,dq5^wM_\G[Ñ1FzT07 څJy4= T;-/sGNW'.aO55Tyw%#: yb9Ype-0iU=-4.TMk[ktmqz;@8K 8#fbW}u?oꚨN Fw7TĜe`H;?7Zۓs7]pUB78N4\. #+:,,>Ug#tx%0gk_>F=Į\l$16ݡx@;;Z˼J'% sBoGz!R>ơË'ߖuo MGЉf12`]u:uO7x`<6GuHB^\pYw X KtcCi|xӦ-v$][O-++Gma9#\.u}*Z%)(MDǪύu$ ~8݊;y( q F$'8՛ʲvt,-p^jH]HIoos-ވ'x}cq) >\gW|cmQ-tk|"ʃ µ|q}-fuU;< 0x2<{#N9=LQ.aX-UOl'D3 /*  仪[j%+TNXn*OtjL;Bg\Mo  ʓt'uǓ'_ŏ4 4wLwY o}C[Xm'UyO|DʮA3 돣a44Q:(mY\j gTn#TpjƆ6F`,x@K`5 0' /S<艴S%n>K:H>h9xmE|NN&A:k'r! H&Gm8 8v1cM'mDr*q⤃<_-+[im#%ؼX,t #6pcOMGOp#n6Ǎ kgc7ZחFԠsOSos[鄩Enn(:ӔEiG$O<"zlto(8yIW:e^1nD¹7ȇ]]i0V2W1_[-K2q_7^^~3}Stʛ2si)9;9G,ߘ/ޢWZ-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZK7˪9[-@K%p4 ew%h ZKh N={v_~9u@AۙW>9D9͵> OD~ޟ9|g\{Xz.Iv9-"KvSerY6ʯ{ `c-h l\q8w ZGOi'q_=Azҭj l\)rdU.z'h lR)NZqP ,'7x`"'{%w9MQ6κ2rǓ:sGȏ?2駟R"r oMuZ@o6-.%gF0MNcA,n}0FT^rk l[ضĻ%i9y>'VNy>aNwfG9|Gۛ a(НyrTɓ'_uӧ1" f>S&#^Cךhoc-%Q0Սi8lɏCL _Gx6«~ ;VwP8A.068 a ;'P ;8Mä=z]nY|g<~8_@ N;FA#_wc%=nZK`Da w6n0'eP> ;&b?1V1hEe&Z&خ%M `Z; C8ixiԷxG ?@ݼ%a 4 4o~qaL$GK` յ- j*b%5 `kZ- `ux4Qw\xt-]H7z8@ h9rN|K3q0g9&`"L~яK/;ہ XmK7ۖx8 !qÑ6PLU-]I7|8 h0=s%s2 :nFCO]v7ˆ\9S7uo-r׮% P%c `̪1  FA18ۑk~P>ƞ>|UN׬&lM]QK0%Qa5|FN`o.֠:_:uUU\G~mҡF`պ;K` %L5z|A\ X9fC@|xQ[uSov-C@oe-K@Cc 54MyΝ}ul08 gC-_$^znhtTE9]ؚz5QwE-㒀"\G)g=Z܊aWu#ֺlj]%m `Z. C3Oq!&ENᴁSh1W7qz *uޖ6%mJj 4]rU$|]7WO_صz[* _N۸97ғxϗio ROm B؅ԻΖ@K`% htGPh3r͏1~b;[K`/$-CGnڸ0rzÍt뮿;. .o덋Gz8'N?4Ool zҿ zҕqǩo'gCkSWi l[ضć\LE W?6]E.ɑn"e[7|EO?N#W_ey7@g@8v-C@o: HkV~TEƸ: Nn 0œ1O> 7˲ @m;v#@8ڏ.% DžTdA=i\$Wi&(U<W< 7 ҁO4Lݼy g+|PN\ Ut֖N$-.cNB^{n(E .1i mQ$]J@=QoУѫމU}$zBrH8>Kufu# 묻j lB؄T,Ӆ2\Y6Uuf섖$Puj S 4E³.Q=WM#^o zg3UYTNfk;WO==t?uC0J7;jt«6rqk][JnP^]%p FPTғ=ד>aENRo,2.!̷8)mR/* ep(_co$."3]S':yɏ.}{9> >'q7P@K`^ͥ).vsh.E˹.No-T^h8 xXpD8! zh_ףnwM@oDхғ  |[Ўj9Aa9fOv6E8ѓ?H p0V: 'CpM[1P>|Yh@'zO> k @o,#Mfa+|,o!B*jاʓgfv-K`jiSW Sά_fo  BIiѓV:ov[o&^Iݓ˜jn|/JűoWz=d3~x>T wI^ gC_O'}t4/ [rTXwcK%0-LRj=`+S6FE_J߅D']yn%X 4縂ȃ[޲VD",o~mX@9q=<'k>o&lȉru.w#/?>77h?0q^P=3xtɓ}-sZK75 $BəT5 8pM|k "SC3VO^.B ,VEȂ2ljZ]Ik[ 0FƚtE~ggЫngߏ>(7G٦;O:Ƒ;=BwAB_?Ī'锏/#h J7y=ŴzC<_]5!$飗N=%WP >Pp}ЕZ{pl@Ke<s ?n7?|Sa#|G^ p@K`y ` YбXf!r=Y`DOP 4M`Y$˅}=BX_C.9eP[7-Pq.x3jDI@IDAT38ɟ2GUi/7 v7y)0r8©%?Z-Y `V4'Љ,C'>w*\]ܒS)߅4O} ]DA ^9v-Ǫ#B/qH#ly ލGلqh ,-,-udttI'}(4xmpLDNj3'q=DzFzC=sWAx! ΰN.%@o4Eutcf]E8LMs 1 WNWxз˼kG4%zˆIo"yn_lpE{ Wtb=۸Nظݪz gr@Nx@^yG77I8'2I-%sa F,'dh  ['V$|kV區q#G}rL!YEgc 5ۅr ]/*Zs: )Lb|lIQܨ~9I9x/twI?xs7ab=`:^omAsl$>O/q+tvd>鷥])[UMɌo 3F8x2AJE,.)GhhƖEmn>}HcL 1'';bM]db9aX6q┇|94; w8A?ÇsTGDnp>Gpy)gq%Y֚Q_aH?֨iPy 77` Xv(=~sBaD8x#8KRW~ @Ɠ̊PwEφ}Negy |76c B]I@~hx1'NFxyI۠DſTדĎ>xN:|8C_@ZH5E['$7YdžcR/+n@4x8ҁ][D1Vw0$0#;zx|.,,n qxH0Ժ^|7nhk?qu2wٯ]]I~8tҝ$T>81q)3pL$'貲Jܲ#>Ǐ} f xn@{=i8<`U%.nj/ {E7J0>' v, ɏvYse7}7`?_b\ xs:Ґ;֠ƞ; Ɲqb|Ϙד'+ maK@ݪy(Go >'zD*B|Uo)Ro 3XØ;r_vݪ#mӮ7$u" Nӷ#εcsvAmU"x\{zIoQY%lSey1L,h6 8x,:yו7;Aصzd'o֒W:q8 F F*m:AEOD.hEEvI3>tAwĚMb&,>HQa5< ;`_Fbd9Q5؉~ܑstǮgGC9-2iE8lj%V‡~xdC'h~QWhYi7th;s~q3xOs6W7=" H^ow{!t =7KF@>+ {w 5%DH GRNTW)|^Of~xpc|`3r=Rdx&FCD(1'ƒ'OM߶ hEw# ]? mp'vN[YO! yYP?tQ=In_pg+o"N~Ł<?SG[7a*=cgr#eK6`?N:vL?OsGM}C= :p_uH܉2N늎h? Eg~tOc>YȎ>h71IdX>裼Yrq`,s=^Axj7%XpWUk~7h5yo@xÿ mHH`r@< egbB*<4$%&?ŀ< ~~ckEyG^ߓwe~&3`rBnXH8IFH V }yqu }Lsb|wNP=~8/t(F@}%?^"|AY? B>y jItX^N񻎁z7ߤރuN~Fv>ݴ{uo.%@'J1P`x@[Y?EBRxm:(,U4^I}T&eóYCgqs)eeB9?QHu$;*?U7xЈܑH-Q/e aKfGo,Cš(0;τ ݅ trIn}I\Ç G?0~o;NY Q GxvO ^eU˘;W>ҪSDN=.M7dNU$uyC@GzMiY]*lEO+b;.¹~偟6.j*d[6<8Qz͔>J7үIrpnK4xH&_}k]Dpꄨ;rv0QՊvti-s"%^'|@U=ui?N#=s <8'N5|:JG{Sg1x?w`,{;u3MO'?]U$V^Ici#?"mevOu~<Ě\*jEXyp2clT*!a^iTl*mdȯRv=^ :ב^ w;Ooh]ܭC)}DSɋ42 ?''y]bC3]6@HA,!eGgvy2Mw]T2iѓh@6Wu|(8k]"4~kyXb0H 2@J!q >QK4BۡY M>=O*a=~$h,qaq~+/d/N4rt̼h'BqHN|c8r#zxe;uLkܮt]@omtB>=w[n?-_~Yh֧^*1˳|C7ߛ/ҡ;c;"46 :1/,4\ eHx18Q$d  b|Pn9:\-i/HwBڜS ~މDRFk4Se_F}8щDIWӾ*/yU6Ok OW4zuIWZFw++~΀@=7IPWE5,I)Q6׶&WoM{p" i(Np #}̟V]L:aM<{3pgqG~mc0ql (t|#csuc]%l߅EG~k9']>*m$8Sw aNrlڐcɆ D$/Q C#Ϻ~)e39Ș^0A: :>(F/Y==!<7̷*Si;7:K{3tEL'?-:mn\WrlDf|0(n._&^CY #~"Wie'2bFVm[,%nWmLy #yVmGߍq4xHX/283퓫]ҧЇ,1 :Y5MoW'|7IS;rmmvG p_?mze@;4]Dc96t7k6RH"OC*T|Ǝ _M~KY jǯȳ߽-#: /SGlF،\ѐ ű;g-'1<Ag.;#ᛟ?aEjP?gM=A '~@kȜqS^I63ok'~z 'LyU6YIw=t*Ze y`R:F#[Aq`̆Ek8H 8GdSrڤHƍH^48:W z: `7rI[ '0~pri<:H:thaZ ]H}TAd 㜠+?3[v)ƙEYЦty3 Pvtވ剎(]-C/͡IǷۭz[ovw`vLDpvI('J\N NQ"R Xsj#1V9yCg|9 AG}Iǁ?kE~_''R ~  yn>:d@Ac~xF~q&#ZnK>8v3C_|gu0l|ՠߜ9٣5zi7?C3?4+hG$mRƔK}^Ջ7cI`&(YNMnmqmW4&xYٽLBG>hL4荀 'VJei<;y9'8teeCcp,:cA8;n,N8)D~ "LAN֤WCS6|\='v;/=eGo' (2Þ|&AO{S7u`}o3zu{!x39]iq&%Nt)]ɗć''Gx^[ 8w<1舆~u;/놃)~惇|v[9ֶ8$|S+m .Q6 9:&&$x/)vL~N@xv8N heZV%8,:ƈ1ũ_44tz@ˡ>뤌Cw/9U[)WP.>Q:8V7/(4u&Gx:oǔ,i ۪<7ފ[өtҪ7~x_vUu70 nh`mVG E9Pp" MmbG 0q'MH'CpxIQCbSe:UO?w|S/TN M@7vx١k_7.׽&-Bqewe :S~#!\5j_ZO#mVm߬zYUL|)ƥ 8p9=y""ߘ2_-cϢyorsmR(ۓ7 7,x5os%yWYPh[5zM8l9T^|c:o##aғ^j*'ۮMbo6)RoD}ʛxs%^h@Ag|Sҩ::Oh1|Yey֙ѢL2:e!uk6he`U ހN4 7'z3@#/ވ.:1 )p rriyR/9vuXu?7~q\grYi>A8ro3@G828R'_h:^髢uc}cDH'{d鿢7 | qxo{7ېMHSݻDs:X5OXC%f_)+N[| rU&1Jʷ.zvuI9Y1#L>E _k6؆''O83_1xɇk[7!qeDk~I'*[oxF΅R큆˗?(VbʣOUG7~>ˍq[7>Iӓ:g$6ڏ+<*?hwJ~ӂo2=y$u p'nS7" \.-7$Dщ$NxϕC=E:C ^R4']uHA'ƙ:gvَ* )>h o~ʙW2vI*߶vpEl|HJC Si}Խ+]IuX8q٧7D> QuS'$xb ~G8]qrbDXpN=tCpIeX.Hz7@vn@ hH@oL@Sf[E|l~gj?/*{494 G_z._ő{->u`}%;nmlCGVɥgvsH7?=2Quw;O,ٯDpz:O$A,^?y␅8q VRH%|Բ<2*mw4M=tO:4P1C O/04.\ov!ӉB>Hd Й 2碲D}teǗ!@s#BʂH::`#7S|lj m|"2i,?{$qk .eH)3ѣb [ =Q&3b @ _L @fwuWUO]03<-zy'vGSԭ<8U஘>vg3O`4!# 5i:!2k;nB.u']o5\>DyphOTN9zġtOl,^p=36H;KkE p^z2Sd ~dėxY30,+v<)O<)9]DX= :t;2O:!C9+n,"?½7o,qC+EO_T"HuCbr/1X-uWUuN?3&MǸ|wYN- >WѝN8Fb3\=lKt%''lBq[vM"m5޶}q~Іr@˹=)lʘ?m}Hs?fM\&1t?gdrds"3GȂ>?b\E ,"[kxE>O9/ 't]o_'E0z"rE 并ӽ> ro AToF3"MQGu]gzDž =\psݣO~C{ȸ?ɧބx7S%㻚 ^]^$__M1ߚMw䚨P.ڷ^bԵgŞxYQ.6'8^;rgQ^I`Y_< =p]#P/}=»(XZ E=R59yW[{^{_QyΘq1V$zG.FOw=,ݵ,fnxdh7d`_(-ް[RzC`6szR"eys7ISϾm`T3k4l[62a ܊s<7=;=nMB_7Wr,zzxn#؟%ڎ\Imv/S`y?޿qrȻ%aN?!G^?(N/'ߖ95$z)KFfp#2MqpD"y\k:r㚞r1zճme 4ݑ>=ѹ*E? dg<5\,f 6i\/5>;ƛ/_+>ٞri=ROةW=^<`s{2 }B~gcN<ySG?M )wL=O_@;`^Cܶ h; r@0ݎYzףr1[~oS95Tvό}\k^nqJle&ҏ0p 0,44|Y jº\!?-g?6xihmv퇞wNx}k@Ns>X~.|%a~~z'O>Q#Qǫ,2 d>\}t%dp,3~e@C+{Nk̿ R 6$X7wIE7ݰּQ~rtG/=xRз{Ed@D2Ǝ;nw=;lwǮ`׌0^`YB' :,Q2堲r >oڥ/<'x 2oP9 RYNIyxF3gD\;c[\ż!ΧCc,aȂB>LYP{˩7hQk5"`8| dݐ6:aAL7W/zAy`{)2C?/w}8@ϵƯH97\?Ɛ 1Zj 2N*\5|.dzE0 u[/~ͳwd|cߛv\ ~gYN^O/?[>BI׬?|/M&lE7 1B-4HT&v 8oRK[\i{0@]VϲEˋkշαu9}T_TOtuϵzeqtv-s)pA.iڹRh (,Z..=rt4Hx{>G}4q PO\j<7Ke/:ιk,+KtNyd%aqn⬤Oa X[ŻGi5`9a:^/i\/EDR/S*\\+G~#fp>#fύڐz>,uz\)5x"eĵ6ӎ/ybK3O|_> vxޤ\u}Zsf4_\l/a 4\gܦCe`\EGmo_Û2t 6nו?lNi630pD `oh3,hosvaS<~3 zMuiKv꫁@_|N涒/婅lNmF30pf 0 n&f܆Υvn"ۦ 1 u %? 0 U 5S{xxmOѥ|,U߮˳"Ȉx]2 |wRQ9B>LG[=иEu)v@6;30pBWIZ9=- ^:4WL:Eu9@y"o!3fPMX1ܘa` `4{0 =wwcwH\w[>[Vba`' dSI1#h`gO|]E>?QWO?tԉ n^oYTşޞ]O}@߸E)6b hRf@CFƵQXa%#F: 3-}vL>V d})u `;g=rz oC0 9ezO\jv k>y'! 웁lpg΀Ƭ#Dv P1l@5lsZW=X-vA#Hw@6wx gƀMC!P>ykG~HgCa\}OO}|U6zE܈ 'M)6a MXN{a#ku$51O|} ;5篞mO=& m'MঌE? [1aXhޢǸ <<OF=Q']Bt72wg3ynDSEl'a 5@*^d\qηܶ8^oFʇ0 mXK0bçPs',z>'@d 2>N Fw l#[kǍ8mfʆM`1..uz6sz.dRG b= 1/k~ ZGcטTTg6 g{- f܊ a`Sg#~2=kzMoڿ腁sesx@a 9~^z>'tD4 "2@܌h0G44{l>Ub  6 <4zxD>ˏ $?<ʘ\[4`Ο0e k)B` sF]/[ @60cx ` tr<{ ok#9#k<'g{^F1s[k<'>OY=߲0f I /iUhGX68-^;i@Dž'l >uK'XFШ=72@،l6)Z E_ cgtq5TOoNJ~@IDAT[`~hz_uwTeHa` dWzOrZ 6 2煑/ wygAdxtWݨCONBCa?qo=|pu% G}@^B3 EcbEE,=37,̠ 8[u&a_ľ>o@trǽQlvI6/1xp 8 ܿ\h~/ Sv05r9<Ǐ_" %G?a 2 *5ɸZ=yh9bnr3a>ϵu,: 3 9M`oQ]!o76K\@?pGs ?x%(I;6sG`#q$yǷAʒG^>a 쏁lmj1=h5b1VQY7w@g F F#o|i曗2S *e>n?dOO4|z '7e(O<,7*͟0@6{615 y@N wǀ9!#\Woʟ0lmH`s;y̯͓ϯbEN?)A= P|ȯ? 9ꇎ'n@洟 (G~͏{Í>0@6kDS@xA6l@ :e }4P#3f@>A!s:|k[w>0@6$cW cYY#Gȷb8z뭡/#-r2O]l( iH> 1y}c ̭ԁϼ駣.N~O{a КJ7a/^S#=65&Eg d:=^06e MޭX5}fC<|"e x>CN`Ό!|õoQM#M a 엁loj߀{Թӿ 7:*w@?Qٌ a \xU/ϯ?3O)2t4*2 |0x'o[n{@Xc 5f"3\;854o(KeM_jxdH\w=9!Dי M=%d F@lr=ypsu7@g@6g:F"@88>߁kzd*!:~zcgM ̞;~Sˑ1 iF41+c1 27T%7cq z 4aF dp#| `Ј<<~=1gMw޹9x7GM^>a &fT0Ia :hC1W?sa 셁lBk*=$<cI>ǏCm<6>0NlN{~3 17U?ut. 3 )N€ϓ<_NNq?8; 986c qnd\0Λl{rD'~?x $)3ca`s؜h0pq1;1,kj\1*\w8/cWYȼ PDn=0fBGyӳ^O˫Ha%Dy7^BMa dp{Φ - 7Aoԕ'7С =QrH =L==yǯH~<|3nܩ'|oCoʹ2C& >"h?wnW}p0%\>QcF:#HG;֫aGhp0? _)ӑHc<ĹcK˗sƸqFW=98kx%s~#m`MҜ dp%=ɄXXz;/bNx)X{<^aDDw}?̏} yףap}'ꩃ=~dS?as@z : a 3 :7YaE``DD @GʒH=z =r1_V'=_Oah0@(,g}NJp'\1^-3..t9~%?pIiE9)CWH=WN]W壇NG&-' 3 );,. 6%^;3cQFޥNGuD=?(à' =ЯzF#G/7Ҍ<4r&-k'q;AOoAU}qGЧ]rM a`lVIƦ .EdKqMqs$I[8n5\*iE(OGb=2H^: mgdOb \t]xzD<6IStGQ$yӃGI>iG}Ѿ'z{'0lS`Ewߑ]mw C9kx!܄YN['rc tduKa dp{Φd_t"̞x|k'C A=^O,'; +/^:c r| g>O7Ѐ>Og9򭛲/ }` dK̀b[Ѓ'GN2pygq1Vy@OADANy'}(>Iz)h #3 3 O ]\?U\RZm ,EtR.F%D@_`Ƌ3Փl5^z i@_$__sq2֥Wt-7 LO]lm[D'<N`ZGo:NlNmF_xXHo׺ȂkDXp]d37׵֧S d>;*rn{Op#}"m~OsM93 9cj,xnD-Rz`2@7k \rz"=$Rm7(cd<2f iH9_&H P< i=k>!6A@AS[/12' (ŰX{d7"clD"N~GIY,=b0k8)c]`oSW)k!OK] iBGs# "'d7 \Sqӟ0p dp~1kj"  zKO/z_}X?ӱ'Ë裏Fʻ =h|1 |>F}PP1/y$z:3ߍ|c|=ۃ?i" :\_S`0C;-|;P2]YB8e8X"O@hE H9aF^Hq (x m}X;|8ԧuXmP{x?pzr t@ːo} ygȍ'sa s-ɢIdś3hy۷щ g@6g4BJ('ϩezz.SY,DO>uZr׎cq8w3W9D2g/f20@6˼,J]7+}9ܜ.$q$T*bq4^Pmic-1upϓoN'+u!H\@6 2%==q݃r뱜򮻏n`v==\:D":.k}ztճ_~>?XeKc0zO(`J d9W} y\//ձX=6W>׍!gLtMtbe$}r tAd{Y(?g|4$x=' !l0.:}F\=&(K@NЈL?M5 2 6yc37 l PϷ5춃!'#h۷ͷM|=y).Xǀ"?DooO0B}}eԥ>elg(O8a8,z~L 4#˳\=6ō jY V!HYHx@~B}@s@C;ec{G:r^Cz\'sc  f\cO: ?Pz qа*WrtJ"aE *iY΍󧯿/F5!O8С/ǏwẈ`_\= zpOȽA>+aw @67# ^/k~P]ᚠh/D8 m/TH?\PA ?o\xA9Q C"!( Gׅ|ʩo=a1IG%Dfyʈ dp5?#łyƍq#'13F5QzQ%Rc 8=h?DIzգl39/=@|67܇rop<:(Gϑȟ0p dp Qk7 (a0:v=ݢ/a ]E. z~uo=KQ7Y]#]nuO{Q#qIWPΟ0p dP`0r{<^ x=aNא[G<r 6*N -}jn3><P>1e 7ƳN>ai[@A_TPʟa ' }f>|"G77zϝ yHX` R6X,$k.>6Uz}A=@!v=[D&~َ-"',ej#y$a zldaz; (OO@DHӿq@r x ^RӧFiʀ5 dp AWep3v| ."p :~.}]{\cC` ח0pj dj0F<<]f&^:~  uy"tO #bxiOH~ON,cWt@ ?'x' 1|D{b9=Gzi.Pi3*by> {u.:12pV <"\= z>Y?/XBB~-*uda$\#{ o}PH9KzT?GÀ9Ԇ{wKW@>9%"imW"=Rߏ>Pܗ;6j0Oa4qֽm}H׌po7 K0o|d@ӵ]{fp&h{^.:12p]cNd'yNy# D"=cϿq6/x'e":zX30p 8O[O{Ol;"'S?w>٫R>'ROO(QYf,6a2Ш2٠c8Kv{ϾhrMhzr} sF Qk8: Œs9϶L0pl @Z'sI7!<YzDۙ7s7m=ڗYXI@@9(K@kp.[6я>P=6 z.o"$g Y H1 ςìo Y|Y]đ,εC`Θw~ÁO9|/tTý=G7b֟Ӗ>IyB;LYlD## #!$k} #>2\/R~r \. ȂgM4NOSvNRDIC30W̷s /^(xm3ـciA铨>y}NS}n:I;ma8  #è٣F@t# zR|0Pz7!} Aڍr,-Z[cc ,~\A|=$R9u=/-s?+ɜ0x='=r'a4g$qy I=o_mNA$XYQƀ!Gr rt4Zh V箱q/g}ewHP>*mG,~ʹ^ QZ#W<3d,.ޖ Z?`>9a> pϻaf~JCz"p?m}OleEGF" 3pcEk-Gu/vRP.. c1||= /;*{(Qz#3 3ps[/vnaTX.EƷ CT2 6w~:Yl4v*ɟa9vN?mуOh4''#e)2pScmj@0 wEzyY~i1 g $gvi 7ȓyCS'&< +gwk=[u(3{=ce΋h>xxj ?k'%f6v 3Zq^i: iO<mK0pN  fEs%*dgcjanz 0=!pD uB7c6 *1TdCWqˇ>r~$ 7>eAyIS-C9oLaܚyy c'mM<=`~m|8unb@,ZKQNhyѺO/qw~n)c /͏Xؑk5< ϴx1 4~R4.ESG8tf"E18x|/C5߿,Djȣ>ʂ2g?]`y 2Yӟo_kOx"I-l$ -\s/?z3oEAdnW'|8ub#&э7e.z.|=m;9dLŖkx5<"wdo gCaiv%ȹ9$z.GݤAcvfYmX|Ǐ ωFACO\=O!8O^5ĀocLjpCzGN?0x ~{}n΀K-O^6׶/:; D0YlF"I<^sn(91 ,)k>,0΀*zocm;93pV FCC%z*C7d\w4Rq+w6y F{v|bI9z)0G䃔?\ߞn9a?<ؾh?lw[kda |Ym R\֎tf`mWq.?gݹ/I 팻nyNﺽ΅tׂxU\z=k:(0鵱H<}.A;~ih}vfw? *gЈMo;.O~bON="x@{ wbj a` <z-0@a$ a 0?i! 01 MI:@a` dBa c t( 0`0@@67%Pa 3 9N a 0lnJҡ0@g s@a ܔCa 0@68-0@888)I@a 쟁lqZa 0pp dppS0@?㴰g^U\i"0@Xaya`g FӧEO?q30N`'4MHwԀcOz uxi?@8w8;Ưqpk_}x__/SQy-0! 0`영n#NGʁn" '.Յ0p dpzXXc5z='|2Çq$}O)O]_|ml`!! 0@6˼D0='xyK~ X^*@'@6'77 :FÎ/Gc3~ DQapplzҽuuݫ<Ѱwu ha` dS h5vuNI<~O \{0y3 yK5t`'53 a `syK0s ~v\)cqv>^뮟0)3f\K/s0#x]rekw@=K5DO $HRw|ITTO(|D]ճ7/}D9@F#,{Ĵa 6A~3]!z;ki{Ox |Sb_5"'@w@MӦѶiߗ5dAd?#SHOٶχTq/n7}^S^)RG.\[uRrԑ@8vFQ>yvDD=qm{}d6Lagcg&xO#C6#9U N AMhkt\3 _>prCZnQ9ngOYO>|8r < VBaXvM~`EΠ!\(k>`?a 5`Ym>0@9^~kڰMm8zzL q@%rM>uD5od@x pQ!P2Ms@$(==`P&p㺫:4ʝ?=?Ctgφ>'l<p3`{w5@`0N{o c73`V.:Y3i2\ȿF;HGh vhwA)cYY+;׵4mF?4t},g]9>^9EDG:Y9p10p `cؓ1;.1,(U7?O|ޠ52ьHR\ϴq(59?>$w'Ξӏ0m'F ȉ22l+:8"ka)5}rlu>o6,UF' V:A%fFӑ>f,>s K< %\?G20Η% cdDɵAj6x ;Ѕ4I;O]G٩pzv=YWvQBrEDOwC1֙?c^!p=sP1aоOƮh_@䬣 ʬ2MÍ6s4Qys\_{ٻ!Zӹ>J{k|T~(I?@wuvQԟ^v)SF Pm`C~=(CP]wpEw(r\z@::>P:o8?WCyхs n 1 gvs>~ߡCv_hTgXv$oU'I/‹S~}iA/5nQA#2a蚦^k@H,5Mdk<ɭqӑk?#D^_ a  ktc7HO:ݨAC6tZb ߊ6}QZGjpUWQ+_^t=f{ 嵪ڭV{c@aDyrq(_AfnCuD@=[;yC9hr2 "ʛ\m׃gmOۣ@/eu[T._[ϰew)7=ȃǵ>~S۪㻲=Oku_̺IHo{sg 'q2N,Ty@3.Fd5SbgDDQX 5r(5JԭM H\/2H^wy;#G㢟͒#ה_בh[03:}è GDb<(q}?6l,5Dn/Y=xZxR c5%V؍E+j _|6W k(TQU}zSJi yGf7Kt@>E.pg,G9ׁtf!⏼$Ϩ/'|!mM0cn~oʮaᥗQN1`-}ϰ\<7pe'RqP(Wo y}Zk3l5߱Ix@eenCQQxPXME<es pKF_X{60QF9X&Nׅ,5F6D<@ԁ!#`cyS@=ڹ u]7#?rcqg=ƉtAN:͈Nf0Q{Б].mhC&ᯔ0 :_:%aѯ0ls]_oKɰ?{xrax  g4Wt6o~t8 (*?(#F}2$/.#W TKJ>Y\y{Aӓ'Q9H5!Ljs >↸|Gw'[Q|/*WO8=O2(ߖ]6 K,r0vk?kiyK_T}aϿoFK]}Ti'56 %x?<\Gn~YycxrabKvmhP_VGS /}SׯUt(Av5*zPY^OU+>)",= 8 J j@FCy^n>M?eYCE UFY #&Q8R eGQ9 6v/b;v^ir!u0~hX4r#}1bܩ# 0 \]YYK~xy+~W}5(ϟ0<5˪Z?k6ud<~ͮr׆6_n:xTzV'ޮ}Dkxl 0\zuzyVc*P={ '0 ۑYNTVNzia~-a `+\u[zZl IDAT 1'Ͽ?aī?UqPb G,qrfSrN4 r̞Tfx=l/?~6Cgx}8&8hb|dXT =/3`߬͊ Er|z ꅗ 0DF\#r#}dˣ(熭|֧mɣ6yag֗Q>Z/'tDO5GLa ͮ۬ۜfc@x08xMw9QtS!t_ᗵfb;௵{|n>gU+q[F2(|jȥ_תSs`+w+ޫξu: Oq,x`h8<6D4<\ j _߉CFcGgr+c/*WOoGD v+>qAGrG=w rrճ a DXϱ\cY{oCu :G_T|TO~\J(B6?Ǝwj]N*;wOoa|N,OOw|i5ƫ*8Pzr[XN0`ukH]Kk> D|hGz#: 0ph Fk`i@号K6>Xl0TǣZ?1'41eaFa }V֓/ZR~ppdүo B/]Zs H'0"z*?&]0tLuE DKs .\Mc DO綨A9 =/H@=vgz@Wr,Ǹ ճ|0 0`v}wwfwcfMGc0Y}/Z +T3~tyُ*_^ Ęw<#~QJtBqO.^Zr=XQɇ%c$x[r\ſFz7E" %#,2 c'#vsl@=בkڟrhkth`z =0q0#iHJع9|7kI-^G. CU2^_?6\t|N@=xR;:jʎ <|ų_Yo ~T%>`+s` tP\9!5k04q$_c A\ē Q~./1.㸯sn㪴m9U=PrsEvn-'*- a LX{dwq]b'4kY+xnj aJ1|]?){'eG׺=ZO_OO{r`~߂|v޻G~aP;' dzAP LZAidM~Œ7[~'4G8z8%̰`4S@¯YFٗ'<7+9^ xyBHS൨:'#8v'8z@{d#n~ʇ0plvI$Z1¾y V=_Mz\> _fnvy ͪ^." *8X>9w/Yy$Ss]sz>d#1mS툽Mm#@kms<}s]cĹXj{$.u׵lxU6m_iѿp'231p¯ BV#I_FF]EBd9^@op 0T:KqGekƯ [5^#0(u:xlݯkm[Ư%xc#PouoIp'y E8/3^K*}7<3@wtBrCpa4! c&RQ{7u\n>zhGܶa Di/l+qz V_/ṖDtFG=?WwdP_V0~33`:/A+vD|m0?*7 @U06 KE-opv}{o|? |aPp ]c@rz NG_8ǯ^-㸿.g c9 'ޥߕc3Pz|=p'Q/E, Q|I =x>S\}eUwxO W.sn7O3ޥGNz߁6l5ȹ/l6}>mDFLa 2F >k_z%0hO9-@8o­a~ҹp'>Pw6|a9/.ro|<>6W \^o߫M' 1r /=ʸE}=r?O[5=m$O& }޶a LX \c*r=>N '}W9X#ÉF x?_k9=4gw|F>m+{ w෉kIfPvDCzc a~!Zʽ*51^1JARxd.X؟nk<|p`> ݹ >nfʇ0Q#k,h2Ƙo+}?_U|l 1&kMEΦcoXil\-&2|6{w`3v9|Q]})"߼0oW1|dcPٯ kn:$ƀKUW =v0pz=>\nl@Loޫ{]~O@mpܢS1^>^7{Ba`,{qro|BM9}e앇1?Hfŏ r_]Yr2< |&w8MK pOç+0r#㚸@-/8Pf@omc; Юm3@kkيq  8ʯqq? 9Q/=ˍ@]c8A?z_VZ)B&~ԇ||p:?i~+ 7E*HC8/xۅU|9EwǕ QW'~0xџ*7S E4pA;|H 76$`E7}ު)@xI rs{c-~!C$B%R6{Q};9W12z*+耋q0^+=6 )x;+ &)l:sQC\W;ckRF`mbxm\_7RGa`}5c.e{%<20>Vu~[*FIٷo+-sSjO_`K6W*0[հYgPAOqG|2J/)2Rx\Q^r^ە8`3#dXo]m^>sgI$ *mz@۴I/q+"wR* 0p8 Y9 =$=dxó|^^?O}K]RK~I@j_-J;9owOJ8>X X{CL]҅X d5LCT0lsZy?&XTﮱ:=5  )ߢ a "98 kN}vƷ//qP /4tWI~;@x~9UoIƳ"w8$SB)sZI&fbCq91?/߹. O]CT.@x x?kt@Mck8~U'§s0~͏OV&a_^'^]`;L? D_: b+h|n@h]c{>:]OBDq_}7@΀D.Bl1,~ҷ}/s|O?}_JN7w1* o8x1qPF쭊(* /cGt)3]I7@a` 9i{@pŚF>0NNN|U0e u#}tQ|3+g33]#u03}Q]{3Yx775|#]W3 '0(_$ 05^yl *9G12I&aƗ`QlgM]Ů_7e,[#{PyV_w_y{*;n P3]f" 0tr:L&wd#-Guy%cy9|6ćb_Jme5?XO|<_fG^+1~` Ѽ*y0@8XY{pxVľ7Vlb$ Ͽ&O󭁯`T/~ $PeOa @,1@DW~G;ƣ ڰ$wݓ@޺Mt`t;crNa g=ຏ h/F.Ep#0>W'WyO篽!sx췿-煾{sv'<i7# a e@z=>xR0ѣ˗9߾!ܖM_V'IPgP_ۓdv @ @ @ @ @ @ @ @ @UJw1IENDB`il32Ѡl8mkicinga2-2.8.1/icinga-studio/icinga.ico000066400000000000000000000013761322762156600175440ustar00rootroot00000000000000 ( @ppwpppppwwpwwxpwxxwppppwpicinga2-2.8.1/icinga-studio/icinga.rc000066400000000000000000000013551322762156600173730ustar00rootroot00000000000000#include #include "icinga-version.h" LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US icinga ICON "icinga.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "Icinga Development Team" VALUE "FileDescription", "Icinga Studio" VALUE "FileVersion", VERSION VALUE "InternalName", "icinga-studio.exe" VALUE "LegalCopyright", " Icinga Development Team" VALUE "OriginalFilename", "icinga-studio.exe" VALUE "ProductName", "Icinga 2" VALUE "ProductVersion", VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 0x04E4 END ENDicinga2-2.8.1/icinga-studio/icinga.xpm000066400000000000000000000024041322762156600175670ustar00rootroot00000000000000/* XPM */ static const char *icinga_xpm[] = { "32 32 5 1", " c None", ". c #808080", "+ c #000000", "@ c #C0C0C0", "# c #FFFFFF", " ", " .++++++++++++++++++++++++. ", " .+++++++++++++++..+++++++++. ", " .+++++++++++++++@##@+++++++++. ", " +++++++++++++++.####.+++++++++ ", " +++++++++++++++.####.+++++++++ ", " ++++++++++++++++####++++++++++ ", " ++++++++++++++++@@..++++++++++ ", " +++++..+++++++++#.++++++++++++ ", " ++++.##@+++++++@#+++++++++++++ ", " ++++.###+++++++#.+++++++++.+++ ", " ++++.###@++.@@@#+++++++++@##.+ ", " +++++++.@#######.+++++++.###@+ ", " +++++++++########++++..@####.+ ", " ++++++++.########@@###@...@.++ ", " ++++++++.#########@..+++++++++ ", " ++++++++.########@++++++++++++ ", " ++++++++.########.++++++++++++ ", " +++++++++########+++++++++++++ ", " +++++++++.######.+++++++++++++ ", " +++++++++.#....#.+++++++++++++ ", " ++++++++.#.++++.#.++++++++++++ ", " ++++++++@@++++++##.+++++++++++ ", " ++++@##@#+++++++##@+++++++++++ ", " +++@####@+++++++..++++++++++++ ", " +++######.++++++++++++++++++++ ", " +++######.++++++++++++++++++++ ", " +++######+++++++++++++++++++++ ", " .++.####.++++++++++++++++++++. ", " .+++..+++++++++++++++++++++. ", " .++++++++++++++++++++++++. ", " "}; icinga2-2.8.1/icinga-studio/mainform.cpp000066400000000000000000000222001322762156600201170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga-studio/mainform.hpp" #include "icinga-studio/aboutform.hpp" #include #include #include using namespace icinga; MainForm::MainForm(wxWindow *parent, const Url::Ptr& url) : MainFormBase(parent) { #ifdef _WIN32 SetIcon(wxICON(icinga)); SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); #endif /* _WIN32 */ String port = url->GetPort(); if (port.IsEmpty()) port = "5665"; m_ApiClient = new ApiClient(url->GetHost(), port, url->GetUsername(), url->GetPassword()); m_ApiClient->GetTypes(boost::bind(&MainForm::TypesCompletionHandler, this, _1, _2, true)); std::string title = url->Format() + " - Icinga Studio"; SetTitle(title); m_ObjectsList->InsertColumn(0, "Name", 0, 300); m_PropertyGrid->SetColumnCount(3); } void MainForm::TypesCompletionHandler(boost::exception_ptr eptr, const std::vector& types, bool forward) { if (forward) { CallAfter(boost::bind(&MainForm::TypesCompletionHandler, this, eptr, types, false)); return; } m_TypesTree->DeleteAllItems(); if (eptr) { try { boost::rethrow_exception(eptr); } catch (const std::exception& ex) { std::string message = "HTTP query failed: " + std::string(ex.what()); wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this); Close(); return; } } wxTreeItemId rootNode = m_TypesTree->AddRoot("root"); for (const ApiType::Ptr& type : types) { m_Types[type->Name] = type; } for (const ApiType::Ptr& type : types) { if (type->Abstract) continue; bool configObject = false; ApiType::Ptr currentType = type; for (;;) { if (currentType->BaseName.IsEmpty()) break; currentType = m_Types[currentType->BaseName]; if (!currentType) break; if (currentType->Name == "ConfigObject") { configObject = true; break; } } if (configObject) { std::string name = type->Name; m_TypesTree->AppendItem(rootNode, name, 0); } } } void MainForm::OnTypeSelected(wxTreeEvent& event) { wxTreeItemId selectedId = m_TypesTree->GetSelection(); wxString typeName = m_TypesTree->GetItemText(selectedId); ApiType::Ptr type = m_Types[typeName.ToStdString()]; std::vector attrs; attrs.push_back("__name"); m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectsCompletionHandler, this, _1, _2, true), std::vector(), attrs); } static bool ApiObjectLessComparer(const ApiObject::Ptr& o1, const ApiObject::Ptr& o2) { return o1->Name < o2->Name; } void MainForm::ObjectsCompletionHandler(boost::exception_ptr eptr, const std::vector& objects, bool forward) { if (forward) { CallAfter(boost::bind(&MainForm::ObjectsCompletionHandler, this, eptr, objects, false)); return; } m_ObjectsList->DeleteAllItems(); m_PropertyGrid->Clear(); if (eptr) { try { boost::rethrow_exception(eptr); } catch (const std::exception& ex) { std::string message = "HTTP query failed: " + std::string(ex.what()); wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this); return; } } std::vector sortedObjects = objects; std::sort(sortedObjects.begin(), sortedObjects.end(), ApiObjectLessComparer); for (const ApiObject::Ptr& object : sortedObjects) { std::string name = object->Name; m_ObjectsList->InsertItem(0, name); } } void MainForm::OnObjectSelected(wxListEvent& event) { wxTreeItemId selectedId = m_TypesTree->GetSelection(); wxString typeName = m_TypesTree->GetItemText(selectedId); ApiType::Ptr type = m_Types[typeName.ToStdString()]; long itemIndex = -1; std::string objectName; while ((itemIndex = m_ObjectsList->GetNextItem(itemIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != wxNOT_FOUND) { objectName = m_ObjectsList->GetItemText(itemIndex); break; } if (objectName.empty()) return; std::vector names; names.push_back(objectName); m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, _1, _2, true), names, std::vector(), std::vector(), true); } wxPGProperty *MainForm::ValueToProperty(const String& name, const Value& value) { wxPGProperty *prop; if (value.IsNumber()) { prop = new wxFloatProperty(name.GetData(), wxPG_LABEL, value); prop->SetAttribute(wxPG_ATTR_UNITS, "Number"); return prop; } else if (value.IsBoolean()) { prop = new wxBoolProperty(name.GetData(), wxPG_LABEL, value); prop->SetAttribute(wxPG_ATTR_UNITS, "Boolean"); return prop; } else if (value.IsObjectType()) { wxArrayString val; Array::Ptr arr = value; { ObjectLock olock(arr); for (const Value& aitem : arr) { String val1 = aitem; val.Add(val1.GetData()); } } prop = new wxArrayStringProperty(name.GetData(), wxPG_LABEL, val); prop->SetAttribute(wxPG_ATTR_UNITS, "Array"); return prop; } else if (value.IsObjectType()) { wxStringProperty *prop = new wxStringProperty(name.GetData(), wxPG_LABEL); Dictionary::Ptr dict = value; { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { if (kv.first != "type") prop->AppendChild(ValueToProperty(kv.first, kv.second)); } } String type = "Dictionary"; if (dict->Contains("type")) type = dict->Get("type"); prop->SetAttribute(wxPG_ATTR_UNITS, type.GetData()); return prop; } else if (value.IsEmpty() && !value.IsString()) { prop = new wxStringProperty(name.GetData(), wxPG_LABEL, ""); prop->SetAttribute(wxPG_ATTR_UNITS, "Empty"); return prop; } else { String val = value; prop = new wxStringProperty(name.GetData(), wxPG_LABEL, val.GetData()); prop->SetAttribute(wxPG_ATTR_UNITS, "String"); return prop; } } void MainForm::ObjectDetailsCompletionHandler(boost::exception_ptr eptr, const std::vector& objects, bool forward) { if (forward) { CallAfter(boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, eptr, objects, false)); return; } m_PropertyGrid->Clear(); if (eptr) { try { boost::rethrow_exception(eptr); } catch (const std::exception& ex) { std::string message = "HTTP query failed: " + std::string(ex.what()); wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this); } } wxTreeItemId selectedId = m_TypesTree->GetSelection(); wxString typeName = m_TypesTree->GetItemText(selectedId); ApiType::Ptr type = m_Types[typeName.ToStdString()]; String nameAttr = type->Name.ToLower() + ".__name"; if (objects.empty()) return; ApiObject::Ptr object = objects[0]; std::map parents; for (const auto& kv : object->Attrs) { std::vector tokens; boost::algorithm::split(tokens, kv.first, boost::is_any_of(".")); std::map::const_iterator it = parents.find(tokens[0]); wxStringProperty *parent; if (it == parents.end()) { parent = new wxStringProperty(tokens[0].GetData(), wxPG_LABEL); parent->SetAttribute(wxPG_ATTR_UNITS, "Object"); parents[tokens[0]] = parent; } else parent = it->second; wxPGProperty *prop = ValueToProperty(tokens[1], kv.second); parent->AppendChild(prop); } /* Make sure the property node for the real object (as opposed to joined objects) is the first one */ String propName = type->Name.ToLower(); wxStringProperty *objProp = parents[propName]; if (objProp) { m_PropertyGrid->Append(objProp); m_PropertyGrid->SetPropertyReadOnly(objProp); parents.erase(propName); } for (const auto& kv : parents) { m_PropertyGrid->Append(kv.second); m_PropertyGrid->SetPropertyReadOnly(kv.second); } m_PropertyGrid->FitColumns(); } void MainForm::OnQuitClicked(wxCommandEvent& event) { Close(); } void MainForm::OnAboutClicked(wxCommandEvent& event) { AboutForm form(this); form.ShowModal(); } icinga2-2.8.1/icinga-studio/mainform.hpp000066400000000000000000000047041322762156600201350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MAINFORM_H #define MAINFORM_H #include "remote/apiclient.hpp" #include "remote/url.hpp" #include "base/exception.hpp" #include "icinga-studio/forms.h" namespace icinga { class MainForm : public MainFormBase { public: MainForm(wxWindow *parent, const Url::Ptr& url); virtual void OnQuitClicked(wxCommandEvent& event) override; virtual void OnAboutClicked(wxCommandEvent& event) override; virtual void OnTypeSelected(wxTreeEvent& event) override; virtual void OnObjectSelected(wxListEvent& event) override; private: ApiClient::Ptr m_ApiClient; std::map m_Types; void TypesCompletionHandler(boost::exception_ptr eptr, const std::vector& types, bool forward); void ObjectsCompletionHandler(boost::exception_ptr eptr, const std::vector& objects, bool forward); void ObjectDetailsCompletionHandler(boost::exception_ptr eptr, const std::vector& objects, bool forward); wxPGProperty *ValueToProperty(const String& name, const Value& value); }; } #endif /* MAINFORM_H */ icinga2-2.8.1/icinga-version.h.cmake000066400000000000000000000000411322762156600172100ustar00rootroot00000000000000#define VERSION "${GIT_VERSION}" icinga2-2.8.1/icinga2.spec000066400000000000000000000030371322762156600152430ustar00rootroot00000000000000#/****************************************************************************** # * Icinga 2 * # * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * # * * # * This program is free software; you can redistribute it and/or * # * modify it under the terms of the GNU General Public License * # * as published by the Free Software Foundation; either version 2 * # * of the License, or (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the Free Software Foundation * # * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * # ******************************************************************************/ # The spec file was moved to https://github.com/Icinga/icinga-packaging %define revision 1 Version: 2.8.1 icinga2-2.8.1/itl/000077500000000000000000000000001322762156600136405ustar00rootroot00000000000000icinga2-2.8.1/itl/CMakeLists.txt000066400000000000000000000021041322762156600163750ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_subdirectory(plugins-contrib.d) install( FILES itl command-icinga.conf hangman plugins command-plugins.conf manubulon command-plugins-manubulon.conf windows-plugins command-plugins-windows.conf nscp command-nscp-local.conf plugins-contrib DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2/include ) icinga2-2.8.1/itl/command-icinga.conf000066400000000000000000000034361322762156600173630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "icinga" { import "icinga-check-command" } object CheckCommand "cluster" { import "cluster-check-command" } object CheckCommand "cluster-zone" { import "cluster-zone-check-command" vars.cluster_zone = "$host.name$" } object CheckCommand "random" { import "random-check-command" } object CheckCommand "exception" { import "exception-check-command" } icinga2-2.8.1/itl/command-nscp-local.conf000066400000000000000000000163331322762156600201640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ if (!globals.contains("NscpPath")) { NscpPath = dirname(msi_get_component_path("{5C45463A-4AE9-4325-96DB-6E239C034F93}")) } object CheckCommand "nscp-local" { command = [ NscpPath + "\\nscp.exe", "client" ] arguments = { "--log" = { value = "$nscp_log_level$" description = "The log level to use" } "--load-all" = { set_if ="$nscp_load_all$" description = "Load all plugins (currently only used with generate)" } "--module" = { value = "$nscp_modules$" description = "Specify which NSClient++ modules are required. 'nscp client' just needs 'CheckSystem' by default." repeat_key = true } "-q" = { value = "$nscp_query$" description = "Run a query with a given name" required = true } "-b" = { set_if = "$nscp_boot$" description = "Boot the client before executing command (similar as running the command from test mode)" } "-a" = { value = "$nscp_arguments$" repeat_key = true description = "List of arguments (arguments gets -- prefixed automatically (--argument foo=bar is the same as setting '--foo bar')" } "--show-all" = { set_if = "$nscp_showall$" description = "" } } vars.nscp_log_level = "critical" vars.nscp_load_all = false vars.nscp_boot = true vars.nscp_showall = false vars.nscp_modules = [ "CheckSystem" ] } object CheckCommand "nscp-local-cpu" { import "nscp-local" arguments += { "--time" = { value = "$nscp_cpu_time$" repeat_key = true description = "The time to check" } "--warning" = { value = "load>$nscp_cpu_warning$" } "--critical" = { value = "load>$nscp_cpu_critical$" } "-a" = { value = "$nscp_cpu_arguments$" repeat_key = true } } vars.nscp_query = "check_cpu" vars.nscp_showall = "$nscp_cpu_showall$" vars.nscp_cpu_time = [ "1m", "5m", "15m" ] vars.nscp_cpu_showall = true vars.nscp_cpu_warning = 80 vars.nscp_cpu_critical = 90 } object CheckCommand "nscp-local-memory" { import "nscp-local" arguments += { "--type=committed" = { set_if = "$nscp_memory_committed$" description = "Total memory (RAM+PAGE)" } "--type=physical" = { set_if = "$nscp_memory_physical$" description = "Physical memory (RAM)" } "--warning" = { value = "$nscp_memory_op$ $nscp_memory_warning$" } "--critical" = { value = "$nscp_memory_op$ $nscp_memory_critical$" } "-a" = { value = "$nscp_memory_arguments$" repeat_key = true } } vars.nscp_query = "check_memory" vars.nscp_showall = "$nscp_memory_showall$" vars.nscp_memory_op = {{ if (!macro("$nscp_memory_free$")) { return "used >" } else { return "free <" } }} vars.nscp_memory_committed = false vars.nscp_memory_physical = true vars.nscp_memory_free = true vars.nscp_memory_warning = {{ if (!macro("$nscp_memory_free$")) { return 80 } else { return 20 } }} vars.nscp_memory_critical = {{ if (!macro("$nscp_memory_free$")) { return 90 } else { return 10 } }} vars.nscp_memory_showall = false } object CheckCommand "nscp-local-os-version" { import "nscp-local" vars.nscp_query = "check_os_version" } object CheckCommand "nscp-local-pagefile" { import "nscp-local" vars.nscp_query = "check_pagefile" } object CheckCommand "nscp-local-process" { import "nscp-local" vars.nscp_query = "check_process" } object CheckCommand "nscp-local-service" { import "nscp-local" arguments += { "--service" = { value = "$nscp_service_name$" repeat_key = true } "--ok" = { value = "$nscp_service_otype$='$nscp_service_ok$'" } "--warning" = { value = "$nscp_service_wtype$='$nscp_service_warning$'" } "--critical" = { value = "$nscp_service_ctype$='$nscp_service_critical$'" } "-a" = { value = "$nscp_service_arguments$" repeat_key = true } } vars.nscp_query = "check_service" vars.nscp_showall = "$nscp_service_showall$" vars.nscp_service_showall = true vars.nscp_service_type = "state" vars.nscp_service_otype = vars.nscp_service_type vars.nscp_service_wtype = vars.nscp_service_type vars.nscp_service_ctype = vars.nscp_service_type } object CheckCommand "nscp-local-uptime" { import "nscp-local" vars.nscp_query = "check_uptime" } object CheckCommand "nscp-local-version" { import "nscp-local" vars.nscp_query = "check_version" vars.nscp_modules = [ "CheckHelpers" ] } object CheckCommand "nscp-local-disk" { import "nscp-local" arguments += { "--drive" = { value = "$nscp_disk_drive$" repeat_key = true } "--warning" = { value = "$nscp_disk_op$ $nscp_disk_warning$" } "--critical" = { value = "$nscp_disk_op$ $nscp_disk_critical$" } "-a" = { value = "$nscp_disk_arguments$" repeat_key = true } } vars.nscp_query = "check_drivesize" vars.nscp_showall = "$nscp_disk_showall$" vars.nscp_disk_op = {{ if (!macro("$nscp_disk_free$")) { return "used >" } else { return "free <" } }} vars.nscp_disk_showall = true vars.nscp_disk_free = false vars.nscp_disk_warning = {{ if (!macro("$nscp_disk_free$")) { return 80 } else { return 20 } }} vars.nscp_disk_critical = {{ if (!macro("$nscp_disk_free$")) { return 90 } else { return 10 } }} vars.nscp_modules = [ "CheckDisk" ] } object CheckCommand "nscp-local-counter" { import "nscp-local" arguments += { "--counter" = { value = "$nscp_counter_name$" repeat_key = true } "--warning" = { value = "value $nscp_counter_op$ $nscp_counter_warning$" } "--critical" = { value = "value $nscp_counter_op$ $nscp_counter_critical$" } "--perf-syntax" = { value = "$nscp_counter_perfsyntax$" } "-a" = { value = "$nscp_counter_arguments$" repeat_key = true } } vars.nscp_counter_op = {{ if (!macro("$nscp_counter_less$")) { return ">" } else { return "<" } }} vars.nscp_query = "check_pdh" vars.nscp_showall = "$nscp_counter_showall$" vars.nscp_counter_less = false vars.nscp_counter_perfsyntax = "$nscp_counter_name$" } icinga2-2.8.1/itl/command-plugins-manubulon.conf000066400000000000000000000250601322762156600216050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * main snmp-manubulon template */ template CheckCommand "snmp-manubulon-command" { import "ipv4-or-ipv6" arguments = { "-H" = { value = "$snmp_address$" description = "Name or IP address of host to check" } "-C" = { set_if = "$snmp_nocrypt$" value = "$snmp_community$" description = "Community name for the host's SNMP agent (implies v1 protocol)" } "-p" = { value = "$snmp_port$" description = "SNMP port (Default 161)" } "-2" = { set_if = "$snmp_v2$" description = "Use snmp v2c" } "-l" = { set_if = "$snmp_v3$" value = "$snmp_login$" description = "Login and auth password for snmpv3 authentication" } "-x" = { set_if = "$snmp_v3$" value = "$snmp_password$" description = "Priv password" } "-L" = { set_if = "$snmp_v3_use_authprotocol$" value = "$snmp_authprotocol$" description = ", - ," } "-X" = { set_if = "$snmp_v3_use_privpass$" value = "$snmp_privpass$" description = "Priv password for snmpv3 (AuthPriv protocol)" } "-w" = { value = "$snmp_warn$" } "-c" = { value = "$snmp_crit$" } "-t" = { value = "$snmp_timeout$" description = "Timeout for SNMP in seconds (Default: 5)" } } vars.snmp_address = "$check_address$" vars.snmp_nocrypt = true vars.snmp_community = "public" vars.snmp_v2 = false vars.snmp_v3 = false vars.snmp_login = "snmpuser" vars.snmp_v3_use_privpass = false vars.snmp_v3_use_authprotocol = false vars.snmp_authprotocol = "md5,des" vars.snmp_timeout = "5" } /** * snmp env * Url reference: http://nagios.manubulon.com/snmp_env.html */ object CheckCommand "snmp-env" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_env.pl" ] arguments += { "-T" = { value = "$snmp_env_type$" description = "Environment Type [cisco|nokia|bc|iron|foundry|linux]" } "-F" = { value = "$snmp_env_fan$" description = "Minimum fan rpm value (only needed for 'iron' & 'linux')" } "-c" = { value = "$snmp_env_celsius$" description = "Maximum temp in degrees celsius (only needed for 'iron' & 'linux')" } "-f" = { set_if = "$snmp_perf$" description = "Perfparse compatible output" } } vars.snmp_env_type = "cisco" vars.snmp_perf = true } /** * snmp load * Url reference: http://nagios.manubulon.com/snmp_load.html */ object CheckCommand "snmp-load" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_load.pl" ] arguments += { "-T" = { value = "$snmp_load_type$" description = "CPU check" } "-f" = { set_if = "$snmp_perf$" description = "Perfparse compatible output" } } vars.snmp_load_type = "stand" vars.snmp_warn = 85 vars.snmp_crit = 95 vars.snmp_perf = true } /** * Memory and swap usage on Linux given by Net-snmp * Memory usage on cisco routers or Pix * For other systems use check_snmp_storage.pl * Url reference: http://nagios.manubulon.com/snmp_mem.html */ object CheckCommand "snmp-memory" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_mem.pl" ] arguments += { "-f" = { set_if = "$snmp_perf$" description = "Performance data output" } "-I" = { set_if = "$snmp_is_cisco$" description = "check cisco memory (sum of all memory pools)" } "-E" = { set_if = "$snmp_is_hp$" description = "check HP / Procurve memory" } } vars.snmp_warn = "94,50" vars.snmp_crit = "98,80" vars.snmp_perf = true vars.snmp_is_cisco = false } /** * snmp storage - Disk/Memory * Url reference: http://nagios.manubulon.com/snmp_storage.html */ object CheckCommand "snmp-storage" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_storage.pl" ] arguments += { "-m" = { value = "$snmp_storage_name$" description = "Name in description OID (can be mounpoints '/home' or 'Swap Space'...)" } "-f" = { set_if = "$snmp_perf$" description = "Perfparse compatible output" } } vars.snmp_storage_name = "^/$$" vars.snmp_warn = 80 vars.snmp_crit = 90 vars.snmp_perf = true } /** * snmp network interfaces * Url reference: http://nagios.manubulon.com/snmp_int.html */ object CheckCommand "snmp-interface" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_int.pl" ] arguments += { "-n" = { value = "$snmp_interface$" description = "Name in description OID (eth0, ppp0 ...). This is treated as a regexp : -n eth will match eth0,eth1,..." } "-k" = { set_if = "$snmp_interface_perf$" description = "Check the input/ouput bandwidth of the interface" } "--label" = { value = "$snmp_interface_label$" description = "Add label before speed in output : in=, out=, errors-out=, etc..." } "-Y" = { set_if = "$snmp_interface_bits_bytes$" description = "Output performance data in bits/s or Bytes/s" } "-y" = { set_if = "$snmp_interface_percent$" description = "Output performance data in % of max speed" } "-B" = { set_if = "$snmp_interface_kbits$" description = "Make the warning and critical levels in K|M|G Bits/s instead of K|M|G Bytes/s" } "-M" = { set_if = "$snmp_interface_megabytes$" description = "Make the warning and critical levels in Mbps" } "--64bits" = { set_if = "$snmp_interface_64bit$" description = "Use 64 bits counters instead of the standard counters when checking bandwidth & performance data for interface >= 1Gbps" } "-e" = { set_if = "$snmp_interface_errors$" description = "Add error & discard to Perfparse output" } "-i" = { set_if = "$snmp_interface_inverse$" description = "Make critical when up" } "-r" = { set_if = "$snmp_interface_noregexp$" description = "Do not use regexp to match NAME in description OID" } "-d" = { value = "$snmp_interface_delta$" description = "Make an average of seconds (default 300=5min)" } "-u" = { set_if = "$snmp_interface_warncrit_percent$" description = "Make the warning and critical levels in % of reported interface speed" } "-N" = { set_if = "$snmp_interface_ifname$" } "-A" = { set_if = "$snmp_interface_ifalias$" } "-f" = { set_if = "$snmp_perf$" description = "Perfparse compatible output (no output when interface is down)" } "-W" = { set_if = "$snmp_interface_weathermap$" description = "Include 'weathermap' data for NagVis in performance data" } } vars.snmp_interface = "eth0" vars.snmp_interface_perf = true vars.snmp_interface_bits_bytes = true vars.snmp_interface_percent = false vars.snmp_interface_kbits = true vars.snmp_interface_megabytes = true vars.snmp_interface_64bit = false vars.snmp_interface_errors = true vars.snmp_interface_noregexp = false vars.snmp_interface_delta = 300 vars.snmp_interface_warncrit_percent = false vars.snmp_interface_ifname = false vars.snmp_interface_ifalias = false vars.snmp_warn = "300,400" vars.snmp_crit = "0,600" vars.snmp_perf = true } /** * snmp process * Url reference: http://nagios.manubulon.com/snmp_process.html */ object CheckCommand "snmp-process" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_process.pl" ] arguments += { "-n" = { value = "$snmp_process_name$" description = "Regex service name eg. ^apache2$" } "-F" = { set_if = "$snmp_perf$" description = "Add performance output (outputs : memory_usage, num_process, cpu_usage)" } "-A" = { set_if = "$snmp_process_use_params$" description = "Add parameters to select processes (ex : 'named.*-t /var/named/chroot' will only select named process with this parameter)" } "-m" = { set_if = "$snmp_process_mem_usage$" value = "$snmp_process_mem_threshold$" description = "Checks memory usage. Values warning and critical in Mb eg. 512,1024" } "-u" = { set_if = "$snmp_process_cpu_usage$" value = "$snmp_process_cpu_threshold$" description = "Checks CPU usage. Values warning and critical in % (value can be > 100% : 100%=1 CPU) eg. 15,50" } } vars.snmp_process_name = ".*" vars.snmp_warn = 0 vars.snmp_crit = 0 vars.snmp_perf = true vars.snmp_process_use_params = false vars.snmp_process_mem_usage = false vars.snmp_process_mem_threshold = "0,0" vars.snmp_process_cpu_usage = false vars.snmp_process_cpu_threshold = "0,0" } /** * snmp service * Url reference: http://nagios.manubulon.com/snmp_windows.html */ object CheckCommand "snmp-service" { import "snmp-manubulon-command" command = [ ManubulonPluginDir + "/check_snmp_win.pl" ] arguments += { "-n" = { value = "$snmp_service_name$" description = "Comma separated names of services (perl regular expressions can be used for every one). By default, it is not case sensitive. eg. ^dns$" } "-N" = { value = "$snmp_service_count$" description = "Compare matching services with instead of the number of names provided." } "-s" = { set_if = "$snmp_service_showall$" description = "Show all services in the output, instead of only the non-active ones." } "-r" = { set_if = "$snmp_service_noregexp$" description = "Do not use regexp to match NAME in service description." } } vars.snmp_service_name = ".*" }icinga2-2.8.1/itl/command-plugins-windows.conf000066400000000000000000000166351322762156600213070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "disk-windows" { command = [ PluginDir + "/check_disk.exe" ] arguments = { "-w" = { value = "$disk_win_warn$" description = "Warning threshold" } "-c" = { value = "$disk_win_crit$" description = "Critical threshold" } "-p" = { value = "$disk_win_path$" description = "Optional paths to check" repeat_key = true } "-u" = { value = "$disk_win_unit$" description = "Use this unit to display disk space" } "-x" = { value = "$disk_win_exclude$" description = "Exclude these drives from check" } "-U" = { set_if = "$disk_win_show_used$" description = "Work with used instead of free space" } } vars.disk_win_unit = "mb" //The default } object CheckCommand "load-windows" { command = [ PluginDir + "/check_load.exe" ] arguments = { "-w" = { value = "$load_win_warn$" description = "Warning threshold" } "-c" = { value = "$load_win_crit$" description = "Critical threshold" } } } object CheckCommand "memory-windows" { command = [ PluginDir + "/check_memory.exe" ] arguments = { "-w" = { value = "$memory_win_warn$" description = "Warning Threshold" } "-c" = { value = "$memory_win_crit$" description = "Critical Threshold" } "-u" = { value = "$memory_win_unit$" description = "Use this unit to display memory" } } vars.memory_win_unit = "mb" //The default } object CheckCommand "network-windows" { command = [ PluginDir + "/check_network.exe" ] arguments = { "-w" = { value = "$network_win_warn$" description = "Warning threshold" } "-c" = { value = "$network_win_crit$" description = "Critical threshold" } "-n" = { set_if = "$network_no_isatap$" description = "Don't show ISATAP interfaces in output" } } vars.network_no_isatap = true } object CheckCommand "perfmon-windows" { command = [ PluginDir + "/check_perfmon.exe" ] arguments = { "-w" = { value = "$perfmon_win_warn$" description = "Warning threshold" } "-c" = { value = "$perfmon_win_crit$" description = "Critical threshold" } "-P" = { value = "$perfmon_win_counter$" description = "The Performance Counter string" required = true } "--performance-wait" = { value = "$perfmon_win_wait$" description = "Wait time between two counter collections in ms" } "--fmt-countertype" = { value = "$perfmon_win_type$" description = "Performance counter type" } "--perf-syntax" = { value = "$perfmon_win_syntax$" description = "Use this instead of the counter name in the perfomance data" } } vars.performance_win_wait = 1000 vars.perfmon_win_type = "double" } template CheckCommand "ping-common-windows" { command = [ PluginDir + "/check_ping.exe" ] arguments = { "-H" = { value = "$ping_win_address$" required = true description = "Address to ping" } "-w" = { value = "$ping_win_wrta$,$ping_win_wpl$%" description = "Warning threshold: RTA and package loss seperated by comma" } "-c" = { value = "$ping_win_crta$,$ping_win_cpl$%" description = "Warning threshold: RTA and package loss seperated by comma" } "-p" = { value = "$ping_win_packets$" description = "Number of packages to send" } "-t" = { value = "$ping_win_timeout$" description = "Timeout in ms" } } vars.ping_win_packets = "5" vars.ping_win_timeout = "1000" } object CheckCommand "ping-windows" { import "ping-common-windows" import "ipv4-or-ipv6" vars.ping_win_address = "$check_address$" } object CheckCommand "ping4-windows" { import "ping-common-windows" command += [ "-4" ] vars.ping_win_address = "$address$" } object CheckCommand "ping6-windows" { import "ping-common-windows" command += [ "-6" ] vars.ping_win_address = "$address6$" } object CheckCommand "procs-windows" { command = [ PluginDir + "/check_procs.exe" ] arguments = { "-w" = { value = "$procs_win_warn$" description = "Warning threshold" } "-c" = { value = "$procs_win_crit$" description = "Critical threshold" } "-u" = { value = "$procs_win_user$" description = "Count only procs of this user" } } } object CheckCommand "service-windows" { command = [ PluginDir + "/check_service.exe" ] arguments = { "-w" = { set_if = "$service_win_warn$" description = "Warn instead of critical when service is not running" } "-s" = { value = "$service_win_service$" required = true description = "Service to check" } "-d" = { set_if = "$service_win_description$" description = "Use service description instead of name" } } } object CheckCommand "swap-windows" { command = [ PluginDir + "/check_swap.exe" ] arguments = { "-w" = { value = "$swap_win_warn$" description = "Warning threshold" } "-c" = { value = "$swap_win_crit$" description = "Critical threshold" } "-u" = { value = "$swap_win_unit$" description = "Unit to display swap in" } } vars.swap_win_unit = "mb" } object CheckCommand "update-windows" { command = [ PluginDir + "/check_update.exe" ] arguments = { "-w" = { set_if = "$update_win_warn$" description = "Warn if there are important updates available" } "-c" = { set_if = "$update_win_crit$" description = "Critical if there are important updates that require a reboot" } "--possible-reboot" = { set_if = "$update_win_reboot$" description = "Treat 'may need update' as 'definitely needs update'" } } timeout = 5m } object CheckCommand "uptime-windows" { command = [ PluginDir + "/check_uptime.exe" ] arguments = { "-w" = { value = "$uptime_win_warn$" description = "Warning threshold" } "-c" = { value = "$uptime_win_crit$" description = "Critical threshold" } "-u" = { value = "$uptime_win_unit$" description = "Time unit to use" } } vars.uptime_win_unit = "s" } object CheckCommand "users-windows" { command = [ PluginDir + "/check_users.exe" ] arguments = { "-w" = { value = "$users_win_warn$" description = "Warning threshold" } "-c" = { value = "$users_win_crit$" description = "Critical threshold" } } } icinga2-2.8.1/itl/command-plugins.conf000066400000000000000000002331751322762156600176170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ template CheckCommand "ipv4-or-ipv6" { vars.check_address = {{ var addr_v4 = macro("$address$") var addr_v6 = macro("$address6$") if (addr_v4 && !macro("$check_ipv6$") || macro("$check_ipv4$")) { return addr_v4 } else { return addr_v6 } }} vars.check_ipv4 = false vars.check_ipv6 = false } template CheckCommand "ping-common" { command = [ PluginDir + "/check_ping" ] arguments = { "-H" = { value = "$ping_address$" description = "host to ping" } "-w" = { value = "$ping_wrta$,$ping_wpl$%" description = "warning threshold pair" } "-c" = { value = "$ping_crta$,$ping_cpl$%" description = "critical threshold pair" } "-p" = { value = "$ping_packets$" description = "number of ICMP ECHO packets to send (Default: 5)" } "-t" = { value = "$ping_timeout$" description = "Seconds before connection times out (default: 10)" } } vars.ping_wrta = 100 vars.ping_wpl = 5 vars.ping_crta = 200 vars.ping_cpl = 15 } object CheckCommand "ping" { import "ping-common" import "ipv4-or-ipv6" vars.ping_address = "$check_address$" } object CheckCommand "ping4" { import "ping-common" command += [ "-4" ] vars.ping_address = "$address$" } object CheckCommand "ping6" { import "ping-common" command += [ "-6" ] vars.ping_address = "$address6$" } template CheckCommand "hostalive-common" { vars.ping_wrta = 3000.0 vars.ping_wpl = 80 vars.ping_crta = 5000.0 vars.ping_cpl = 100 } object CheckCommand "hostalive" { import "ping" import "hostalive-common" } object CheckCommand "hostalive4" { import "ping4" import "hostalive-common" } object CheckCommand "hostalive6" { import "ping6" import "hostalive-common" } template CheckCommand "fping-common" { command = [ PluginDir + "/check_fping", "$fping_address$" ] arguments = { "-w" = { value = "$fping_wrta$,$fping_wpl$%" description = "warning threshold pair" } "-c" = { value = "$fping_crta$,$fping_cpl$%" description = "critical threshold pair" } "-n" = { value = "$fping_number$" description = "number of ICMP packets to send (default: 1)" } "-i" = { value = "$fping_interval$" description = "Interval (ms) between sending packets (default: fping's default for -p)" } "-b" = { value = "$fping_bytes$" description = "size of ICMP packet (default: 56)" } "-T" = { value = "$fping_target_timeout$" description = "Target timeout (ms) (default: fping's default for -t)" } "-S" = { value = "$fping_source_ip$" description = "name or IP Address of sourceip" } "-I" = { value = "$fping_source_interface$" description = "source interface name" } } vars.fping_wrta = 100 vars.fping_wpl = 5 vars.fping_crta = 200 vars.fping_cpl = 15 vars.fping_number = 5 vars.fping_interval = 500 } object CheckCommand "fping4" { import "fping-common" command += [ "-4" ] vars.fping_address = "$address$" } object CheckCommand "fping6" { import "fping-common" command += [ "-6" ] vars.fping_address = "$address6$" } object CheckCommand "dummy" { command = [ PluginDir + "/check_dummy" ] arguments = { "state" = { value = "$dummy_state$" skip_key = true order = 1 description = "The state. Can be one of 0 (ok), 1 (warning), 2 (critical) and 3 (unknown). Defaults to 0." } "text" = { value = "$dummy_text$" skip_key = true order = 2 description = "Plugin output. Defaults to Check was successful." } } vars.dummy_state = 0 vars.dummy_text = "Check was successful." } object CheckCommand "passive" { import "dummy" vars.dummy_state = 3 vars.dummy_text = "No Passive Check Result Received." } object CheckCommand "tcp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_tcp" ] arguments = { "-H" = { value = "$tcp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)." } "-p" = { value = "$tcp_port$" description = "The TCP port number." } "-e" = { value = "$tcp_expect$" description = "String to expect in server response (may be repeated)." } "-A" = { set_if = "$tcp_all$" description = "All expect strings need to occur in server response. Defaults to false." } "-E_send" = { key = "-E" order = 1 set_if = "$tcp_escape_send$" description = "Enable usage of \n, \r, \t or \\ in send string." } "-s" = { order = 2 value = "$tcp_send$" description = "String to send to the server." } "-E_quit" = { key = "-E" order = 3 set_if = "$tcp_escape_quit$" description = "Enable usage of \n, \r, \t or \\ in quit string." } "-q" = { order = 4 value = "$tcp_quit$" description = "String to send server to initiate a clean close of the connection." } "-r" = { value = "$tcp_refuse$" description = "Accept TCP refusals with states ok, warn, crit. Defaults to crit." } "-M" = { value = "$tcp_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit. Defaults to warn." } "-j" = { set_if = "$tcp_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$tcp_maxbytes$" description = "Close connection once more than this number of bytes are received." } "-d" = { value = "$tcp_delay$" description = "Seconds to wait between sending string and polling for response." } "-D" = { value = "$tcp_certificate$" description = "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) - seperated by comma." } "-S" = { set_if = "$tcp_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$tcp_wtime$" description = "Response time to result in warning status (seconds)." } "-c" = { value = "$tcp_ctime$" description = "Response time to result in critical status (seconds)." } "-t" = { value = "$tcp_timeout$" description = "Seconds before connection times out. Defaults to 10." } "-4" = { set_if = "$tcp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$tcp_ipv6$" description = "Use IPv6 connection" } } vars.tcp_address = "$check_address$" vars.tcp_all = false vars.tcp_refuse = "crit" vars.tcp_mismatch = "warn" vars.tcp_timeout = 10 vars.check_ipv4 = "$tcp_ipv4$" vars.check_ipv6 = "$tcp_ipv6$" } object CheckCommand "ssl" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_tcp" ] arguments = { "-H" = { value = "$ssl_address$" description = "Host address" } "-p" = { value = "$ssl_port$" description ="TCP port (default: 443)" } "--ssl" = { description = "Use SSL for the connection" } "-t" = { value = "$ssl_timeout$" description = "Seconds before connection times out (default: 10)" } "-D" = {{ var days_warn = macro("$ssl_cert_valid_days_warn$") var days_critical = macro("$ssl_cert_valid_days_critical$") if (days_warn) { if (days_critical) { return days_warn + "," + days_critical } else { return days_warn } } }} "-N" = { value = "$ssl_sni$" description = "Enable SSL/TLS hostname extension support (SNI)" } } vars.ssl_address = "$check_address$" vars.ssl_port = 443 vars.ssl_cert_valid_days_warn = false vars.ssl_cert_valid_days_critical = false } object CheckCommand "udp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_udp", "-H", "$udp_address$", "-p", "$udp_port$" ] arguments = { "-s" = { value = "$udp_send$" required = true description = "String to send to the server" } "-e" = { value = "$udp_expect$" required = true description = " String to expect in server response" } "-q" = { value = "$udp_quit$" description = "String to send server to initiate a clean close of the connection" } "-4" = { set_if = "$udp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$udp_ipv6$" description = "Use IPv6 connection" } } vars.udp_address = "$check_address$" vars.check_ipv4 = "$udp_ipv4$" vars.check_ipv6 = "$udp_ipv6$" } object CheckCommand "http" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_http" ] arguments = { "-H" = { value = "$http_vhost$" description = "Host name argument for servers using host headers (virtual host)" } "-I" = { value = "$http_address$" description = "IP address or name (use numeric address if possible to bypass DNS lookup)" } "-u" = { value = "$http_uri$" description = "URL to GET or POST (default: /)" } "-p" = { value = "$http_port$" description = "Port number (default: 80)" } "-S" = { set_if = "$http_ssl$" description = "Connect via SSL" } "-S1" = { set_if = "$http_ssl_force_tlsv1$" description = "Connect via SSL version TLSv1" } "-S1.1" = { set_if = "$http_ssl_force_tlsv1_1$" description = "Connect via SSL version TLSv1.1" } "-S1.2" = { set_if = "$http_ssl_force_tlsv1_2$" description = "Connect via SSL version TLSv1.2" } "-S2" = { set_if = "$http_ssl_force_sslv2$" description = "Connect via SSL version SSLv2" } "-S3" = { set_if = "$http_ssl_force_sslv3$" description = "Connect via SSL version SSLv3" } "-S1+" = { set_if = "$http_ssl_force_tlsv1_or_higher$" description = "Connect via SSL version TLSv1 and newer" } "-S1.1+" = { set_if = "$http_ssl_force_tlsv1_1_or_higher$" description = "Connect via SSL version TLSv1.1 and newer" } "-S1.2+" = { set_if = "$http_ssl_force_tlsv1_2_or_higher$" description = "Connect via SSL version TLSv1.2 and newer" } "-S2+" = { set_if = "$http_ssl_force_sslv2_or_higher$" description = "Connect via SSL version SSLv2 and newer" } "-S3+" = { set_if = "$http_ssl_force_sslv3_or_higher$" description = "Connect via SSL version SSLv3 and newer" } "--sni" = { set_if = "$http_sni$" description = "Enable SSL/TLS hostname extension support (SNI)" } "-C" = { value = "$http_certificate$" description = "Minimum number of days a certificate has to be valid. This parameter explicitely sets the port to 443 and ignores the URL if passed." } "-J" = { value = "$http_clientcert$" description = "Name of file contains the client certificate (PEM format)" } "-K" = { value = "$http_privatekey$" description = "Name of file contains the private key (PEM format)" } "-a" = { value = "$http_auth_pair$" description = "Username:password on sites with basic authentication" } "--no-body" = { set_if = "$http_ignore_body$" description = "Don't wait for document body: stop reading after headers" } "-w" = { value = "$http_warn_time$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$http_critical_time$" description = "Response time to result in critical status (seconds)" } "-e" = { value = "$http_expect$" description = "Comma-delimited list of strings, at least one of them is expected in the first (status) line of the server response (default: HTTP/1.)" } "-d" = { value = "$http_headerstring$" description = "String to expect in the response headers" } "-s" = { value = "$http_string$" description = "String to expect in the content" } "-P" = { value = "$http_post$" description = "URL encoded http POST data" } "-j" = { value = "$http_method$" description = "Set http method (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)" } "-M" = { value = "$http_maxage$" description = "Warn if document is more than seconds old" } "-T" = { value = "$http_contenttype$" description = "Specify Content-Type header when POSTing" } "-l" = { set_if = "$http_linespan$" description = "Allow regex to span newline" order = 1 } "-r" = { value = "$http_expect_body_regex$" description = "Search page for regex" order = 2 } "-R" = { value = "$http_expect_body_eregi$" description = "Search page for case-insensitive regex" order = 2 } "--invert-regex" = { set_if = "$http_invertregex$" description = "Return CRITICAL if found, OK if not" } "-b" = { value = "$http_proxy_auth_pair$" description = "Username:password on proxy-servers with basic authentication" } "-A" = { value = "$http_useragent$" description = "String to be sent in http header as User Agent" } "-k" = { value = "$http_header$" description = "Any other tags to be sent in http header" } "-E" = { set_if = "$http_extendedperfdata$" description = "Print additional perfdata" } "-f" = { value = "$http_onredirect$" description = "How to handle redirect pages" } "-m" = { value = "$http_pagesize$" description = "Minim page size required:Maximum page size required" } "-t" = { value = "$http_timeout$" description = "Seconds before connection times out" } "-4" = { set_if = "$http_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$http_ipv6$" description = "Use IPv6 connection" } "-L" = { set_if = "$http_link$" description = "Wrap output in HTML link" } "-v" = { set_if = "$http_verbose$" description = "Show details for command-line debugging" } } vars.http_address = "$check_address$" vars.http_ssl = false vars.http_sni = false vars.http_linespan = false vars.http_invertregex = false vars.check_ipv4 = "$http_ipv4$" vars.check_ipv6 = "$http_ipv6$" vars.http_link = false vars.http_verbose = false } object CheckCommand "ftp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ftp" ] arguments = { "-H" = { value = "$ftp_address$" description = "The host's address. Defaults to $address$ or $address6$ if the address attribute is not set." } "-p" = { value = "$ftp_port$" description = "The FTP port number. Defaults to none" } "-e" = { value = "$ftp_expect$" description = "String to expect in server response (may be repeated)." } "-A" = { set_if = "$ftp_all$" description = "All expect strings need to occur in server response. Default is any." } "-E_send" = { key = "-E" order = 1 set_if = "$ftp_escape_send$" description = "Enable usage of \n, \r, \t or \\ in send string. Default is nothing." } "-s" = { order = 2 value = "$ftp_send$" description = "String to send to the server." } "-E_quit" = { key = "-E" order = 3 set_if = "$ftp_escape_quit$" description = "Can use \n, \r, \t or \\ in quit string. Default is \r\n added to end of quit." } "-q" = { order = 4 value = "$ftp_quit$" description = "String to send server to initiate a clean close of the connection." } "-r" = { value = "$ftp_refuse$" description = "Accept TCP refusals with states ok, warn, crit. Defaults to crit." } "-M" = { value = "$ftp_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit. Defaults to warn." } "-j" = { set_if = "$ftp_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$ftp_maxbytes$" description = "Close connection once more than this number of bytes are received." } "-d" = { value = "$ftp_delay$" description = "Seconds to wait between sending string and polling for response." } "-D" = { value = "$ftp_certificate$" description = "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) - seperated by comma." } "-S" = { set_if = "$ftp_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$ftp_wtime$" description = "Response time to result in warning status (seconds)." } "-c" = { value = "$ftp_ctime$" description = "Response time to result in critical status (seconds)." } "-t" = { value = "$ftp_timeout$" description = "Seconds before connection times out. Defaults to 10." } "-4" = { set_if = "$ftp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$ftp_ipv6$" description = "Use IPv6 connection" } } vars.ftp_address = "$check_address$" vars.ftp_ssl = false vars.ftp_refuse = "crit" vars.ftp_mismatch = "warn" vars.ftp_timeout = 10 vars.check_ipv4 = "$ftp_ipv4$" vars.check_ipv6 = "$ftp_ipv6$" } object CheckCommand "smtp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_smtp" ] arguments = { "-H" = { value = "$smtp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$smtp_port$" description = "Port number (default: 25)" } "-f" = { value = "$smtp_mail_from$" description = "FROM-address to include in MAIL command, required by Exchange 2000" } "-e" = { value = "$smtp_expect$" description = "String to expect in first line of server response (default: '220')" } "-C" = { value = "$smtp_command$" description = "SMTP command" } "-R" = { value = "$smtp_response$" description = "Expected response to command (may be used repeatedly)" } "-F" = { value = "$smtp_helo_fqdn$" description = "FQDN used for HELO" } "-D" = { value = "$smtp_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$smtp_starttls$" description = "Use STARTTLS for the connection." } "-A" = { value = "$smtp_authtype$" description = "SMTP AUTH type to check (default none, only LOGIN supported)" } "-U" = { value = "$smtp_authuser$" description = "SMTP AUTH username" } "-P" = { value = "$smtp_authpass$" description = "SMTP AUTH password" } "-q" = { value = "$smtp_ignore_quit$" description = "Ignore failure when sending QUIT command to server" } "-w" = { value = "$smtp_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$smtp_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$smtp_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$smtp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$smtp_ipv6$" description = "Use IPv6 connection" } } vars.smtp_address = "$check_address$" vars.check_ipv4 = "$smtp_ipv4$" vars.check_ipv6 = "$smtp_ipv6$" } object CheckCommand "ssmtp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ssmtp" ] arguments = { "-H" = { value = "$ssmtp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$ssmtp_port$" description = "Port number (default: none)" } "-E" = { value = "$ssmtp_escape$" description = "Can use \n, \r, \t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \r\n added to end of quit" } "-s" = { value = "$ssmtp_send$" description = "String to send to the server" } "-e" = { value = "$ssmtp_expect$" description = "String to expect in server response (may be repeated)" } "-A" = { set_if = "$ssmtp_all$" description = "All expect strings need to occur in server response. Default is any." } "-q" = { value = "$ssmtp_quit$" description = "String to send server to initiate a clean close of the connection" } "-r" = { value = "$ssmtp_refuse$" description = "Accept TCP refusals with states ok, warn, crit (default: crit)" } "-M" = { value = "$ssmtp_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit (default: warn)" } "-j" = { set_if = "$ssmtp_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$ssmtp_maxbytes$" description = "Close connection once more than this number of bytes are received" } "-d" = { value = "$ssmtp_delay$" description = "Seconds to wait between sending string and polling for response" } "-D" = { value = "$ssmtp_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$ssmtp_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$ssmtp_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$ssmtp_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$ssmtp_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$ssmtp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$ssmtp_ipv6$" description = "Use IPv6 connection" } } vars.ssmtp_address = "$check_address$" vars.check_ipv4 = "$ssmtp_ipv4$" vars.check_ipv6 = "$ssmtp_ipv6$" } object CheckCommand "imap" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_imap" ] arguments = { "-H" = { value = "$imap_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$imap_port$" description = "Port number (default: none)" } "-E" = { value = "$imap_escape$" description = "Can use \n, \r, \t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \r\n added to end of quit" } "-s" = { value = "$imap_send$" description = "String to send to the server" } "-e" = { value = "$imap_expect$" description = "String to expect in server response (may be repeated)" } "-A" = { set_if = "$imap_all$" description = "All expect strings need to occur in server response. Default is any." } "-q" = { value = "$imap_quit$" description = "String to send server to initiate a clean close of the connection" } "-r" = { value = "$imap_refuse$" description = "Accept TCP refusals with states ok, warn, crit (default: crit)" } "-M" = { value = "$imap_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit (default: warn)" } "-j" = { set_if = "$imap_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$imap_maxbytes$" description = "Close connection once more than this number of bytes are received" } "-d" = { value = "$imap_delay$" description = "Seconds to wait between sending string and polling for response" } "-D" = { value = "$imap_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$imap_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$imap_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$imap_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$imap_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$imap_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$imap_ipv6$" description = "Use IPv6 connection" } } vars.imap_address = "$check_address$" vars.check_ipv4 = "$imap_ipv4$" vars.check_ipv6 = "$imap_ipv6$" } object CheckCommand "simap" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_simap" ] arguments = { "-H" = { value = "$simap_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$simap_port$" description = "Port number (default: none)" } "-E" = { value = "$simap_escape$" description = "Can use \n, \r, \t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \r\n added to end of quit" } "-s" = { value = "$simap_send$" description = "String to send to the server" } "-e" = { value = "$simap_expect$" description = "String to expect in server response (may be repeated)" } "-A" = { set_if = "$simap_all$" description = "All expect strings need to occur in server response. Default is any." } "-q" = { value = "$simap_quit$" description = "String to send server to initiate a clean close of the connection" } "-r" = { value = "$simap_refuse$" description = "Accept TCP refusals with states ok, warn, crit (default: crit)" } "-M" = { value = "$simap_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit (default: warn)" } "-j" = { set_if = "$simap_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$simap_maxbytes$" description = "Close connection once more than this number of bytes are received" } "-d" = { value = "$simap_delay$" description = "Seconds to wait between sending string and polling for response" } "-D" = { value = "$simap_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$simap_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$simap_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$simap_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$simap_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$simap_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$simap_ipv6$" description = "Use IPv6 connection" } } vars.simap_address = "$check_address$" vars.check_ipv4 = "$simap_ipv4$" vars.check_ipv6 = "$simap_ipv6$" } object CheckCommand "pop" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_pop" ] arguments = { "-H" = { value = "$pop_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$pop_port$" description = "Port number (default: none)" } "-E" = { value = "$pop_escape$" description = "Can use \n, \r, \t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \r\n added to end of quit" } "-s" = { value = "$pop_send$" description = "String to send to the server" } "-e" = { value = "$pop_expect$" description = "String to expect in server response (may be repeated)" } "-A" = { set_if = "$pop_all$" description = "All expect strings need to occur in server response. Default is any." } "-q" = { value = "$pop_quit$" description = "String to send server to initiate a clean close of the connection" } "-r" = { value = "$pop_refuse$" description = "Accept TCP refusals with states ok, warn, crit (default: crit)" } "-M" = { value = "$pop_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit (default: warn)" } "-j" = { set_if = "$pop_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$pop_maxbytes$" description = "Close connection once more than this number of bytes are received" } "-d" = { value = "$pop_delay$" description = "Seconds to wait between sending string and polling for response" } "-D" = { value = "$pop_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$pop_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$pop_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$pop_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$pop_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$pop_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$pop_ipv6$" description = "Use IPv6 connection" } } vars.pop_address = "$check_address$" vars.check_ipv4 = "$pop_ipv4$" vars.check_ipv6 = "$pop_ipv6$" } object CheckCommand "spop" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_spop" ] arguments = { "-H" = { value = "$spop_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$spop_port$" description = "Port number (default: none)" } "-E" = { value = "$spop_escape$" description = "Can use \n, \r, \t or \\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \r\n added to end of quit" } "-s" = { value = "$spop_send$" description = "String to send to the server" } "-e" = { value = "$spop_expect$" description = "String to expect in server response (may be repeated)" } "-A" = { set_if = "$spop_all$" description = "All expect strings need to occur in server response. Default is any." } "-q" = { value = "$spop_quit$" description = "String to send server to initiate a clean close of the connection" } "-r" = { value = "$spop_refuse$" description = "Accept TCP refusals with states ok, warn, crit (default: crit)" } "-M" = { value = "$spop_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit (default: warn)" } "-j" = { set_if = "$spop_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$spop_maxbytes$" description = "Close connection once more than this number of bytes are received" } "-d" = { value = "$spop_delay$" description = "Seconds to wait between sending string and polling for response" } "-D" = { value = "$spop_certificate_age$" description = "Minimum number of days a certificate has to be valid" } "-S" = { set_if = "$spop_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$spop_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$spop_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$spop_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$spop_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$spop_ipv6$" description = "Use IPv6 connection" } } vars.spop_address = "$check_address$" vars.check_ipv4 = "$spop_ipv4$" vars.check_ipv6 = "$spop_ipv6$" } object CheckCommand "ntp_time" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ntp_time" ] arguments = { "-H" = { value = "$ntp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$ntp_port$" description = "Port number (default: 123)" } "-q" = { set_if = "$ntp_quiet$" description = "Returns UNKNOWN instead of CRITICAL if offset cannot be found" } "-w" = { value = "$ntp_warning$" description = "Offset to result in warning status (seconds)" } "-c" = { value = "$ntp_critical$" description = "Offset to result in critical status (seconds)" } "-o" = { value = "$ntp_timeoffset$" description = "Expected offset of the ntp server relative to local server (seconds)" } "-t" = { value = "$ntp_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$ntp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$ntp_ipv6$" description = "Use IPv6 connection" } } vars.ntp_address = "$check_address$" vars.check_ipv4 = "$ntp_ipv4$" vars.check_ipv6 = "$ntp_ipv6$" } object CheckCommand "ntp_peer" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ntp_peer" ] arguments = { "-H" = { value = "$ntp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$ntp_port$" description = "Port number (default: 123)" } "-q" = { set_if = "$ntp_quiet$" description = "Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized" } "-w" = { value = "$ntp_warning$" description = "Offset to result in warning status (seconds)" } "-c" = { value = "$ntp_critical$" description = "Offset to result in critical status (seconds)" } "-W" = { value = "$ntp_wstratum$" description = "Warning threshold for stratum of server's synchronization peer" } "-C" = { value = "$ntp_cstratum$" description = "Critical threshold for stratum of server's synchronization peer" } "-j" = { value = "$ntp_wjitter$" description = "Warning threshold for jitter" } "-k" = { value = "$ntp_cjitter$" description = "Critical threshold for jitter" } "-m" = { value = "$ntp_wsource$" description = "Warning threshold for number of usable time sources (truechimers)" } "-n" = { value = "$ntp_csource$" description = "Critical threshold for number of usable time sources (truechimers)" } "-t" = { value = "$ntp_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$ntp_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$ntp_ipv6$" description = "Use IPv6 connection" } } vars.ntp_address = "$check_address$" vars.check_ipv4 = "$ntp_ipv4$" vars.check_ipv6 = "$ntp_ipv6$" } object CheckCommand "ssh" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ssh" ] arguments = { "-p" = { value = "$ssh_port$" description = "Port number (default: 22)" } "-t" = { value = "$ssh_timeout$" description = "Seconds before connection times out (default: 10)" } "host" = { value = "$ssh_address$" skip_key = true order = 1 } "-4" = { set_if = "$ssh_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$ssh_ipv6$" description = "Use IPv6 connection" } } vars.ssh_address = "$check_address$" vars.check_ipv4 = "$ssh_ipv4$" vars.check_ipv6 = "$ssh_ipv6$" } object CheckCommand "disk" { command = [ PluginDir + "/check_disk" ] arguments = { "-w" = { value = "$disk_wfree$" description = "Exit with WARNING status if less than INTEGER units of disk are free or Exit with WARNING status if less than PERCENT of disk space is free" required = true order = -3 } "-c" = { value = "$disk_cfree$" description = "Exit with CRITICAL status if less than INTEGER units of disk are free or Exit with CRITCAL status if less than PERCENT of disk space is free" required = true order = -3 } "-W" = { value = "$disk_inode_wfree$" description = "Exit with WARNING status if less than PERCENT of inode space is free" } "-K" = { value = "$disk_inode_cfree$" description = "Exit with CRITICAL status if less than PERCENT of inode space is free" } "-p" = { value = "$disk_partitions$" description = "Path or partition (may be repeated)" repeat_key = true order = 1 } "-p_old" = { key = "-p" value = "$disk_partition$" order = 1 } "-x" = { value = "$disk_partitions_excluded$" description = "Ignore device (only works if -p unspecified)" } "-x_old" = { key = "-x" value = "$disk_partition_excluded$" } "-C" = { set_if = "$disk_clear$" description = "Clear thresholds" } "-E" = { set_if = "$disk_exact_match$" description = "For paths or partitions specified with -p, only check for exact paths" } "-e" = { set_if = "$disk_errors_only$" description = "Display only devices/mountpoints with errors" } "-f" = { set_if = "$disk_ignore_reserved$" description = "Don't account root-reserved blocks into freespace in perfdata" } "-g" = { value = "$disk_group$" description = "Group paths. Thresholds apply to (free-)space of all partitions together" } "-k" = { set_if = "$disk_kilobytes$" description = "Same as --units kB" } "-l" = { set_if = "$disk_local$" description = " Only check local filesystems" } "-L" = { set_if = "$disk_stat_remote_fs$" description = "Only check local filesystems against thresholds. Yet call stat on remote filesystems to test if they are accessible (e.g. to detect Stale NFS Handles)" } "-M" = { set_if = "$disk_mountpoint$" description = "Display the mountpoint instead of the partition" } "-m" = { set_if = "$disk_megabytes$" description = "Same as --units MB" } "-A" = { set_if = "$disk_all$" description = "Explicitly select all paths. This is equivalent to -R .*" } "-R" = { value = "$disk_eregi_path$" description = "Case insensitive regular expression for path/partition (may be repeated)" repeat_key = true } "-r" = { value = "$disk_ereg_path$" description = "Regular expression for path or partition (may be repeated)" repeat_key = true } "-I" = { value = "$disk_ignore_eregi_path$" description = "Regular expression to ignore selected path/partition (case insensitive) (may be repeated)" repeat_key = true order = 2 } "-i" = { value = "$disk_ignore_ereg_path$" description = "Regular expression to ignore selected path or partition (may be repeated)" repeat_key = true order = 2 } "-t" = { value = "$disk_timeout$" description = "Seconds before connection times out (default: 10)" } "-u" = { value = "$disk_units$" description = "Choose bytes, kB, MB, GB, TB (default: MB)" } "-X" = { value = "$disk_exclude_type$" description = "Ignore all filesystems of indicated type (may be repeated)" repeat_key = true } } vars.disk_wfree = "20%" vars.disk_cfree = "10%" vars.disk_megabytes = true vars.disk_exclude_type = [ "none", "tmpfs", "sysfs", "proc", "configfs", "devtmpfs", "devfs", "mtmfs", "tracefs", "cgroup", "fuse.gvfsd-fuse", "fuse.gvfs-fuse-daemon", "fdescfs" ] } object CheckCommand "disk_smb" { command = [ PluginDir + "/check_disk_smb" ] arguments = { "-H" = { value = "$disk_smb_hostname$" description = "NetBIOS name of the server." } "-s" = { value = "$disk_smb_share$" description = "Share name to be tested." } "-W" = { value = "$disk_smb_workgroup$" description = "Workgroup or Domain used (Defaults to 'WORKGROUP' if omitted)." } "-a" = { value = "$disk_smb_address$" description = "IP-address of HOST (only necessary if HOST is in another network)." } "-u" = { value = "$disk_smb_username$" description = "Username to log in to server. (Defaults to 'guest' if omitted)." } "-p" = { value = "$disk_smb_password$" description = "Password to log in to server. (Defaults to an empty password if omitted)." } "-w" = { value = "$disk_smb_wused$" description = "Percent of used space at which a warning will be generated (Default: 85%)." } "-c" = { value = "$disk_smb_cused$" description = "Percent of used space at which a critical will be generated (Defaults: 95%)" } "-P" = { value = "$disk_smb_port$" description = "Port to be used to connect to. Some Windows boxes use 139, others 445 (Defaults to smbclient default if omitted)." } } vars.disk_smb_wused = "85%" vars.disk_smb_cused = "95%" } object CheckCommand "users" { command = [ PluginDir + "/check_users" ] arguments = { "-w" = { value = "$users_wgreater$" description = "Set WARNING status if more than INTEGER users are logged in" } "-c" = { value = "$users_cgreater$" description = "Set CRITICAL status if more than INTEGER users are logged in" } } vars.users_wgreater = 20 vars.users_cgreater = 50 } object CheckCommand "procs" { command = [ PluginDir + "/check_procs" ] arguments = { "-w" = { value = "$procs_warning$" description = "Generate warning state if metric is outside this range" } "-c" = { value = "$procs_critical$" description = "Generate critical state if metric is outside this range" } "-m" = { value = "$procs_metric$" description = "Check thresholds against metric" } "-t" = { value = "$procs_timeout$" description = "Seconds before plugin times out" } "-T" = { set_if = "$procs_traditional$" description = "Filter own process the traditional way by PID instead of /proc/pid/exe" } "-s" = { value = "$procs_state$" description = "Only scan for processes that have one or more of the status flags you specify" } "-p" = { value = "$procs_ppid$" description = "Only scan for children of the parent process ID indicated" } "-z" = { value = "$procs_vsz$" description = "Only scan for processes with VSZ higher than indicated" } "-r" = { value = "$procs_rss$" description = "Only scan for processes with RSS higher than indicated" } "-P" = { value = "$procs_pcpu$" description = "Only scan for processes with PCPU higher than indicated" } "-u" = { value = "$procs_user$" description = "Only scan for processes with user name or ID indicated" } "-a" = { value = "$procs_argument$" description = "Only scan for processes with args that contain STRING" } "--ereg-argument-array" = { value = "$procs_argument_regex$" description = "Only scan for processes with args that contain the regex STRING" } "-C" = { value = "$procs_command$" description = "Only scan for exact matches of COMMAND (without path)" } "-k" = { set_if = "$procs_nokthreads$" description = "Only scan for non kernel threads" } } vars.procs_traditional = false vars.procs_nokthreads = false vars.procs_warning = 250 vars.procs_critical = 400 } object CheckCommand "swap" { command = [ PluginDir + "/check_swap" ] arguments = { "-w" = {{ if (macro("$swap_integer$")) { return macro("$swap_wfree$") } else { return macro("$swap_wfree$%") } }} "-c" = {{ if (macro("$swap_integer$")) { return macro("$swap_cfree$") } else { return macro("$swap_cfree$%") } }} "-a" = { set_if = "$swap_allswaps$" description = "Conduct comparisons for all swap partitions, one by one" } "-n" = { value = "$swap_noswap$" description = "Resulting state when there is no swap regardless of thresholds. Possible values are \"ok\", \"warning\", \"critical\", \"unknown\". Defaults to \"critical\"" } } vars.swap_wfree = 50 vars.swap_cfree = 25 vars.swap_integer = false vars.swap_allswaps = false } object CheckCommand "load" { command = [ PluginDir + "/check_load" ] arguments = { "-w" = { value = "$load_wload1$,$load_wload5$,$load_wload15$" description = "Exit with WARNING status if load average exceeds WLOADn" } "-c" = { value = "$load_cload1$,$load_cload5$,$load_cload15$" description = "Exit with CRITICAL status if load average exceed CLOADn; the load average format is the same used by 'uptime' and 'w'" } "-r" = { set_if = "$load_percpu$" description = "Divide the load averages by the number of CPUs (when possible)" } } vars.load_wload1 = 5.0 vars.load_wload5 = 4.0 vars.load_wload15 = 3.0 vars.load_cload1 = 10.0 vars.load_cload5 = 6.0 vars.load_cload15 = 4.0 vars.load_percpu = false } object CheckCommand "snmp" { command = [ PluginDir + "/check_snmp" ] arguments = { "-H" = { value = "$snmp_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-o" = { value = "$snmp_oid$" description = "Object identifier(s) or SNMP variables whose value you wish to query" } "-C" = { value = "$snmp_community$" description = "Optional community string for SNMP communication (default is 'public')" } "-c" = { value = "$snmp_crit$" description = "Critical threshold range(s)" } "-w" = { value = "$snmp_warn$" description = "Warning threshold range(s)" } "-s" = { value = "$snmp_string$" description = "Return OK state (for that OID) if STRING is an exact match" } "-r" = { value = "$snmp_ereg$" description = "Return OK state (for that OID) if extended regular expression REGEX matches" } "-R" = { value = "$snmp_eregi$" description = "Return OK state (for that OID) if case-insensitive extended REGEX matches" } "-l" = { value = "$snmp_label$" description = "Prefix label for output from plugin" } "-u" = { value = "$snmp_units$" description = "Units label(s) for output data (e.g., 'sec.')" } "-t" = { value = "$snmp_timeout$" description = "Seconds before connection times out (default: 10)" } "-p" = { value = "$snmp_port$" description = "Port number (default: 161)" } "-e" = { value = "$snmp_retries$" description = "Number of retries to be used in the requests" } "--invert-search" = { set_if = "$snmp_invert_search$" description = "Invert search result and return CRITICAL if found" } "-P" = { value = "$snmp_version$" description = "SNMP protocol version" } "-m" = { value = "$snmp_miblist$" description = "List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL' for symbolic OIDs.)" } "--rate-multiplier" = { value = "$snmp_rate_multiplier$" description = "Converts rate per second. For example, set to 60 to convert to per minute" } "--rate" = { set_if = "$snmp_rate$" description = "Enable rate calculation" } "-n" = { set_if = "$snmp_getnext$" description = "Use SNMP GETNEXT instead of SNMP GET" } "--offset" = { value = "$snmp_offset$" description = "Add/substract the specified OFFSET to numeric sensor data" } "-D" = { value = "$snmp_output_delimiter$" description = "Separates output on multiple OID requests" } "-O" = { set_if = "$snmp_perf_oids$" description = "Label performance data with OIDs instead of --label's" } } vars.snmp_address = {{ var addr_v4 = macro("$address$") var addr_v6 = macro("$address6$") if (addr_v4) { return addr_v4 } else { return "udp6:[" + addr_v6 + "]" } }} vars.snmp_community = "public" vars.snmp_invert_search = false vars.snmp_timeout = "10" } object CheckCommand "snmpv3" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_snmp" ] arguments = { "-H" = { value = "$snmpv3_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$snmpv3_port$" description = "Port number" } "-n" = { set_if = "$snmpv3_getnext$" description = "Use SNMP GETNEXT instead of SNMP GET" } "-P" = { value = 3 description = "SNMP protocol version" } "-L" = { value = "$snmpv3_seclevel$" description = "SNMPv3 securityLevel" } "-a" = { value = "$snmpv3_auth_alg$" description = "SNMPv3 auth proto" } "-U" = { value = "$snmpv3_user$" description = "SNMPv3 username" } "-A" = { value = "$snmpv3_auth_key$" description = "SNMPv3 authentication password" } "-X" = { value = "$snmpv3_priv_key$" description = "SNMPv3 privacy password" } "-o" = { value = "$snmpv3_oid$" description = "Object identifier(s) or SNMP variables whose value you wish to query" } "-x" = { value = "$snmpv3_priv_alg$" description = "SNMPv3 priv proto (default DES)" } "-w" = { value = "$snmpv3_warn$" description = "Warning threshold range(s)" } "-c" = { value = "$snmpv3_crit$" description = "Critical threshold range(s)" } "-s" = { value = "$snmpv3_string$" description = "Return OK state (for that OID) if STRING is an exact match" } "-r" = { value = "$snmpv3_ereg$" description = "Return OK state (for that OID) if extended regular expression REGEX matches" } "-R" = { value = "$snmpv3_eregi$" description = "Return OK state (for that OID) if case-insensitive extended REGEX matches" } "--invert-search" = { set_if = "$snmpv3_invert_search$" description = "Invert search result and return CRITICAL if found" } "-l" = { value = "$snmpv3_label$" description = "Prefix label for output from plugin" } "-m" = { value = "$snmpv3_miblist$" description = "List of SNMP MIBs for translating OIDs between numeric and textual representation" } "-u" = { value = "$snmpv3_units$" description = "Units label(s) for output data (e.g., 'sec.')" } "--rate-multiplier" = { value = "$snmpv3_rate_multiplier$" description = "Converts rate per second. For example, set to 60 to convert to per minute" } "--rate" = { set_if = "$snmpv3_rate$" description = "Enable rate calculation" } "-t" = { value = "$snmpv3_timeout$" description = "Seconds before connection times out (default: 10)" } } vars.snmpv3_address = "$check_address$" vars.snmpv3_auth_alg = "SHA" vars.snmpv3_priv_alg = "AES" vars.snmpv3_seclevel = "authPriv" vars.snmpv3_timeout = "10" } object CheckCommand "snmp-uptime" { import "snmp" vars.snmp_oid = "1.3.6.1.2.1.1.3.0" } object CheckCommand "apt" { command = [ PluginDir + "/check_apt" ] arguments = { "--extra-opts" = { value = "$apt_extra_opts$" description = "Read options from an ini file." } "--upgrade" = { value = "$apt_upgrade$" description = "[Default] Perform an upgrade. If an optional OPTS argument is provided, apt-get will be run with these command line options instead of the default." } "--dist-upgrade" = { value = "$apt_dist_upgrade$" description = "Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS can be provided to override the default options." } "--include" = { value = "$apt_include$" description = "Include only packages matching REGEXP. Can be specified multiple times the values will be combined together." } "--exclude" = { value = "$apt_exclude$" description = "Exclude packages matching REGEXP from the list of packages that would otherwise be included. Can be specified multiple times." } "--critical" = { value = "$apt_critical$" description = "If the full package information of any of the upgradable packages match this REGEXP, the plugin will return CRITICAL status. Can be specified multiple times." } "--timeout" = { value = "$apt_timeout$" description = "Seconds before plugin times out (default: 10)." } "--only-critical" = { set_if = "$apt_only_critical$" description = "Only warn about critical upgrades." } } timeout = 5m } object CheckCommand "dhcp" { command = [ PluginDir + "/check_dhcp" ] arguments = { "-s" = { value = "$dhcp_serverip$" description = "IP address of DHCP server that we must hear from" } "-r" = { value = "$dhcp_requestedip$" description = "IP address that should be offered by at least one DHCP server" } "-t" = { value = "$dhcp_timeout$" description = "Seconds to wait for DHCPOFFER before timeout occurs" } "-i" = { value = "$dhcp_interface$" description = "Interface to to use for listening (i.e. eth0)" } "-m" = { value = "$dhcp_mac$" description = "MAC address to use in the DHCP request" } "-u" = { set_if = "$dhcp_unicast$" description = "Unicast testing: mimic a DHCP relay" } } vars.dhcp_unicast = false } object CheckCommand "dns" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_dns" ] arguments = { "-H" = { value = "$dns_lookup$" description = "The name or address you want to query." } "-s" = { value = "$dns_server$" description = "Optional DNS server you want to use for the lookup." } "-q" = { value = "$dns_query_type$" description = "Optional DNS record query type where TYPE =(A, AAAA, SRV, TXT, MX, ANY). The default query type is 'A' (IPv4 host entry)" } "-a" = { value = "$dns_expected_answers$" description = "Optional ip address or host you expect the DNS server to return. Host must end with a dot (.). This option can be repeated multiple times (Returns OK if any value match). If multiple addresses are returned at once, you have to match the whole string of addresses separated with commas (sorted alphabetically)." } "-A" = { set_if = "$dns_authoritative$" description = "Optionally expect the DNS server to be authoritative for the lookup" } "-n" = { set_if = "$dns_accept_cname$" description = "Optionally accept cname responses as a valid result to a query. The default is to ignore cname responses as part of the result" } "-w" = { value = "$dns_wtime$" description = "Return warning if elapsed time exceeds value." } "-c" = { value = "$dns_ctime$" description = "Return critical if elapsed time exceeds value." } "-t" = { value = "$dns_timeout$" description = "Seconds before connection times out. Defaults to 10." } } vars.dns_lookup = "$host.name$" vars.dns_timeout = 10 } object CheckCommand "dig" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_dig" ] arguments = { "-H" = { value = "$dig_server$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$dig_port$" description = "Port number (default: 53)" } "-l" = { value = "$dig_lookup$" required = true description = "Machine name to lookup" } "-T" = { value = "$dig_record_type$" description = "Record type to lookup (default: A)" } "-a" = { value = "$dig_expected_address$" description = "An address expected to be in the answer section" } "-A" = { value = "$dig_arguments$" description = "Pass STRING as argument(s) to dig" } "-w" = { value = "$dig_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$dig_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$dig_timeout$" description = "Seconds before connection times out (default: 10)" } "-4" = { set_if = "$dig_ipv4$" description = "Force dig to only use IPv4 query transport" } "-6" = { set_if = "$dig_ipv6$" description = "Force dig to only use IPv6 query transport" } } vars.dig_server = "$check_address$" vars.check_ipv4 = "$dig_ipv4$" vars.check_ipv6 = "$dig_ipv6$" } object CheckCommand "nscp" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_nt" ] arguments = { "-H" = { value = "$nscp_address$" description = "Name of the host to check" } "-p" = { value = "$nscp_port$" description = "Optional port number (default: 1248)" } "-s" = { value = "$nscp_password$" description = "Password needed for the request" } "-v" = { value = "$nscp_variable$" required = true description = "Variable to check" } "-l" = { value = "$nscp_params$" repeat_key = false } "-w" = { value = "$nscp_warn$" description = "Threshold which will result in a warning status" } "-c" = { value = "$nscp_crit$" description = "Threshold which will result in a critical status" } "-t" = { value = "$nscp_timeout$" description = "Seconds before connection attempt times out" } "-d" = { value = "SHOWALL" set_if = "$nscp_showall$" description = "Use with SERVICESTATE to see working services or PROCSTATE for running processes" } } vars.nscp_address = "$check_address$" vars.nscp_port = 12489 vars.nscp_showall = false } object CheckCommand "by_ssh" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_by_ssh" ] arguments = { "-H" = { value = "$by_ssh_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$by_ssh_port$" description = "Port number (default: none)" } "-C" = {{ var command = macro("$by_ssh_command$") var arguments = macro("$by_ssh_arguments$") if (typeof(command) == String && !arguments) { return command } var escaped_args = [] for (arg in resolve_arguments(command, arguments)) { escaped_args.add(escape_shell_arg(arg)) } return escaped_args.join(" ") }} "-l" = { value = "$by_ssh_logname$" description = "SSH user name on remote host [optional]" } "-i" = { value = "$by_ssh_identity$" description = "identity of an authorized key [optional]" } "-q" = { set_if = "$by_ssh_quiet$" description = "Tell ssh to suppress warning and diagnostic messages [optional]" } "-w" = { value = "$by_ssh_warn$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$by_ssh_crit$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$by_ssh_timeout$" description = "Seconds before connection times out (default: 10)" } "-o" = { value = "$by_ssh_options$" description = "Provide ssh options (may be repeated)" } "-4" = { set_if = "$by_ssh_ipv4$" description = "Use IPv4 only" } "-6" = { set_if = "$by_ssh_ipv6$" description = "Use IPv6 only" } } vars.by_ssh_address = "$check_address$" vars.by_ssh_quiet = false vars.check_ipv4 = "$by_ssh_ipv4$" vars.check_ipv6 = "$by_ssh_ipv6$" } object CheckCommand "ups" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ups" ] arguments = { "-H" = { value = "$ups_address$" description = "Address of the upsd server" required = true } "-u" = { value = "$ups_name$" description = "Name of the UPS to monitor" required = true } "-p" = { value = "$ups_port$" description = "Port number (default: 3493)" } "-v" = { value = "$ups_variable$" description = "Variable to monitor, valid strings are LINE, TEMP, BATTPCT or LOADPCT" } "-w" = { value = "$ups_warning$" description = "Warning threshold for the selected variable" } "-c" = { value = "$ups_critical$" description = "Critical threshold for the selected variable" } "-T" = { set_if = "$ups_celsius$" description = "Display temperature in degrees Celsius instead of Fahrenheit" } "-t" = { value = "$ups_timeout$" description = "Seconds before the connection times out (default: 10)" } } vars.ups_address = "$check_address$" vars.ups_name = "ups" } object CheckCommand "nrpe" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_nrpe" ] arguments = { "-H" = { value = "$nrpe_address$" description = "The address of the host running the NRPE daemon" } "-p" = { value = "$nrpe_port$" } "-c" = { value = "$nrpe_command$" } "-n" = { set_if = "$nrpe_no_ssl$" description = "Do not use SSL" } "-u" = { set_if = "$nrpe_timeout_unknown$" description = "Make socket timeouts return an UNKNOWN state instead of CRITICAL" } "-t" = { value = "$nrpe_timeout$" description = ": = :" } "-a" = { value = "$nrpe_arguments$" repeat_key = false order = 1 } "-4" = { set_if = "$nrpe_ipv4$" description = "Use IPv4 connection" } "-6" = { set_if = "$nrpe_ipv6$" description = "Use IPv6 connection" } "-2" = { set_if = "$nrpe_version_2$" description = "Use this if you want to connect to NRPE v2" } } vars.nrpe_address = "$check_address$" vars.nrpe_no_ssl = false vars.nrpe_timeout_unknown = false vars.check_ipv4 = "$nrpe_ipv4$" vars.check_ipv6 = "$nrpe_ipv6$" vars.nrpe_version_2 = false timeout = 5m } object CheckCommand "hpjd" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_hpjd" ] arguments = { "-H" = { value = "$hpjd_address$" description = "Host address" } "-C" = { value = "$hpjd_community$" description = "The SNMP community name (default=public)" } "-p" = { value = "$hpjd_port$" description = "Specify the port to check (default=161)" } } vars.hpjd_address = "$check_address$" } object CheckCommand "icmp" { command = [ PluginDir + "/check_icmp" ] arguments = { "-H" = { value = "$icmp_address$" repeat_key = false order = 1 description = "Host address" } "-w" = { value = "$icmp_wrta$,$icmp_wpl$%" description = "warning threshold (currently 200.000ms,40%)" } "-c" = { value = "$icmp_crta$,$icmp_cpl$%" description = "critical threshold (currently 500.000ms,80%)" } "-s" = { value = "$icmp_source$" description = "specify a source IP address or device name" } "-n" = { value = "$icmp_packets$" description = "number of packets to send (currently 5)" } "-i" = { value = "$icmp_packet_interval$" description = "max packet interval (currently 80.000ms)" } "-I" = { value = "$icmp_target_interval$" description = "max target interval (currently 0.000ms)" } "-m" = { value = "$icmp_hosts_alive$" description = "number of alive hosts required for success" } "-b" = { value = "$icmp_data_bytes$" description = "Number of icmp data bytes to send. Packet size will be data bytes + icmp header (currently 68 + 8)" } "-t" = { value = "$icmp_timeout$" description = "timeout value (seconds, currently 10)" } "-l" = { value = "$icmp_ttl$" description = "TTL on outgoing packets (currently 0)" } } vars.icmp_address = "$address$" vars.icmp_wrta = 100 vars.icmp_wpl = 5 vars.icmp_crta = 200 vars.icmp_cpl = 15 } object CheckCommand "ldap" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_ldap" ] arguments = { "-H" = { value = "$ldap_address$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-p" = { value = "$ldap_port$" description = "Port number (default: 389)" } "-a" = { value = "$ldap_attr$" description = "ldap attribute to search (default: \"(objectclass=*)\"" } "-b" = { value = "$ldap_base$" required = true description = "ldap base (eg. ou=my unit, o=my org, c=at" } "-D" = { value = "$ldap_bind$" description = "ldap bind DN (if required)" } "-P" = { value = "$ldap_pass$" description = "ldap password (if required)" } "-T" = { set_if = "$ldap_starttls$" description = "use starttls mechanism introduced in protocol version 3" } "-S" = { set_if = "$ldap_ssl$" description = "use ldaps (ldap v2 ssl method). this also sets the default port to 636" } "-2" = { set_if = "$ldap_v2$" description = "Use LDAP protocol version 2" } "-3" = { set_if = "$ldap_v3$" description = "Use LDAP protocol version 3" } "-w" = { value = "$ldap_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$ldap_critical$" description = "Response time to result in critical status (seconds)" } "-W" = { value = "$ldap_warning_entries$" description = "Number of found entries to result in warning status (optional)" } "-C" = { value = "$ldap_critical_entries$" description = "Number of found entries to result in critical status (optional)" } "-t" = { value = "$ldap_timeout$" description = "Seconds before connection times out (default: 10)" } "-v" = { set_if = "$ldap_verbose$" description = "Show details for command-line debugging" } } vars.ldap_address = "$check_address$" vars.ldap_v2 = true vars.ldap_v3 = false vars.ldap_timeout = 10s vars.ldap_verbose = false } object CheckCommand "clamd" { command = [ PluginDir + "/check_clamd" ] arguments = { "-H" = { value = "$clamd_address$" description = "The host's address or unix socket (must be an absolute path)." required = true } "-p" = { value = "$clamd_port$" description = "Port number (default: none)." } "-e" = { value = "$clamd_expect$" description = "String to expect in server response (may be repeated)." repeat_key = true } "-A" = { set_if = "$clamd_all$" description = "All expect strings need to occur in server response. Default is any." } "-E_send" = { key = "-E" order = 1 set_if = "$clamd_escape_send$" description = "Enable usage of \n, \r, \t or \\ in send string. Default is nothing." } "-s" = { order = 2 value = "$clamd_send$" description = "String to send to the server." } "-E_quit" = { key = "-E" order = 3 set_if = "$clamd_escape_quit$" description = "Can use \n, \r, \t or \\ in quit string. Default is \r\n added to end of quit." } "-q" = { order = 4 value = "$clamd_quit$" description = "String to send server to initiate a clean close of the connection." } "-r" = { value = "$clamd_refuse$" description = "Accept TCP refusals with states ok, warn, crit. Defaults to crit." } "-M" = { value = "$clamd_mismatch$" description = "Accept expected string mismatches with states ok, warn, crit. Defaults to warn." } "-j" = { set_if = "$clamd_jail$" description = "Hide output from TCP socket." } "-m" = { value = "$clamd_maxbytes$" description = "Close connection once more than this number of bytes are received." } "-d" = { value = "$clamd_delay$" description = "Seconds to wait between sending string and polling for response." } "-D" = { value = "$clamd_certificate$" description = "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) - seperated by comma." } "-S" = { set_if = "$clamd_ssl$" description = "Use SSL for the connection." } "-w" = { value = "$clamd_wtime$" description = "Response time to result in warning status (seconds)." } "-c" = { value = "$clamd_ctime$" description = "Response time to result in critical status (seconds)." } "-t" = { value = "$clamd_timeout$" description = "Seconds before connection times out. Defaults to 10." } "-4" = { set_if = "$clamd_ipv4$" description = "Use IPv4 only" } "-6" = { set_if = "$clamd_ipv6$" description = "Use IPv6 only" } } vars.clamd_ssl = false vars.clamd_refuse = "crit" vars.clamd_mismatch = "warn" vars.clamd_timeout = 10 vars.check_ipv4 = "$clamd_ipv4$" vars.check_ipv6 = "$clamd_ipv6$" } object CheckCommand "mailq" { command = [ PluginDir + "/check_mailq" ] arguments = { "-w" = { value = "$mailq_warning$" description = "Min. number of messages in queue to generate warning" required = true } "-c" = { value = "$mailq_critical$" description = "Min. number of messages in queue to generate critical alert ( w < c )" required = true } "-W" = { value = "$mailq_domain_warning$" description = "Min. number of messages for same domain in queue to generate warning" } "-C" = { value = "$mailq_domain_critical$" description = "Min. number of messages for same domain in queue to generate critical alert ( W < C )" } "-t" = { value = "$mailq_timeout$" description = "Plugin timeout in seconds (default = 15)" } "-M" = { value = "$mailq_servertype$" description = "[ sendmail | qmail | postfix | exim | nullmailer ] (default = autodetect)" } "-s" = { set_if = "$mailq_sudo$" description = "Use sudo for mailq command" } } } object CheckCommand "pgsql" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_pgsql" ] arguments = { "-H" = { value = "$pgsql_hostname$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-P" = { value = "$pgsql_port$" description = "Port number (default: 5432)" } "-d" = { value = "$pgsql_database$" description = "Database to check (default: template1)" } "-l" = { value = "$pgsql_username$" description = "Login name of user" } "-p" = { value = "$pgsql_password$" description = "Password (BIG SECURITY ISSUE)" } "-o" = { value = "$pgsql_options$" description = "Connection parameters (keyword = value), see below" } "-w" = { value = "$pgsql_warning$" description = "Response time to result in warning status (seconds)" } "-c" = { value = "$pgsql_critical$" description = "Response time to result in critical status (seconds)" } "-t" = { value = "$pgsql_timeout$" description = "Seconds before connection times out (default: 10)" } "-q" = { value = "$pgsql_query$" description = "SQL query to run. Only first column in first row will be read" } "-W" = { value = "$pgsql_query_warning$" description = "SQL query value to result in warning status (double)" } "-C" = { value = "$pgsql_query_critical$" description = "SQL query value to result in critical status (double)" } } vars.pgsql_hostname = "$check_address$" } object CheckCommand "mysql" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_mysql" ] arguments = { "-H" = { value = "$mysql_hostname$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-P" = { value = "$mysql_port$" description = "Port number (default: 3306)" } "-n" = { set_if = "$mysql_ignore_auth$" description = "Ignore authentication failure and check for mysql connectivity only" } "-s" = { value = "$mysql_socket$" description = "Use the specified socket" } "-d" = { value = "$mysql_database$" description = "Check database with indicated name" } "-f" = { value = "$mysql_file$" description = "Read from the specified client options file" } "-g" = { value = "$mysql_group$" description = "Use a client options group" } "-u" = { value = "$mysql_username$" description = "Connect using the indicated username" } "-p" = { value = "$mysql_password$" description = "Use the indicated password to authenticate the connection" } "-S" = { set_if = "$mysql_check_slave$" description = "Check if the slave thread is running properly" } "-w" = { value = "$mysql_warning$" description = "Exit with WARNING status if slave server is more than INTEGER seconds behind master" } "-c" = { value = "$mysql_critical$" description = "Exit with CRITICAL status if slave server is more then INTEGER seconds behind master" } "-l" = { set_if = "$mysql_ssl$" description = "Use ssl encryptation" } "-C" = { value = "$mysql_cacert$" description = "Path to CA signing the cert" } "-a" = { value = "$mysql_cert$" description = "Path to SSL certificate" } "-k" = { value = "$mysql_key$" description = "Path to private SSL key" } "-D" = { value = "$mysql_cadir$" description = "Path to CA directory" } "-L" = { value = "$mysql_ciphers$" description = "List of valid SSL ciphers" } } vars.mysql_hostname = "$check_address$" } object CheckCommand "negate" { command = [ PluginDir + "/negate" ] arguments = { "-t" = { value = "$negate_timeout$" description = "Seconds before plugin times out (default: 11)" } "-T" = { value = "$negate_timeout_result$" description = "Custom result on Negate timeouts" } "-o" = { value = "$negate_ok$" } "-w" = { value = "$negate_warning$" } "-c" = { value = "$negate_critical$" } "-u" = { value = "$negate_unknown$" } "-s" = { set_if = "$negate_substitute$" description = "Substitute output text as well. Will only substitute text in CAPITALS" } "--wrapped-plugin" = { value = {{ var command = macro("$negate_command$") var arguments = macro("$negate_arguments$") if (typeof(command) == String && !arguments) { return command } var escaped_args = [] for (arg in resolve_arguments(command, arguments)) { escaped_args.add(arg) } return escaped_args.join(" ") }} skip_key = true order = 1 } } vars.negate_timeout_result = "UNKNOWN" } object CheckCommand "file_age" { command = [ PluginDir + "/check_file_age" ] arguments = { "-w" = { value = "$file_age_warning_time$" description = "File must be no more than this many seconds old (default: 240s)" } "-c" = { value = "$file_age_critical_time$" description = "File must be no more than this many seconds old (default: 600s)" } "-W" = { value = "$file_age_warning_size$" description = "File must be at least this many bytes long" } "-C" = { value = "$file_age_critical_size$" description = "File must be at least this many bytes long (default: 0B)" } "-i" = { set_if = "$file_age_ignoremissing$" description = "return OK if the file does not exist" } "-f" = { value = "$file_age_file$" description = "File to monitor" } } vars.file_age_ignoremissing = false } object CheckCommand "smart" { command = [ PluginDir + "/check_ide_smart" ] arguments = { "-d" = { value = "$smart_device$" description = "Name of a local hard drive to monitor" required = true } } } object CheckCommand "breeze" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_breeze" ] arguments = { "-H" = { value = "$breeze_hostname$" description = "Name or IP address of host to check" required = true } "-C" = { value = "$breeze_community$" description = "SNMPv1 community (default public)" } "-w" = { value = "$breeze_warning$" description = "Percentage strength below which a WARNING status will result" required = true } "-c" = { value = "$breeze_critical$" description = "Percentage strength below which a CRITICAL status will result" required = true } } vars.breeze_hostname = "$check_address$" vars.breeze_warning = "50" vars.breeze_critical = "20" } object CheckCommand "flexlm" { command = [ PluginDir + "/check_flexlm" ] arguments = { "-F" = { value = "$flexlm_licensefile$" description = "Name of license file (usually license.dat)" required = true } "-t" = { value = "$flexlm_timeout$" description = "Plugin time out in seconds (default = 15)" } } } object CheckCommand "game" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_game" ] arguments = { "-P" = { value = "$game_port$" description = "Port to connect to" } "-t" = { value = "$game_timeout$" description = "Seconds before connection times out (default: 10)" } "-g" = { value = "$game_gamefield$" description = "Field number in raw qstat output that contains game name" } "-m" = { value = "$game_mapfield$" description = "Field number in raw qstat output that contains map name" } "-p" = { value = "$game_pingfield$" description = "Field number in raw qstat output that contains ping time" } "-G" = { value = "$game_gametime$" description = "Field number in raw qstat output that contains game time" } "-H" = { value = "$game_hostname$" description = "Name of the host running the game" } "game" = { value = "$game_game$" description = "Name of the game" order = 1 skip_key = true } "ipaddress" = { value = "$game_ipaddress$" description = "Ipaddress of the game server to query" order = 2 skip_key = true } } } object CheckCommand "mysql_query" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_mysql_query" ] arguments = { "-H" = { value = "$mysql_query_hostname$" description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-P" = { value = "$mysql_query_port$" description = "Port number (default: 3306)" } "-u" = { value = "$mysql_query_username$" description = "Username to login with" } "-p" = { value = "$mysql_query_password$" description = "Password to login with" } "-d" = { value = "$mysql_query_database$" description = "Database to check" } "-f" = { value = "$mysql_query_file$" description = "Read from the specified client options file" } "-g" = { value = "$mysql_query_group$" description = "Use a client options group" } "-q" = { value = "$mysql_query_execute$" description = "SQL query to run. Only first column in first row will be read" } "-w" = { value = "$mysql_query_warning$" description = "Warning range (format: start:end). Alert if outside this range" } "-c" = { value = "$mysql_query_critical$" description = "Critical range" } } vars.mysql_query_hostname = "$check_address$" } object CheckCommand "radius" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_radius", ] arguments = { "-H" = { value = "$radius_address$", description = "Host name, IP Address, or unix socket (must be an absolute path)" } "-F" = { value = "$radius_config_file$", description = "Configuration file" } "-u" = { value = "$radius_username$", description = "The user to authenticate" } "-p" = { value = "$radius_password$", description = "Password for authentication" } "-P" = { value = "$radius_port$", description = "Port number (default: 1645)" }, "-n" = { value = "$radius_nas_id$", description = "NAS identifier" } "-N" = { value = "$radius_nas_address$", description = "NAS IP Address" }, "-e" = { value = "$radius_expect$", description = "Response string to expect from the server" }, "-r" = { value = "$radius_retries$", description = "Number of times to retry a failed connection" }, "-t" = { value = "$radius_timeout$", description = "Seconds before connection times out (default: 10) Optional : can be a state integer (0,1,2,3) or a state STRING" }, } vars.radius_address = "$check_address$" } object CheckCommand "nscp_api" { import "ipv4-or-ipv6" command = [ PluginDir + "/check_nscp_api" ] arguments = { "-H" = { value = "$nscp_api_host$" description = "NSCP API host address" required = true } "-P" = { value = "$nscp_api_port$" description = "NSCP API host port. Defaults to 8443." } "--password" = { value = "$nscp_api_password$" description = "NSCP API password" } "-q" = { value = "$nscp_api_query$" description = "NSCPI API Query endpoint to use" } "-a" = { value = "$nscp_api_arguments$" description = "NSCP API Query arguments" repeat_key = true } } vars.nscp_api_host = "$check_address$" } icinga2-2.8.1/itl/hangman000066400000000000000000000074451322762156600152060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ if (!globals.irc) { globals.irc = globals.log } hm = { max_errors = 6 h_word = null h_arr = null guesses = 0 errors = 0 a_arr = null misses = "" if (irc) { hangman_output = irc } else { hangman_output = log } function str2arr(str) { var arr = [] for (i in range(str.len())) { arr.add(str.substr(i, 1)) } return arr } function init(s) { s = s.upper() h_word = s h_arr = str2arr(h_word) guesses = 0 errors = 0 a_arr = h_arr.clone() misses = "" for (x in range(a_arr.len())) { a_arr[x] = (h_arr[x] == " ") } } function print_progress() { var ir for (x in range(a_arr.len())) { if (a_arr[x]) { ir += h_arr[x] } else { ir += "_" } ir += " " } hangman_output(ir) hangman_output(errors + "/" + (max_errors + 1) + " errors made: " + misses) } function create_hint() { var r = Math.floor(Math.random() * a_arr.len()) if (!a_arr[r]) { a_arr[r] = true for (x in range(h_arr.len())) { if (h_arr[x] == h_arr[r]) { a_arr[x]=true } } } else { if (a_arr.contains(false)) { create_hint() } else { winner() } } if (!a_arr.contains(false)) { winner() } } function hint(i) { for (x in range(i)) { create_hint() } print_progress() } function winner() { if (h_word) { hangman_output("Congratulations, you are a winner in " + guesses + " guesses.") h_word = null } } function guess(s) { if (!h_word) { hangman_output("Please set a word with hm.init(\"word\")") return } s = s.upper() if (s.len() != 1) { hangman_output("NEIN!") return } var correct = false for (x in range(h_arr.len())) { if (h_arr[x] == s) { a_arr[x] = true correct = true } } if (!correct) { misses += s + " " errors += 1 } print_progress() guesses += 1 if (!a_arr.contains(false)) { winner() return } if (errors > max_errors) { hangman_output("You died...") hangman_output(" ________") hangman_output(" |/ |") hangman_output(" | (_)") hangman_output(" | \\|/") hangman_output(" | |") hangman_output(" | / \\") hangman_output(" |") hangman_output("_|___") remove("h_word") return } } function clone() { var n = Dictionary.prototype.clone.call(this) if (h_arr) { n.h_arr = h_arr.clone() } if (a_arr) { n.a_arr = a_arr.clone() } return n } } icinga2-2.8.1/itl/itl000066400000000000000000000030641322762156600143560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * This is the Icinga Templare Library, a collection of general purpose Icinga * configuration templates. */ include "command-icinga.conf" icinga2-2.8.1/itl/manubulon000066400000000000000000000030041322762156600155600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * This is the SNMP Manubulon Template Library. */ include "command-plugins-manubulon.conf" icinga2-2.8.1/itl/nscp000066400000000000000000000027041322762156600145310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ include "command-nscp-local.conf" icinga2-2.8.1/itl/plugins000066400000000000000000000031351322762156600152460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * This is the Icinga Templare Library, a collection of general purpose Icinga * configuration templates. This part includes the plugin commands. */ include "command-plugins.conf" icinga2-2.8.1/itl/plugins-contrib000066400000000000000000000032041322762156600167010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * This is a directory for various contributed command definitions. * Plugins should be organized by a category, e.g. database plugins are in * plugins-contrib.d/databases.conf */ include_recursive "plugins-contrib.d" icinga2-2.8.1/itl/plugins-contrib.d/000077500000000000000000000000001322762156600172015ustar00rootroot00000000000000icinga2-2.8.1/itl/plugins-contrib.d/CMakeLists.txt000066400000000000000000000021541322762156600217430ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. install( FILES databases.conf hardware.conf icingacli.conf ipmi.conf logmanagement.conf metrics.conf network-components.conf network-services.conf operating-system.conf raid-controller.conf smart-attributes.conf storage.conf virtualization.conf vmware.conf web.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2/include/plugins-contrib.d ) icinga2-2.8.1/itl/plugins-contrib.d/databases.conf000066400000000000000000000655421322762156600220130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "mssql_health" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_mssql_health" ] arguments = { "--hostname" = { value = "$mssql_health_hostname$" description = "the database server's hostname" } "--username" = { value = "$mssql_health_username$" description = "the mssql db user" } "--password" = { value = "$mssql_health_password$" description = "the mssql db user's password" } "--port" = { value = "$mssql_health_port$" description = "the database's port" } "--server" = { value = "$mssql_health_server$" description = "the name of a predefined connection" } "--currentdb" = { value = "$mssql_health_currentdb$" description = "the name of a database which is used as the current database for the connection" } "--offlineok" = { set_if = "$mssql_health_offlineok$" description = "if offline databases are perfectly ok for you" } "--nooffline" = { set_if = "$mssql_health_nooffline$" description = "Skip the offline databases" } "--dbthresholds" = { value = "$mssql_health_dbthresholds$" description = "Read thresholds from a database table" } "--notemp" = { set_if = "$mssql_health_notemp$" description = "Ignore temporary databases/tablespaces" } "--commit" = { set_if = "$mssql_health_commit$" description = "turns on autocommit for the dbd::sybase module" } "--method" = { value = "$mssql_health_method$" description = "how the plugin should connect to the database (dbi for using DBD::Sybase (default), sqlrelay for the SQLRelay proxy)" } "--mode" = { value = "$mssql_health_mode$" description = "the mode of the plugin" } "--regexp" = { set_if = "$mssql_health_regexp$" description = "name will be interpreted as a regular expression" } "--warning" = { value = "$mssql_health_warning$" description = "the warning range" } "--critical" = { value = "$mssql_health_critical$" description = "the critical range" } "--warningx" = { value = "$mssql_health_warningx$" description = "The extended warning thresholds" } "--criticalx" = { value = "$mssql_health_criticalx$" description = "The extended critical thresholds" } "--units" = { value = "$mssql_health_units$" description = "This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free" } "--name" = { value = "$mssql_health_name$" description = "the name of the database etc depending on the mode" } "--name2" = { value = "$mssql_health_name2$" description = "if name is a sql statement, name2 can be used to appear in the output and the performance data" } "--name3" = { value = "$mssql_health_name3$" description = "The tertiary name of a component" } "--extra-opts" = { value = "$mssql_health_extraopts$" description = "read command line arguments from an external file" } "--blacklist" = { value = "$mssql_health_blacklist$" description = "Blacklist some (missing/failed) components" } "--mitigation" = { value = "$mssql_health_mitigation$" description = "The parameter allows you to change a critical error to a warning." } "--lookback" = { value = "$mssql_health_lookback$" description = "The amount of time you want to look back when calculating average rates" } "--environment" = { value = "$mssql_health_environment$" description = "Add a variable to the plugin's environment." } "--negate" = { value = "$mssql_health_negate$" description = "Emulate the negate plugin. --negate warning=critical --negate unknown=critical." } "--morphmessage" = { value = "$mssql_health_morphmessage$" description = "Modify the final output message." } "--morphperfdata" = { value = "$mssql_health_morphperfdata$" description = "The parameter allows you to change performance data labels." } "--selectedperfdata" = { value = "$mssql_health_selectedperfdata$" description = "The parameter allows you to limit the list of performance data." } "--report" = { value = "$mssql_health_report$" description = "Report can be used to output only the bad news (short,long,html)" } "--multiline" = { value = "$mssql_health_multiline$" description = "Multiline output." } "--with-mymodules-dyn-dir" = { value = "$mssql_health_withmymodulesdyndir$" description = "Add-on modules for the my-modes will be searched in this directory." } "--statefilesdir" = { value = "$mssql_health_statefilesdir$" description = "An alternate directory where the plugin can save files." } "--isvalidtime" = { value = "$mssql_health_isvalidtime$" description = "Signals the plugin to return OK if now is not a valid check time." } "--timeout" = { value = "$mssql_health_timeout$" description = "Seconds before plugin times out (default: 15)" } } vars.mssql_health_regexp = false vars.mssql_health_offlineok = false vars.mssql_health_commit = false vars.mssql_health_notemp = false vars.mssql_health_nooffline = false vars.mssql_health_report = "short" } object CheckCommand "mysql_health" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_mysql_health" ] arguments = { "--hostname" = { value = "$mysql_health_hostname$" description = "the database server's hostname" } "--port" = { value = "$mysql_health_port$" description = "the database's port" } "--socket" = { value = "$mysql_health_socket$" description = "the database's unix socket" } "--username" = { value = "$mysql_health_username$" description = "the mysql db user" } "--password" = { value = "$mysql_health_password$" description = "the mysql db user's password" } "--database" = { value = "$mysql_health_database$" description = "the database's name" } "--warning" = { value = "$mysql_health_warning$" description = "the warning range" } "--critical" = { value = "$mysql_health_critical$" description = "the critical range" } "--warningx" = { value = "$mysql_health_warningx$" description = "The extended warning thresholds" } "--criticalx" = { value = "$mysql_health_criticalx$" description = "The extended critical thresholds" } "--mode" = { value = "$mysql_health_mode$" description = "the mode of the plugin" } "--method" = { value = "$mysql_health_method$" description = "how the plugin should connect to the database (dbi for using DBD::mysql (default), mysql for using the mysql-Tool)" } "--commit" = { value = "$mysql_health_commit$" description = "turns on autocommit for the dbd::* module" } "--notemp" = { value = "$mysql_health_notemp$" description = "Ignore temporary databases/tablespaces" } "--nooffline" = { value = "$mysql_health_nooffline$" description = "skip the offline databases" } "--regexp" = { value = "$mysql_health_regexp$" description = " Parameter name/name2/name3 will be interpreted as (perl) regular expression." } "--name" = { value = "$mysql_health_name$" description = "The name of a specific component to check" } "--name2" = { value = "$mysql_health_name2$" description = "The secondary name of a component" } "--name3" = { value = "$mysql_health_name3$" description = "The tertiary name of a component" } "--units" = { value = "$mysql_health_units$" description = "This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free" } "--labelformat" = { value = "$mysql_health_labelformat$" description = "one of pnp4nagios (which is the default) or groundwork" } "--extra-opts" = { value = "$mysql_health_extraopts$" description = "Read command line arguments from an external file." } "--blacklist" = { value = "$mysql_health_blacklist$" description = "Blacklist some (missing/failed) components" } "--mitigation" = { value = "$mysql_health_mitigation$" description = "The parameter allows you to change a critical error to a warning." } "--lookback" = { value = "$mysql_health_lookback$" description = "The amount of time you want to look back when calculating average rates." } "--environment" = { value = "$mysql_health_environment$" description = "Add a variable to the plugin's environment." } "--morphmessage" = { value = "$mysql_health_morphmessage$" description = "Modify the final output message." } "--morphperfdata" = { value = "$mysql_health_morphperfdata$" description = "The parameter allows you to change performance data labels." } "--selectedperfdata" = { value = "$mysql_health_selectedperfdata$" description = "The parameter allows you to limit the list of performance data." } "--report" = { value = "$mysql_health_report$" description = "Can be used to shorten the output." } "--multiline" = { value = "$mysql_health_multiline$" description = "Multiline output." } "--negate" = { value = "$mysql_health_negate$" description = "Emulate the negate plugin. --negate warning=critical --negate unknown=critical." } "--with-mymodules-dyn-dir" = { value = "$mysql_health_withmymodulesdyndir$" description = "Add-on modules for the my-modes will be searched in this directory." } "--statefilesdir" = { value = "$mysql_health_statefilesdir$" description = "An alternate directory where the plugin can save files." } "--isvalidtime" = { value = "$mysql_health_isvalidtime$" description = "Signals the plugin to return OK if now is not a valid check time." } "--timeout" = { value = "$mysql_health_timeout$" description = "plugin timeout. Default is 60 seconds" } } vars.mysql_health_hostname = "$check_address$" } object CheckCommand "db2_health" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_db2_health" ] arguments = { "--hostname" = { value = "$db2_health_hostname$" description = "the host to connect" order = -2 } "--database" = { value = "$db2_health_database$" description = "the database to connect" order = 0 } "--username" = { value = "$db2_health_username$" description = "the db2 user" order = 1 } "--password" = { value = "$db2_health_password$" description = "the db2 user's password" order = 2 } "--port" = { value = "$db2_health_port$" description = "the db2 port for connection" order = -1 } "--warning" = { value = "$db2_health_warning$" description = "the warning range" order = 5 } "--critical" = { value = "$db2_health_critical$" description = "the critical range" order = 6 } "--mode" = { value = "$db2_health_mode$" description = "the mode of the plugin" order = 3 } "--name" = { value = "$db2_health_name$" description = "the name of the tablespace, datafile, wait event, latch, enqueue, or sql statement depending on the mode" order = 4 } "--name2" = { value = "$db2_health_name2$" description = "if name is a sql statement, name2 can be used to appear in the output and the performance data" order = 7 } "--regexp" = { set_if = "$db2_health_regexp$" description = "name will be interpreted as a regular expression" } "--units" = { value = "$db2_health_units$" description = "This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free" } "--maxinactivity" = { value = "$db2_health_maxinactivity$" description = "used for the maximum amount of time a certain event has not happened." } "--mitigation" = { value = "$db2_health_mitigation$" description = "let you classify the severity of an offline tablespace." } "--lookback" = { value = "$db2_health_lookback$" description = "How many days iin the past db2_health check should look back to calculate exitcode." } "--report" = { value = "$db2_health_report$" description = "Report can be used to output only the bad news (short,long,html)" } } env = { "DB2_HOME" = "$db2_health_env_db2_home$" "DB2_VERSION" = "$db2_health_env_db2_version$" } vars.db2_health_regexp = false vars.db2_health_hostname = "$check_address$" vars.db2_health_report = "short" vars.db2_health_env_db2_home = "/opt/ibm/db2/V10.5" vars.db2_health_env_db2_version = "10.5" } object CheckCommand "oracle_health" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_oracle_health" ] arguments = { "--connect" = { value = "$oracle_health_connect$" description = "the connect string" } "--username" = { value = "$oracle_health_username$" description = "the oracle user" } "--password" = { value = "$oracle_health_password$" description = "the oracle user's password" } "--warning" = { value = "$oracle_health_warning$" description = "the warning range" } "--critical" = { value = "$oracle_health_critical$" description = "the critical range" } "--mode" = { value = "$oracle_health_mode$" description = "the mode of the plugin" } "--method" = { value = "$oracle_health_method$" description = "how the plugin should connect to the database (dbi for using DBD::Oracle (default), sqlplus for using the sqlplus-Tool)" } "--name" = { value = "$oracle_health_name$" description = "the name of the tablespace, datafile, wait event, latch, enqueue, or sql statement depending on the mode" } "--name2" = { value = "$oracle_health_name2$" description = "if name is a sql statement, name2 can be used to appear in the output and the performance data" } "--regexp" = { set_if = "$oracle_health_regexp$" description = "name will be interpreted as a regular expression" } "--units" = { value = "$oracle_health_units$" description = "This is used for a better output of mode=sql and for specifying thresholds for mode=tablespace-free" } "--ident" = { set_if = "$oracle_health_ident$" description = "outputs instance and database names" } "--commit" = { set_if = "$oracle_health_commit$" description = "turns on autocommit for the dbd::oracle module" } "--noperfdata" = { set_if = "$oracle_health_noperfdata$" description = "do not output performance data" } "--timeout" = { value = "$oracle_health_timeout$" description = "plugin timeout. Default is 60 seconds" } "--report" = { value = "$oracle_health_report$" description = "select the plugin output format. Can be short, long or html. Default is long" } } env = { "ORACLE_HOME" = "$oracle_home$" "TNS_ADMIN" = "$oracle_tns_admin$" } vars.oracle_health_regexp = false vars.oracle_health_ident = false vars.oracle_health_commit = false vars.oracle_health_noperfdata = false vars.oracle_health_report = "long" vars.oracle_home = "/usr/lib/oracle/11.2/client64/lib" vars.oracle_tns_admin = SysconfDir + "/icinga2/plugin-configs" } object CheckCommand "postgres" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_postgres.pl" ] arguments = { "-H" = { value = "$postgres_host$" set_if = {{ macro("$postgres_unixsocket$") == false }} description = "hostname(s) to connect to; defaults to none (Unix socket)" } "-p" = { value = "$postgres_port$" description = "port(s) to connect to; defaults to 5432" } "-db" = { value = "$postgres_dbname$" description = "database name(s) to connect to; defaults to 'postgres' or 'template1'" } "-u" = { value = "$postgres_dbuser$" description = "database user(s) to connect as; defaults to 'postgres'" } "--dbpass" = { value = "$postgres_dbpass$" description = "database password(s); use a .pgpass file instead when possible" } "--dbservice" = { value = "$postgres_dbservice$" description = "service name to use inside of pg_service.conf" } "-w" = { value = "$postgres_warning$" description = "the warning threshold, range depends on the action" } "-c" = { value = "$postgres_critical$" description = "the critical threshold, range depends on the action" } "--include" = { value = "$postgres_include$" description = "name(s) items to specifically include (e.g. tables), depends on the action" } "--exclude" = { value = "$postgres_exclude$" description = "name(s) items to specifically exclude (e.g. tables), depends on the action" } "--includeuser" = { value = "$postgres_includeuser$" description = "include objects owned by certain users" } "--excludeuser" = { value = "$postgres_excludeuser$" description = "exclude objects owned by certain users" } "--assume-standby-mode" = { set_if = "$postgres_standby$" description = "assume that server in continious WAL recovery mode" } "--assume-prod" = { set_if = "$postgres_production$" description = "assume that server in production mode" } "--action" = { value = "$postgres_action$" description = "determines the test executed" } "--query" = { value = "$postgres_query$" description = "query for custom_query action" } "--valtype" = { value = "$postgres_valtype$" description = "determines the result type for custom_query action" } "--reverse" = { set_if = "$postgres_reverse$" description = "reverses warning and critical for custom_query action" } "--tempdir" = { value = "$postgres_tempdir$" description = "specify directory for temporary files. default depends on the OS" } } vars.postgres_host = "$check_address$" vars.postgres_standby = false vars.postgres_production = false vars.postgres_unixsocket = false } object CheckCommand "mongodb" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_mongodb.py" ] arguments = { "-H" = { value = "$mongodb_address$" description = "The hostname you want to connect to" } "-P" = { value = "$mongodb_port$" description = "The port mongodb is runnung on" } "-u" = { value = "$mongodb_user$" description = "The username you want to login as" } "-p" = { value = "$mongodb_passwd$" description = "The password you want to use for that user" } "-A" = { value = "$mongodb_action$" description = "The action you want to take" } "-c" = { value = "$mongodb_collection$" description = "Specify the collection to check" } "-T" = { value = "$mongodb_sampletime$" description = "Time used to sample number of pages faults" } "-q" = { value = "$mongodb_querytype$" description = "The query type to check [query|insert|update|delete|getmore|command] from queries_per_second" } "--database" = { value = "$mongodb_database$" description = "Specify the database to check" } "-D" = { set_if = "$mongodb_perfdata$" description = "Enable output of Nagios performance data" } "--max-lag" = { set_if = "$mongodb_maxlag$" description = "Get max replication lag (for replication_lag action only)" } "--mapped-memory" = { set_if = "$mongodb_mappedmemory$" description = "Get mapped memory instead of resident (if resident memory can not be read)" } "--ssl" = { set_if = "$mongodb_ssl$" description = "Connect using SSL" } "--replicaset" = { value = "$mongodb_replicaset$" set_if = "$mongodb_replcheck$" description = "Connect to replicaset" } "--all-databases" = { set_if = "$mongodb_alldatabases$" description = "Check all databases (action database_size)" } "-C" = { value = "$mongodb_critical$" description = "The critical threshold we want to set" } "-W" = { value = "$mongodb_warning$" description = "The warning threshold we want to set" } } vars.mongodb_address = "$check_address$" vars.mongodb_perfdata = true vars.mongodb_action = "connections" } object CheckCommand "elasticsearch" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_elasticsearch" ] arguments = { "--failure-domain" = { value = "$elasticsearch_failuredomain$" description = "A comma-separated list of ElasticSearch attributes that make up your cluster's failure domain" } "--host" = { value = "$elasticsearch_host$" description = "Hostname or network address to probe, defaults to 'localhost'" } "--master-nodes" = { value = "$elasticsearch_masternodes$" description = "Issue a warning if the number of master-eligible nodes in the cluster drops below this number. By default, do not monitor the number of nodes in the cluster" } "--port" = { value = "$elasticsearch_port$" description = "TCP port to probe, defaults to 9200" } "--prefix" = { value = "$elasticsearch_prefix$" description = "Optional prefix for the ElasticSearch API, defaults to ''" } "--yellow-critical" = { value = "TRUE" set_if = "$elasticsearch_yellowcritical$" description = "Instead of issuing a 'warning' for a yellow cluster state, issue a 'critical' alert" } } vars.elasticsearch_host = "$check_address$" vars.elasticsearch_yellowcritical = false } object CheckCommand "redis" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_redis.pl" ] arguments = { "--hostname" = { value = "$redis_hostname$" description = "Hostname or IP Address to check." } "--port" = { value = "$redis_port$" description = "Port number (default: 6379)." } "--database" = { value = "$redis_database$" description = "Optional database name (usually a number), needed for redis_query." } "--password" = { value = "$redis_password$" description = "Password for Redis authentication. Safer alternative is to put them in a file and use redis_credentials." } "--credentials" = { value = "$redis_credentials$" description = "Credentials file to read for Redis authentication." } "--timeout" = { value = "$redis_timeout$" description = "Allows to set timeout for execution of this plugin." } "--variables" = { value = "$redis_variables$" description = "List of variables from info data to do threshold checks on." } "--warn" = { value = "$redis_warn$" description = "This option can only be used if redis_variables is used and number of values listed here must exactly match number of variables specified." } "--crit" = { value = "$redis_crit$" description = "This option can only be used if redis_variables is used and number of values listed here must exactly match number of variables specified." } "--perfparse" = { set_if = "$redis_perfparse$" description = "This should only be used with variables and causes variable data not only to be printed as part of main status line but also as perfparse compatible output." } "--perfvars" = { value = "$redis_perfvars$" description = "This allows to list variables which values will go only into perfparse output (and not for threshold checking)." } "--prev_perfdata" = { value = "$service.perfdata$" set_if = "$redis_prev_perfdata$" description = "Previous performance data used to calculate rate of change for counter statistics variables and for proper calculation of hitrate." } "--rate_label" = { value = "$redis_rate_label$" description = "Prefix or Suffix label used to create a new variable which has rate of change of another base variable." } "--query" = { value = "$redis_query$" repeat_key = true description = "Option specifies key to query and optional variable name to assign the results to after. See the help output of the plugin for the detailed format." } "--option" = { value = "$redis_option$" repeat_key = true description = "Specifiers are separated by , and must include NAME or PATTERN. See the help output of the plugin for the detailed format." } "--response_time" = { value = "$redis_response_time$" description = "If this is used plugin will measure and output connection response time in seconds. With perfparse this would also be provided on perf variables." } "--hitrate" = { value = "$redis_hitrate$" description = "Calculates Hitrate." } "--memory_utilization" = { value = "$redis_memory_utilization$" description = "This calculates percent of total memory on system used by redis." } "--total_memory" = { value = "$redis_total_memory$" description = "Amount of memory on a system for memory utilization calculations above." } "--replication_delay" = { value = "$redis_replication_delay$" description = "Allows to set threshold on replication delay info." } } vars.redis_hostname = "$check_address$" vars.redis_perfparse = false vars.redis_prev_perfdata = false } icinga2-2.8.1/itl/plugins-contrib.d/hardware.conf000066400000000000000000000105351322762156600216510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "hpasm" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_hpasm" ] arguments = { "--hostname" = { value = "$hpasm_hostname$" set_if = "$hpasm_remote$" description = "Hostname or IP-address of the server (SNMP mode only)" } "--community" = { value = "$hpasm_community$" description = "SNMP community of the server (SNMP v1/2 only)" } "--protocol" = { value = "$hpasm_protocol$" description = "The SNMP protocol to use (default: 2c, other possibilities: 1,3)" } "--port" = { value = "$hpasm_port$" description = "The SNMP port to use (default: 161)" } "--blacklist" = { value = "$hpasm_blacklist$" description = "Blacklist some (missing/failed) components" } "--ignore-dimms" = { set_if = "$hpasm_ignore-dimms$" description = "Ignore \"N/A\"-DIMM status on misc. servers (e.g. older DL320)" } "--ignore-fan-redundancy" = { set_if = "$hpasm_ignore-fan-redundancy$" description = "Ignore missing redundancy partners" } "--customthresholds" = { value = "$hpasm_customthresholds$" description = "Use custom thresholds for certain temperatures" } "--eventrange" = { value = "$hpasm_eventrange$" description = "Period of time before critical IML events respecively become warnings or vanish. A range is descibed as a number and a unit (s, m, h, d), e.g. --eventrange 1h/20m." } "--perfdata" = { value = "$hpasm_perfdata$" description = "Output performance data. If your performance data string becomes too long and is truncated by Nagios, then you can use --perfdata=short instead. This will output temperature tags without location information" } "--username" = { value = "$hpasm_username$" description = "The securityName for the USM security model (SNMPv3 only)" } "--authpassword" = { value = "$hpasm_authpassword$" description = "The authentication password for SNMPv3" } "--authprotocol" = { value = "$hpasm_authprotocol$" description = "The authentication protocol for SNMPv3 (md5|sha)" } "--privpassword" = { value = "$hpasm_privpassword$" description = "The password for authPriv security level" } "--privprotocol" = { value = "$hpasm_privprotocol$" description = "The private protocol for SNMPv3 (des|aes|aes128|3des|3desde)" } "--servertype" = { value = "$hpasm_servertype$" description = "The type of the server: proliant (default) or bladesystem" } "--eval-nics" = { set_if = "$hpasm_eval-nics$" description = "Check network interfaces (and groups). Try it and report me whyt you think about it. I need to build up some know how on this subject. If get an error and you think, it is not justified for your configuration, please tell me about it. (alwasy send the output of \"snmpwalk -On .... 1.3.6.1.4.1.232\" and a description how you setup your nics and why it is correct opposed to the plugins error message" } } vars.hpasm_remote = true vars.hpasm_hostname = "$check_address$" } icinga2-2.8.1/itl/plugins-contrib.d/icingacli.conf000066400000000000000000000045211322762156600217740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ template CheckCommand "icingacli" { command = [ PrefixDir + "/bin/icingacli" ] } object CheckCommand "icingacli-businessprocess" { import "icingacli" command += [ "businessprocess", "process", "check" ] arguments = { "--config" = { value = "$icingacli_businessprocess_config$" description = "Configuration file containing your business process without file extension" } "--details" = { set_if = "$icingacli_businessprocess_details$" description = "Get details for root cause analysis" } "--state-type" = { value = "$icingacli_businessprocess_statetype$" description = "Define which state type to look at. Could be either soft or hard, overrides an eventually configured default" } "--process" = { value = "$icingacli_businessprocess_process$" description = "Business process to monitor" skip_key = true required = true order = -1 } } vars.icingacli_businessprocess_details = false } icinga2-2.8.1/itl/plugins-contrib.d/ipmi.conf000066400000000000000000000105151322762156600210100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "ipmi-sensor" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_ipmi_sensor" ] arguments = { "-H" = { value = "$ipmi_address$" description = "Hostname or ip address of the IPMI interface (default: host.address or host.address6)" } "-f" = { value = "$ipmi_config_file$" description = "Path to the FreeIPMI configuration file" } "-U" = { value = "$ipmi_username$" description = "Username to connect with" } "-P" = { value = "$ipmi_password$" description = "Password to use" } "-L" = { value = "$ipmi_privilege_level$" description = "Privilege level of the user" } "-b" = { set_if = "$ipmi_backward_compatibility_mode$" description = "Enable backward compatibility mode (for FreeIPMI 0.5.*)" } "-T" = { value = "$ipmi_sensor_type$" description = "Limit sensors to query based on IPMI sensor type (seperated by comma)" } "-ST" = { value = "$ipmi_sel_type$" description = "Limit SEL entries to specific types. (seperated by comma)" } "-x" = { value = "$ipmi_exclude_sensor_id$" description = "Exclude sensor matching ipmi_sensor_id" } "-xT" = { value = "$ipmi_exclude_sensor$" description = "Exclude sensors based on IPMI sensor type. (seperated by comma)" } "-xST" = { value = "$ipmi_exclude_sel$" description = "Exclude SEL entries of specific sensor types. (seperated by comma)" } "-i" = { value = "$ipmi_sensor_id$" description = "Include sensor matching ipmi_sensor_id" } "--nosel" = { set_if = "$ipmi_no_sel_checking$" description = "Turn off system event log checking via ipmi-sel" } "--nothresholds" = { set_if = "$ipmi_no_thresholds$" description = "Turn off performance data thresholds from output-sensor-thresholds" } "-D" = { value = "$ipmi_protocol_lan_version$" description = "Change the protocol LAN version (default: LAN_2_0)" } "-fc" = { value = "$ipmi_number_of_active_fans$" description = "Number of fans that should be active" } "--fru" = { set_if = "$ipmi_show_fru$" description = "Print the product serial number got by ipmi-fru" } "--noentityabsent" = { set_if = "$ipmi_noentityabsent$" description = "Skip sensor checks for sensors that have 'noentityabsent' as event state" } "-vv" = { set_if = "$ipmi_verbose$" description = "Be Verbose multi line output, also with additional details for warnings" } "-vvv" = { set_if = "$ipmi_debug$" description = "Be Verbose debugging output, followed by normal multi line output" } } vars.ipmi_address = "$check_address$" vars.ipmi_protocol_lan_version = "LAN_2_0" } /* * Icinga2 CheckCommand definition for an IPMI interface ping check */ template CheckCommand "ipmi-alive-common" { vars.ping_wrta = 5000.0 vars.ping_wpl = 100 vars.ping_crta = 5000.0 vars.ping_cpl = 100 vars.ping_packets = 1 } object CheckCommand "ipmi-alive" { import "ping" import "ipmi-alive-common" } icinga2-2.8.1/itl/plugins-contrib.d/logmanagement.conf000066400000000000000000000060351322762156600226720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "logstash" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_logstash" ] arguments = { "-H" = { value = "$logstash_hostname$" description = "Hostname where Logstash is running" } "-p" = { value = "$logstash_port$" description = "Port where Logstash is listening for API requests" } "--file-descriptor-threshold-warn" = { value = "$logstash_filedesc_warn$" description = "Warning threshold of file descriptor usage in percent" } "--file-descriptor-threshold-crit" = { value = "$logstash_filedesc_crit$" description = "Critical threshold of file descriptor usage in percent" } "--heap-usage-threshold-warn" = { value = "$logstash_heap_warn$" description = "Warning threshold of heap usage in percent" } "--heap-usage-threshold-crit" = { value = "$logstash_heap_crit$" description = "Critical threshold of heap usage in percent" } "--inflight-events-warn" = { value = "$logstash_inflight_warn$" description = "Warning threshold of inflight events" } "--inflight-events-crit" = { value = "$logstash_inflight_crit$" description = "Critical threshold of inflight events" } "--cpu-usage-threshold-warn" = { value = "$logstash_cpu_warn$" description = "Warning threshold for cpu usage in percent" } "--cpu-usage-threshold-crit" = { value = "$logstash_cpu_crit$" description = "Critical threshold for cpu usage in percent" } } vars.logstash_hostname = "$check_address$" vars.logstash_port = 9600 vars.logstash_filedesc_warn = 85 vars.logstash_filedesc_crit = 95 vars.logstash_heap_warn = 70 vars.logstash_heap_crit = 80 } icinga2-2.8.1/itl/plugins-contrib.d/metrics.conf000066400000000000000000000057521322762156600215270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "graphite" { command = [ PluginContribDir + "/check_graphite" ] arguments = { "-u" = { value = "$graphite_url$" description = "Target url" required = true } "-m" = { value = "$graphite_metric$" description = "Metric path string" required = true } "-s" = { value = "$graphite_shortname$" description = "Metric short name (used for performance data)" } "-d" = { value = "$graphite_duration$" description = "Length, in minute of data to parse (default: 5)" } "-f" = { value = "$graphite_function$" description = "Function applied to metrics for thresholds (default: average)" } "-w" = { value = "$graphite_warning$" description = "Warning threshold" required = true } "-c" = { value = "$graphite_critical$" description = "Critical threshold" required = true } "-U" = { value = "$graphite_units$" description = "Adds a text tag to the metric count in the plugin output. Useful to identify the metric units. Doesn't affect data queries." } "-M" = { value = "$graphite_message$" description = "Text message to output (default: 'metric count:')" } "-z" = { set_if = "$graphite_zero_on_error$" description = "Return 0 on a graphite 500 error" } "-l" = { set_if = "$graphite_link_graph$" description = "Add a link in the plugin output, showing a 24h graph for this metric in graphite." } } vars.graphite_duration = "5" vars.graphite_function = "average" vars.graphite_message = "metric count:" vars.graphite_zero_on_error = false vars.graphite_link_graph = false } icinga2-2.8.1/itl/plugins-contrib.d/network-components.conf000066400000000000000000000552601322762156600237340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "interfacetable" { command = [ PluginContribDir + "/check_interface_table_v3t" ] arguments = { "-H" = { value = "$interfacetable_hostquery$" description = "Specifies the remote host to poll" } "-h" = { value = "$interfacetable_hostdisplay$" description = "Specifies the hostname to display in the HTML link" } "-r" = { set_if = "$interfacetable_regex$" description = "Interface names and property names for some other options will be interpreted as regular expressions" } "--outputshort" = { set_if = "$interfacetable_outputshort$" description = "Reduce the verbosity of the plugin output" } "-e" = { value = "$interfacetable_exclude$" description = "Comma separated list of interfaces globally excluded from the monitoring" } "-i" = { value = "$interfacetable_include$" description = "Comma separated list of interfaces globally included in the monitoring" } "--alias-matching" = { set_if = "$interfacetable_aliasmatching$" description = "Allow you to specify alias in addition to interface names" } "--et" = { value = "$interfacetable_excludetraffic$" description = "Comma separated list of interfaces excluded from traffic checks" } "--it" = { value = "$interfacetable_includetraffic$" description = "Comma separated list of interfaces included for traffic checks" } "--wt" = { value = "$interfacetable_warningtraffic$" description = "Interface traffic load percentage leading to a warning alert" } "--ct" = { value = "$interfacetable_criticaltraffic$" description = "Interface traffic load percentage leading to a critical alert" } "--pkt" = { set_if = "$interfacetable_pkt$" description = "Add unicast/non-unicast pkt stats for each interface" } "--trafficwithpkt" = { set_if = "$interfacetable_trafficwithpkt$" description = "Enable traffic calculation using pkt counters instead of octet counters. Useful when using 32-bit counters to track the load on > 1GbE interfaces." } "--tp" = { value = "$interfacetable_trackproperty$" description = "List of tracked properties" } "--ep" = { value = "$interfacetable_excludeproperty$" description = "Comma separated list of interfaces excluded from the property tracking" } "--ip" = { value = "$interfacetable_includeproperty$" description = "Comma separated list of interfaces included in the property tracking" } "--wp" = { value = "$interfacetable_warningproperty$" description = "Number of property changes before leading to a warning alert" } "--cp" = { value = "$interfacetable_criticalproperty$" description = "Number of property changes before leading to a critical alert" } "-C" = { value = "$interfacetable_community$" description = "Specifies the snmp v1/v2c community string" } "-2" = { set_if = "$interfacetable_snmpv2$" description = "Use snmp v2c" } "-l" = { value = "$interfacetable_login$" description = "Login for snmpv3 authentication" } "-x" = { value = "$interfacetable_passwd$" description = "Auth password for snmpv3 authentication" } "-X" = { value = "$interfacetable_privpass$" description = "Priv password for snmpv3" } "-L" = { value = "$interfacetable_protocols$" description = "Authentication protocol,Priv protocol" } "--domain" = { value = "$interfacetable_domain$" description = "SNMP transport domain" } "--contextname" = { value = "$interfacetable_contextname$" description = "Context name for the snmp requests" } "-P" = { value = "$interfacetable_port$" description = "SNMP port" } "--64bits" = { set_if = "$interfacetable_64bits$" description = "Use SNMP 64-bits counters" } "--max-repetitions" = { value = "$interfacetable_maxrepetitions$" description = "Increasing this value may enhance snmp query performances by gathering more results at one time" } "--snmp-timeout" = { value = "$interfacetable_snmptimeout$" description = "Define the Transport Layer timeout for the snmp queries" } "--snmp-retries" = { value = "$interfacetable_snmpretries$" description = "Define the number of times to retry sending a SNMP message" } "--snmp-maxmsgsize" = { value = "$interfacetable_snmpmaxmsgsize$" description = "Size of the SNMP message in octets, usefull in case of too long responses. Be carefull with network filters. Range 484 - 65535. Apply only to netsnmp perl bindings. The default is 1472 octets for UDP/IPv4, 1452 octets for UDP/IPv6, 1460 octets for TCP/IPv4, and 1440 octets for TCP/IPv6." } "--unixsnmp" = { set_if = "$interfacetable_unixsnmp$" description = "Use unix snmp utilities for snmp requests" } "-f" = { set_if = "$interfacetable_enableperfdata$" description = "Enable port performance data" } "--perfdataformat" = { value = "$interfacetable_perfdataformat$" description = "Define which performance data will be generated" } "--perfdatathreshold" = { value = "$interfacetable_perfdatathreshold$" description = "Define which thresholds are printed in the generated performance data" } "--perfdatadir" = { value = "$interfacetable_perfdatadir$" description = "When specified, the performance data are also written directly to a file, in the specified location" } "--perfdataservicedesc" = { value = "$interfacetable_perfdataservicedesc$" description = "Specify additional parameters for output performance data to PNP" } "-g" = { value = "$interfacetable_grapher$" description = "Specify the used graphing solution" } "--grapherurl" = { value = "$interfacetable_grapherurl$" description = "Graphing system url" } "--portperfunit" = { value = "$interfacetable_portperfunit$" description = "Traffic could be reported in bits (counters) or in bps (calculated value)" } "--nodetype" = { value = "$interfacetable_nodetype$" description = "Specify the node type, for specific information to be printed / specific oids to be used" } "--duplex" = { set_if = "$interfacetable_duplex$" description = "Add the duplex mode property for each interface in the interface table" } "--stp" = { set_if = "$interfacetable_stp$" description = "Add the stp state property for each interface in the interface table" } "--vlan" = { set_if = "$interfacetable_vlan$" description = "Add the vlan attribution property for each interface in the interface table" } "--noipinfo" = { set_if = "$interfacetable_noipinfo$" description = "Remove the ip information for each interface from the interface table" } "--alias" = { set_if = "$interfacetable_alias$" description = "Add the alias information for each interface in the interface table" } "--accessmethod" = { value = "$interfacetable_accessmethod$" description = "Access method for a shortcut to the host in the HTML page" } "--htmltablelinktarget" = { value = "$interfacetable_htmltablelinktarget$" description = "Specifies the windows or the frame where the [details] link will load the generated html page" } "--delta" = { value = "$interfacetable_delta$" description = "Set the delta used for interface throuput calculation" } "--ifs" = { value = "$interfacetable_ifs$" description = "Input field separator" } "--cache" = { value = "$interfacetable_cache$" description = "Define the retention time of the cached data" } "--noifloadgradient" = { set_if = "$interfacetable_noifloadgradient$" description = "Disable color gradient from green over yellow to red for the load percentage" } "--nohuman" = { set_if = "$interfacetable_nohuman$" description = "Do not translate bandwidth usage in human readable format" } "--snapshot" = { set_if = "$interfacetable_snapshot$" description = "Force the plugin to run like if it was the first launch" } "--timeout" = { value = "$interfacetable_timeout$" description = "Define the global timeout limit of the plugin" } "--css" = { value = "$interfacetable_css$" description = "Define the css stylesheet used by the generated html files" } "--config" = { value = "$interfacetable_config$" description = "Specify a config file to load" } "--noconfigtable" = { set_if = "$interfacetable_noconfigtable$" description = "Disable configuration table on the generated HTML page" } "--notips" = { set_if = "$interfacetable_notips$" description = "Disable the tips in the generated html tables" } "--default-table-sorting" = { value = "$interfacetable_defaulttablesorting$" description = "Default table sorting" } "--table-split" = { set_if = "$interfacetable_tablesplit$" description = "Generate multiple interface tables, one per interface type" } "--notype" = { set_if = "$interfacetable_notype$" description = "Remove the interface type for each interface" } } vars.interfacetable_hostquery = "$address$" vars.interfacetable_hostdisplay = "$host.display_name$" vars.interfacetable_perfdataservicedesc = "$service.name$" vars.interfacetable_regex = false vars.interfacetable_outputshort = false vars.interfacetable_aliasmatching = false vars.interfacetable_pkt = false vars.interfacetable_trafficwithpkt = false vars.interfacetable_snmpv2 = false vars.interfacetable_64bits = false vars.interfacetable_unixsnmp = false vars.interfacetable_enableperfdata = false vars.interfacetable_duplex = false vars.interfacetable_stp = false vars.interfacetable_vlan = false vars.interfacetable_noipinfo = false vars.interfacetable_noifloadgradient = false vars.interfacetable_nohuman = false vars.interfacetable_snapshot = false vars.interfacetable_noconfigtable = false vars.interfacetable_notips = false vars.interfacetable_notype = false } object CheckCommand "iftraffic" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_iftraffic.pl"] arguments = { "-H" = { value = "$iftraffic_address$" description = "Check interface on the indicated host." required = true } "-C" = { value = "$iftraffic_community$" description = "SNMP community. Defaults to 'public' if omitted." } "-i" = { value = "$iftraffic_interface$" description = "Interface name." required = true } "-b" = { value = "$iftraffic_bandwidth$" description = "Interface maximum speed in kilo/mega/giga/bits per second." required = true } "-u" = { value = "$iftraffic_units$" description = "g=gigabits/s,m=megabits/s,k=kilobits/s,b=bits/s." } "-w" = { value = "$iftraffic_warn$" description = "% of bandwidth usage necessary to result in warning status (default: 85)" } "-c" = { value = "$iftraffic_crit$" description = "% of bandwidth usage necessary to result in critical status (default: 98)" } "-M" = { value = "$iftraffic_max_counter$" description = "Max counter value of net devices in kilo/mega/giga/bytes." } } vars.iftraffic_address = "$check_address$" vars.iftraffic_warn = "85" vars.iftraffic_crit = "98" } object CheckCommand "iftraffic64" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_iftraffic64.pl"] arguments = { "-H" = { value = "$iftraffic64_address$" description = "Check interface on the indicated host." required = true } "-C" = { value = "$iftraffic64_community$" description = "SNMP community. Defaults to 'public' if omitted." } "-i" = { value = "$iftraffic64_interface$" description = "Interface name." required = true } "-b" = { value = "$iftraffic64_bandwidth$" description = "Interface maximum speed in kilo/mega/giga/bits per second." required = true } "-u" = { value = "$iftraffic64_units$" description = "g=gigabits/s,m=megabits/s,k=kilobits/s,b=bits/s." } "-w" = { value = "$iftraffic64_warn$" description = "% of bandwidth usage necessary to result in warning status (default: 85)" } "-c" = { value = "$iftraffic64_crit$" description = "% of bandwidth usage necessary to result in critical status (default: 98)" } "-M" = { value = "$iftraffic64_max_counter$" description = "Max counter value of net devices in kilo/mega/giga/bytes." } } vars.iftraffic64_address = "$check_address$" vars.iftraffic64_warn = "85" vars.iftraffic64_crit = "98" } object CheckCommand "interfaces" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_interfaces" ] arguments = { "--hostname" = "$interfaces_address$" "--community" = { value = "$interfaces_community$" description = "The community string (default public)." } "--regex" = { value = "$interfaces_regex$" description = "Interface list regexp." } "--exclude-regex" = { value = "$interfaces_exclude_regex$" description = "Interface list negative regexp." } "--errors" = { value = "$interfaces_errors$" description = "Number of in errors (CRC errors for cisco) to consider a warning (default 50)." } "--out-errors" = { value = "$interface_out_errors$" description = "Number of out errors (collisions for cisco) to consider a warning (default same as in errors)." } "--perfdata" = { value = "$interfaces_perfdata$" } "--prefix" = { value = "$interfaces_prefix$" description = "Prefix interface names with this label." } "--lastcheck" = { value = "$interfaces_lastcheck$" description = "Last checktime (unixtime)." } "--bandwidth" = { value = "$interfaces_bandwidth$" description = "Bandwidth warn level in percent." } "--speed" = { value = "$interfaces_speed$" description = "Override speed detection with this value (bits per sec)." } "--trim" = { value = "$interfaces_trim$" description = "Cut this number of characters from the start of interface descriptions." } "--mode" = { value = "$interfaces_mode$" description = "Special operating mode (default,cisco,nonbulk,bintec)." } "--auth-proto" = { value = "$interfaces_auth_proto$" description = "SNMPv3 Auth Protocol (SHA|MD5)" } "--auth-phrase" = { value = "$interfaces_auth_phrase$" description = "SNMPv3 Auth Phrase" } "--priv-proto" = { value = "$interfaces_priv_proto$" description = "SNMPv3 Privacy Protocol (AES|DES)" } "--priv-phrase" = { value = "$interfaces_priv_phrase$" description = "SNMPv3 Privacy Phrase" } "--user" = { value = "$interfaces_user$" description = "SNMPv3 User" } "--down-is-ok" = { set_if = "$interfaces_down_is_ok$" description = "Disables critical alerts for down interfaces." } "--aliases" = { set_if = "$interfaces_aliases$" description = "Retrieves the interface description." } "--match-aliases" = { set_if = "$interfaces_match_aliases$" description = "Also match against aliases (Option --aliases automatically enabled)." } "--timeout" = { value = "$interfaces_timeout$" description = "Sets the SNMP timeout (in ms)." } "--sleep" = { value = "$interfaces_sleep$" description = "Sleep between every SNMP query (in ms)." } "--if-names" = { set_if = "$interfaces_names$" description = "Use ifName instead of ifDescr." } } vars.interfaces_address = "$check_address$" vars.interfaces_down_is_ok = false vars.interfaces_aliases = false vars.interfaces_match_aliases = false } object CheckCommand "nwc_health" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_nwc_health" ] arguments = { "--timeout" = { value = "$nwc_health_timeout$" description = "Seconds before plugin times out (default: 15)" } "--blacklist" = { value = "$nwc_health_blacklist$" description = "Blacklist some (missing/failed) components" } "--hostname" = { value = "$nwc_health_hostname$" description = "Hostname or IP-address of the switch or router" } "--port" = { value = "$nwc_health_port$" description = "The SNMP port to use (default: 161)" } "--domain" = { value = "$nwc_health_domain$" description = "The transport domain to use (default: udp/ipv4, other possible values: udp6, udp/ipv6, tcp, tcp4, tcp/ipv4, tcp6, tcp/ipv6)" } "--protocol" = { value = "$nwc_health_protocol$" description = "The SNMP protocol to use (default: 2c, other possibilities: 1,3)" } "--community" = { value = "$nwc_health_community$" description = "SNMP community of the server (SNMP v1/2 only)" } "--username" = { value = "$nwc_health_username$" description = "The securityName for the USM security model (SNMPv3 only)" } "--authpassword" = { value = "$nwc_health_authpassword$" description = "The authentication password for SNMPv3" } "--authprotocol" = { value = "$nwc_health_authprotocol$" description = "The authentication protocol for SNMPv3 (md5|sha)" } "--privpassword" = { value = "$nwc_health_privpassword$" description = "The password for authPriv security level" } "--privprotocol" = { value = "$nwc_health_privprotocol$" description = "The private protocol for SNMPv3 (des|aes|aes128|3des|3desde)" } "--contextengineid" = { value = "$nwc_health_contextengineid$" description = "The context engine id for SNMPv3 (10 to 64 hex characters)" } "--contextname" = { value = "$nwc_health_contextname$" description = "The context name for SNMPv3 (empty represents the default context)" } "--mode" = { value = "$nwc_health_mode$" description = "Which mode should be executed. A list of all available modes can be found in the plugin documentation" } "--name" = { value = "$nwc_health_name$" description = "The name of an interface (ifDescr)" } "--drecksptkdb" = { value = "$nwc_health_drecksptkdb$" description = "This parameter must be used instead of --name, because Devel::ptkdb is stealing the latter from the command line" } "--alias" = { value = "$nwc_health_alias$" description = "The alias name of a 64bit-interface (ifAlias)" } "--regexp" = { set_if = "$nwc_health_regexp$" description = "A flag indicating that --name is a regular expression" } "--ifspeedin" = { value = "$nwc_health_ifspeedin$" description = "Override the ifspeed oid of an interface (only inbound)" } "--ifspeedout" = { value = "$nwc_health_ifspeedout$" description = "Override the ifspeed oid of an interface (only outbound)" } "--ifspeed" = { value = "$nwc_health_ifspeed$" description = "Override the ifspeed oid of an interface" } "--units" = { value = "$nwc_health_units$" description = "One of %, B, KB, MB, GB, Bit, KBi, MBi, GBi. (used for e.g. mode interface-usage)" } "--name2" = { value = "$nwc_health_name2$" description = "The secondary name of a component" } "--role" = { value = "$nwc_health_role$" description = "The role of this device in a hsrp group (active/standby/listen)" } "--report" = { value = "$nwc_health_report$" description = "Can be used to shorten the output. Possible values are: 'long' (default), 'short' (to shorten if available), or 'html' (to produce some html outputs if available)" } "--lookback" = { value = "$nwc_health_lookback$" description = "The amount of time you want to look back when calculating average rates. Use it for mode interface-errors or interface-usage. Without --lookback the time between two runs of check_nwc_health is the base for calculations. If you want your checkresult to be based for example on the past hour, use --lookback 3600." } "--critical" = { value = "$nwc_health_critical$" description = "The critical threshold" } "--warning" = { value = "$nwc_health_warning$" description = "The warning threshold" } "--warningx" = { value = "$nwc_health_warningx$" description = "The extended warning thresholds" } "--criticalx" = { value = "$nwc_health_criticalx$" description = "The extended critical thresholds" } "--mitigation" = { value = "$nwc_health_mitigation$" description = "The parameter allows you to change a critical error to a warning." } "--selectedperfdata" = { value = "$nwc_health_selectedperfdata$" description = "The parameter allows you to limit the list of performance data. It's a perl regexp. Only matching perfdata show up in the output." } "--morphperfdata" = { value = "$nwc_health_morphperfdata$" description = "The parameter allows you to change performance data labels. It's a perl regexp and a substitution. --morphperfdata '(.*)ISATAP(.*)'='$1patasi$2'" } "--negate" = { value = "$nwc_health_negate$" description = "The parameter allows you to map exit levels, such as warning=critical" } "--with-mymodules-dyn-dir" = { value = "$nwc_health_mymodules-dyn-dir$" description = "A directory where own extensions can be found" } "--servertype" = { value = "$nwc_health_servertype$" description = "The type of the network device: cisco (default). Use it if auto-detection is not possible" } "--statefilesdir" = { value = "$nwc_health_statefilesdir$" description = "An alternate directory where the plugin can save files" } "--oids" = { value = "$nwc_health_oids$" description = "A list of oids which are downloaded and written to a cache file. Use it together with --mode oidcache" } "--offline" = { value = "$nwc_health_offline$" description = "The maximum number of seconds since the last update of cache file before it is considered too old" } "--multiline" = { set_if = "$nwc_health_multiline$" description = "Multiline output" } } vars.nwc_health_hostname = "$check_address$" vars.nwc_health_mode = "hardware-health" } icinga2-2.8.1/itl/plugins-contrib.d/network-services.conf000066400000000000000000000054271322762156600233720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "kdc" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_kdc" ] arguments = { "-H" = { value = "$kdc_address$" description = "Name or IP address of KDC to check." } "-P" = { value = "$kdc_port$" description = "Port on which KDC runs (default 88)." } "-p" = { value = "$kdc_principal$" description = "Principal name to authenticate as (including realm)." required = true } "-k" = { value = "$kdc_keytab$" description = "Keytab file containing principal's key." required = true } } vars.kdc_address = "$check_address$" } object CheckCommand "rbl" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_rbl" ] arguments = { "-H" = { value = "$rbl_hostname$" description = "Name or IP address of SMTP server to check." } "-s" = { value = "$rbl_server$" description = "List of RBL servers as an array." required = true repeat_key = true } "-w" = { value = "$rbl_warning$" description = "Number of blacklisting servers for a warning." } "-c" = { value = "$rbl_critical$" description = "Number of blacklisting servers for a critical." } "-t" = { value = "$rbl_timeout$" description = "Seconds before plugin times out (default: 15)." } } vars.rbl_hostname = "$check_address$" vars.rbl_timeout = 15 vars.rbl_warning = 1 vars.rbl_critical = 1 } icinga2-2.8.1/itl/plugins-contrib.d/operating-system.conf000066400000000000000000000141561322762156600233710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "mem" { command = [ PluginContribDir + "/check_mem.pl" ] arguments = { "-u" = { set_if = "$mem_used$" description = "Check USED memory" } "-f" = { set_if = "$mem_free$" description = "Check FREE memory" } "-C" = { set_if = "$mem_cache$" description = "Count OS caches as FREE memory" } "-w" = { value = "$mem_warning$" description = "Percent free/used when to warn" } "-c" = { value = "$mem_critical$" description = "Percent free/used when critical" } } vars.mem_used = false vars.mem_free = false vars.mem_cache = false } object CheckCommand "running_kernel" { command = {{ var use_sudo = macro("$running_kernel_use_sudo$") if (use_sudo == null && PlatformName == "Ubuntu") { use_sudo = true } var args if (use_sudo) { args = [ "sudo" ] } else { args = [] } args += [ PluginContribDir + "/check_running_kernel" ] return args }} } object CheckCommand "yum" { command = [ PluginContribDir + "/check_yum" ] arguments = { "--all-updates" = { set_if = "$yum_all_updates$" description = "Do not distinguish between security and non-security updates. This may be used if the YUM security plugin is absent." } "--warn-on-any-update" = { set_if = "$yum_warn_on_any_update$" description = "Warns if there are any (non-security) package updates available." } "--cache-only" = { set_if = "$yum_cache_only$" description = "Run entirely from cache and do not update the cache." } "--no-warn-on-lock" = { set_if = "$yum_no_warn_on_lock$" description = "Return OK instead of WARNING when YUM is locked." } "--no-warn-on-updates" = { set_if = "$yum_no_warn_on_updates$" description = "Return OK instead of WARNING even when updates are available." } "--enablerepo" = { value = "$yum_enablerepo$" description = "Explicitly enables a reposity when calling YUM. Can take a comma separated list of repositories." } "--disablerepo" = { value = "$yum_disablerepo$" description = "Explicitly disables a reposity when calling YUM. Can take a comma separated list of repositories." } "--installroot" = { value = "$yum_installroot$" description = "Specifies another installation root directory" } "--timeout" = { value = "$yum_timeout$" description = "Sets a timeout in seconds after which the plugin will exit (defaults to 55 seconds)." } } vars.yum_all_updates = false vars.yum_warn_on_any_update = false vars.yum_cache_only = false vars.yum_no_warn_on_lock = false vars.yum_no_warn_on_updates = false timeout = 5m } object CheckCommand "iostat" { command = [ PluginContribDir + "/check_iostat" ] arguments = { "-d" = { value = "$iostat_disk$" description = "Device to check without path. e.g. sda" } "-w" = { value ="$iostat_wtps$,$iostat_wread$,$iostat_wwrite$" description = "warning threshold for tps, KB_read/s and KB_written/s" } "-c" = { value ="$iostat_ctps$,$iostat_cread$,$iostat_cwrite$" description = "warning threshold for tps, KB_read/s and KB_written/s" } } vars.iostat_disk = "sda" vars.iostat_wtps = 100 vars.iostat_wread = 100 vars.iostat_wwrite = 100 vars.iostat_ctps = 200 vars.iostat_cread = 200 vars.iostat_cwrite = 200 } object CheckCommand "iostats" { command = [ PluginContribDir + "/check_iostats" ] arguments = { "-d" = { value = "$iostats_disk$" description = "Device to check without path. e.g. sda" } "-w" = { value ="$iostats_warning_tps$,$iostats_warning_read$,$iostats_warning_write$" description = "Sets the WARNING level for tps, KB_read/s and KB_written/s, respectively" } "-c" = { value ="$iostats_critical_tps$,$iostats_critical_read$,$iostats_critical_write$" description = "Sets the CRITICAL level for tps, KB_read/s and KB_written/s, respectively" } "-W" = { value ="$iostats_warning_wait$" description = "Sets the WARNING level for iowait" } "-C" = { value ="$iostats_critical_wait$" description = "Sets the CRITICAL level for iowait" } } vars.iostats_disk = "sda" vars.iostats_warning_tps = 3000 vars.iostats_warning_read = 50000 vars.iostats_warning_write = 10000 vars.iostats_warning_wait = 50 vars.iostats_critical_tps = 5000 vars.iostats_critical_read = 80000 vars.iostats_critical_write = 25000 vars.iostats_critical_wait = 80 } icinga2-2.8.1/itl/plugins-contrib.d/raid-controller.conf000066400000000000000000000020471322762156600231530ustar00rootroot00000000000000/* * Icinga2 CheckCommand definitions to monitor RAID controller from Adaptec and Broadcom using * the Adaptec RAID Monitoring Plugin and the LSI RAID Monitoring Plugin */ object CheckCommand "adaptec-raid" { import "plugin-check-command" command = [ PluginDir + "/check_adaptec_raid" ] arguments = { "-C" = { required = true value = "$adaptec_controller_number$" description = "Insert the controller number to be checked." } "-p" = { required = true value = "$arcconf_path$" description = "Insert the path to arcconf (e.g. /sbin/arcconf)." } } vars.arcconf_path = "/sbin/arcconf" } object CheckCommand "lsi-raid" { import "plugin-check-command" command = [ PluginDir + "/check_lsi_raid" ] arguments = { "-C" = { required = true value = "$lsi_controller_number$" description = "Insert the controller number to be checked." } "-p" = { required = true value = "$storcli_path$" description = "Insert the path to storcli (e.g. /usr/sbin/storcli)." } } vars.storcli_path = "/usr/sbin/storcli" } icinga2-2.8.1/itl/plugins-contrib.d/smart-attributes.conf000066400000000000000000000011761322762156600233670ustar00rootroot00000000000000/* * Icinga2 CheckCommand definition for the SMART Attributes Monitoring Plugin */ object CheckCommand "smart-attributes" { import "plugin-check-command" command = [ PluginDir + "/check_smart_attributes" ] arguments = { "-dbj" = { required = true value = "$smart_attributes_config_path$" description = "Path to the smart attributes config file (e.g. check_smartdb.json)" } "-d" = { required = true value = "$smart_attributes_device$" description = "Insert the device name (e.g. /dev/sda) to monitor" } } vars.smart_attributes_config_path = SysconfDir + "/icinga2/plugins-config/check_smartdb.json" } icinga2-2.8.1/itl/plugins-contrib.d/storage.conf000066400000000000000000000054121322762156600215160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "glusterfs" { command = [ "sudo", PluginDir + "/check_glusterfs" ] arguments = { "--perfdata" = { set_if = "$glusterfs_perfdata$" description = "Optional. Print perfdata of all or the specified volume." } "--warnonfailedheal" = { set_if = "$glusterfs_warnonfailedheal$" description = "Optional. Warn if the *heal-failed* log contains entries. The log can be cleared by restarting glusterd." } "--volume" = { value = "$glusterfs_volume$" description = "Optional. Only check the specified *VOLUME*. If --volume is not set, all volumes are checked." } "-w" = { value = "$glusterfs_disk_warning$" description = "Optional. Warn if disk usage is above *DISKWARN*. Defaults to 90 (percent)." } "-c" = { value = "$glusterfs_disk_critical$" description = "Optional. Return a critical error if disk usage is above *DISKCRIT*. Defaults to 95 (percent)." } "-W" = { value = "$glusterfs_inode_warning$" description = "Optional. Warn if inode usage is above *DISKWARN*. Defaults to 90 (percent)." } "-C" = { value = "$glusterfs_inode_critical$" description = "Optional. Return a critical error if inode usage is above *DISKCRIT*. Defaults to 95 (percent)." } } vars.glusterfs_disk_warning = 90 vars.glusterfs_disk_critical = 95 vars.glusterfs_inode_warning = 90 vars.glusterfs_inode_critical = 95 } icinga2-2.8.1/itl/plugins-contrib.d/virtualization.conf000066400000000000000000000064441322762156600231440ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "esxi_hardware" { command = [ PluginContribDir + "/check_esxi_hardware.py" ] arguments = { "-H" = { value = "$esxi_hardware_host$" description = "report on HOST" } "-U" = { value = "$esxi_hardware_user$" description = "user to connect as" } "-P" = { value = "$esxi_hardware_pass$" description = "password" } "-C" = { value = "$esxi_hardware_port$" description = "cim port" } "-V" = { value = "$esxi_hardware_vendor$" description = "Vendor code: auto, dell, hp, ibm, intel, or unknown" } "-I" = { value = "$esxi_hardware_html$" description = "generate html links for country XX" } "-i" = { value = "$esxi_hardware_ignore$" description = "comma-separated list of elements to ignore" } "-p" = { set_if = "$esxi_hardware_perfdata$" description = "collect performance data for pnp4nagios" } "--no-power" = { set_if = "$esxi_hardware_nopower$" description = "don't collect power performance data" } "--no-volts" = { set_if = "$esxi_hardware_novolts$" description = "don't collect voltage performance data" } "--no-current" = { set_if = "$esxi_hardware_nocurrent$" description = "don't collect current performance data" } "--no-temp" = { set_if = "$esxi_hardware_notemp$" description = "don't collect temperature performance data" } "--no-fan" = { set_if = "$esxi_hardware_nofan$" description = "don't collect fan performance data" } "--no-lcd" = { set_if = "$esxi_hardware_nolcd$" description = "don't collect lcd/display status data" } } vars.esxi_hardware_host = "$address$" vars.esxi_hardware_port = 5989 vars.esxi_hardware_perfdata = false vars.esxi_hardware_nopower = false vars.esxi_hardware_novolts = false vars.esxi_hardware_nocurrent = false vars.esxi_hardware_notemp = false vars.esxi_hardware_nofan = false vars.esxi_hardware_nolcd = false } icinga2-2.8.1/itl/plugins-contrib.d/vmware.conf000066400000000000000000000603751322762156600213640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ /** * main vmware-esx template */ template CheckCommand "vmware-esx-command" { command = [ PluginContribDir + "/check_vmware_esx" ] arguments = { "--ignore_unknown" = { set_if = "$vmware_ignoreunknown$" description = "Sometimes 3 (unknown) is returned from a component. But the check itself is ok. With this option the plugin will return OK (0) instead of UNKNOWN (3)." } "--ignore_warning" = { set_if = "$vmware_ignorewarning$" description = "Sometimes 2 (warning) is returned from a component. But the check itself is ok (from an operator view)." } "--timeout" = { value = "$vmware_timeout$" description = "Seconds before plugin times out (default: 90)." } "--trace" = { set_if = "$vmware_trace$" description = "Set verbosity level of vSphere API request/respond trace." } "--sessionfile" = { value = "$vmware_sessionfile$" description = "Vmware auth session file - no efect if $vmware_nosession$ var is true." } "--sessionfiledir" = { value = "$vmware_sessionfiledir$" description = "Vmware auth session file directory - no efect if $vmware_nosession$ var is true." } "--nosession" = { set_if = "$vmware_nosession$" description = "No auth session - IT SHOULD BE USED FOR TESTING PURPOSES ONLY!." } "--username" = { value = "$vmware_username$" description = "Username to connect with." } "--password" = { value = "$vmware_password$" description = "Password to use with the username." } "--authfile" = { value = "$vmware_authfile$" description = "Autentication file content: \ username= \ password=" } } vars.vmware_timeout = "90" vars.vmware_ignorewarning = false vars.vmware_auth_nosession = false vars.vmware_sessionfiledir = "/var/spool/icinga2/tmp" } /** * VMware DC */ template CheckCommand "vmware-esx-dc" { import "vmware-esx-command" arguments += { "--datacenter" = { value = "$vmware_datacenter$" required = true description = "Datacenter/Vcenter hostname." } "--cluster" = { value = "$vmware_cluster$" required = false description = "ESX or ESXi clustername." } "--sslport" = { value = "$vmware_sslport$" description = "If a SSL port different from 443 is used." } } vars.vmware_sslport = "443" } object CheckCommand "vmware-esx-dc-volumes" { import "vmware-esx-dc" arguments += { "--select" = "volumes" "--subselect" = "$vmware_subselect$" "--gigabyte" = { set_if = "$vmware_gigabyte$" description = "Output in GB instead of MB." } "--usedspace" = { set_if = "$vmware_usedspace$" description = "Output used space instead of free." } "--alertonly" = { set_if = "$vmware_alertonly$" description = "List only alerting volumes." } "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_usedspace = true vars.vmware_alertonly = false vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-dc-runtime-info" { import "vmware-esx-dc" arguments += { "--select" = { value = "runtime" description = "Shows all runtime info for the datacenter/Vcenter." } } } object CheckCommand "vmware-esx-dc-runtime-listvms" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "listvms" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } "--alertonly" = { set_if = "$vmware_alertonly$" } } } object CheckCommand "vmware-esx-dc-runtime-listhost" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "listhost" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } "--alertonly" = { set_if = "$vmware_alertonly$" } } } object CheckCommand "vmware-esx-dc-runtime-listcluster" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "listcluster" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } "--alertonly" = { set_if = "$vmware_alertonly$" } } } object CheckCommand "vmware-esx-dc-runtime-issues" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "issues" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-dc-runtime-status" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "status" } } object CheckCommand "vmware-esx-dc-runtime-tools" { import "vmware-esx-dc" arguments += { "--select" = "runtime" "--subselect" = "tools" "--poweredonly" = { set_if = "$vmware_poweredonly$" } "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } "--alertonly" = { set_if = "$vmware_alertonly$" } "--open-vm-tools" = { set_if = "$vmware_openvmtools$" } } } /** * VMware HOST */ template CheckCommand "vmware-esx-soap-host" { import "vmware-esx-command" arguments += { "--host" = { value = "$vmware_host$" required = true description = "ESX or ESXi hostname." } "--datacenter" = { value = "$vmware_datacenter$" required = false description = "Datacenter/Vcenter hostname." } "--sslport" = { value = "$vmware_sslport$" description = "If a SSL port different from 443 is used." } } vars.vmware_host = "$address$" vars.vmware_sslport = "443" } object CheckCommand "vmware-esx-soap-host-check" { import "vmware-esx-soap-host" arguments += { "--select" = { value = "soap" description = "Simple check to verify a successfull connection to VMWare SOAP API." } } } object CheckCommand "vmware-esx-soap-host-uptime" { import "vmware-esx-soap-host" arguments += { "--select" = "uptime" } } object CheckCommand "vmware-esx-soap-host-cpu" { import "vmware-esx-soap-host" arguments += { "--select" = "cpu" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-host-cpu-ready" { import "vmware-esx-soap-host" arguments += { "--select" = "cpu" "--subselect" = "ready" } } object CheckCommand "vmware-esx-soap-host-cpu-wait" { import "vmware-esx-soap-host" arguments += { "--select" = "cpu" "--subselect" = "wait" } } object CheckCommand "vmware-esx-soap-host-cpu-usage" { import "vmware-esx-soap-host" arguments += { "--select" = "cpu" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-host-mem" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" } } object CheckCommand "vmware-esx-soap-host-mem-usage" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-host-mem-consumed" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" "--subselect" = "consumed" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-mem-swapused" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" "--subselect" = "swapused" "--multiline" = { set_if = "$vmware_multiline$" } "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-mem-overhead" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" "--subselect" = "overhead" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-mem-memctl" { import "vmware-esx-soap-host" arguments += { "--select" = "mem" "--subselect" = "memctl" "--multiline" = { set_if = "$vmware_multiline$" } "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-net" { import "vmware-esx-soap-host" arguments += { "--select" = "net" "--exclude" = "$vmware_exclude$" "--isregexp" = { set_if = "$vmware_isregexp$" } } } object CheckCommand "vmware-esx-soap-host-net-usage" { import "vmware-esx-soap-host" arguments += { "--select" = "net" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-net-receive" { import "vmware-esx-soap-host" arguments += { "--select" = "net" "--subselect" = "receive" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-net-send" { import "vmware-esx-soap-host" arguments += { "--select" = "net" "--subselect" = "send" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-net-nic" { import "vmware-esx-soap-host" arguments += { "--select" = "net" "--subselect" = "nic" "--exclude" = "$vmware_exclude$" "--isregexp" = { set_if = "$vmware_isregexp$" } } } object CheckCommand "vmware-esx-soap-host-volumes" { import "vmware-esx-soap-host" arguments += { "--select" = "volumes" "--subselect" = "$vmware_subselect$" "--gigabyte" = { set_if = "$vmware_gigabyte$" description = "Output in GB instead of MB." } "--usedspace" = { set_if = "$vmware_usedspace$" description = "Output used space instead of free." } "--alertonly" = { set_if = "$vmware_alertonly$" description = "List only alerting volumes." } "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" "--spaceleft" = { set_if = "$vmware_spaceleft$" } } vars.vmware_usedspace = true vars.vmware_alertonly = false vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-host-io" { import "vmware-esx-soap-host" arguments += { "--select" = "io" } } object CheckCommand "vmware-esx-soap-host-io-aborted" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "aborted" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-resets" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "resets" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-read" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "read" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-read-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "read_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-write" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "write" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-write-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "write_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-usage" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-kernel-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "kernel_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-device-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "device_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-queue-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "queue_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-io-total-latency" { import "vmware-esx-soap-host" arguments += { "--select" = "io" "--subselect" = "total_latency" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-host-media" { import "vmware-esx-soap-host" arguments += { "--select" = "hostmedia" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-service" { import "vmware-esx-soap-host" arguments += { "--select" = "service" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-runtime" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" } } object CheckCommand "vmware-esx-soap-host-runtime-con" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "con" } } object CheckCommand "vmware-esx-soap-host-runtime-listvms" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "listvms" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-runtime-status" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "status" } } object CheckCommand "vmware-esx-soap-host-runtime-health" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "health" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } } } object CheckCommand "vmware-esx-soap-host-runtime-health-listsensors" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "health" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--listsensors" = {} } } object CheckCommand "vmware-esx-soap-host-runtime-health-nostoragestatus" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "health" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--nostoragestatus" = {} } } object CheckCommand "vmware-esx-soap-host-runtime-storagehealth" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "storagehealth" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-runtime-temp" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "temp" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-runtime-issues" { import "vmware-esx-soap-host" arguments += { "--select" = "runtime" "--subselect" = "issues" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-storage" { import "vmware-esx-soap-host" arguments += { "--select" = "storage" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } } } object CheckCommand "vmware-esx-soap-host-storage-adapter" { import "vmware-esx-soap-host" arguments += { "--select" = "storage" "--subselect" = "adapter" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-storage-lun" { import "vmware-esx-soap-host" arguments += { "--select" = "storage" "--subselect" = "lun" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--alertonly" = { set_if = "$vmware_alertonly$" } "--multiline" = { set_if = "$vmware_multiline$" } } } object CheckCommand "vmware-esx-soap-host-storage-path" { import "vmware-esx-soap-host" arguments += { "--select" = "storage" "--subselect" = "path" "--exclude" = "$vmware_exclude$" "--include" = "$vmware_include$" "--isregexp" = { set_if = "$vmware_isregexp$" } "--alertonly" = { set_if = "$vmware_alertonly$" } "--multiline" = { set_if = "$vmware_multiline$" } "--standbyok" = { set_if = "$vmware_standbyok$" } } } /** * VMware VM */ template CheckCommand "vmware-esx-soap-vm" { import "vmware-esx-command" arguments += { "--datacenter" = { value = "$vmware_datacenter$" description = "Datacenter/Vcenter hostname." } "--host" = { value = "$vmware_host$" description = "ESX or ESXi hostname." } "--name" = { value = "$vmware_vmname$" required = true description = "Virtual machine name." } "--sslport" = { value = "$vmware_sslport$" description = "If a SSL port different from 443 is used." } } vars.vmware_host = "$address$" vars.vmware_sslport = "443" } object CheckCommand "vmware-esx-soap-vm-cpu" { import "vmware-esx-soap-vm" arguments += { "--select" = "cpu" } } object CheckCommand "vmware-esx-soap-vm-cpu-ready" { import "vmware-esx-soap-vm" arguments += { "--select" = "cpu" "--subselect" = "ready" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-cpu-wait" { import "vmware-esx-soap-vm" arguments += { "--select" = "cpu" "--subselect" = "wait" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-cpu-usage" { import "vmware-esx-soap-vm" arguments += { "--select" = "cpu" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-vm-mem" { import "vmware-esx-soap-vm" arguments += { "--select" = "mem" } } object CheckCommand "vmware-esx-soap-vm-mem-usage" { import "vmware-esx-soap-vm" arguments += { "--select" = "mem" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } vars.vmware_warn = "80%" vars.vmware_crit = "90%" } object CheckCommand "vmware-esx-soap-vm-mem-consumed" { import "vmware-esx-soap-vm" arguments += { "--select" = "mem" "--subselect" = "consumed" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-mem-memctl" { import "vmware-esx-soap-vm" arguments += { "--select" = "mem" "--subselect" = "memctl" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-net" { import "vmware-esx-soap-vm" arguments += { "--select" = "net" } } object CheckCommand "vmware-esx-soap-vm-net-usage" { import "vmware-esx-soap-vm" arguments += { "--select" = "net" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-net-receive" { import "vmware-esx-soap-vm" arguments += { "--select" = "net" "--subselect" = "receive" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-net-send" { import "vmware-esx-soap-vm" arguments += { "--select" = "net" "--subselect" = "send" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-io" { import "vmware-esx-soap-vm" arguments += { "--select" = "io" } } object CheckCommand "vmware-esx-soap-vm-io-read" { import "vmware-esx-soap-vm" arguments += { "--select" = "io" "--subselect" = "read" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-io-write" { import "vmware-esx-soap-vm" arguments += { "--select" = "io" "--subselect" = "write" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-io-usage" { import "vmware-esx-soap-vm" arguments += { "--select" = "io" "--subselect" = "usage" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-runtime" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" } } object CheckCommand "vmware-esx-soap-vm-runtime-con" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "con" } } object CheckCommand "vmware-esx-soap-vm-runtime-powerstate" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "powerstate" } } object CheckCommand "vmware-esx-soap-vm-runtime-status" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "status" } } object CheckCommand "vmware-esx-soap-vm-runtime-consoleconnections" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "consoleconnections" "--warning" = "$vmware_warn$" "--critical" = "$vmware_crit$" } } object CheckCommand "vmware-esx-soap-vm-runtime-gueststate" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "gueststate" } } object CheckCommand "vmware-esx-soap-vm-runtime-tools" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "tools" "--open-vm-tools" = { set_if = "$vmware_openvmtools$" } } } object CheckCommand "vmware-esx-soap-vm-runtime-issues" { import "vmware-esx-soap-vm" arguments += { "--select" = "runtime" "--subselect" = "issues" "--multiline" = { set_if = "$vmware_multiline$" } } } icinga2-2.8.1/itl/plugins-contrib.d/web.conf000066400000000000000000000437731322762156600206430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ object CheckCommand "webinject" { command = [ PluginContribDir + "/check_webinject" ] arguments = { "-c" = { value = "$webinject_config_file$" description = "There is a configuration file named 'config.xml' that is used to store configuration settings for your project. You can use this to specify which test case files to run and to set some constants and settings to be used by WebInject." } "-o" = { value = "$webinject_output$" description = "This option is followed by a directory name or a prefix to prepended to the output files. This is used to specify the location for writing output files (http.log, results.html, and results.xml). If a directory name is supplied (use either an absolute or relative path and make sure to add the trailing slash), all output files are written to this directory. If the trailing slash is ommitted, it is assumed to a prefix and this will be prepended to the output files. You may also use a combination of a directory and prefix." } "-n" = { set_if = "$webinject_no_output$" description = "Suppresses all output to STDOUT except the results summary." } "-t" = { value = "$webinject_timeout$" description = "The value [given in seconds] will be compared to the global time elapsed to run all the tests. If the tests have all been successful, but have taken more time than the 'globaltimeout' value, a warning message is sent back to Icinga." } "-r" = { value = "$webinject_report_type$" description = "This setting is used to enable output formatting that is compatible for use with specific external programs. The available values you can set this to are: nagios, mrtg, external and standard" } "-s" = { value = "$webinject_key_value$" description = "key=value" } "testcase_file" = { value = "$webinject_testcase_file$" description = "When you launch WebInject in console mode, you can optionally supply an argument for a testcase file to run. It will look for this file in the directory that webinject.pl resides in. If no filename is passed from the command line, it will look in config.xml for testcasefile declarations. If no files are specified, it will look for a default file named 'testcases.xml' in the current [webinject] directory. If none of these are found, the engine will stop and give you an error." skip_key = true order = 1 } } } object CheckCommand "jmx4perl" { command = [ PluginContribDir + "/check_jmx4perl" ] arguments = { "-u" = { value = "$jmx4perl_url$" description = "URL to agent web application (e.g. http://server:8080/jolokia/)" } "--product" = { value = "$jmx4perl_product$" description = "Name of app server product (e.g. jboss)" } "--alias" = { value = "$jmx4perl_alias$" description = "Alias name for attribute (e.g. MEMORY_HEAP_USED)" } "-m" = { value = "$jmx4perl_mbean$" description = "MBean name (e.g. java.lang:type=Memory)" } "-a" = { value = "$jmx4perl_attribute$" description = "Attribute name (e.g. HeapMemoryUsage)" } "-o" = { value = "$jmx4perl_operation$" description = "Operation to execute" } "--value" = { value = "$jmx4perl_value$" description = "Shortcut for specifying mbean/attribute/path. Slashes within names must be escaped with backslash" } "--delta" = { value = "$jmx4perl_delta$" description = "Switches on incremental mode. Optional argument are seconds used for normalizing." } "-p" = { value = "$jmx4perl_path$" description = "Inner path for extracting a single value from a complex attribute or return value (e.g. used)" } "--target" = { value = "$jmx4perl_target$" description = "JSR-160 Service URL specifing the target server" } "--target-user" = { value = "$jmx4perl_target_user$" description = "Username to use for JSR-160 connection" } "--target-password" = { value = "$jmx4perl_target_password$" description = "Password to use for JSR-160 connection" } "--proxy" = { value = "$jmx4perl_proxy$" description = "Proxy to use" } "--user" = { value = "$jmx4perl_user$" description = "User for HTTP authentication" } "--password" = { value = "$jmx4perl_password$" description = "Password for HTTP authentication" } "-n" = { value = "$jmx4perl_name$" description = "Name to use for output. Optional, by default a standard value based on the MBean and attribute will be used" } "--method" = { value = "$jmx4perl_method$" description = "HTTP method to use. Either get or post" } "-b" = { value = "$jmx4perl_base$" description = "Base name, which when given, interprets critical and warning values as relative in the range 0 .. 100%. Must be given in the form mbean/attribute/path" } "--base-mbean" = { value = "$jmx4perl_base_mbean$" description = "Base MBean name, interprets critical and warning values as relative in the range 0 .. 100%. Requires a base-attribute, too" } "--base-attribute" = { value = "$jmx4perl_base_attribute$" description = "Base attribute for a relative check. Used together with base-mbean" } "--base-path" = { value = "$jmx4perl_base_path$" description = "Base path for relative checks, where this path is used on the base attribute's value" } "--unit" = { value = "$jmx4perl_unit$" description = "Unit of measurement of the data retreived. Recognized values are [B|KB|MN|GB|TB] for memory values and [us|ms|s|m|h|d] for time values" } "--null" = { value = "$jmx4perl_null$" description = "Value which should be used in case of a null return value of an operation or attribute. Is null by default" } "--string" = { set_if = "$jmx4perl_string$" description = "Force string comparison for critical and warning checks" } "--numeric" = { set_if = "$jmx4perl_numeric$" description = "Force numeric comparison for critical and warning checks" } "-c" = { value = "$jmx4perl_critical$" description = "Critical threshold for value" } "-w" = { value = "$jmx4perl_warning$" description = "Warning threshold for value" } "-l" = { value = "$jmx4perl_label$" description = "Label to be used for printing out the result of the check. Placeholders can be used." } "--perfdata" = { value = "$jmx4perl_perfdata$" description = "Whether performance data should be omitted, which are included by default." } "--unknown-is-critical" = { set_if = "$jmx4perl_unknown_is_critical$" description = "Map UNKNOWN errors to errors with a CRITICAL status" } "-t" = { value = "$jmx4perl_timeout$" description = "Seconds before plugin times out (default: 15)" } "--config" = { value = "$jmx4perl_config$" description = "Path to configuration file." } "--server" = { value = "$jmx4perl_server$" description = "Symbolic name of server url to use, which needs to be configured in the configuration file." } "--check" = { value = "$jmx4perl_check$" description = "Name of a check configuration as defined in the configuration file, use array if you need arguments." order = 1 repeat_key = false } } vars.jmx4perl_url = "http://$address$:8080/jolokia" vars.jmx4perl_string = false vars.jmx4perl_numeric = false vars.jmx4perl_unknown_is_critical = false } object CheckCommand "squid" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_squid" ] arguments = { "--host" = { value = "$squid_hostname$" description = "Name of the proxy to check (default: localhost)" } "--data" = { value = "$squid_data$" description = "Optional data to fetch (default: Connections) available data : Connections Cache Resources Memory FileDescriptors" } "--port" = { value = "$squid_port$" description = "Optional port number (default: 3128)" } "--user" = { value = "$squid_user$" description = "WWW user" } "--password" = { value = "$squid_password$" description = "WWW password" } "--warning" = { value = "$squid_warning$" description = "Warning threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format." } "--critical" = { value = "$squid_critical$" description = "Critical threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format." } "--squidclient" = { value = "$squid_client$" description = "Path of squidclient (default: /usr/bin/squidclient)" } "--timeout" = { value = "$squid_timeout$" description = "Seconds before plugin times out (default: 15)" } } vars.squid_hostname = "$check_address$" vars.squid_client = "/usr/bin/squidclient" } object CheckCommand "nginx_status" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_nginx_status.pl" ] arguments = { "--hostname" = { value = "$nginx_status_host_address$" description = "name or IP address of host to check" } "--port" = { value = "$nginx_status_port$" description = "the http port" } "--url" = { value = "$nginx_status_url$" description = "Specific URL to use, instead of the default 'http:///nginx_status'" } "--servername" = { value = "$nginx_status_servername$" description = "ServerName, use it if you specified an IP in -H to match the good Virtualhost in your target" } "--ssl" = { set_if = "$nginx_status_ssl$" description = "Wether we should use HTTPS instead of HTTP" } "--disable-sslverifyhostname" = { set_if = "$nginx_status_disable_sslverify$" description = "Disable SSL hostname verification" } "--user" = { value = "$nginx_status_user$" description = "Username for basic auth" } "--pass" = { value = "$nginx_status_pass$" description = "Password for basic auth" } "--realm" = { value = "$nginx_status_realm$" description = "Realm for basic auth" } "--maxreach" = { value = "$nginx_status_maxreach$" description = "Number of max processes reached (since last check) that should trigger an alert" } "--timeout" = { value = "$nginx_status_timeout$" description = "timeout in seconds" } "--warn" = { value = "$nginx_status_warn$" description = "number of active connections, ReqPerSec or ConnPerSec that will cause a WARNING" } "--critical" = { value = "$nginx_status_critical$" description = "number of active connections, ReqPerSec or ConnPerSec that will cause a CRITICAL" } } vars.nginx_status_host_address = "$check_address$" vars.nginx_status_ssl = false vars.nginx_status_disable_sslverify = false vars.nginx_status_warn = "10000,100,200" vars.nginx_status_critical = "20000,200,300" vars.nginx_status_timeout = 15 } object CheckCommand "apache-status" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_apache_status.pl" ] arguments = { "-H" = { value = "$apache_status_address$" description = "name or IP address of host to check" } "-p" = { value = "$apache_status_port$" description = "the http port" } "-s" = { set_if = "$apache_status_ssl$" description = "Wether we should use HTTPS instead of HTTP" } "-u" = { value = "$apache_status_uri$" description = "Specific URL to use, instead of the default 'http:///server-status'" } "-w" = { value = "$apache_status_warning$" description = "number of open slots, busy workers and idle workers that will cause a WARNING" } "-c" = { value = "$apache_status_critical$" description = "number of open slots, busy workers and idle workers that will cause a CRITICAL" } "-t" = { value = "$apache_status_timeout$" description = "timeout in seconds" } } vars.apache_status_address = "$check_address$" vars.apache_status_ssl = false } object CheckCommand "ssl_cert" { import "ipv4-or-ipv6" command = [ PluginContribDir + "/check_ssl_cert" ] arguments = { "-H" = { value = "$ssl_cert_address$" description = "The host's address" required = true } "-p" = { value = "$ssl_cert_port$" description = "TCP port number (default: 443)" } "-f" = { value = "$ssl_cert_file$" description = "Local file path (works with -H localhost only)" } "-w" = { value = "$ssl_cert_warn$" description = "Minimum number of days a certificate has to be valid" } "-c" = { value = "$ssl_cert_critical$" description = "Minimum number of days a certificate has to be valid to issue a critical status" } "-n" = { value = "$ssl_cert_cn$" description = "Pattern to match the CN of the certificate" } "--altnames" = { set_if = "$ssl_cert_altnames$" description = "Matches the pattern specified in -n with alternate" } "-i" = { value = "$ssl_cert_issuer$" description = "Pattern to match the issuer of the certificate" } "-o" = { value = "$ssl_cert_org$" description = "Pattern to match the organization of the certificate" } "-e" = { value = "$ssl_cert_email$" description = "Pattern to match the email address contained in the certificate" } "-N" = { set_if = "$ssl_cert_match_host$" description = "Match CN with the host name" } "--serial" = { value = "$ssl_cert_serial$" description = "Pattern to match the serial number" } "-A" = { set_if = "$ssl_cert_noauth$" description = "Ignore authority warnings (expiration only)" } "-s" = { set_if = "$ssl_cert_selfsigned$" description = "Allow self-signed certificate" } "--sni" = { value = "$ssl_cert_sni$" description = "Sets the TLS SNI (Server Name Indication) extension" } "-t" = { value = "$ssl_cert_timeout$" description = "Seconds before connection times out (default: 15)" } "-P" = { value = "$ssl_cert_protocol$" description = "Use the specific protocol {http|smtp|pop3|imap|ftp|xmpp|irc|ldap} (default: http)" } "-C" = { value = "$ssl_cert_clientssl_cert$" description = "Use client certificate to authenticate" } "--clientpass" = { value = "$ssl_cert_clientpass$" description = "Set passphrase for client certificate" } "-L" = { value = "$ssl_cert_ssllabs$" description = "SSL Labs assestment" } "--ignore-ssl-labs-cache" = { set_if = "$ssl_cert_ssllabs_nocache$" description = "Forces a new check by SSL Labs" } "-r" = { value = "$ssl_cert_rootssl_cert$" description = "Root certificate or directory to be used for certificate validation" } "--ssl2" = { set_if = {{ return macro("$ssl_cert_ssl_version$") == "ssl2" }} } "--ssl3" = { set_if = {{ return macro("$ssl_cert_ssl_version$") == "ssl3" }} } "--tls1" = { set_if = {{ return macro("$ssl_cert_ssl_version$") == "tls1" }} } "--tls1_1" = { set_if = {{ return macro("$ssl_cert_ssl_version$") == "tls1_1" }} } "--tls1_2" = { set_if = {{ return macro("$ssl_cert_ssl_version$") == "tls1_2" }} } "--no_ssl2" = { set_if = {{ var disable_versions = macro("$ssl_cert_disable_ssl_versions$") if (typeof(disable_versions) == String) { disable_versions = [ disable_versions ] } return "ssl2" in disable_versions }} } "--no_ssl3" = { set_if = {{ var disable_versions = macro("$ssl_cert_disable_ssl_versions$") if (typeof(disable_versions) == String) { disable_versions = [ disable_versions ] } return "ssl3" in disable_versions }} } "--no_tls1" = { set_if = {{ var disable_versions = macro("$ssl_cert_disable_ssl_versions$") if (typeof(disable_versions) == String) { disable_versions = [ disable_versions ] } return "tls1" in disable_versions }} } "--no_tls1_1" = { set_if = {{ var disable_versions = macro("$ssl_cert_disable_ssl_versions$") if (typeof(disable_versions) == String) { disable_versions = [ disable_versions ] } return "tls1_1" in disable_versions }} } "--no_tls1_2" = { set_if = {{ var disable_versions = macro("$ssl_cert_disable_ssl_versions$") if (typeof(disable_versions) == String) { disable_versions = [ disable_versions ] } return "tls1_2" in disable_versions }} } "--ecdsa" = { set_if = {{ return macro("$ssl_cert_cipher$") == "ecdsa" }} description = "Cipher selection: force ECDSA authentication" } "--rsa" = { set_if = {{ return macro("$ssl_cert_cipher$") == "rsa" }} description = "Cipher selection: force RSA authentication" } "--ignore-sig-alg" = { set_if = "$ssl_cert_ignore_signature$" description = "Do not check if the certificate was signed with SHA1 od MD5" } "--ignore-exp" = { set_if = "$ssl_cert_ignore_expiration$" description = "Ignore expiration date" } "--ignore-ocsp" = { set_if = "$ssl_cert_ignore_ocsp$" description = "Do not check revocation with OCSP" } } vars.ssl_cert_address = "$check_address$" vars.ssl_cert_port = 443 } icinga2-2.8.1/itl/windows-plugins000066400000000000000000000027121322762156600167360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ include "command-plugins-windows.conf" icinga2-2.8.1/lib/000077500000000000000000000000001322762156600136165ustar00rootroot00000000000000icinga2-2.8.1/lib/CMakeLists.txt000066400000000000000000000032161322762156600163600ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_subdirectory(base) add_subdirectory(cli) add_subdirectory(config) add_subdirectory(remote) add_subdirectory(icinga) add_subdirectory(methods) if(ICINGA2_WITH_HELLO) add_subdirectory(hello) endif() if(ICINGA2_WITH_CHECKER) add_subdirectory(checker) endif() if(ICINGA2_WITH_COMPAT) add_subdirectory(compat) endif() if(ICINGA2_WITH_MYSQL OR ICINGA2_WITH_PGSQL) add_subdirectory(db_ido) endif() if(ICINGA2_WITH_MYSQL) add_subdirectory(db_ido_mysql) endif() if(ICINGA2_WITH_PGSQL) add_subdirectory(db_ido_pgsql) endif() if(ICINGA2_WITH_DEMO) add_subdirectory(demo) endif() if(ICINGA2_WITH_LIVESTATUS) add_subdirectory(livestatus) endif() if(ICINGA2_WITH_NOTIFICATION) add_subdirectory(notification) endif() if(ICINGA2_WITH_PERFDATA) add_subdirectory(perfdata) endif() set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/base/000077500000000000000000000000001322762156600145305ustar00rootroot00000000000000icinga2-2.8.1/lib/base/CMakeLists.txt000066400000000000000000000103151322762156600172700ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(application.ti application.tcpp application.thpp) mkclass_target(configobject.ti configobject.tcpp configobject.thpp) mkclass_target(datetime.ti datetime.tcpp datetime.thpp) mkclass_target(filelogger.ti filelogger.tcpp filelogger.thpp) mkclass_target(function.ti function.tcpp function.thpp) mkclass_target(logger.ti logger.tcpp logger.thpp) mkclass_target(perfdatavalue.ti perfdatavalue.tcpp perfdatavalue.thpp) mkclass_target(streamlogger.ti streamlogger.tcpp streamlogger.thpp) mkclass_target(sysloglogger.ti sysloglogger.tcpp sysloglogger.thpp) set(base_SOURCES application.cpp application.thpp application-version.cpp array.cpp array-script.cpp boolean.cpp boolean-script.cpp base64.cpp console.cpp context.cpp convert.cpp datetime.cpp datetime.thpp datetime-script.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp configobject.cpp configobject.thpp configobject-script.cpp configtype.cpp configwriter.cpp dependencygraph.cpp exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp json-script.cpp loader.cpp logger.cpp logger.thpp math-script.cpp netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp objecttype.cpp primitivetype.cpp process.cpp ringbuffer.cpp scriptframe.cpp function.cpp function.thpp function-script.cpp functionwrapper.cpp perfdatavalue.cpp perfdatavalue.thpp scriptglobal.cpp scriptutils.cpp serializer.cpp socket.cpp socketevents.cpp socketevents-epoll.cpp socketevents-poll.cpp stacktrace.cpp statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp string-script.cpp sysloglogger.cpp sysloglogger.thpp tcpsocket.cpp threadpool.cpp timer.cpp tlsstream.cpp tlsutility.cpp type.cpp typetype-script.cpp unixsocket.cpp utility.cpp value.cpp value-operators.cpp workqueue.cpp ) set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/application-version.cpp PROPERTY EXCLUDE_UNITY_BUILD TRUE) if(ICINGA2_UNITY_BUILD) mkunity_target(base base base_SOURCES) endif() add_library(base SHARED ${base_SOURCES}) target_link_libraries(base ${CMAKE_DL_LIBS} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${YAJL_LIBRARIES} mmatch socketpair) if(HAVE_LIBEXECINFO) target_link_libraries(base execinfo) endif() include_directories(${icinga2_SOURCE_DIR}/third-party/execvpe) link_directories(${icinga2_BINARY_DIR}/third-party/execvpe) include_directories(${icinga2_SOURCE_DIR}/third-party/mmatch) link_directories(${icinga2_BINARY_DIR}/third-party/mmatch) include_directories(${icinga2_SOURCE_DIR}/third-party/socketpair) link_directories(${icinga2_BINARY_DIR}/third-party/socketpair) if(UNIX OR CYGWIN) target_link_libraries(base execvpe) endif() if(WIN32) target_link_libraries(base ws2_32 dbghelp shlwapi msi) endif() set_target_properties ( base PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_BASE_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/icinga2\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/icinga2/crash\")") install( TARGETS base RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS base LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/base/application-version.cpp000066400000000000000000000032351322762156600212250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" #include "icinga-version.h" #include "icinga-spec-version.h" using namespace icinga; String Application::GetAppVersion(void) { return VERSION; } String Application::GetAppSpecVersion(void) { return SPEC_VERSION; } icinga2-2.8.1/lib/base/application.cpp000066400000000000000000001076161322762156600175520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" #include "base/application.tcpp" #include "base/stacktrace.hpp" #include "base/timer.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/loader.hpp" #include "base/debug.hpp" #include "base/type.hpp" #include "base/convert.hpp" #include "base/scriptglobal.hpp" #include "base/process.hpp" #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #endif /* __linux__ */ #ifdef _WIN32 #include #endif /* _win32 */ using namespace icinga; REGISTER_TYPE(Application); boost::signals2::signal Application::OnReopenLogs; Application::Ptr Application::m_Instance = NULL; bool Application::m_ShuttingDown = false; bool Application::m_RequestRestart = false; bool Application::m_RequestReopenLogs = false; pid_t Application::m_ReloadProcess = 0; static bool l_Restarting = false; static bool l_InExceptionHandler = false; int Application::m_ArgC; char **Application::m_ArgV; double Application::m_StartTime; double Application::m_MainTime; bool Application::m_ScriptDebuggerEnabled = false; double Application::m_LastReloadFailed; /** * Constructor for the Application class. */ void Application::OnConfigLoaded(void) { m_PidFile = NULL; ASSERT(m_Instance == NULL); m_Instance = this; } /** * Destructor for the application class. */ void Application::Stop(bool runtimeRemoved) { m_ShuttingDown = true; #ifdef _WIN32 WSACleanup(); #endif /* _WIN32 */ // Getting a shutdown-signal when a restart is in progress usually // means that the restart succeeded and the new process wants to take // over. Write the PID of the new process to the pidfile before this // process exits to keep systemd happy. if (l_Restarting) { try { UpdatePidFile(GetPidPath(), m_ReloadProcess); } catch (const std::exception&) { /* abort restart */ Log(LogCritical, "Application", "Cannot update PID file. Aborting restart operation."); return; } Log(LogDebug, "Application") << "Keeping pid '" << m_ReloadProcess << "' open."; ClosePidFile(false); } else ClosePidFile(true); ObjectImpl::Stop(runtimeRemoved); } Application::~Application(void) { m_Instance = NULL; } void Application::Exit(int rc) { std::cout.flush(); std::cerr.flush(); for (const Logger::Ptr& logger : Logger::GetLoggers()) { logger->Flush(); } UninitializeBase(); #ifdef I2_DEBUG exit(rc); #else /* I2_DEBUG */ _exit(rc); // Yay, our static destructors are pretty much beyond repair at this point. #endif /* I2_DEBUG */ } void Application::InitializeBase(void) { #ifdef _WIN32 /* disable GUI-based error messages for LoadLibrary() */ SetErrorMode(SEM_FAILCRITICALERRORS); WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("WSAStartup") << errinfo_win32_error(WSAGetLastError())); } #else /* _WIN32 */ struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); #endif /* _WIN32 */ Loader::ExecuteDeferredInitializers(); /* make sure the thread pool gets initialized */ GetTP().Start(); Timer::Initialize(); } void Application::UninitializeBase(void) { Timer::Uninitialize(); GetTP().Stop(); } /** * Retrieves a pointer to the application singleton object. * * @returns The application object. */ Application::Ptr Application::GetInstance(void) { return m_Instance; } void Application::SetResourceLimits(void) { #ifdef __linux__ rlimit rl; # ifdef RLIMIT_NOFILE rlim_t fileLimit = GetRLimitFiles(); if (fileLimit != 0) { if (fileLimit < GetDefaultRLimitFiles()) { Log(LogWarning, "Application") << "The user-specified value for RLimitFiles cannot be smaller than the default value (" << GetDefaultRLimitFiles() << "). Using the default value instead."; fileLimit = GetDefaultRLimitFiles(); } rl.rlim_cur = fileLimit; rl.rlim_max = rl.rlim_cur; if (setrlimit(RLIMIT_NOFILE, &rl) < 0) Log(LogNotice, "Application", "Could not adjust resource limit for open file handles (RLIMIT_NOFILE)"); # else /* RLIMIT_NOFILE */ Log(LogNotice, "Application", "System does not support adjusting the resource limit for open file handles (RLIMIT_NOFILE)"); # endif /* RLIMIT_NOFILE */ } # ifdef RLIMIT_NPROC rlim_t processLimit = GetRLimitProcesses(); if (processLimit != 0) { if (processLimit < GetDefaultRLimitProcesses()) { Log(LogWarning, "Application") << "The user-specified value for RLimitProcesses cannot be smaller than the default value (" << GetDefaultRLimitProcesses() << "). Using the default value instead."; processLimit = GetDefaultRLimitProcesses(); } rl.rlim_cur = processLimit; rl.rlim_max = rl.rlim_cur; if (setrlimit(RLIMIT_NPROC, &rl) < 0) Log(LogNotice, "Application", "Could not adjust resource limit for number of processes (RLIMIT_NPROC)"); # else /* RLIMIT_NPROC */ Log(LogNotice, "Application", "System does not support adjusting the resource limit for number of processes (RLIMIT_NPROC)"); # endif /* RLIMIT_NPROC */ } # ifdef RLIMIT_STACK int argc = Application::GetArgC(); char **argv = Application::GetArgV(); bool set_stack_rlimit = true; for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "--no-stack-rlimit") == 0) { set_stack_rlimit = false; break; } } if (getrlimit(RLIMIT_STACK, &rl) < 0) { Log(LogWarning, "Application", "Could not determine resource limit for stack size (RLIMIT_STACK)"); rl.rlim_max = RLIM_INFINITY; } rlim_t stackLimit; stackLimit = GetRLimitStack(); if (stackLimit != 0) { if (stackLimit < GetDefaultRLimitStack()) { Log(LogWarning, "Application") << "The user-specified value for RLimitStack cannot be smaller than the default value (" << GetDefaultRLimitStack() << "). Using the default value instead."; stackLimit = GetDefaultRLimitStack(); } if (set_stack_rlimit) rl.rlim_cur = stackLimit; else rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_STACK, &rl) < 0) Log(LogNotice, "Application", "Could not adjust resource limit for stack size (RLIMIT_STACK)"); else if (set_stack_rlimit) { char **new_argv = static_cast(malloc(sizeof(char *) * (argc + 2))); if (!new_argv) { perror("malloc"); Exit(EXIT_FAILURE); } new_argv[0] = argv[0]; new_argv[1] = strdup("--no-stack-rlimit"); if (!new_argv[1]) { perror("strdup"); exit(1); } for (int i = 1; i < argc; i++) new_argv[i + 1] = argv[i]; new_argv[argc + 1] = NULL; (void) execvp(new_argv[0], new_argv); perror("execvp"); _exit(EXIT_FAILURE); } # else /* RLIMIT_STACK */ Log(LogNotice, "Application", "System does not support adjusting the resource limit for stack size (RLIMIT_STACK)"); # endif /* RLIMIT_STACK */ } #endif /* __linux__ */ } int Application::GetArgC(void) { return m_ArgC; } void Application::SetArgC(int argc) { m_ArgC = argc; } char **Application::GetArgV(void) { return m_ArgV; } void Application::SetArgV(char **argv) { m_ArgV = argv; } /** * Processes events for registered sockets and timers and calls whatever * handlers have been set up for these events. */ void Application::RunEventLoop(void) { Timer::Initialize(); double lastLoop = Utility::GetTime(); mainloop: while (!m_ShuttingDown && !m_RequestRestart) { /* Watches for changes to the system time. Adjusts timers if necessary. */ Utility::Sleep(2.5); if (m_RequestReopenLogs) { Log(LogNotice, "Application", "Reopening log files"); m_RequestReopenLogs = false; OnReopenLogs(); } double now = Utility::GetTime(); double timeDiff = lastLoop - now; if (std::fabs(timeDiff) > 15) { /* We made a significant jump in time. */ Log(LogInformation, "Application") << "We jumped " << (timeDiff < 0 ? "forward" : "backward") << " in time: " << std::fabs(timeDiff) << " seconds"; Timer::AdjustTimers(-timeDiff); } lastLoop = now; } if (m_RequestRestart) { m_RequestRestart = false; // we are now handling the request, once is enough // are we already restarting? ignore request if we already are if (l_Restarting) goto mainloop; l_Restarting = true; m_ReloadProcess = StartReloadProcess(); goto mainloop; } Log(LogInformation, "Application", "Shutting down..."); ConfigObject::StopObjects(); Application::GetInstance()->OnShutdown(); UninitializeBase(); } bool Application::IsShuttingDown(void) { return m_ShuttingDown; } void Application::OnShutdown(void) { /* Nothing to do here. */ } static void ReloadProcessCallbackInternal(const ProcessResult& pr) { if (pr.ExitStatus != 0) { Application::SetLastReloadFailed(Utility::GetTime()); Log(LogCritical, "Application", "Found error in config: reloading aborted"); } #ifdef _WIN32 else Application::Exit(7); /* keep this exit code in sync with icinga-app */ #endif /* _WIN32 */ } static void ReloadProcessCallback(const ProcessResult& pr) { l_Restarting = false; boost::thread t(boost::bind(&ReloadProcessCallbackInternal, pr)); t.detach(); } pid_t Application::StartReloadProcess(void) { Log(LogInformation, "Application", "Got reload command: Starting new instance."); // prepare arguments Array::Ptr args = new Array(); args->Add(GetExePath(m_ArgV[0])); for (int i=1; i < Application::GetArgC(); i++) { if (std::string(Application::GetArgV()[i]) != "--reload-internal") args->Add(Application::GetArgV()[i]); else i++; // the next parameter after --reload-internal is the pid, remove that too } #ifndef _WIN32 args->Add("--reload-internal"); args->Add(Convert::ToString(Utility::GetPid())); #else /* _WIN32 */ args->Add("--validate"); #endif /* _WIN32 */ Process::Ptr process = new Process(Process::PrepareCommand(args)); process->SetTimeout(300); process->Run(&ReloadProcessCallback); return process->GetPID(); } /** * Signals the application to shut down during the next * execution of the event loop. */ void Application::RequestShutdown(void) { Log(LogInformation, "Application", "Received request to shut down."); m_ShuttingDown = true; } /** * Signals the application to restart during the next * execution of the event loop. */ void Application::RequestRestart(void) { m_RequestRestart = true; } /** * Signals the application to reopen log files during the * next execution of the event loop. */ void Application::RequestReopenLogs(void) { m_RequestReopenLogs = true; } /** * Retrieves the full path of the executable. * * @param argv0 The first command-line argument. * @returns The path. */ String Application::GetExePath(const String& argv0) { String executablePath; #ifndef _WIN32 char buffer[MAXPATHLEN]; if (getcwd(buffer, sizeof(buffer)) == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("getcwd") << boost::errinfo_errno(errno)); } String workingDirectory = buffer; if (argv0[0] != '/') executablePath = workingDirectory + "/" + argv0; else executablePath = argv0; bool foundSlash = false; for (size_t i = 0; i < argv0.GetLength(); i++) { if (argv0[i] == '/') { foundSlash = true; break; } } if (!foundSlash) { const char *pathEnv = getenv("PATH"); if (pathEnv != NULL) { std::vector paths; boost::algorithm::split(paths, pathEnv, boost::is_any_of(":")); bool foundPath = false; for (const String& path : paths) { String pathTest = path + "/" + argv0; if (access(pathTest.CStr(), X_OK) == 0) { executablePath = pathTest; foundPath = true; break; } } if (!foundPath) { executablePath.Clear(); BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine executable path.")); } } } if (realpath(executablePath.CStr(), buffer) == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("realpath") << boost::errinfo_errno(errno) << boost::errinfo_file_name(executablePath)); } return buffer; #else /* _WIN32 */ char FullExePath[MAXPATHLEN]; if (!GetModuleFileName(NULL, FullExePath, sizeof(FullExePath))) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("GetModuleFileName") << errinfo_win32_error(GetLastError())); return FullExePath; #endif /* _WIN32 */ } /** * Display version and path information. */ void Application::DisplayInfoMessage(std::ostream& os, bool skipVersion) { os << "Application information:" << "\n"; if (!skipVersion) os << " Application version: " << GetAppVersion() << "\n"; os << " Installation root: " << GetPrefixDir() << "\n" << " Sysconf directory: " << GetSysconfDir() << "\n" << " Run directory: " << GetRunDir() << "\n" << " Local state directory: " << GetLocalStateDir() << "\n" << " Package data directory: " << GetPkgDataDir() << "\n" << " State path: " << GetStatePath() << "\n" << " Modified attributes path: " << GetModAttrPath() << "\n" << " Objects path: " << GetObjectsPath() << "\n" << " Vars path: " << GetVarsPath() << "\n" << " PID path: " << GetPidPath() << "\n"; os << "\n" << "System information:" << "\n" << " Platform: " << Utility::GetPlatformName() << "\n" << " Platform version: " << Utility::GetPlatformVersion() << "\n" << " Kernel: " << Utility::GetPlatformKernel() << "\n" << " Kernel version: " << Utility::GetPlatformKernelVersion() << "\n" << " Architecture: " << Utility::GetPlatformArchitecture() << "\n"; os << "\n" << "Build information:" << "\n" << " Compiler: " << ScriptGlobal::Get("BuildCompilerName") << " " << ScriptGlobal::Get("BuildCompilerVersion") << "\n" << " Build host: " << ScriptGlobal::Get("BuildHostName") << "\n"; } /** * Displays a message that tells users what to do when they encounter a bug. */ void Application::DisplayBugMessage(std::ostream& os) { os << "***" << "\n" << "* This would indicate a runtime problem or configuration error. If you believe this is a bug in Icinga 2" << "\n" << "* please submit a bug report at https://github.com/Icinga/icinga2 and include this stack trace as well as any other" << "\n" << "* information that might be useful in order to reproduce this problem." << "\n" << "***" << "\n"; } String Application::GetCrashReportFilename(void) { return GetLocalStateDir() + "/log/icinga2/crash/report." + Convert::ToString(Utility::GetTime()); } void Application::AttachDebugger(const String& filename, bool interactive) { #ifndef _WIN32 #ifdef __linux__ prctl(PR_SET_DUMPABLE, 1); #endif /* __linux __ */ String my_pid = Convert::ToString(Utility::GetPid()); pid_t pid = fork(); if (pid < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fork") << boost::errinfo_errno(errno)); } if (pid == 0) { if (!interactive) { int fd = open(filename.CStr(), O_CREAT | O_RDWR | O_APPEND, 0600); if (fd < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("open") << boost::errinfo_errno(errno) << boost::errinfo_file_name(filename)); } if (fd != 1) { /* redirect stdout to the file */ dup2(fd, 1); close(fd); } /* redirect stderr to stdout */ if (fd != 2) close(2); dup2(1, 2); } char **argv; char *my_pid_str = strdup(my_pid.CStr()); if (interactive) { const char *uargv[] = { "gdb", "-p", my_pid_str, NULL }; argv = const_cast(uargv); } else { const char *uargv[] = { "gdb", "--batch", "-p", my_pid_str, "-ex", "thread apply all bt full", "-ex", "detach", "-ex", "quit", NULL }; argv = const_cast(uargv); } (void)execvp(argv[0], argv); perror("Failed to launch GDB"); free(my_pid_str); _exit(0); } int status; if (waitpid(pid, &status, 0) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("waitpid") << boost::errinfo_errno(errno)); } #ifdef __linux__ prctl(PR_SET_DUMPABLE, 0); #endif /* __linux __ */ #else /* _WIN32 */ DebugBreak(); #endif /* _WIN32 */ } #ifndef _WIN32 /** * Signal handler for SIGINT and SIGTERM. Prepares the application for cleanly * shutting down during the next execution of the event loop. * * @param - The signal number. */ void Application::SigIntTermHandler(int signum) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigaction(signum, &sa, NULL); Application::Ptr instance = Application::GetInstance(); if (!instance) return; instance->RequestShutdown(); } #endif /* _WIN32 */ /** * Signal handler for SIGUSR1. This signal causes Icinga to re-open * its log files and is mainly for use by logrotate. * * @param - The signal number. */ void Application::SigUsr1Handler(int) { RequestReopenLogs(); } /** * Signal handler for SIGABRT. Helps with debugging ASSERT()s. * * @param - The signal number. */ void Application::SigAbrtHandler(int) { #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigaction(SIGABRT, &sa, NULL); #endif /* _WIN32 */ std::cerr << "Caught SIGABRT." << std::endl << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << std::endl << std::endl; String fname = GetCrashReportFilename(); String dirName = Utility::DirName(fname); if (!Utility::PathExists(dirName)) { #ifndef _WIN32 if (mkdir(dirName.CStr(), 0700) < 0 && errno != EEXIST) { #else /*_ WIN32 */ if (mkdir(dirName.CStr()) < 0 && errno != EEXIST) { #endif /* _WIN32 */ std::cerr << "Could not create directory '" << dirName << "': Error " << errno << ", " << strerror(errno) << "\n"; } } bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger")); if (!interactive_debugger) { std::ofstream ofs; ofs.open(fname.CStr()); Log(LogCritical, "Application") << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'" << "\n"; DisplayInfoMessage(ofs); StackTrace trace; ofs << "Stacktrace:" << "\n"; trace.Print(ofs, 1); DisplayBugMessage(ofs); ofs << "\n"; ofs.close(); } else { Log(LogCritical, "Application", "Icinga 2 has terminated unexpectedly. Attaching debugger..."); } AttachDebugger(fname, interactive_debugger); } #ifdef _WIN32 /** * Console control handler. Prepares the application for cleanly * shutting down during the next execution of the event loop. */ BOOL WINAPI Application::CtrlHandler(DWORD type) { Application::Ptr instance = Application::GetInstance(); if (!instance) return TRUE; instance->RequestShutdown(); SetConsoleCtrlHandler(NULL, FALSE); return TRUE; } bool Application::IsProcessElevated(void) { BOOL fIsElevated = FALSE; DWORD dwError = ERROR_SUCCESS; HANDLE hToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) dwError = GetLastError(); else { TOKEN_ELEVATION elevation; DWORD dwSize; if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) dwError = GetLastError(); else fIsElevated = elevation.TokenIsElevated; } if (hToken) { CloseHandle(hToken); hToken = NULL; } if (ERROR_SUCCESS != dwError) { LPSTR mBuf = NULL; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), mBuf, 0, NULL)) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to format error message, last error was: " + dwError)); else BOOST_THROW_EXCEPTION(std::runtime_error(mBuf)); } return fIsElevated; } #endif /* _WIN32 */ /** * Handler for unhandled exceptions. */ void Application::ExceptionHandler(void) { if (l_InExceptionHandler) for (;;) Utility::Sleep(5); l_InExceptionHandler = true; #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigaction(SIGABRT, &sa, NULL); #endif /* _WIN32 */ String fname = GetCrashReportFilename(); String dirName = Utility::DirName(fname); if (!Utility::PathExists(dirName)) { #ifndef _WIN32 if (mkdir(dirName.CStr(), 0700) < 0 && errno != EEXIST) { #else /*_ WIN32 */ if (mkdir(dirName.CStr()) < 0 && errno != EEXIST) { #endif /* _WIN32 */ std::cerr << "Could not create directory '" << dirName << "': Error " << errno << ", " << strerror(errno) << "\n"; } } bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger")); if (!interactive_debugger) { std::ofstream ofs; ofs.open(fname.CStr()); ofs << "Caught unhandled exception." << "\n" << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n" << "\n"; DisplayInfoMessage(ofs); try { RethrowUncaughtException(); } catch (const std::exception& ex) { Log(LogCritical, "Application") << DiagnosticInformation(ex, false) << "\n" << "\n" << "Additional information is available in '" << fname << "'" << "\n"; ofs << "\n" << DiagnosticInformation(ex) << "\n"; } DisplayBugMessage(ofs); ofs.close(); } AttachDebugger(fname, interactive_debugger); abort(); } #ifdef _WIN32 LONG CALLBACK Application::SEHUnhandledExceptionFilter(PEXCEPTION_POINTERS exi) { if (l_InExceptionHandler) return EXCEPTION_CONTINUE_SEARCH; l_InExceptionHandler = true; String fname = GetCrashReportFilename(); String dirName = Utility::DirName(fname); if (!Utility::PathExists(dirName)) { #ifndef _WIN32 if (mkdir(dirName.CStr(), 0700) < 0 && errno != EEXIST) { #else /*_ WIN32 */ if (mkdir(dirName.CStr()) < 0 && errno != EEXIST) { #endif /* _WIN32 */ std::cerr << "Could not create directory '" << dirName << "': Error " << errno << ", " << strerror(errno) << "\n"; } } std::ofstream ofs; ofs.open(fname.CStr()); Log(LogCritical, "Application") << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'"; DisplayInfoMessage(ofs); ofs << "Caught unhandled SEH exception." << "\n" << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n" << "\n"; StackTrace trace(exi); ofs << "Stacktrace:" << "\n"; trace.Print(ofs, 1); DisplayBugMessage(ofs); return EXCEPTION_CONTINUE_SEARCH; } #endif /* _WIN32 */ /** * Installs the exception handlers. */ void Application::InstallExceptionHandlers(void) { std::set_terminate(&Application::ExceptionHandler); #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = &Application::SigAbrtHandler; sigaction(SIGABRT, &sa, NULL); #else /* _WIN32 */ SetUnhandledExceptionFilter(&Application::SEHUnhandledExceptionFilter); #endif /* _WIN32 */ } /** * Runs the application. * * @returns The application's exit code. */ int Application::Run(void) { #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = &Application::SigIntTermHandler; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sa.sa_handler = &Application::SigUsr1Handler; sigaction(SIGUSR1, &sa, NULL); #else /* _WIN32 */ SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE); #endif /* _WIN32 */ try { UpdatePidFile(GetPidPath()); } catch (const std::exception&) { Log(LogCritical, "Application") << "Cannot update PID file '" << GetPidPath() << "'. Aborting."; return EXIT_FAILURE; } SetMainTime(Utility::GetTime()); return Main(); } /** * Grabs the PID file lock and updates the PID. Terminates the application * if the PID file is already locked by another instance of the application. * * @param filename The name of the PID file. * @param pid The PID to write; default is the current PID */ void Application::UpdatePidFile(const String& filename, pid_t pid) { ObjectLock olock(this); if (m_PidFile != NULL) fclose(m_PidFile); /* There's just no sane way of getting a file descriptor for a * C++ ofstream which is why we're using FILEs here. */ m_PidFile = fopen(filename.CStr(), "r+"); if (m_PidFile == NULL) m_PidFile = fopen(filename.CStr(), "w"); if (m_PidFile == NULL) { Log(LogCritical, "Application") << "Could not open PID file '" << filename << "'."; BOOST_THROW_EXCEPTION(std::runtime_error("Could not open PID file '" + filename + "'")); } #ifndef _WIN32 int fd = fileno(m_PidFile); Utility::SetCloExec(fd); struct flock lock; lock.l_start = 0; lock.l_len = 0; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; if (fcntl(fd, F_SETLK, &lock) < 0) { Log(LogCritical, "Application", "Could not lock PID file. Make sure that only one instance of the application is running."); Application::Exit(EXIT_FAILURE); } if (ftruncate(fd, 0) < 0) { Log(LogCritical, "Application") << "ftruncate() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("ftruncate") << boost::errinfo_errno(errno)); } #endif /* _WIN32 */ fprintf(m_PidFile, "%lu\n", (unsigned long)pid); fflush(m_PidFile); } /** * Closes the PID file. Does nothing if the PID file is not currently open. */ void Application::ClosePidFile(bool unlink) { ObjectLock olock(this); if (m_PidFile != NULL) { if (unlink) { String pidpath = GetPidPath(); ::unlink(pidpath.CStr()); } fclose(m_PidFile); } m_PidFile = NULL; } /** * Checks if another process currently owns the pidfile and read it * * @param filename The name of the PID file. * @returns 0: no process owning the pidfile, pid of the process otherwise */ pid_t Application::ReadPidFile(const String& filename) { FILE *pidfile = fopen(filename.CStr(), "r"); if (pidfile == NULL) return 0; #ifndef _WIN32 int fd = fileno(pidfile); struct flock lock; lock.l_start = 0; lock.l_len = 0; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; if (fcntl(fd, F_GETLK, &lock) < 0) { int error = errno; fclose(pidfile); BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fcntl") << boost::errinfo_errno(error)); } if (lock.l_type == F_UNLCK) { // nobody has locked the file: no icinga running fclose(pidfile); return -1; } #endif /* _WIN32 */ pid_t runningpid; int res = fscanf(pidfile, "%d", &runningpid); fclose(pidfile); // bogus result? if (res != 1) return 0; #ifdef _WIN32 HANDLE hProcess = OpenProcess(0, FALSE, runningpid); if (!hProcess) return 0; CloseHandle(hProcess); #endif /* _WIN32 */ return runningpid; } /** * Retrieves the path of the installation prefix. * * @returns The path. */ String Application::GetPrefixDir(void) { return ScriptGlobal::Get("PrefixDir"); } /** * Sets the path for the installation prefix. * * @param path The new path. */ void Application::DeclarePrefixDir(const String& path) { if (!ScriptGlobal::Exists("PrefixDir")) ScriptGlobal::Set("PrefixDir", path); } /** * Retrives the path of the sysconf dir. * * @returns The path. */ String Application::GetSysconfDir(void) { return ScriptGlobal::Get("SysconfDir"); } /** * Sets the path of the sysconf dir. * * @param path The new path. */ void Application::DeclareSysconfDir(const String& path) { if (!ScriptGlobal::Exists("SysconfDir")) ScriptGlobal::Set("SysconfDir", path); } /** * Retrieves the path for the run dir. * * @returns The path. */ String Application::GetRunDir(void) { return ScriptGlobal::Get("RunDir"); } /** * Sets the path of the run dir. * * @param path The new path. */ void Application::DeclareRunDir(const String& path) { if (!ScriptGlobal::Exists("RunDir")) ScriptGlobal::Set("RunDir", path); } /** * Retrieves the path for the local state dir. * * @returns The path. */ String Application::GetLocalStateDir(void) { return ScriptGlobal::Get("LocalStateDir"); } /** * Sets the path for the local state dir. * * @param path The new path. */ void Application::DeclareLocalStateDir(const String& path) { if (!ScriptGlobal::Exists("LocalStateDir")) ScriptGlobal::Set("LocalStateDir", path); } /** * Retrieves the path for the local state dir. * * @returns The path. */ String Application::GetZonesDir(void) { return ScriptGlobal::Get("ZonesDir", &Empty); } /** * Sets the path of the zones dir. * * @param path The new path. */ void Application::DeclareZonesDir(const String& path) { if (!ScriptGlobal::Exists("ZonesDir")) ScriptGlobal::Set("ZonesDir", path); } /** * Retrieves the path for the package data dir. * * @returns The path. */ String Application::GetPkgDataDir(void) { String defaultValue = ""; return ScriptGlobal::Get("PkgDataDir", &Empty); } /** * Sets the path for the package data dir. * * @param path The new path. */ void Application::DeclarePkgDataDir(const String& path) { if (!ScriptGlobal::Exists("PkgDataDir")) ScriptGlobal::Set("PkgDataDir", path); } /** * Retrieves the path for the include conf dir. * * @returns The path. */ String Application::GetIncludeConfDir(void) { return ScriptGlobal::Get("IncludeConfDir", &Empty); } /** * Sets the path for the package data dir. * * @param path The new path. */ void Application::DeclareIncludeConfDir(const String& path) { if (!ScriptGlobal::Exists("IncludeConfDir")) ScriptGlobal::Set("IncludeConfDir", path); } /** * Retrieves the path for the state file. * * @returns The path. */ String Application::GetStatePath(void) { return ScriptGlobal::Get("StatePath", &Empty); } /** * Sets the path for the state file. * * @param path The new path. */ void Application::DeclareStatePath(const String& path) { if (!ScriptGlobal::Exists("StatePath")) ScriptGlobal::Set("StatePath", path); } /** * Retrieves the path for the modified attributes file. * * @returns The path. */ String Application::GetModAttrPath(void) { return ScriptGlobal::Get("ModAttrPath", &Empty); } /** * Sets the path for the modified attributes file. * * @param path The new path. */ void Application::DeclareModAttrPath(const String& path) { if (!ScriptGlobal::Exists("ModAttrPath")) ScriptGlobal::Set("ModAttrPath", path); } /** * Retrieves the path for the objects file. * * @returns The path. */ String Application::GetObjectsPath(void) { return ScriptGlobal::Get("ObjectsPath", &Empty); } /** * Sets the path for the objects file. * * @param path The new path. */ void Application::DeclareObjectsPath(const String& path) { if (!ScriptGlobal::Exists("ObjectsPath")) ScriptGlobal::Set("ObjectsPath", path); } /** * Retrieves the path for the vars file. * * @returns The path. */ String Application::GetVarsPath(void) { return ScriptGlobal::Get("VarsPath", &Empty); } /** * Sets the path for the vars file. * * @param path The new path. */ void Application::DeclareVarsPath(const String& path) { if (!ScriptGlobal::Exists("VarsPath")) ScriptGlobal::Set("VarsPath", path); } /** * Retrieves the path for the PID file. * * @returns The path. */ String Application::GetPidPath(void) { return ScriptGlobal::Get("PidPath", &Empty); } /** * Sets the path for the PID file. * * @param path The new path. */ void Application::DeclarePidPath(const String& path) { if (!ScriptGlobal::Exists("PidPath")) ScriptGlobal::Set("PidPath", path); } /** * Retrieves the name of the user. * * @returns The name. */ String Application::GetRunAsUser(void) { return ScriptGlobal::Get("RunAsUser"); } /** * Sets the name of the user. * * @param path The new user name. */ void Application::DeclareRunAsUser(const String& user) { if (!ScriptGlobal::Exists("RunAsUser")) ScriptGlobal::Set("RunAsUser", user); } /** * Retrieves the name of the group. * * @returns The name. */ String Application::GetRunAsGroup(void) { return ScriptGlobal::Get("RunAsGroup"); } /** * Sets the name of the group. * * @param path The new group name. */ void Application::DeclareRunAsGroup(const String& group) { if (!ScriptGlobal::Exists("RunAsGroup")) ScriptGlobal::Set("RunAsGroup", group); } /** * Retrieves the file rlimit. * * @returns The limit. */ int Application::GetRLimitFiles(void) { return ScriptGlobal::Get("RLimitFiles"); } int Application::GetDefaultRLimitFiles(void) { return 16 * 1024; } /** * Sets the file rlimit. * * @param path The new file rlimit. */ void Application::DeclareRLimitFiles(int limit) { if (!ScriptGlobal::Exists("RLimitFiles")) ScriptGlobal::Set("RLimitFiles", limit); } /** * Retrieves the process rlimit. * * @returns The limit. */ int Application::GetRLimitProcesses(void) { return ScriptGlobal::Get("RLimitProcesses"); } int Application::GetDefaultRLimitProcesses(void) { return 16 * 1024; } /** * Sets the process rlimit. * * @param path The new process rlimit. */ void Application::DeclareRLimitProcesses(int limit) { if (!ScriptGlobal::Exists("RLimitProcesses")) ScriptGlobal::Set("RLimitProcesses", limit); } /** * Retrieves the stack rlimit. * * @returns The limit. */ int Application::GetRLimitStack(void) { return ScriptGlobal::Get("RLimitStack"); } int Application::GetDefaultRLimitStack(void) { return 256 * 1024; } /** * Sets the stack rlimit. * * @param path The new stack rlimit. */ void Application::DeclareRLimitStack(int limit) { if (!ScriptGlobal::Exists("RLimitStack")) ScriptGlobal::Set("RLimitStack", limit); } /** * Sets the concurrency level. * * @param path The new concurrency level. */ void Application::DeclareConcurrency(int ncpus) { if (!ScriptGlobal::Exists("Concurrency")) ScriptGlobal::Set("Concurrency", ncpus); } /** * Retrieves the concurrency level. * * @returns The concurrency level. */ int Application::GetConcurrency(void) { Value defaultConcurrency = boost::thread::hardware_concurrency(); return ScriptGlobal::Get("Concurrency", &defaultConcurrency); } /** * Returns the global thread pool. * * @returns The global thread pool. */ ThreadPool& Application::GetTP(void) { static ThreadPool tp; return tp; } double Application::GetStartTime(void) { return m_StartTime; } void Application::SetStartTime(double ts) { m_StartTime = ts; } double Application::GetMainTime(void) { return m_MainTime; } void Application::SetMainTime(double ts) { m_MainTime = ts; } bool Application::GetScriptDebuggerEnabled(void) { return m_ScriptDebuggerEnabled; } void Application::SetScriptDebuggerEnabled(bool enabled) { m_ScriptDebuggerEnabled = enabled; } double Application::GetLastReloadFailed(void) { return m_LastReloadFailed; } void Application::SetLastReloadFailed(double ts) { m_LastReloadFailed = ts; } void Application::ValidateName(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateName(value, utils); if (value != "app") BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("name"), "Application object must be named 'app'.")); } icinga2-2.8.1/lib/base/application.hpp000066400000000000000000000153641322762156600175550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APPLICATION_H #define APPLICATION_H #include "base/i2-base.hpp" #include "base/application.thpp" #include "base/threadpool.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include namespace icinga { /** * Abstract base class for applications. * * @ingroup base */ class I2_BASE_API Application : public ObjectImpl { public: DECLARE_OBJECT(Application); static boost::signals2::signal OnReopenLogs; ~Application(void); static void InitializeBase(void); static void UninitializeBase(void); static Application::Ptr GetInstance(void); static void Exit(int rc); int Run(void); /** * Starts the application. * * @returns The exit code of the application. */ virtual int Main(void) = 0; static void SetResourceLimits(void); static int GetArgC(void); static void SetArgC(int argc); static char **GetArgV(void); static void SetArgV(char **argv); static void InstallExceptionHandlers(void); static void RequestShutdown(void); static void RequestRestart(void); static void RequestReopenLogs(void); static bool IsShuttingDown(void); static void SetDebuggingSeverity(LogSeverity severity); static LogSeverity GetDebuggingSeverity(void); void UpdatePidFile(const String& filename, pid_t pid = Utility::GetPid()); void ClosePidFile(bool unlink); static pid_t ReadPidFile(const String& filename); static String GetExePath(const String& argv0); static String GetPrefixDir(void); static void DeclarePrefixDir(const String& path); static String GetSysconfDir(void); static void DeclareSysconfDir(const String& path); static String GetZonesDir(void); static void DeclareZonesDir(const String& path); static String GetRunDir(void); static void DeclareRunDir(const String& path); static String GetLocalStateDir(void); static void DeclareLocalStateDir(const String& path); static String GetPkgDataDir(void); static void DeclarePkgDataDir(const String& path); static String GetIncludeConfDir(void); static void DeclareIncludeConfDir(const String& path); static String GetStatePath(void); static void DeclareStatePath(const String& path); static String GetModAttrPath(void); static void DeclareModAttrPath(const String& path); static String GetObjectsPath(void); static void DeclareObjectsPath(const String& path); static String GetVarsPath(void); static void DeclareVarsPath(const String& path); static String GetPidPath(void); static void DeclarePidPath(const String& path); static String GetRunAsUser(void); static void DeclareRunAsUser(const String& user); static String GetRunAsGroup(void); static void DeclareRunAsGroup(const String& group); #ifdef _WIN32 static bool IsProcessElevated(void); #endif /* _WIN32 */ static int GetRLimitFiles(void); static int GetDefaultRLimitFiles(void); static void DeclareRLimitFiles(int limit); static int GetRLimitProcesses(void); static int GetDefaultRLimitProcesses(void); static void DeclareRLimitProcesses(int limit); static int GetRLimitStack(void); static int GetDefaultRLimitStack(void); static void DeclareRLimitStack(int limit); static int GetConcurrency(void); static void DeclareConcurrency(int ncpus); static ThreadPool& GetTP(void); static String GetAppVersion(void); static String GetAppSpecVersion(void); static double GetStartTime(void); static void SetStartTime(double ts); static double GetMainTime(void); static void SetMainTime(double ts); static bool GetScriptDebuggerEnabled(void); static void SetScriptDebuggerEnabled(bool enabled); static double GetLastReloadFailed(void); static void SetLastReloadFailed(double ts); static void DisplayInfoMessage(std::ostream& os, bool skipVersion = false); protected: virtual void OnConfigLoaded(void) override; virtual void Stop(bool runtimeRemoved) override; void RunEventLoop(void); pid_t StartReloadProcess(void); virtual void OnShutdown(void); virtual void ValidateName(const String& value, const ValidationUtils& utils) override; private: static Application::Ptr m_Instance; /**< The application instance. */ static bool m_ShuttingDown; /**< Whether the application is in the process of shutting down. */ static bool m_RequestRestart; /**< A restart was requested through SIGHUP */ static pid_t m_ReloadProcess; /**< The PID of a subprocess doing a reload, only valid when l_Restarting==true */ static bool m_RequestReopenLogs; /**< Whether we should re-open log files. */ static int m_ArgC; /**< The number of command-line arguments. */ static char **m_ArgV; /**< Command-line arguments. */ FILE *m_PidFile; /**< The PID file */ static bool m_Debugging; /**< Whether debugging is enabled. */ static LogSeverity m_DebuggingSeverity; /**< Whether debugging severity is set. */ static double m_StartTime; static double m_MainTime; static bool m_ScriptDebuggerEnabled; static double m_LastReloadFailed; #ifndef _WIN32 static void SigIntTermHandler(int signum); #else /* _WIN32 */ static BOOL WINAPI CtrlHandler(DWORD type); static LONG WINAPI SEHUnhandledExceptionFilter(PEXCEPTION_POINTERS exi); #endif /* _WIN32 */ static void DisplayBugMessage(std::ostream& os); static void SigAbrtHandler(int signum); static void SigUsr1Handler(int signum); static void ExceptionHandler(void); static String GetCrashReportFilename(void); static void AttachDebugger(const String& filename, bool interactive); }; } #endif /* APPLICATION_H */ icinga2-2.8.1/lib/base/application.ti000066400000000000000000000030311322762156600173660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library base; namespace icinga { abstract class Application : ConfigObject { }; } icinga2-2.8.1/lib/base/array-script.cpp000066400000000000000000000217721322762156600176650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/array.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" using namespace icinga; static double ArrayLen(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); return self->GetLength(); } static void ArraySet(int index, const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); self->Set(index, value); } static Value ArrayGet(int index) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); return self->Get(index); } static void ArrayAdd(const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); self->Add(value); } static void ArrayRemove(int index) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); self->Remove(index); } static bool ArrayContains(const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); return self->Contains(value); } static void ArrayClear(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); self->Clear(); } static bool ArraySortCmp(const Function::Ptr& cmp, const Value& a, const Value& b) { std::vector args; args.push_back(a); args.push_back(b); return cmp->Invoke(args); } static Array::Ptr ArraySort(const std::vector& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); Array::Ptr arr = self->ShallowClone(); if (args.empty()) { ObjectLock olock(arr); std::sort(arr->Begin(), arr->End()); } else { Function::Ptr function = args[0]; if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free.")); ObjectLock olock(arr); std::sort(arr->Begin(), arr->End(), boost::bind(ArraySortCmp, args[0], _1, _2)); } return arr; } static Array::Ptr ArrayShallowClone(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); return self->ShallowClone(); } static Value ArrayJoin(const Value& separator) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); Value result; bool first = true; ObjectLock olock(self); for (const Value& item : self) { if (first) { first = false; } else { result = result + separator; } result = result + item; } return result; } static Array::Ptr ArrayReverse(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); return self->Reverse(); } static Array::Ptr ArrayMap(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free.")); Array::Ptr result = new Array(); ObjectLock olock(self); for (const Value& item : self) { std::vector args; args.push_back(item); result->Add(function->Invoke(args)); } return result; } static Value ArrayReduce(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free.")); if (self->GetLength() == 0) return Empty; Value result = self->Get(0); ObjectLock olock(self); for (size_t i = 1; i < self->GetLength(); i++) { std::vector args; args.push_back(result); args.push_back(self->Get(i)); result = function->Invoke(args); } return result; } static Array::Ptr ArrayFilter(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free.")); Array::Ptr result = new Array(); ObjectLock olock(self); for (const Value& item : self) { std::vector args; args.push_back(item); if (function->Invoke(args)) result->Add(item); } return result; } static bool ArrayAny(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free.")); ObjectLock olock(self); for (const Value& item : self) { std::vector args; args.push_back(item); if (function->Invoke(args)) return true; } return false; } static bool ArrayAll(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free.")); ObjectLock olock(self); for (const Value& item : self) { std::vector args; args.push_back(item); if (!function->Invoke(args)) return false; } return true; } static Array::Ptr ArrayUnique(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); std::set result; ObjectLock olock(self); for (const Value& item : self) { result.insert(item); } return Array::FromSet(result); } Object::Ptr Array::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("len", new Function("Array#len", WrapFunction(ArrayLen), {}, true)); prototype->Set("set", new Function("Array#set", WrapFunction(ArraySet), { "index", "value" })); prototype->Set("get", new Function("Array#get", WrapFunction(ArrayGet), { "index" })); prototype->Set("add", new Function("Array#add", WrapFunction(ArrayAdd), { "value" })); prototype->Set("remove", new Function("Array#remove", WrapFunction(ArrayRemove), { "index" })); prototype->Set("contains", new Function("Array#contains", WrapFunction(ArrayContains), { "value" }, true)); prototype->Set("clear", new Function("Array#clear", WrapFunction(ArrayClear))); prototype->Set("sort", new Function("Array#sort", WrapFunction(ArraySort), { "less_cmp" }, true)); prototype->Set("shallow_clone", new Function("Array#shallow_clone", WrapFunction(ArrayShallowClone), {}, true)); prototype->Set("join", new Function("Array#join", WrapFunction(ArrayJoin), { "separator" }, true)); prototype->Set("reverse", new Function("Array#reverse", WrapFunction(ArrayReverse), {}, true)); prototype->Set("map", new Function("Array#map", WrapFunction(ArrayMap), { "func" }, true)); prototype->Set("reduce", new Function("Array#reduce", WrapFunction(ArrayReduce), { "reduce" }, true)); prototype->Set("filter", new Function("Array#filter", WrapFunction(ArrayFilter), { "func" }, true)); prototype->Set("any", new Function("Array#any", WrapFunction(ArrayAny), { "func" }, true)); prototype->Set("all", new Function("Array#all", WrapFunction(ArrayAll), { "func" }, true)); prototype->Set("unique", new Function("Array#unique", WrapFunction(ArrayUnique), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/array.cpp000066400000000000000000000137521322762156600163620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/debug.hpp" #include "base/primitivetype.hpp" #include "base/dictionary.hpp" #include "base/configwriter.hpp" #include "base/convert.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_PRIMITIVE_TYPE(Array, Object, Array::GetPrototype()); /** * Restrieves a value from an array. * * @param index The index. * @returns The value. */ Value Array::Get(unsigned int index) const { ObjectLock olock(this); return m_Data.at(index); } /** * Sets a value in the array. * * @param index The index. * @param value The value. */ void Array::Set(unsigned int index, const Value& value) { ObjectLock olock(this); m_Data.at(index) = value; } /** * Sets a value in the array. * * @param index The index. * @param value The value. */ void Array::Set(unsigned int index, Value&& value) { ObjectLock olock(this); m_Data.at(index).Swap(value); } /** * Adds a value to the array. * * @param value The value. */ void Array::Add(const Value& value) { ObjectLock olock(this); m_Data.push_back(value); } /** * Adds a value to the array. * * @param value The value. */ void Array::Add(Value&& value) { ObjectLock olock(this); m_Data.push_back(std::move(value)); } /** * Returns the number of elements in the array. * * @returns Number of elements. */ size_t Array::GetLength(void) const { ObjectLock olock(this); return m_Data.size(); } /** * Checks whether the array contains the specified value. * * @param value The value. * @returns true if the array contains the value, false otherwise. */ bool Array::Contains(const Value& value) const { ObjectLock olock(this); return (std::find(m_Data.begin(), m_Data.end(), value) != m_Data.end()); } /** * Insert the given value at the specified index * * @param index The index * @param value The value to add */ void Array::Insert(unsigned int index, const Value& value) { ObjectLock olock(this); ASSERT(index <= m_Data.size()); m_Data.insert(m_Data.begin() + index, value); } /** * Removes the specified index from the array. * * @param index The index. */ void Array::Remove(unsigned int index) { ObjectLock olock(this); m_Data.erase(m_Data.begin() + index); } /** * Removes the item specified by the iterator from the array. * * @param it The iterator. */ void Array::Remove(Array::Iterator it) { ASSERT(OwnsLock()); m_Data.erase(it); } void Array::Resize(size_t new_size) { ObjectLock olock(this); m_Data.resize(new_size); } void Array::Clear(void) { ObjectLock olock(this); m_Data.clear(); } void Array::Reserve(size_t new_size) { ObjectLock olock(this); m_Data.reserve(new_size); } void Array::CopyTo(const Array::Ptr& dest) const { ObjectLock olock(this); ObjectLock xlock(dest); std::copy(m_Data.begin(), m_Data.end(), std::back_inserter(dest->m_Data)); } /** * Makes a shallow copy of an array. * * @returns a copy of the array. */ Array::Ptr Array::ShallowClone(void) const { Array::Ptr clone = new Array(); CopyTo(clone); return clone; } /** * Makes a deep clone of an array * and its elements. * * @returns a copy of the array. */ Object::Ptr Array::Clone(void) const { Array::Ptr arr = new Array(); ObjectLock olock(this); for (const Value& val : m_Data) { arr->Add(val.Clone()); } return arr; } Array::Ptr Array::Reverse(void) const { Array::Ptr result = new Array(); ObjectLock olock(this); ObjectLock xlock(result); std::copy(m_Data.rbegin(), m_Data.rend(), std::back_inserter(result->m_Data)); return result; } void Array::Sort(void) { ObjectLock olock(this); std::sort(m_Data.begin(), m_Data.end()); } String Array::ToString(void) const { std::ostringstream msgbuf; ConfigWriter::EmitArray(msgbuf, 1, const_cast(this)); return msgbuf.str(); } Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const { int index; try { index = Convert::ToLong(field); } catch (...) { return Object::GetFieldByName(field, sandboxed, debugInfo); } ObjectLock olock(this); if (index < 0 || static_cast(index) >= GetLength()) BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo)); return Get(index); } void Array::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) { ObjectLock olock(this); int index = Convert::ToLong(field); if (index < 0) BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo)); if (static_cast(index) >= GetLength()) Resize(index + 1); Set(index, value); } icinga2-2.8.1/lib/base/array.hpp000066400000000000000000000103721322762156600163620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ARRAY_H #define ARRAY_H #include "base/i2-base.hpp" #include "base/objectlock.hpp" #include "base/value.hpp" #include #include #include namespace icinga { /** * An array of Value items. * * @ingroup base */ class I2_BASE_API Array : public Object { public: DECLARE_OBJECT(Array); /** * An iterator that can be used to iterate over array elements. */ typedef std::vector::iterator Iterator; typedef std::vector::size_type SizeType; inline Array(void) { } inline Array(std::initializer_list init) : m_Data(init) { } inline ~Array(void) { } Value Get(unsigned int index) const; void Set(unsigned int index, const Value& value); void Set(unsigned int index, Value&& value); void Add(const Value& value); void Add(Value&& value); /** * Returns an iterator to the beginning of the array. * * Note: Caller must hold the object lock while using the iterator. * * @returns An iterator. */ inline Iterator Begin(void) { ASSERT(OwnsLock()); return m_Data.begin(); } /** * Returns an iterator to the end of the array. * * Note: Caller must hold the object lock while using the iterator. * * @returns An iterator. */ inline Iterator End(void) { ASSERT(OwnsLock()); return m_Data.end(); } size_t GetLength(void) const; bool Contains(const Value& value) const; void Insert(unsigned int index, const Value& value); void Remove(unsigned int index); void Remove(Iterator it); void Resize(size_t new_size); void Clear(void); void Reserve(size_t new_size); void CopyTo(const Array::Ptr& dest) const; Array::Ptr ShallowClone(void) const; static Object::Ptr GetPrototype(void); template static Array::Ptr FromVector(const std::vector& v) { Array::Ptr result = new Array(); ObjectLock olock(result); std::copy(v.begin(), v.end(), std::back_inserter(result->m_Data)); return result; } template std::set ToSet(void) { ObjectLock olock(this); return std::set(Begin(), End()); } template static Array::Ptr FromSet(const std::set& v) { Array::Ptr result = new Array(); ObjectLock olock(result); std::copy(v.begin(), v.end(), std::back_inserter(result->m_Data)); return result; } virtual Object::Ptr Clone(void) const override; Array::Ptr Reverse(void) const; void Sort(void); virtual String ToString(void) const override; virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; virtual void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; private: std::vector m_Data; /**< The data for the array. */ }; inline Array::Iterator begin(Array::Ptr x) { return x->Begin(); } inline Array::Iterator end(Array::Ptr x) { return x->End(); } } #endif /* ARRAY_H */ icinga2-2.8.1/lib/base/base64.cpp000066400000000000000000000051001322762156600163140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/base64.hpp" #include #include #include #include using namespace icinga; String Base64::Encode(const String& input) { BIO *biomem = BIO_new(BIO_s_mem()); BIO *bio64 = BIO_new(BIO_f_base64()); BIO_push(bio64, biomem); BIO_set_flags(bio64, BIO_FLAGS_BASE64_NO_NL); BIO_write(bio64, input.CStr(), input.GetLength()); (void) BIO_flush(bio64); char *outbuf; long len = BIO_get_mem_data(biomem, &outbuf); String ret = String(outbuf, outbuf + len); BIO_free_all(bio64); return ret; } String Base64::Decode(const String& input) { BIO *biomem = BIO_new_mem_buf( const_cast(input.CStr()), input.GetLength()); BIO *bio64 = BIO_new(BIO_f_base64()); BIO_push(bio64, biomem); BIO_set_flags(bio64, BIO_FLAGS_BASE64_NO_NL); char *outbuf = new char[input.GetLength()]; size_t len = 0; int rc; while ((rc = BIO_read(bio64, outbuf + len, input.GetLength() - len)) > 0) len += rc; String ret = String(outbuf, outbuf + len); BIO_free_all(bio64); delete [] outbuf; if (ret.IsEmpty() && !input.IsEmpty()) throw std::invalid_argument("Not a valid base64 string"); return ret; } icinga2-2.8.1/lib/base/base64.hpp000066400000000000000000000033141322762156600163260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef BASE64_H #define BASE64_H #include "remote/i2-remote.hpp" #include "base/string.hpp" namespace icinga { /** * Base64 * * @ingroup remote */ struct I2_BASE_API Base64 { static String Decode(const String& data); static String Encode(const String& data); }; } #endif /* BASE64_H */ icinga2-2.8.1/lib/base/boolean-script.cpp000066400000000000000000000037671322762156600201720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/boolean.hpp" #include "base/convert.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static String BooleanToString(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); bool self = vframe->Self; return self ? "true" : "false"; } Object::Ptr Boolean::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("to_string", new Function("Boolean#to_string", WrapFunction(BooleanToString), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/boolean.cpp000066400000000000000000000030641322762156600166560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/boolean.hpp" #include "base/primitivetype.hpp" using namespace icinga; REGISTER_BUILTIN_TYPE(Boolean, Boolean::GetPrototype()); icinga2-2.8.1/lib/base/boolean.hpp000066400000000000000000000032771322762156600166710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef BOOLEAN_H #define BOOLEAN_H #include "base/i2-base.hpp" #include "base/object.hpp" namespace icinga { class Value; /** * Boolean class. */ class I2_BASE_API Boolean { public: static Object::Ptr GetPrototype(void); private: Boolean(void); }; } #endif /* BOOLEAN_H */ icinga2-2.8.1/lib/base/configobject-script.cpp000066400000000000000000000047371322762156600212050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static void ConfigObjectModifyAttribute(const String& attr, const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); ConfigObject::Ptr self = vframe->Self; return self->ModifyAttribute(attr, value); } static void ConfigObjectRestoreAttribute(const String& attr) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); ConfigObject::Ptr self = vframe->Self; return self->RestoreAttribute(attr); } Object::Ptr ConfigObject::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("modify_attribute", new Function("ConfigObject#modify_attribute", WrapFunction(ConfigObjectModifyAttribute), { "attr", "value" }, false)); prototype->Set("restore_attribute", new Function("ConfigObject#restore_attribute", WrapFunction(ConfigObjectRestoreAttribute), { "attr", "value" }, false)); } return prototype; } icinga2-2.8.1/lib/base/configobject.cpp000066400000000000000000000434021322762156600176730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/configobject.tcpp" #include "base/configtype.hpp" #include "base/serializer.hpp" #include "base/netstring.hpp" #include "base/json.hpp" #include "base/stdiostream.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/function.hpp" #include "base/initialize.hpp" #include "base/workqueue.hpp" #include "base/context.hpp" #include "base/application.hpp" #include #include #include #include #include #include using namespace icinga; REGISTER_TYPE_WITH_PROTOTYPE(ConfigObject, ConfigObject::GetPrototype()); boost::signals2::signal ConfigObject::OnStateChanged; ConfigObject::ConfigObject(void) { } bool ConfigObject::IsActive(void) const { return GetActive(); } bool ConfigObject::IsPaused(void) const { return GetPaused(); } void ConfigObject::SetExtension(const String& key, const Value& value) { Dictionary::Ptr extensions = GetExtensions(); if (!extensions) { extensions = new Dictionary(); SetExtensions(extensions); } extensions->Set(key, value); } Value ConfigObject::GetExtension(const String& key) { Dictionary::Ptr extensions = GetExtensions(); if (!extensions) return Empty; return extensions->Get(key); } void ConfigObject::ClearExtension(const String& key) { Dictionary::Ptr extensions = GetExtensions(); if (!extensions) return; extensions->Remove(key); } class ModAttrValidationUtils : public ValidationUtils { public: virtual bool ValidateName(const String& type, const String& name) const override { Type::Ptr ptype = Type::GetByName(type); ConfigType *dtype = dynamic_cast(ptype.get()); if (!dtype) return false; if (!dtype->GetObject(name)) return false; return true; } }; void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool updateVersion) { Dictionary::Ptr original_attributes = GetOriginalAttributes(); bool updated_original_attributes = false; Type::Ptr type = GetReflectionType(); std::vector tokens; boost::algorithm::split(tokens, attr, boost::is_any_of(".")); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Field field = type->GetFieldInfo(fid); if (field.Attributes & FANoUserModify) BOOST_THROW_EXCEPTION(std::invalid_argument("Attribute cannot be modified.")); if (field.Attributes & FAConfig) { if (!original_attributes) { original_attributes = new Dictionary(); SetOriginalAttributes(original_attributes, true); } } Value oldValue = GetField(fid); Value newValue; if (tokens.size() > 1) { newValue = oldValue.Clone(); Value current = newValue; if (current.IsEmpty()) { current = new Dictionary(); newValue = current; } String prefix = tokens[0]; for (std::vector::size_type i = 1; i < tokens.size() - 1; i++) { if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[i]; prefix += "." + key; if (!dict->Get(key, ¤t)) { current = new Dictionary(); dict->Set(key, current); } } if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[tokens.size() - 1]; prefix += "." + key; /* clone it for original attributes */ oldValue = dict->Get(key).Clone(); if (field.Attributes & FAConfig) { updated_original_attributes = true; if (oldValue.IsObjectType()) { Dictionary::Ptr oldDict = oldValue; ObjectLock olock(oldDict); for (const auto& kv : oldDict) { String key = prefix + "." + kv.first; if (!original_attributes->Contains(key)) original_attributes->Set(key, kv.second); } /* store the new value as null */ if (value.IsObjectType()) { Dictionary::Ptr valueDict = value; ObjectLock olock(valueDict); for (const auto& kv : valueDict) { String key = attr + "." + kv.first; if (!original_attributes->Contains(key)) original_attributes->Set(key, Empty); } } } else if (!original_attributes->Contains(attr)) original_attributes->Set(attr, oldValue); } dict->Set(key, value); } else { newValue = value; if (field.Attributes & FAConfig) { if (!original_attributes->Contains(attr)) { updated_original_attributes = true; original_attributes->Set(attr, oldValue); } } } ModAttrValidationUtils utils; ValidateField(fid, newValue, utils); SetField(fid, newValue); if (updateVersion && (field.Attributes & FAConfig)) SetVersion(Utility::GetTime()); if (updated_original_attributes) NotifyOriginalAttributes(); } void ConfigObject::RestoreAttribute(const String& attr, bool updateVersion) { Type::Ptr type = GetReflectionType(); std::vector tokens; boost::algorithm::split(tokens, attr, boost::is_any_of(".")); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Value currentValue = GetField(fid); Dictionary::Ptr original_attributes = GetOriginalAttributes(); if (!original_attributes) return; Value oldValue = original_attributes->Get(attr); Value newValue; if (tokens.size() > 1) { newValue = currentValue.Clone(); Value current = newValue; if (current.IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existent object attribute")); String prefix = tokens[0]; for (std::vector::size_type i = 1; i < tokens.size() - 1; i++) { if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[i]; prefix += "." + key; if (!dict->Contains(key)) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existent object attribute")); current = dict->Get(key); } if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[tokens.size() - 1]; prefix += "." + key; std::vector restoredAttrs; { ObjectLock olock(original_attributes); for (const auto& kv : original_attributes) { std::vector originalTokens; boost::algorithm::split(originalTokens, kv.first, boost::is_any_of(".")); if (tokens.size() > originalTokens.size()) continue; bool match = true; for (std::vector::size_type i = 0; i < tokens.size(); i++) { if (tokens[i] != originalTokens[i]) { match = false; break; } } if (!match) continue; Dictionary::Ptr dict; if (tokens.size() == originalTokens.size()) dict = current; else { Value currentSub = current; for (std::vector::size_type i = tokens.size() - 1; i < originalTokens.size() - 1; i++) { dict = currentSub; currentSub = dict->Get(originalTokens[i]); if (!currentSub.IsObjectType()) { currentSub = new Dictionary(); dict->Set(originalTokens[i], currentSub); } } dict = currentSub; } dict->Set(originalTokens[originalTokens.size() - 1], kv.second); restoredAttrs.push_back(kv.first); } } for (const String& attr : restoredAttrs) original_attributes->Remove(attr); } else { newValue = oldValue; } original_attributes->Remove(attr); SetField(fid, newValue); if (updateVersion) SetVersion(Utility::GetTime()); } bool ConfigObject::IsAttributeModified(const String& attr) const { Dictionary::Ptr original_attributes = GetOriginalAttributes(); if (!original_attributes) return false; return original_attributes->Contains(attr); } void ConfigObject::Register(void) { ASSERT(!OwnsLock()); TypeImpl::Ptr type = static_pointer_cast >(GetReflectionType()); type->RegisterObject(this); } void ConfigObject::Unregister(void) { ASSERT(!OwnsLock()); TypeImpl::Ptr type = static_pointer_cast >(GetReflectionType()); type->UnregisterObject(this); } void ConfigObject::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); ObjectLock olock(this); SetStartCalled(true); } void ConfigObject::PreActivate(void) { CONTEXT("Setting 'active' to true for object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'"); ASSERT(!IsActive()); SetActive(true, true); } void ConfigObject::Activate(bool runtimeCreated) { CONTEXT("Activating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'"); { ObjectLock olock(this); Start(runtimeCreated); ASSERT(GetStartCalled()); if (GetHAMode() == HARunEverywhere) SetAuthority(true); } NotifyActive(); } void ConfigObject::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); ObjectLock olock(this); SetStopCalled(true); } void ConfigObject::Deactivate(bool runtimeRemoved) { CONTEXT("Deactivating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'"); { ObjectLock olock(this); if (!IsActive()) return; SetActive(false, true); SetAuthority(false); Stop(runtimeRemoved); } ASSERT(GetStopCalled()); NotifyActive(); } void ConfigObject::OnConfigLoaded(void) { /* Nothing to do here. */ } void ConfigObject::OnAllConfigLoaded(void) { static ConfigType *ctype; if (!ctype) { Type::Ptr type = Type::GetByName("Zone"); ctype = dynamic_cast(type.get()); } String zoneName = GetZoneName(); if (!zoneName.IsEmpty()) m_Zone = ctype->GetObject(zoneName); } void ConfigObject::CreateChildObjects(const Type::Ptr& childType) { /* Nothing to do here. */ } void ConfigObject::OnStateLoaded(void) { /* Nothing to do here. */ } void ConfigObject::Pause(void) { SetPauseCalled(true); } void ConfigObject::Resume(void) { SetResumeCalled(true); } void ConfigObject::SetAuthority(bool authority) { ObjectLock olock(this); if (authority && GetPaused()) { SetResumeCalled(false); Resume(); ASSERT(GetResumeCalled()); SetPaused(false); } else if (!authority && !GetPaused()) { SetPaused(true); SetPauseCalled(false); Pause(); ASSERT(GetPauseCalled()); } } void ConfigObject::DumpObjects(const String& filename, int attributeTypes) { Log(LogInformation, "ConfigObject") << "Dumping program state to file '" << filename << "'"; std::fstream fp; String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", 0600, fp); fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); if (!fp) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); StdioStream::Ptr sfp = new StdioStream(&fp, false); for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { Dictionary::Ptr persistentObject = new Dictionary(); persistentObject->Set("type", type->GetName()); persistentObject->Set("name", object->GetName()); Dictionary::Ptr update = Serialize(object, attributeTypes); if (!update) continue; persistentObject->Set("update", update); String json = JsonEncode(persistentObject); NetString::WriteStringToStream(sfp, json); } } sfp->Close(); fp.close(); #ifdef _WIN32 _unlink(filename.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), filename.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } } void ConfigObject::RestoreObject(const String& message, int attributeTypes) { Dictionary::Ptr persistentObject = JsonDecode(message); String type = persistentObject->Get("type"); String name = persistentObject->Get("name"); ConfigObject::Ptr object = GetObject(type, name); if (!object) return; #ifdef I2_DEBUG Log(LogDebug, "ConfigObject") << "Restoring object '" << name << "' of type '" << type << "'."; #endif /* I2_DEBUG */ Dictionary::Ptr update = persistentObject->Get("update"); Deserialize(object, update, false, attributeTypes); object->OnStateLoaded(); object->SetStateLoaded(true); } void ConfigObject::RestoreObjects(const String& filename, int attributeTypes) { if (!Utility::PathExists(filename)) return; Log(LogInformation, "ConfigObject") << "Restoring program state from file '" << filename << "'"; std::fstream fp; fp.open(filename.CStr(), std::ios_base::in); StdioStream::Ptr sfp = new StdioStream (&fp, false); unsigned long restored = 0; WorkQueue upq(25000, Application::GetConcurrency()); upq.SetName("ConfigObject::RestoreObjects"); String message; StreamReadContext src; for (;;) { StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; upq.Enqueue(boost::bind(&ConfigObject::RestoreObject, message, attributeTypes)); restored++; } sfp->Close(); upq.Join(); unsigned long no_state = 0; for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { if (!object->GetStateLoaded()) { object->OnStateLoaded(); object->SetStateLoaded(true); no_state++; } } } Log(LogInformation, "ConfigObject") << "Restored " << restored << " objects. Loaded " << no_state << " new objects without state."; } void ConfigObject::StopObjects(void) { for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { object->Deactivate(); } } } void ConfigObject::DumpModifiedAttributes(const boost::function& callback) { for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { Dictionary::Ptr originalAttributes = object->GetOriginalAttributes(); if (!originalAttributes) continue; ObjectLock olock(originalAttributes); for (const Dictionary::Pair& kv : originalAttributes) { String key = kv.first; Type::Ptr type = object->GetReflectionType(); std::vector tokens; boost::algorithm::split(tokens, key, boost::is_any_of(".")); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Value currentValue = object->GetField(fid); Value modifiedValue; if (tokens.size() > 1) { Value current = currentValue; for (std::vector::size_type i = 1; i < tokens.size() - 1; i++) { if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[i]; if (!dict->Contains(key)) break; current = dict->Get(key); } if (!current.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[tokens.size() - 1]; modifiedValue = dict->Get(key); } else modifiedValue = currentValue; callback(object, key, modifiedValue); } } } } ConfigObject::Ptr ConfigObject::GetObject(const String& type, const String& name) { Type::Ptr ptype = Type::GetByName(type); ConfigType *ctype = dynamic_cast(ptype.get()); if (!ctype) return ConfigObject::Ptr(); return ctype->GetObject(name); } ConfigObject::Ptr ConfigObject::GetZone(void) const { return m_Zone; } Dictionary::Ptr ConfigObject::GetSourceLocation(void) const { DebugInfo di = GetDebugInfo(); Dictionary::Ptr result = new Dictionary(); result->Set("path", di.Path); result->Set("first_line", di.FirstLine); result->Set("first_column", di.FirstColumn); result->Set("last_line", di.LastLine); result->Set("last_column", di.LastColumn); return result; } NameComposer::~NameComposer(void) { } icinga2-2.8.1/lib/base/configobject.hpp000066400000000000000000000101731322762156600176770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGOBJECT_H #define CONFIGOBJECT_H #include "base/i2-base.hpp" #include "base/configobject.thpp" #include "base/object.hpp" #include "base/type.hpp" #include "base/dictionary.hpp" #include namespace icinga { class ConfigType; /** * A dynamic object that can be instantiated from the configuration file. * * @ingroup base */ class I2_BASE_API ConfigObject : public ObjectImpl { public: DECLARE_OBJECT(ConfigObject); static boost::signals2::signal OnStateChanged; bool IsActive(void) const; bool IsPaused(void) const; void SetExtension(const String& key, const Value& value); Value GetExtension(const String& key); void ClearExtension(const String& key); ConfigObject::Ptr GetZone(void) const; void ModifyAttribute(const String& attr, const Value& value, bool updateVersion = true); void RestoreAttribute(const String& attr, bool updateVersion = true); bool IsAttributeModified(const String& attr) const; void Register(void); void Unregister(void); void PreActivate(void); void Activate(bool runtimeCreated = false); void Deactivate(bool runtimeRemoved = false); void SetAuthority(bool authority); virtual void Start(bool runtimeCreated = false) override; virtual void Stop(bool runtimeRemoved = false) override; virtual void Pause(void); virtual void Resume(void); virtual void OnConfigLoaded(void); virtual void CreateChildObjects(const Type::Ptr& childType); virtual void OnAllConfigLoaded(void); virtual void OnStateLoaded(void); virtual Dictionary::Ptr GetSourceLocation(void) const override; template static intrusive_ptr GetObject(const String& name) { typedef TypeImpl ObjType; ObjType *ptype = static_cast(T::TypeInstance.get()); return static_pointer_cast(ptype->GetObject(name)); } static ConfigObject::Ptr GetObject(const String& type, const String& name); static void DumpObjects(const String& filename, int attributeTypes = FAState); static void RestoreObjects(const String& filename, int attributeTypes = FAState); static void StopObjects(void); static void DumpModifiedAttributes(const boost::function& callback); static Object::Ptr GetPrototype(void); protected: explicit ConfigObject(void); private: ConfigObject::Ptr m_Zone; static void RestoreObject(const String& message, int attributeTypes); }; #define DECLARE_OBJECTNAME(klass) \ inline static String GetTypeName(void) \ { \ return #klass; \ } \ \ inline static intrusive_ptr GetByName(const String& name) \ { \ return ConfigObject::GetObject(name); \ } } #endif /* CONFIGOBJECT_H */ icinga2-2.8.1/lib/base/configobject.ti000066400000000000000000000066101322762156600175250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/debuginfo.hpp" #include "base/configtype.hpp" library base; namespace icinga { code {{{ enum HAMode { HARunOnce, HARunEverywhere }; class I2_BASE_API NameComposer { public: virtual ~NameComposer(void); virtual String MakeName(const String& shortName, const Object::Ptr& context) const = 0; virtual Dictionary::Ptr ParseName(const String& name) const = 0; }; }}} abstract class ConfigObjectBase { }; code {{{ class I2_BASE_API ConfigObjectBase : public ObjectImpl { public: inline DebugInfo GetDebugInfo(void) const { return m_DebugInfo; } void SetDebugInfo(const DebugInfo& di) { m_DebugInfo = di; } inline virtual void Start(bool /* runtimeCreated */) { } inline virtual void Stop(bool /* runtimeRemoved */) { } private: DebugInfo m_DebugInfo; }; }}} abstract class ConfigObject : ConfigObjectBase < ConfigType { [config, no_user_modify] String __name (Name); [config, no_user_modify] String "name" (ShortName) { get {{{ if (m_ShortName.IsEmpty()) return GetName(); else return m_ShortName; }}} }; [config, no_user_modify] name(Zone) zone (ZoneName); [config, no_user_modify] String package; [config, get_protected, no_user_modify] Array::Ptr templates; [config, no_storage, no_user_modify] Dictionary::Ptr source_location { get; }; [get_protected, no_user_modify] bool active; [get_protected, no_user_modify] bool paused { default {{{ return true; }}} }; [get_protected, no_user_view, no_user_modify] bool start_called; [get_protected, no_user_view, no_user_modify] bool stop_called; [get_protected, no_user_view, no_user_modify] bool pause_called; [get_protected, no_user_view, no_user_modify] bool resume_called; [enum] HAMode ha_mode (HAMode); [protected, no_user_view, no_user_modify] Dictionary::Ptr extensions; [protected, no_user_view, no_user_modify] bool state_loaded; [no_user_modify] Dictionary::Ptr original_attributes; [state, no_user_modify] double version { default {{{ return 0; }}} }; }; } icinga2-2.8.1/lib/base/configtype.cpp000066400000000000000000000061661322762156600174140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/convert.hpp" #include "base/exception.hpp" using namespace icinga; ConfigType::~ConfigType(void) { } ConfigObject::Ptr ConfigType::GetObject(const String& name) const { boost::mutex::scoped_lock lock(m_Mutex); auto nt = m_ObjectMap.find(name); if (nt == m_ObjectMap.end()) return ConfigObject::Ptr(); return nt->second; } void ConfigType::RegisterObject(const ConfigObject::Ptr& object) { String name = object->GetName(); { boost::mutex::scoped_lock lock(m_Mutex); auto it = m_ObjectMap.find(name); if (it != m_ObjectMap.end()) { if (it->second == object) return; Type *type = dynamic_cast(this); BOOST_THROW_EXCEPTION(ScriptError("An object with type '" + type->GetName() + "' and name '" + name + "' already exists (" + Convert::ToString(it->second->GetDebugInfo()) + "), new declaration: " + Convert::ToString(object->GetDebugInfo()), object->GetDebugInfo())); } m_ObjectMap[name] = object; m_ObjectVector.push_back(object); } } void ConfigType::UnregisterObject(const ConfigObject::Ptr& object) { String name = object->GetName(); { boost::mutex::scoped_lock lock(m_Mutex); m_ObjectMap.erase(name); m_ObjectVector.erase(std::remove(m_ObjectVector.begin(), m_ObjectVector.end(), object), m_ObjectVector.end()); } } std::vector ConfigType::GetObjects(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_ObjectVector; } std::vector ConfigType::GetObjectsHelper(Type *type) { return static_cast *>(type)->GetObjects(); } int ConfigType::GetObjectCount(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_ObjectVector.size(); } icinga2-2.8.1/lib/base/configtype.hpp000066400000000000000000000054241322762156600174150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGTYPE_H #define CONFIGTYPE_H #include "base/i2-base.hpp" #include "base/object.hpp" #include "base/type.hpp" #include "base/dictionary.hpp" namespace icinga { class ConfigObject; class I2_BASE_API ConfigType { public: virtual ~ConfigType(void); intrusive_ptr GetObject(const String& name) const; void RegisterObject(const intrusive_ptr& object); void UnregisterObject(const intrusive_ptr& object); std::vector > GetObjects(void) const; template static TypeImpl *Get(void) { typedef TypeImpl ObjType; return static_cast(T::TypeInstance.get()); } template static std::vector > GetObjectsByType(void) { std::vector > objects = GetObjectsHelper(T::TypeInstance.get()); std::vector > result; for (const auto& object : objects) { result.push_back(static_pointer_cast(object)); } return result; } int GetObjectCount(void) const; private: typedef std::map > ObjectMap; typedef std::vector > ObjectVector; mutable boost::mutex m_Mutex; ObjectMap m_ObjectMap; ObjectVector m_ObjectVector; static std::vector > GetObjectsHelper(Type *type); }; } #endif /* CONFIGTYPE_H */ icinga2-2.8.1/lib/base/configwriter.cpp000066400000000000000000000173131322762156600177430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configwriter.hpp" #include "base/exception.hpp" #include #include #include #include #include #include using namespace icinga; void ConfigWriter::EmitBoolean(std::ostream& fp, bool val) { fp << (val ? "true" : "false"); } void ConfigWriter::EmitNumber(std::ostream& fp, double val) { fp << std::fixed << val; } void ConfigWriter::EmitString(std::ostream& fp, const String& val) { fp << "\"" << EscapeIcingaString(val) << "\""; } void ConfigWriter::EmitEmpty(std::ostream& fp) { fp << "null"; } void ConfigWriter::EmitArray(std::ostream& fp, int indentLevel, const Array::Ptr& val) { fp << "[ "; EmitArrayItems(fp, indentLevel, val); if (val->GetLength() > 0) fp << " "; fp << "]"; } void ConfigWriter::EmitArrayItems(std::ostream& fp, int indentLevel, const Array::Ptr& val) { bool first = true; ObjectLock olock(val); for (const Value& item : val) { if (first) first = false; else fp << ", "; EmitValue(fp, indentLevel, item); } } void ConfigWriter::EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports, bool splitDot) { fp << "{"; if (imports && imports->GetLength() > 0) { ObjectLock xlock(imports); for (const Value& import : imports) { fp << "\n"; EmitIndent(fp, indentLevel); fp << "import \"" << import << "\""; } fp << "\n"; } if (val) { ObjectLock olock(val); for (const Dictionary::Pair& kv : val) { fp << "\n"; EmitIndent(fp, indentLevel); if (splitDot) { std::vector tokens; boost::algorithm::split(tokens, kv.first, boost::is_any_of(".")); EmitIdentifier(fp, tokens[0], true); for (std::vector::size_type i = 1; i < tokens.size(); i++) { fp << "["; EmitString(fp, tokens[i]); fp << "]"; } } else EmitIdentifier(fp, kv.first, true); fp << " = "; EmitValue(fp, indentLevel + 1, kv.second); } } fp << "\n"; EmitIndent(fp, indentLevel - 1); fp << "}"; } void ConfigWriter::EmitValue(std::ostream& fp, int indentLevel, const Value& val) { if (val.IsObjectType()) EmitArray(fp, indentLevel, val); else if (val.IsObjectType()) EmitScope(fp, indentLevel, val); else if (val.IsObjectType()) EmitIdentifier(fp, static_cast(val)->GetName(), false); else if (val.IsString()) EmitString(fp, val); else if (val.IsNumber()) EmitNumber(fp, val); else if (val.IsBoolean()) EmitBoolean(fp, val); else if (val.IsEmpty()) EmitEmpty(fp); } void ConfigWriter::EmitRaw(std::ostream& fp, const String& val) { fp << val; } void ConfigWriter::EmitIndent(std::ostream& fp, int indentLevel) { for (int i = 0; i < indentLevel; i++) fp << "\t"; } void ConfigWriter::EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment) { static std::set keywords; static boost::mutex mutex; { boost::mutex::scoped_lock lock(mutex); if (keywords.empty()) { const std::vector& vkeywords = GetKeywords(); std::copy(vkeywords.begin(), vkeywords.end(), std::inserter(keywords, keywords.begin())); } } if (keywords.find(identifier) != keywords.end()) { fp << "@" << identifier; return; } boost::regex expr("^[a-zA-Z_][a-zA-Z0-9\\_]*$"); boost::smatch what; if (boost::regex_search(identifier.GetData(), what, expr)) fp << identifier; else if (inAssignment) EmitString(fp, identifier); else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid identifier")); } void ConfigWriter::EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate, bool ignoreOnError, const Array::Ptr& imports, const Dictionary::Ptr& attrs) { if (isTemplate) fp << "template "; else fp << "object "; EmitIdentifier(fp, type, false); fp << " "; EmitString(fp, name); if (ignoreOnError) fp << " ignore_on_error"; fp << " "; EmitScope(fp, 1, attrs, imports, true); } void ConfigWriter::EmitComment(std::ostream& fp, const String& text) { fp << "/* " << text << " */\n"; } void ConfigWriter::EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments) { EmitIdentifier(fp, name, false); fp << "("; EmitArrayItems(fp, 0, arguments); fp << ")"; } String ConfigWriter::EscapeIcingaString(const String& str) { String result = str; boost::algorithm::replace_all(result, "\\", "\\\\"); boost::algorithm::replace_all(result, "\n", "\\n"); boost::algorithm::replace_all(result, "\t", "\\t"); boost::algorithm::replace_all(result, "\r", "\\r"); boost::algorithm::replace_all(result, "\b", "\\b"); boost::algorithm::replace_all(result, "\f", "\\f"); boost::algorithm::replace_all(result, "\"", "\\\""); return result; } const std::vector& ConfigWriter::GetKeywords(void) { static std::vector keywords; static boost::mutex mutex; boost::mutex::scoped_lock lock(mutex); if (keywords.empty()) { keywords.push_back("object"); keywords.push_back("template"); keywords.push_back("include"); keywords.push_back("include_recursive"); keywords.push_back("include_zones"); keywords.push_back("library"); keywords.push_back("null"); keywords.push_back("true"); keywords.push_back("false"); keywords.push_back("const"); keywords.push_back("var"); keywords.push_back("this"); keywords.push_back("globals"); keywords.push_back("locals"); keywords.push_back("use"); keywords.push_back("__using"); keywords.push_back("default"); keywords.push_back("ignore_on_error"); keywords.push_back("current_filename"); keywords.push_back("current_line"); keywords.push_back("apply"); keywords.push_back("to"); keywords.push_back("where"); keywords.push_back("import"); keywords.push_back("assign"); keywords.push_back("ignore"); keywords.push_back("function"); keywords.push_back("return"); keywords.push_back("break"); keywords.push_back("continue"); keywords.push_back("for"); keywords.push_back("if"); keywords.push_back("else"); keywords.push_back("while"); keywords.push_back("throw"); keywords.push_back("try"); keywords.push_back("except"); } return keywords; } ConfigIdentifier::ConfigIdentifier(const String& identifier) : m_Name(identifier) { } String ConfigIdentifier::GetName(void) const { return m_Name; } icinga2-2.8.1/lib/base/configwriter.hpp000066400000000000000000000063621322762156600177520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGWRITER_H #define CONFIGWRITER_H #include "base/object.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include namespace icinga { /** * A config identifier. * * @ingroup base */ class I2_BASE_API ConfigIdentifier : public Object { public: DECLARE_PTR_TYPEDEFS(ConfigIdentifier); ConfigIdentifier(const String& name); String GetName(void) const; private: String m_Name; }; /** * A configuration writer. * * @ingroup base */ class I2_BASE_API ConfigWriter { public: static void EmitBoolean(std::ostream& fp, bool val); static void EmitNumber(std::ostream& fp, double val); static void EmitString(std::ostream& fp, const String& val); static void EmitEmpty(std::ostream& fp); static void EmitArray(std::ostream& fp, int indentLevel, const Array::Ptr& val); static void EmitArrayItems(std::ostream& fp, int indentLevel, const Array::Ptr& val); static void EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports = Array::Ptr(), bool splitDot = false); static void EmitValue(std::ostream& fp, int indentLevel, const Value& val); static void EmitRaw(std::ostream& fp, const String& val); static void EmitIndent(std::ostream& fp, int indentLevel); static void EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment); static void EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate, bool ignoreOnError, const Array::Ptr& imports, const Dictionary::Ptr& attrs); static void EmitComment(std::ostream& fp, const String& text); static void EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments); static const std::vector& GetKeywords(void); private: static String EscapeIcingaString(const String& str); ConfigWriter(void); }; } #endif /* CONFIGWRITER_H */ icinga2-2.8.1/lib/base/console.cpp000066400000000000000000000133261322762156600167030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/console.hpp" #include "base/initialize.hpp" #include using namespace icinga; static ConsoleType l_ConsoleType = Console_Dumb; static void InitializeConsole(void) { l_ConsoleType = Console_Dumb; #ifndef _WIN32 if (isatty(1)) l_ConsoleType = Console_VT100; #else /* _WIN32 */ l_ConsoleType = Console_Windows; #endif /* _WIN32 */ } INITIALIZE_ONCE(InitializeConsole); ConsoleColorTag::ConsoleColorTag(int color, ConsoleType consoleType) : m_Color(color), m_ConsoleType(consoleType) { } std::ostream& icinga::operator<<(std::ostream& fp, const ConsoleColorTag& cct) { #ifndef _WIN32 if (cct.m_ConsoleType == Console_VT100 || Console::GetType(fp) == Console_VT100) Console::PrintVT100ColorCode(fp, cct.m_Color); #else /* _WIN32 */ if (Console::GetType(fp) == Console_Windows) { fp.flush(); Console::SetWindowsConsoleColor(fp, cct.m_Color); } #endif /* _WIN32 */ return fp; } void Console::SetType(std::ostream& fp, ConsoleType type) { if (&fp == &std::cout || &fp == &std::cerr) l_ConsoleType = type; } ConsoleType Console::GetType(std::ostream& fp) { if (&fp == &std::cout || &fp == &std::cerr) return l_ConsoleType; else return Console_Dumb; } #ifndef _WIN32 void Console::PrintVT100ColorCode(std::ostream& fp, int color) { if (color == Console_Normal) { fp << "\33[0m"; return; } switch (color & 0xff) { case Console_ForegroundBlack: fp << "\33[30m"; break; case Console_ForegroundRed: fp << "\33[31m"; break; case Console_ForegroundGreen: fp << "\33[32m"; break; case Console_ForegroundYellow: fp << "\33[33m"; break; case Console_ForegroundBlue: fp << "\33[34m"; break; case Console_ForegroundMagenta: fp << "\33[35m"; break; case Console_ForegroundCyan: fp << "\33[36m"; break; case Console_ForegroundWhite: fp << "\33[37m"; break; } switch (color & 0xff00) { case Console_BackgroundBlack: fp << "\33[40m"; break; case Console_BackgroundRed: fp << "\33[41m"; break; case Console_BackgroundGreen: fp << "\33[42m"; break; case Console_BackgroundYellow: fp << "\33[43m"; break; case Console_BackgroundBlue: fp << "\33[44m"; break; case Console_BackgroundMagenta: fp << "\33[45m"; break; case Console_BackgroundCyan: fp << "\33[46m"; break; case Console_BackgroundWhite: fp << "\33[47m"; break; } if (color & Console_Bold) fp << "\33[1m"; } #else /* _WIN32 */ void Console::SetWindowsConsoleColor(std::ostream& fp, int color) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; HANDLE hConsole; if (&fp == &std::cout) hConsole = GetStdHandle(STD_OUTPUT_HANDLE); else if (&fp == &std::cerr) hConsole = GetStdHandle(STD_ERROR_HANDLE); else return; if (!GetConsoleScreenBufferInfo(hConsole, &consoleInfo)) return; WORD attrs = 0; if (color == Console_Normal) attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; switch (color & 0xff) { case Console_ForegroundBlack: attrs |= 0; break; case Console_ForegroundRed: attrs |= FOREGROUND_RED; break; case Console_ForegroundGreen: attrs |= FOREGROUND_GREEN; break; case Console_ForegroundYellow: attrs |= FOREGROUND_RED | FOREGROUND_GREEN; break; case Console_ForegroundBlue: attrs |= FOREGROUND_BLUE; break; case Console_ForegroundMagenta: attrs |= FOREGROUND_RED | FOREGROUND_BLUE; break; case Console_ForegroundCyan: attrs |= FOREGROUND_GREEN | FOREGROUND_BLUE; break; case Console_ForegroundWhite: attrs |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; } switch (color & 0xff00) { case Console_BackgroundBlack: attrs |= 0; break; case Console_BackgroundRed: attrs |= BACKGROUND_RED; break; case Console_BackgroundGreen: attrs |= BACKGROUND_GREEN; break; case Console_BackgroundYellow: attrs |= BACKGROUND_RED | BACKGROUND_GREEN; break; case Console_BackgroundBlue: attrs |= BACKGROUND_BLUE; break; case Console_BackgroundMagenta: attrs |= BACKGROUND_RED | BACKGROUND_BLUE; break; case Console_BackgroundCyan: attrs |= BACKGROUND_GREEN | BACKGROUND_BLUE; break; case Console_BackgroundWhite: attrs |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break; } if (color & Console_Bold) attrs |= FOREGROUND_INTENSITY; SetConsoleTextAttribute(hConsole, attrs); } #endif /* _WIN32 */ icinga2-2.8.1/lib/base/console.hpp000066400000000000000000000061021322762156600167020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONSOLE_H #define CONSOLE_H #include "base/i2-base.hpp" #include namespace icinga { enum ConsoleColor { Console_Normal, // bit 0-7: foreground Console_ForegroundBlack = 1, Console_ForegroundRed = 2, Console_ForegroundGreen = 3, Console_ForegroundYellow = 4, Console_ForegroundBlue = 5, Console_ForegroundMagenta = 6, Console_ForegroundCyan = 7, Console_ForegroundWhite = 8, // bit 8-15: background Console_BackgroundBlack = 256, Console_BackgroundRed = 266, Console_BackgroundGreen = 267, Console_BackgroundYellow = 268, Console_BackgroundBlue = 269, Console_BackgroundMagenta = 270, Console_BackgroundCyan = 271, Console_BackgroundWhite = 272, // bit 16-23: flags Console_Bold = 65536 }; enum ConsoleType { Console_Autodetect = -1, Console_Dumb, #ifndef _WIN32 Console_VT100, #else /* _WIN32 */ Console_Windows, #endif /* _WIN32 */ }; class I2_BASE_API ConsoleColorTag { public: ConsoleColorTag(int color, ConsoleType consoleType = Console_Autodetect); friend I2_BASE_API std::ostream& operator<<(std::ostream& fp, const ConsoleColorTag& cct); private: int m_Color; int m_ConsoleType; }; I2_BASE_API std::ostream& operator<<(std::ostream& fp, const ConsoleColorTag& cct); /** * Console utilities. * * @ingroup base */ class I2_BASE_API Console { public: static void DetectType(void); static void SetType(std::ostream& fp, ConsoleType type); static ConsoleType GetType(std::ostream& fp); #ifndef _WIN32 static void PrintVT100ColorCode(std::ostream& fp, int color); #else /* _WIN32 */ static void SetWindowsConsoleColor(std::ostream& fp, int color); #endif /* _WIN32 */ private: Console(void); }; } #endif /* CONSOLE_H */ icinga2-2.8.1/lib/base/context.cpp000066400000000000000000000045221322762156600167230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/context.hpp" #include using namespace icinga; static boost::thread_specific_ptr > l_Frames; ContextFrame::ContextFrame(const String& message) { GetFrames().push_front(message); } ContextFrame::~ContextFrame(void) { GetFrames().pop_front(); } std::list& ContextFrame::GetFrames(void) { if (l_Frames.get() == NULL) l_Frames.reset(new std::list()); return *l_Frames; } ContextTrace::ContextTrace(void) : m_Frames(ContextFrame::GetFrames()) { } void ContextTrace::Print(std::ostream& fp) const { if (m_Frames.empty()) return; fp << std::endl; int i = 0; for (const String& frame : m_Frames) { fp << "\t(" << i << ") " << frame << std::endl; i++; } } size_t ContextTrace::GetLength(void) const { return m_Frames.size(); } std::ostream& icinga::operator<<(std::ostream& stream, const ContextTrace& trace) { trace.Print(stream); return stream; } icinga2-2.8.1/lib/base/context.hpp000066400000000000000000000043731322762156600167340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONTEXT_H #define CONTEXT_H #include "base/i2-base.hpp" #include "base/string.hpp" #include namespace icinga { class I2_BASE_API ContextTrace { public: ContextTrace(void); void Print(std::ostream& fp) const; size_t GetLength(void) const; private: std::list m_Frames; }; I2_BASE_API std::ostream& operator<<(std::ostream& stream, const ContextTrace& trace); /** * A context frame. * * @ingroup base */ class I2_BASE_API ContextFrame { public: ContextFrame(const String& message); ~ContextFrame(void); private: static std::list& GetFrames(void); friend class ContextTrace; }; /* The currentContextFrame variable has to be volatile in order to prevent * the compiler from optimizing it away. */ #define CONTEXT(message) volatile icinga::ContextFrame currentContextFrame(message) } #endif /* CONTEXT_H */ icinga2-2.8.1/lib/base/convert.cpp000066400000000000000000000043431322762156600167200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/convert.hpp" #include "base/datetime.hpp" #include using namespace icinga; String Convert::ToString(const String& val) { return val; } String Convert::ToString(const Value& val) { return val; } String Convert::ToString(double val) { double integral; double fractional = std::modf(val, &integral); if (fractional == 0) return Convert::ToString(static_cast(val)); std::ostringstream msgbuf; msgbuf << std::fixed << val; return msgbuf.str(); } double Convert::ToDateTimeValue(double val) { return val; } double Convert::ToDateTimeValue(const Value& val) { if (val.IsNumber()) return val; else if (val.IsObjectType()) return static_cast(val)->GetValue(); else BOOST_THROW_EXCEPTION(std::invalid_argument("Not a DateTime value.")); } icinga2-2.8.1/lib/base/convert.hpp000066400000000000000000000055551322762156600167330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONVERT_H #define CONVERT_H #include "base/i2-base.hpp" #include "base/value.hpp" #include namespace icinga { /** * Utility class for converting types. * * @ingroup base */ class I2_BASE_API Convert { public: template static long ToLong(const T& val) { try { return boost::lexical_cast(val); } catch (const std::exception&) { std::ostringstream msgbuf; msgbuf << "Can't convert '" << val << "' to an integer."; BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); } } template static double ToDouble(const T& val) { try { return boost::lexical_cast(val); } catch (const std::exception&) { std::ostringstream msgbuf; msgbuf << "Can't convert '" << val << "' to a floating point number."; BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); } } static inline long ToLong(const Value& val) { return val; } static inline double ToDouble(const Value& val) { return val; } static inline bool ToBool(const Value& val) { return val.ToBool(); } template static String ToString(const T& val) { return boost::lexical_cast(val); } static String ToString(const String& val); static String ToString(const Value& val); static String ToString(double val); static double ToDateTimeValue(double val); static double ToDateTimeValue(const Value& val); private: Convert(void); }; } #endif /* CONVERT_H */ icinga2-2.8.1/lib/base/datetime-script.cpp000066400000000000000000000040541322762156600203350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/datetime.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/objectlock.hpp" using namespace icinga; static String DateTimeFormat(const String& format) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); DateTime::Ptr self = static_cast(vframe->Self); return self->Format(format); } Object::Ptr DateTime::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("format", new Function("DateTime#format", WrapFunction(DateTimeFormat), { "format" })); } return prototype; } icinga2-2.8.1/lib/base/datetime.cpp000066400000000000000000000050721322762156600170340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/datetime.hpp" #include "base/datetime.tcpp" #include "base/utility.hpp" #include "base/primitivetype.hpp" using namespace icinga; REGISTER_TYPE_WITH_PROTOTYPE(DateTime, DateTime::GetPrototype()); DateTime::DateTime(double value) : m_Value(value) { } DateTime::DateTime(const std::vector& args) { if (args.empty()) m_Value = Utility::GetTime(); else if (args.size() == 3 || args.size() == 6) { struct tm tms; tms.tm_year = args[0] - 1900; tms.tm_mon = args[1] - 1; tms.tm_mday = args[2]; if (args.size() == 6) { tms.tm_hour = args[3]; tms.tm_min = args[4]; tms.tm_sec = args[5]; } else { tms.tm_hour = 0; tms.tm_min = 0; tms.tm_sec = 0; } tms.tm_isdst = -1; m_Value = mktime(&tms); } else if (args.size() == 1) m_Value = args[0]; else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid number of arguments for the DateTime constructor.")); } double DateTime::GetValue(void) const { return m_Value; } String DateTime::Format(const String& format) const { return Utility::FormatDateTime(format.CStr(), m_Value); } String DateTime::ToString(void) const { return Format("%Y-%m-%d %H:%M:%S %z"); } icinga2-2.8.1/lib/base/datetime.hpp000066400000000000000000000040101322762156600170300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DATETIME_H #define DATETIME_H #include "base/i2-base.hpp" #include "base/datetime.thpp" #include "base/value.hpp" #include namespace icinga { /** * A date/time value. * * @ingroup base */ class I2_BASE_API DateTime : public ObjectImpl { public: DECLARE_OBJECT(DateTime); DateTime(double value); DateTime(const std::vector& args); String Format(const String& format) const; virtual double GetValue(void) const override; virtual String ToString(void) const override; static Object::Ptr GetPrototype(void); private: double m_Value; }; } #endif /* DATETIME_H */ icinga2-2.8.1/lib/base/datetime.ti000066400000000000000000000030411322762156600166600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ library base; namespace icinga { vararg_constructor class DateTime { [state, no_storage] Timestamp value { get; }; }; } icinga2-2.8.1/lib/base/debug.hpp000066400000000000000000000051211322762156600163260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DEBUG_H #define DEBUG_H #include "i2-base.hpp" #ifndef I2_DEBUG # define ASSERT(expr) ((void)0) #else /* I2_DEBUG */ # define ASSERT(expr) ((expr) ? 0 : icinga_assert_fail(#expr, __FILE__, __LINE__)) #endif /* I2_DEBUG */ #define VERIFY(expr) ((expr) ? 0 : icinga_assert_fail(#expr, __FILE__, __LINE__)) #ifdef _MSC_VER # define NORETURNPRE __declspec(noreturn) #else /* _MSC_VER */ # define NORETURNPRE #endif /* _MSC_VER */ #ifdef __GNUC__ # define NORETURNPOST __attribute__((noreturn)) #else /* __GNUC__ */ # define NORETURNPOST #endif /* __GNUC__ */ NORETURNPRE int icinga_assert_fail(const char *expr, const char *file, int line) NORETURNPOST; #ifdef _MSC_VER # pragma warning( push ) # pragma warning( disable : 4646 ) /* function declared with __declspec(noreturn) has non-void return type */ #endif /* _MSC_VER */ inline int icinga_assert_fail(const char *expr, const char *file, int line) { fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, expr); std::abort(); #if !defined(__GNUC__) && !defined(_MSC_VER) return 0; #endif /* !defined(__GNUC__) && !defined(_MSC_VER) */ } #ifdef _MSC_VER # pragma warning( pop ) #endif /* _MSC_VER */ #endif /* DEBUG_H */ icinga2-2.8.1/lib/base/debuginfo.cpp000066400000000000000000000066621322762156600172100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/debuginfo.hpp" #include "base/convert.hpp" #include using namespace icinga; DebugInfo::DebugInfo(void) : FirstLine(0), FirstColumn(0), LastLine(0), LastColumn(0) { } /** * Outputs a DebugInfo struct to a stream. * * @param out The output stream. * @param val The DebugInfo struct. * @returns The output stream. */ std::ostream& icinga::operator<<(std::ostream& out, const DebugInfo& val) { out << "in " << val.Path << ": " << val.FirstLine << ":" << val.FirstColumn << "-" << val.LastLine << ":" << val.LastColumn; return out; } DebugInfo icinga::DebugInfoRange(const DebugInfo& start, const DebugInfo& end) { DebugInfo result; result.Path = start.Path; result.FirstLine = start.FirstLine; result.FirstColumn = start.FirstColumn; result.LastLine = end.LastLine; result.LastColumn = end.LastColumn; return result; } #define EXTRA_LINES 2 void icinga::ShowCodeLocation(std::ostream& out, const DebugInfo& di, bool verbose) { if (di.Path.IsEmpty()) return; out << "Location: " << di; std::ifstream ifs; ifs.open(di.Path.CStr(), std::ifstream::in); int lineno = 0; char line[1024]; while (ifs.good() && lineno <= di.LastLine + EXTRA_LINES) { if (lineno == 0) out << "\n"; lineno++; ifs.getline(line, sizeof(line)); for (int i = 0; line[i]; i++) if (line[i] == '\t') line[i] = ' '; int extra_lines = verbose ? EXTRA_LINES : 0; if (lineno < di.FirstLine - extra_lines || lineno > di.LastLine + extra_lines) continue; String pathInfo = di.Path + "(" + Convert::ToString(lineno) + "): "; out << pathInfo; out << line << "\n"; if (lineno >= di.FirstLine && lineno <= di.LastLine) { int start, end; start = 0; end = strlen(line); if (lineno == di.FirstLine) start = di.FirstColumn - 1; if (lineno == di.LastLine) end = di.LastColumn; if (start < 0) { end -= start; start = 0; } out << String(pathInfo.GetLength(), ' '); out << String(start, ' '); out << String(end - start, '^'); out << "\n"; } } } icinga2-2.8.1/lib/base/debuginfo.hpp000066400000000000000000000040211322762156600172000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DEBUGINFO_H #define DEBUGINFO_H #include "base/i2-base.hpp" #include "base/string.hpp" namespace icinga { /** * Debug information for a configuration element. * * @ingroup config */ struct I2_BASE_API DebugInfo { String Path; int FirstLine; int FirstColumn; int LastLine; int LastColumn; DebugInfo(void); }; I2_BASE_API std::ostream& operator<<(std::ostream& out, const DebugInfo& val); I2_BASE_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end); I2_BASE_API void ShowCodeLocation(std::ostream& out, const DebugInfo& di, bool verbose = true); } #endif /* DEBUGINFO_H */ icinga2-2.8.1/lib/base/dependencygraph.cpp000066400000000000000000000046611322762156600204030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dependencygraph.hpp" using namespace icinga; boost::mutex DependencyGraph::m_Mutex; std::map > DependencyGraph::m_Dependencies; void DependencyGraph::AddDependency(Object *parent, Object *child) { boost::mutex::scoped_lock lock(m_Mutex); m_Dependencies[child][parent]++; } void DependencyGraph::RemoveDependency(Object *parent, Object *child) { boost::mutex::scoped_lock lock(m_Mutex); auto& refs = m_Dependencies[child]; auto it = refs.find(parent); if (it == refs.end()) return; it->second--; if (it->second == 0) refs.erase(it); if (refs.empty()) m_Dependencies.erase(child); } std::vector DependencyGraph::GetParents(const Object::Ptr& child) { std::vector objects; boost::mutex::scoped_lock lock(m_Mutex); auto it = m_Dependencies.find(child.get()); if (it != m_Dependencies.end()) { typedef std::pair kv_pair; for (const kv_pair& kv : it->second) { objects.push_back(kv.first); } } return objects; } icinga2-2.8.1/lib/base/dependencygraph.hpp000066400000000000000000000040331322762156600204010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DEPENDENCYGRAPH_H #define DEPENDENCYGRAPH_H #include "base/i2-base.hpp" #include "base/object.hpp" #include namespace icinga { /** * A graph that tracks dependencies between objects. * * @ingroup base */ class I2_BASE_API DependencyGraph { public: static void AddDependency(Object *parent, Object *child); static void RemoveDependency(Object *parent, Object *child); static std::vector GetParents(const Object::Ptr& child); private: DependencyGraph(void); static boost::mutex m_Mutex; static std::map > m_Dependencies; }; } #endif /* DEPENDENCYGRAPH_H */ icinga2-2.8.1/lib/base/dictionary-script.cpp000066400000000000000000000105621322762156600207070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/array.hpp" using namespace icinga; static double DictionaryLen(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); return self->GetLength(); } static void DictionarySet(const String& key, const Value& value) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); self->Set(key, value); } static Value DictionaryGet(const String& key) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); return self->Get(key); } static void DictionaryRemove(const String& key) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); self->Remove(key); } static bool DictionaryContains(const String& key) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); return self->Contains(key); } static Dictionary::Ptr DictionaryShallowClone(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); return self->ShallowClone(); } static Array::Ptr DictionaryKeys(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); Array::Ptr keys = new Array(); ObjectLock olock(self); for (const Dictionary::Pair& kv : self) { keys->Add(kv.first); } return keys; } static Array::Ptr DictionaryValues(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Dictionary::Ptr self = static_cast(vframe->Self); Array::Ptr keys = new Array(); ObjectLock olock(self); for (const Dictionary::Pair& kv : self) { keys->Add(kv.second); } return keys; } Object::Ptr Dictionary::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("len", new Function("Dictionary#len", WrapFunction(DictionaryLen), {}, true)); prototype->Set("set", new Function("Dictionary#set", WrapFunction(DictionarySet), { "key", "value" })); prototype->Set("get", new Function("Dictionary#get", WrapFunction(DictionaryGet), { "key" })); prototype->Set("remove", new Function("Dictionary#remove", WrapFunction(DictionaryRemove), { "key" })); prototype->Set("contains", new Function("Dictionary#contains", WrapFunction(DictionaryContains), { "key" }, true)); prototype->Set("shallow_clone", new Function("Dictionary#shallow_clone", WrapFunction(DictionaryShallowClone), {}, true)); prototype->Set("keys", new Function("Dictionary#keys", WrapFunction(DictionaryKeys), {}, true)); prototype->Set("values", new Function("Dictionary#values", WrapFunction(DictionaryValues), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/dictionary.cpp000066400000000000000000000126421322762156600174060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/objectlock.hpp" #include "base/debug.hpp" #include "base/primitivetype.hpp" #include "base/configwriter.hpp" using namespace icinga; REGISTER_PRIMITIVE_TYPE(Dictionary, Object, Dictionary::GetPrototype()); /** * Retrieves a value from a dictionary. * * @param key The key whose value should be retrieved. * @returns The value of an empty value if the key was not found. */ Value Dictionary::Get(const String& key) const { ObjectLock olock(this); auto it = m_Data.find(key); if (it == m_Data.end()) return Empty; return it->second; } /** * Retrieves a value from a dictionary. * * @param key The key whose value should be retrieved. * @param result The value of the dictionary item (only set when the key exists) * @returns true if the key exists, false otherwise. */ bool Dictionary::Get(const String& key, Value *result) const { ObjectLock olock(this); auto it = m_Data.find(key); if (it == m_Data.end()) return false; *result = it->second; return true; } /** * Sets a value in the dictionary. * * @param key The key. * @param value The value. */ void Dictionary::Set(const String& key, const Value& value) { ObjectLock olock(this); m_Data[key] = value; } /** * Sets a value in the dictionary. * * @param key The key. * @param value The value. */ void Dictionary::Set(const String& key, Value&& value) { ObjectLock olock(this); m_Data[key] = std::move(value); } /** * Returns the number of elements in the dictionary. * * @returns Number of elements. */ size_t Dictionary::GetLength(void) const { ObjectLock olock(this); return m_Data.size(); } /** * Checks whether the dictionary contains the specified key. * * @param key The key. * @returns true if the dictionary contains the key, false otherwise. */ bool Dictionary::Contains(const String& key) const { ObjectLock olock(this); return (m_Data.find(key) != m_Data.end()); } /** * Removes the specified key from the dictionary. * * @param key The key. */ void Dictionary::Remove(const String& key) { ObjectLock olock(this); Dictionary::Iterator it; it = m_Data.find(key); if (it == m_Data.end()) return; m_Data.erase(it); } /** * Removes all dictionary items. */ void Dictionary::Clear(void) { ObjectLock olock(this); m_Data.clear(); } void Dictionary::CopyTo(const Dictionary::Ptr& dest) const { ObjectLock olock(this); for (const Dictionary::Pair& kv : m_Data) { dest->Set(kv.first, kv.second); } } /** * Makes a shallow copy of a dictionary. * * @returns a copy of the dictionary. */ Dictionary::Ptr Dictionary::ShallowClone(void) const { Dictionary::Ptr clone = new Dictionary(); CopyTo(clone); return clone; } /** * Makes a deep clone of a dictionary * and its elements. * * @returns a copy of the dictionary. */ Object::Ptr Dictionary::Clone(void) const { Dictionary::Ptr dict = new Dictionary(); ObjectLock olock(this); for (const Dictionary::Pair& kv : m_Data) { dict->Set(kv.first, kv.second.Clone()); } return dict; } /** * Returns an array containing all keys * which are currently set in this directory. * * @returns an array of key names */ std::vector Dictionary::GetKeys(void) const { ObjectLock olock(this); std::vector keys; for (const Dictionary::Pair& kv : m_Data) { keys.push_back(kv.first); } return keys; } String Dictionary::ToString(void) const { std::ostringstream msgbuf; ConfigWriter::EmitScope(msgbuf, 1, const_cast(this)); return msgbuf.str(); } Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const { Value value; if (Get(field, &value)) return value; else return GetPrototypeField(const_cast(this), field, false, debugInfo); } void Dictionary::SetFieldByName(const String& field, const Value& value, const DebugInfo&) { Set(field, value); } bool Dictionary::HasOwnField(const String& field) const { return Contains(field); } bool Dictionary::GetOwnField(const String& field, Value *result) const { return Get(field, result); } icinga2-2.8.1/lib/base/dictionary.hpp000066400000000000000000000076711322762156600174210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DICTIONARY_H #define DICTIONARY_H #include "base/i2-base.hpp" #include "base/object.hpp" #include "base/value.hpp" #include #include #include namespace icinga { /** * A container that holds key-value pairs. * * @ingroup base */ class I2_BASE_API Dictionary : public Object { public: DECLARE_OBJECT(Dictionary); /** * An iterator that can be used to iterate over dictionary elements. */ typedef std::map::iterator Iterator; typedef std::map::size_type SizeType; typedef std::map::value_type Pair; inline Dictionary(void) { } inline ~Dictionary(void) { } Value Get(const String& key) const; bool Get(const String& key, Value *result) const; void Set(const String& key, const Value& value); void Set(const String& key, Value&& value); bool Contains(const String& key) const; /** * Returns an iterator to the beginning of the dictionary. * * Note: Caller must hold the object lock while using the iterator. * * @returns An iterator. */ inline Iterator Begin(void) { ASSERT(OwnsLock()); return m_Data.begin(); } /** * Returns an iterator to the end of the dictionary. * * Note: Caller must hold the object lock while using the iterator. * * @returns An iterator. */ inline Iterator End(void) { ASSERT(OwnsLock()); return m_Data.end(); } size_t GetLength(void) const; void Remove(const String& key); /** * Removes the item specified by the iterator from the dictionary. * * @param it The iterator. */ inline void Remove(Iterator it) { ASSERT(OwnsLock()); m_Data.erase(it); } void Clear(void); void CopyTo(const Dictionary::Ptr& dest) const; Dictionary::Ptr ShallowClone(void) const; std::vector GetKeys(void) const; static Object::Ptr GetPrototype(void); virtual Object::Ptr Clone(void) const override; virtual String ToString(void) const override; virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; virtual void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; virtual bool HasOwnField(const String& field) const override; virtual bool GetOwnField(const String& field, Value *result) const override; private: std::map m_Data; /**< The data for the dictionary. */ }; inline Dictionary::Iterator begin(Dictionary::Ptr x) { return x->Begin(); } inline Dictionary::Iterator end(Dictionary::Ptr x) { return x->End(); } } #endif /* DICTIONARY_H */ icinga2-2.8.1/lib/base/exception.cpp000066400000000000000000000252631322762156600172420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/exception.hpp" #ifdef HAVE_CXXABI_H # include #endif /* HAVE_CXXABI_H */ using namespace icinga; static boost::thread_specific_ptr l_LastExceptionStack; static boost::thread_specific_ptr l_LastExceptionContext; #ifdef HAVE_CXXABI_H #ifdef _LIBCPPABI_VERSION class libcxx_type_info : public std::type_info { public: virtual ~libcxx_type_info(); virtual void noop1() const; virtual void noop2() const; virtual bool can_catch(const libcxx_type_info *thrown_type, void *&adjustedPtr) const = 0; }; #endif /* _LIBCPPABI_VERSION */ #if defined(__GLIBCXX__) || defined(_LIBCPPABI_VERSION) inline void *cast_exception(void *obj, const std::type_info *src, const std::type_info *dst) { #ifdef __GLIBCXX__ void *thrown_ptr = obj; /* Check if the exception is a pointer type. */ if (src->__is_pointer_p()) thrown_ptr = *(void **)thrown_ptr; if (dst->__do_catch(src, &thrown_ptr, 1)) return thrown_ptr; else return NULL; #else /* __GLIBCXX__ */ const libcxx_type_info *srcInfo = static_cast(src); const libcxx_type_info *dstInfo = static_cast(dst); void *adj = obj; if (dstInfo->can_catch(srcInfo, adj)) return adj; else return NULL; #endif /* __GLIBCXX__ */ } #else /* defined(__GLIBCXX__) || defined(_LIBCPPABI_VERSION) */ #define NO_CAST_EXCEPTION #endif /* defined(__GLIBCXX__) || defined(_LIBCPPABI_VERSION) */ # if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ > 3) # define TYPEINFO_TYPE std::type_info # else # define TYPEINFO_TYPE void # endif # if !defined(__GLIBCXX__) && !defined(_WIN32) static boost::thread_specific_ptr l_LastExceptionObj; static boost::thread_specific_ptr l_LastExceptionPvtInfo; typedef void (*DestCallback)(void *); static boost::thread_specific_ptr l_LastExceptionDest; # endif /* !__GLIBCXX__ && !_WIN32 */ extern "C" I2_EXPORT void __cxa_throw(void *obj, TYPEINFO_TYPE *pvtinfo, void (*dest)(void *)); #endif /* HAVE_CXXABI_H */ void icinga::RethrowUncaughtException(void) { #if defined(__GLIBCXX__) || !defined(HAVE_CXXABI_H) throw; #else /* __GLIBCXX__ || !HAVE_CXXABI_H */ __cxa_throw(*l_LastExceptionObj.get(), *l_LastExceptionPvtInfo.get(), *l_LastExceptionDest.get()); #endif /* __GLIBCXX__ || !HAVE_CXXABI_H */ } #ifdef HAVE_CXXABI_H extern "C" void __cxa_throw(void *obj, TYPEINFO_TYPE *pvtinfo, void (*dest)(void *)) { std::type_info *tinfo = static_cast(pvtinfo); typedef void (*cxa_throw_fn)(void *, std::type_info *, void (*)(void *)) __attribute__((noreturn)); static cxa_throw_fn real_cxa_throw; #if !defined(__GLIBCXX__) && !defined(_WIN32) l_LastExceptionObj.reset(new void *(obj)); l_LastExceptionPvtInfo.reset(new TYPEINFO_TYPE *(pvtinfo)); l_LastExceptionDest.reset(new DestCallback(dest)); #endif /* !defined(__GLIBCXX__) && !defined(_WIN32) */ if (real_cxa_throw == 0) real_cxa_throw = (cxa_throw_fn)dlsym(RTLD_NEXT, "__cxa_throw"); #ifndef NO_CAST_EXCEPTION void *uex = cast_exception(obj, tinfo, &typeid(user_error)); boost::exception *ex = reinterpret_cast(cast_exception(obj, tinfo, &typeid(boost::exception))); if (!uex) { #endif /* NO_CAST_EXCEPTION */ StackTrace stack; SetLastExceptionStack(stack); #ifndef NO_CAST_EXCEPTION if (ex && boost::get_error_info(*ex) == NULL) *ex << StackTraceErrorInfo(stack); } #endif /* NO_CAST_EXCEPTION */ ContextTrace context; SetLastExceptionContext(context); #ifndef NO_CAST_EXCEPTION if (ex && boost::get_error_info(*ex) == NULL) *ex << ContextTraceErrorInfo(context); #endif /* NO_CAST_EXCEPTION */ real_cxa_throw(obj, tinfo, dest); } #endif /* HAVE_CXXABI_H */ StackTrace *icinga::GetLastExceptionStack(void) { return l_LastExceptionStack.get(); } void icinga::SetLastExceptionStack(const StackTrace& trace) { l_LastExceptionStack.reset(new StackTrace(trace)); } ContextTrace *icinga::GetLastExceptionContext(void) { return l_LastExceptionContext.get(); } void icinga::SetLastExceptionContext(const ContextTrace& context) { l_LastExceptionContext.reset(new ContextTrace(context)); } String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, StackTrace *stack, ContextTrace *context) { std::ostringstream result; String message = ex.what(); const ValidationError *vex = dynamic_cast(&ex); if (message.IsEmpty()) result << boost::diagnostic_information(ex) << "\n"; else result << "Error: " << message << "\n"; const ScriptError *dex = dynamic_cast(&ex); if (dex && !dex->GetDebugInfo().Path.IsEmpty()) ShowCodeLocation(result, dex->GetDebugInfo()); if (vex) { DebugInfo di; ConfigObject::Ptr dobj = vex->GetObject(); if (dobj) di = dobj->GetDebugInfo(); Dictionary::Ptr currentHint = vex->GetDebugHint(); Array::Ptr messages; if (currentHint) { for (const String& attr : vex->GetAttributePath()) { Dictionary::Ptr props = currentHint->Get("properties"); if (!props) break; currentHint = props->Get(attr); if (!currentHint) break; messages = currentHint->Get("messages"); } } if (messages && messages->GetLength() > 0) { Array::Ptr message = messages->Get(messages->GetLength() - 1); di.Path = message->Get(1); di.FirstLine = message->Get(2); di.FirstColumn = message->Get(3); di.LastLine = message->Get(4); di.LastColumn = message->Get(5); } if (!di.Path.IsEmpty()) ShowCodeLocation(result, di); } const user_error *uex = dynamic_cast(&ex); const posix_error *pex = dynamic_cast(&ex); if (!uex && !pex && verbose) { const StackTrace *st = boost::get_error_info(ex); if (st) { result << *st; } else { result << std::endl; if (!stack) stack = GetLastExceptionStack(); if (stack) result << *stack; } } const ContextTrace *ct = boost::get_error_info(ex); if (ct) { result << *ct; } else { result << std::endl; if (!context) context = GetLastExceptionContext(); if (context) result << *context; } return result.str(); } String icinga::DiagnosticInformation(boost::exception_ptr eptr, bool verbose) { StackTrace *pt = GetLastExceptionStack(); StackTrace stack; ContextTrace *pc = GetLastExceptionContext(); ContextTrace context; if (pt) stack = *pt; if (pc) context = *pc; try { boost::rethrow_exception(eptr); } catch (const std::exception& ex) { return DiagnosticInformation(ex, verbose, pt ? &stack : NULL, pc ? &context : NULL); } return boost::diagnostic_information(eptr); } ScriptError::ScriptError(const String& message) : m_Message(message), m_IncompleteExpr(false) { } ScriptError::ScriptError(const String& message, const DebugInfo& di, bool incompleteExpr) : m_Message(message), m_DebugInfo(di), m_IncompleteExpr(incompleteExpr), m_HandledByDebugger(false) { } ScriptError::~ScriptError(void) throw() { } const char *ScriptError::what(void) const throw() { return m_Message.CStr(); } DebugInfo ScriptError::GetDebugInfo(void) const { return m_DebugInfo; } bool ScriptError::IsIncompleteExpression(void) const { return m_IncompleteExpr;; } bool ScriptError::IsHandledByDebugger(void) const { return m_HandledByDebugger; } void ScriptError::SetHandledByDebugger(bool handled) { m_HandledByDebugger = handled; } posix_error::posix_error(void) : m_Message(NULL) { } posix_error::~posix_error(void) throw() { free(m_Message); } const char *posix_error::what(void) const throw() { if (!m_Message) { std::ostringstream msgbuf; const char * const *func = boost::get_error_info(*this); if (func) msgbuf << "Function call '" << *func << "'"; else msgbuf << "Function call"; const std::string *fname = boost::get_error_info(*this); if (fname) msgbuf << " for file '" << *fname << "'"; msgbuf << " failed"; const int *errnum = boost::get_error_info(*this); if (errnum) msgbuf << " with error code " << *errnum << ", '" << strerror(*errnum) << "'"; String str = msgbuf.str(); m_Message = strdup(str.CStr()); } return m_Message; } ValidationError::ValidationError(const ConfigObject::Ptr& object, const std::vector& attributePath, const String& message) : m_Object(object), m_AttributePath(attributePath), m_Message(message) { String path; for (const String& attribute : attributePath) { if (!path.IsEmpty()) path += " -> "; path += "'" + attribute + "'"; } Type::Ptr type = object->GetReflectionType(); m_What = "Validation failed for object '" + object->GetName() + "' of type '" + type->GetName() + "'"; if (!path.IsEmpty()) m_What += "; Attribute " + path; m_What += ": " + message; } ValidationError::~ValidationError(void) throw() { } const char *ValidationError::what(void) const throw() { return m_What.CStr(); } ConfigObject::Ptr ValidationError::GetObject(void) const { return m_Object; } std::vector ValidationError::GetAttributePath(void) const { return m_AttributePath; } String ValidationError::GetMessage(void) const { return m_Message; } void ValidationError::SetDebugHint(const Dictionary::Ptr& dhint) { m_DebugHint = dhint; } Dictionary::Ptr ValidationError::GetDebugHint(void) const { return m_DebugHint; } icinga2-2.8.1/lib/base/exception.hpp000066400000000000000000000126051322762156600172430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXCEPTION_H #define EXCEPTION_H #include "base/i2-base.hpp" #include "base/string.hpp" #include "base/stacktrace.hpp" #include "base/context.hpp" #include "base/utility.hpp" #include "base/debuginfo.hpp" #include "base/dictionary.hpp" #include "base/configobject.hpp" #include #include #include #include #include #include #ifdef _WIN32 # include #endif /* _WIN32 */ namespace icinga { class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception { }; /* * @ingroup base */ class I2_BASE_API ScriptError : virtual public user_error { public: ScriptError(const String& message); ScriptError(const String& message, const DebugInfo& di, bool incompleteExpr = false); ~ScriptError(void) throw(); virtual const char *what(void) const throw() override; DebugInfo GetDebugInfo(void) const; bool IsIncompleteExpression(void) const; bool IsHandledByDebugger(void) const; void SetHandledByDebugger(bool handled); private: String m_Message; DebugInfo m_DebugInfo; bool m_IncompleteExpr; bool m_HandledByDebugger; }; /* * @ingroup base */ class I2_BASE_API ValidationError : virtual public user_error { public: ValidationError(const ConfigObject::Ptr& object, const std::vector& attributePath, const String& message); ~ValidationError(void) throw(); virtual const char *what(void) const throw() override; ConfigObject::Ptr GetObject(void) const; std::vector GetAttributePath(void) const; String GetMessage(void) const; void SetDebugHint(const Dictionary::Ptr& dhint); Dictionary::Ptr GetDebugHint(void) const; private: ConfigObject::Ptr m_Object; std::vector m_AttributePath; String m_Message; String m_What; Dictionary::Ptr m_DebugHint; }; I2_BASE_API StackTrace *GetLastExceptionStack(void); I2_BASE_API void SetLastExceptionStack(const StackTrace& trace); I2_BASE_API ContextTrace *GetLastExceptionContext(void); I2_BASE_API void SetLastExceptionContext(const ContextTrace& context); I2_BASE_API void RethrowUncaughtException(void); typedef boost::error_info StackTraceErrorInfo; inline std::string to_string(const StackTraceErrorInfo&) { return ""; } typedef boost::error_info ContextTraceErrorInfo; inline std::string to_string(const ContextTraceErrorInfo& e) { std::ostringstream msgbuf; msgbuf << "[Context] = " << e.value(); return msgbuf.str(); } I2_BASE_API String DiagnosticInformation(const std::exception& ex, bool verbose = true, StackTrace *stack = NULL, ContextTrace *context = NULL); I2_BASE_API String DiagnosticInformation(boost::exception_ptr eptr, bool verbose = true); class I2_BASE_API posix_error : virtual public std::exception, virtual public boost::exception { public: posix_error(void); virtual ~posix_error(void) throw(); virtual const char *what(void) const throw() override; private: mutable char *m_Message; }; #ifdef _WIN32 class I2_BASE_API win32_error : virtual public std::exception, virtual public boost::exception { }; struct errinfo_win32_error_; typedef boost::error_info errinfo_win32_error; inline std::string to_string(const errinfo_win32_error& e) { return "[errinfo_win32_error] = " + Utility::FormatErrorNumber(e.value()) + "\n"; } #endif /* _WIN32 */ struct errinfo_getaddrinfo_error_; typedef boost::error_info errinfo_getaddrinfo_error; inline std::string to_string(const errinfo_getaddrinfo_error& e) { String msg; #ifdef _WIN32 msg = gai_strerrorA(e.value()); #else /* _WIN32 */ msg = gai_strerror(e.value()); #endif /* _WIN32 */ return "[errinfo_getaddrinfo_error] = " + String(msg) + "\n"; } struct errinfo_message_; typedef boost::error_info errinfo_message; } #endif /* EXCEPTION_H */ icinga2-2.8.1/lib/base/fifo.cpp000066400000000000000000000071261322762156600161650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/fifo.hpp" using namespace icinga; /** * Constructor for the FIFO class. */ FIFO::FIFO(void) : m_Buffer(NULL), m_DataSize(0), m_AllocSize(0), m_Offset(0) { } /** * Destructor for the FIFO class. */ FIFO::~FIFO(void) { free(m_Buffer); } /** * Resizes the FIFO's buffer so that it is at least newSize bytes long. * * @param newSize The minimum new size of the FIFO buffer. */ void FIFO::ResizeBuffer(size_t newSize, bool decrease) { if (m_AllocSize >= newSize && !decrease) return; newSize = (newSize / FIFO::BlockSize + 1) * FIFO::BlockSize; if (newSize == m_AllocSize) return; char *newBuffer = static_cast(realloc(m_Buffer, newSize)); if (newBuffer == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); m_Buffer = newBuffer; m_AllocSize = newSize; } /** * Optimizes memory usage of the FIFO buffer by reallocating * and moving the buffer. */ void FIFO::Optimize(void) { if (m_Offset > m_DataSize / 10 && m_Offset - m_DataSize > 1024) { std::memmove(m_Buffer, m_Buffer + m_Offset, m_DataSize); m_Offset = 0; if (m_DataSize > 0) ResizeBuffer(m_DataSize, true); return; } } size_t FIFO::Peek(void *buffer, size_t count, bool allow_partial) { ASSERT(allow_partial); if (count > m_DataSize) count = m_DataSize; if (buffer != NULL) std::memcpy(buffer, m_Buffer + m_Offset, count); return count; } /** * Implements IOQueue::Read. */ size_t FIFO::Read(void *buffer, size_t count, bool allow_partial) { ASSERT(allow_partial); if (count > m_DataSize) count = m_DataSize; if (buffer != NULL) std::memcpy(buffer, m_Buffer + m_Offset, count); m_DataSize -= count; m_Offset += count; Optimize(); return count; } /** * Implements IOQueue::Write. */ void FIFO::Write(const void *buffer, size_t count) { ResizeBuffer(m_Offset + m_DataSize + count, false); std::memcpy(m_Buffer + m_Offset + m_DataSize, buffer, count); m_DataSize += count; SignalDataAvailable(); } void FIFO::Close(void) { } bool FIFO::IsEof(void) const { return false; } size_t FIFO::GetAvailableBytes(void) const { return m_DataSize; } bool FIFO::SupportsWaiting(void) const { return true; } bool FIFO::IsDataAvailable(void) const { return m_DataSize > 0; } icinga2-2.8.1/lib/base/fifo.hpp000066400000000000000000000045371322762156600161750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FIFO_H #define FIFO_H #include "base/i2-base.hpp" #include "base/stream.hpp" namespace icinga { /** * A byte-based FIFO buffer. * * @ingroup base */ class I2_BASE_API FIFO : public Stream { public: DECLARE_PTR_TYPEDEFS(FIFO); static const size_t BlockSize = 512; FIFO(void); ~FIFO(void); virtual size_t Peek(void *buffer, size_t count, bool allow_partial = false) override; virtual size_t Read(void *buffer, size_t count, bool allow_partial = false) override; virtual void Write(const void *buffer, size_t count) override; virtual void Close(void) override; virtual bool IsEof(void) const override; virtual bool SupportsWaiting(void) const override; virtual bool IsDataAvailable(void) const override; size_t GetAvailableBytes(void) const; private: char *m_Buffer; size_t m_DataSize; size_t m_AllocSize; size_t m_Offset; void ResizeBuffer(size_t newSize, bool decrease); void Optimize(void); }; } #endif /* FIFO_H */ icinga2-2.8.1/lib/base/filelogger.cpp000066400000000000000000000051561322762156600173620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/filelogger.hpp" #include "base/filelogger.tcpp" #include "base/configtype.hpp" #include "base/statsfunction.hpp" #include "base/application.hpp" #include using namespace icinga; REGISTER_TYPE(FileLogger); REGISTER_STATSFUNCTION(FileLogger, &FileLogger::StatsFunc); void FileLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const FileLogger::Ptr& filelogger : ConfigType::GetObjectsByType()) { nodes->Set(filelogger->GetName(), 1); //add more stats } status->Set("filelogger", nodes); } /** * Constructor for the FileLogger class. */ void FileLogger::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); ReopenLogFile(); Application::OnReopenLogs.connect(boost::bind(&FileLogger::ReopenLogFile, this)); } void FileLogger::ReopenLogFile(void) { std::ofstream *stream = new std::ofstream(); String path = GetPath(); try { stream->open(path.CStr(), std::fstream::app | std::fstream::out); if (!stream->good()) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open logfile '" + path + "'")); } catch (...) { delete stream; throw; } BindStream(stream, true); } icinga2-2.8.1/lib/base/filelogger.hpp000066400000000000000000000036561322762156600173720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FILELOGGER_H #define FILELOGGER_H #include "base/i2-base.hpp" #include "base/filelogger.thpp" namespace icinga { /** * A logger that logs to a file. * * @ingroup base */ class I2_BASE_API FileLogger : public ObjectImpl { public: DECLARE_OBJECT(FileLogger); DECLARE_OBJECTNAME(FileLogger); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void Start(bool runtimeCreated) override; private: void ReopenLogFile(void); }; } #endif /* FILELOGGER_H */ icinga2-2.8.1/lib/base/filelogger.ti000066400000000000000000000030601322762156600172040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/streamlogger.hpp" library base; namespace icinga { class FileLogger : StreamLogger { [config, required] String path; }; } icinga2-2.8.1/lib/base/function-script.cpp000066400000000000000000000052041322762156600203640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" using namespace icinga; static Value FunctionCall(const std::vector& args) { if (args.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for call()")); ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Function::Ptr self = static_cast(vframe->Self); std::vector uargs(args.begin() + 1, args.end()); return self->Invoke(args[0], uargs); } static Value FunctionCallV(const Value& thisArg, const Array::Ptr& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Function::Ptr self = static_cast(vframe->Self); std::vector uargs; { ObjectLock olock(args); uargs = std::vector(args->Begin(), args->End()); } return self->Invoke(thisArg, uargs); } Object::Ptr Function::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("call", new Function("Function#call", WrapFunction(FunctionCall))); prototype->Set("callv", new Function("Function#callv", WrapFunction(FunctionCallV))); } return prototype; } icinga2-2.8.1/lib/base/function.cpp000066400000000000000000000044341322762156600170660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/function.hpp" #include "base/function.tcpp" #include "base/array.hpp" #include "base/scriptframe.hpp" using namespace icinga; REGISTER_TYPE_WITH_PROTOTYPE(Function, Function::GetPrototype()); Function::Function(const String& name, const Callback& function, const std::vector& args, bool side_effect_free, bool deprecated) : m_Callback(function) { SetName(name, true); SetSideEffectFree(side_effect_free, true); SetDeprecated(deprecated, true); SetArguments(Array::FromVector(args), true); } Value Function::Invoke(const std::vector& arguments) { ScriptFrame frame; return m_Callback(arguments); } Value Function::Invoke(const Value& otherThis, const std::vector& arguments) { ScriptFrame frame; frame.Self = otherThis; return m_Callback(arguments); } Object::Ptr Function::Clone(void) const { return const_cast(this); } icinga2-2.8.1/lib/base/function.hpp000066400000000000000000000117451322762156600170760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCRIPTFUNCTION_H #define SCRIPTFUNCTION_H #include "base/i2-base.hpp" #include "base/function.thpp" #include "base/value.hpp" #include "base/functionwrapper.hpp" #include "base/scriptglobal.hpp" #include #include namespace icinga { /** * A script function that can be used to execute a script task. * * @ingroup base */ class I2_BASE_API Function : public ObjectImpl { public: DECLARE_OBJECT(Function); typedef boost::function& arguments)> Callback; Function(const String& name, const Callback& function, const std::vector& args = std::vector(), bool side_effect_free = false, bool deprecated = false); Value Invoke(const std::vector& arguments = std::vector()); Value Invoke(const Value& otherThis, const std::vector& arguments = std::vector()); inline bool IsSideEffectFree(void) const { return GetSideEffectFree(); } inline bool IsDeprecated(void) const { return GetDeprecated(); } static Object::Ptr GetPrototype(void); virtual Object::Ptr Clone(void) const override; private: Callback m_Callback; }; #define REGISTER_SCRIPTFUNCTION_NS(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ }, 10) #define REGISTER_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#__" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), false, true); \ ScriptGlobal::Set("Deprecated.__" #name, dsf); \ }, 10) #define REGISTER_SCRIPTFUNCTION_NS_DEPRECATED(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), false, true); \ ScriptGlobal::Set("Deprecated." #name, dsf); \ }, 10) #define REGISTER_SAFE_SCRIPTFUNCTION_NS(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ }, 10) #define REGISTER_SAFE_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#__" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), true, true); \ ScriptGlobal::Set("Deprecated.__" #name, dsf); \ }, 10) #define REGISTER_SAFE_SCRIPTFUNCTION_NS_DEPRECATED(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), String(args).Split(":"), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("Deprecated#" #name " (deprecated)", WrapFunction(callback), String(args).Split(":"), true, true); \ ScriptGlobal::Set("Deprecated." #name, dsf); \ }, 10) } #endif /* SCRIPTFUNCTION_H */ icinga2-2.8.1/lib/base/function.ti000066400000000000000000000031761322762156600167220ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library base; namespace icinga { abstract class Function { [config] String "name"; [config] bool side_effect_free; [config] bool "deprecated"; [config] Array::Ptr arguments; }; } icinga2-2.8.1/lib/base/functionwrapper.cpp000066400000000000000000000036271322762156600204720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/functionwrapper.hpp" using namespace icinga; Value icinga::FunctionWrapperVV(void (*function)(void), const std::vector&) { function(); return Empty; } Value icinga::FunctionWrapperVA(void (*function)(const std::vector&), const std::vector& arguments) { function(arguments); return Empty; } boost::function& arguments)> icinga::WrapFunction(void (*function)(void)) { return boost::bind(&FunctionWrapperVV, function, _1); } icinga2-2.8.1/lib/base/functionwrapper.hpp000066400000000000000000000374151322762156600205010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCRIPTFUNCTIONWRAPPER_H #define SCRIPTFUNCTIONWRAPPER_H #include "base/i2-base.hpp" #include "base/value.hpp" #include #include #include namespace icinga { Value FunctionWrapperVV(void (*function)(void), const std::vector& arguments); Value FunctionWrapperVA(void (*function)(const std::vector&), const std::vector& arguments); boost::function& arguments)> I2_BASE_API WrapFunction(void (*function)(void)); template Value FunctionWrapperR(TR (*function)(void), const std::vector&) { return function(); } template boost::function& arguments)> WrapFunction(TR (*function)(void)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0), const std::vector& arguments) { if (arguments.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0), const std::vector& arguments) { if (arguments.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1), const std::vector& arguments) { if (arguments.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1), const std::vector& arguments) { if (arguments.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2), const std::vector& arguments) { if (arguments.size() < 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2), const std::vector& arguments) { if (arguments.size() < 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2, T3), const std::vector& arguments) { if (arguments.size() < 4) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 4) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3), const std::vector& arguments) { if (arguments.size() < 4) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 4) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4), const std::vector& arguments) { if (arguments.size() < 5) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 5) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4), const std::vector& arguments) { if (arguments.size() < 5) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 5) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5), const std::vector& arguments) { if (arguments.size() < 6) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 6) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5), const std::vector& arguments) { if (arguments.size() < 6) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 6) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) { if (arguments.size() < 7) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 7) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5]), static_cast(arguments[6])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6), const std::vector& arguments) { if (arguments.size() < 7) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 7) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5]), static_cast(arguments[6])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6)) { return boost::bind(&FunctionWrapperR, function, _1); } template Value FunctionWrapperV(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) { if (arguments.size() < 8) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 8) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5]), static_cast(arguments[6]), static_cast(arguments[7])); return Empty; } template boost::function& arguments)> WrapFunction(void (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) { return boost::bind(&FunctionWrapperV, function, _1); } template Value FunctionWrapperR(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7), const std::vector& arguments) { if (arguments.size() < 8) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); else if (arguments.size() > 8) BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); return function(static_cast(arguments[0]), static_cast(arguments[1]), static_cast(arguments[2]), static_cast(arguments[3]), static_cast(arguments[4]), static_cast(arguments[5]), static_cast(arguments[6]), static_cast(arguments[7])); } template boost::function& arguments)> WrapFunction(TR (*function)(T0, T1, T2, T3, T4, T5, T6, T7)) { return boost::bind(&FunctionWrapperR, function, _1); } template boost::function& arguments)> WrapFunction(TR (*function)(const std::vector&)) { return boost::bind(function, _1); } inline boost::function& arguments)> WrapFunction(void (*function)(const std::vector&)) { return boost::bind(&FunctionWrapperVA, function, _1); } } #endif /* SCRIPTFUNCTION_H */ icinga2-2.8.1/lib/base/i2-base.hpp000066400000000000000000000064471322762156600164760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2BASE_H #define I2BASE_H /** * @mainpage Icinga Documentation * * Icinga implements a framework for run-time-loadable components which can * pass messages between each other. These components can either be hosted in * the same process or in several host processes (either on the same machine or * on different machines). * * The framework's code critically depends on the following patterns: * * * Smart pointers * * The shared_ptr and weak_ptr template classes are used to simplify memory * management and to avoid accidental memory leaks and use-after-free * bugs. * * Observer pattern * * Framework classes expose events which other objects can subscribe to. This * is used to decouple clients of a class from the class' internal * implementation. * */ /** * @defgroup base Base class library * * The base class library implements commonly-used functionality like * event handling for sockets and timers. */ #ifdef _MSC_VER # pragma warning(disable:4251) # pragma warning(disable:4275) # pragma warning(disable:4345) #endif /* _MSC_VER */ #include "config.h" #ifdef _WIN32 # include "base/win32.hpp" #else # include "base/unix.hpp" #endif #include #include #include #include #include #include #include #include #include #include #if defined(__APPLE__) && defined(__MACH__) # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include "base/visibility.hpp" #ifdef I2_BASE_BUILD # define I2_BASE_API I2_EXPORT #else /* I2_BASE_BUILD */ # define I2_BASE_API I2_IMPORT #endif /* I2_BASE_BUILD */ #if defined(__GNUC__) # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) #else # define likely(x) (x) # define unlikely(x) (x) #endif #endif /* I2BASE_H */ icinga2-2.8.1/lib/base/initialize.cpp000066400000000000000000000031761322762156600174040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/initialize.hpp" #include "base/loader.hpp" using namespace icinga; bool icinga::InitializeOnceHelper(void (*func)(void), int priority) { Loader::AddDeferredInitializer(func, priority); return true; } icinga2-2.8.1/lib/base/initialize.hpp000066400000000000000000000037301322762156600174050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef INITIALIZE_H #define INITIALIZE_H #include "base/i2-base.hpp" namespace icinga { I2_BASE_API bool InitializeOnceHelper(void (*func)(void), int priority = 0); #define INITIALIZE_ONCE(func) \ namespace { namespace UNIQUE_NAME(io) { \ I2_EXPORT bool l_InitializeOnce(icinga::InitializeOnceHelper(func)); \ } } #define INITIALIZE_ONCE_WITH_PRIORITY(func, priority) \ namespace { namespace UNIQUE_NAME(io) { \ I2_EXPORT bool l_InitializeOnce(icinga::InitializeOnceHelper(func, priority)); \ } } } #endif /* INITIALIZE_H */ icinga2-2.8.1/lib/base/json-script.cpp000066400000000000000000000040151322762156600175070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/initialize.hpp" #include "base/json.hpp" using namespace icinga; static String JsonEncodeShim(const Value& value) { return JsonEncode(value); } INITIALIZE_ONCE([]() { Dictionary::Ptr jsonObj = new Dictionary(); /* Methods */ jsonObj->Set("encode", new Function("Json#encode", WrapFunction(JsonEncodeShim), { "value" }, true)); jsonObj->Set("decode", new Function("Json#decode", WrapFunction(JsonDecode), { "value" }, true)); ScriptGlobal::Set("Json", jsonObj); }); icinga2-2.8.1/lib/base/json.cpp000066400000000000000000000201101322762156600161770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/json.hpp" #include "base/debug.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include #include #include #include #include using namespace icinga; static void Encode(yajl_gen handle, const Value& value); #if YAJL_MAJOR < 2 typedef unsigned int yajl_size; #else /* YAJL_MAJOR */ typedef size_t yajl_size; #endif /* YAJL_MAJOR */ static void EncodeDictionary(yajl_gen handle, const Dictionary::Ptr& dict) { yajl_gen_map_open(handle); ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { yajl_gen_string(handle, reinterpret_cast(kv.first.CStr()), kv.first.GetLength()); Encode(handle, kv.second); } yajl_gen_map_close(handle); } static void EncodeArray(yajl_gen handle, const Array::Ptr& arr) { yajl_gen_array_open(handle); ObjectLock olock(arr); for (const Value& value : arr) { Encode(handle, value); } yajl_gen_array_close(handle); } static void Encode(yajl_gen handle, const Value& value) { switch (value.GetType()) { case ValueNumber: if (yajl_gen_double(handle, value.Get()) == yajl_gen_invalid_number) yajl_gen_double(handle, 0); break; case ValueBoolean: yajl_gen_bool(handle, value.ToBool()); break; case ValueString: yajl_gen_string(handle, reinterpret_cast(value.Get().CStr()), value.Get().GetLength()); break; case ValueObject: if (value.IsObjectType()) EncodeDictionary(handle, value); else if (value.IsObjectType()) EncodeArray(handle, value); else yajl_gen_null(handle); break; case ValueEmpty: yajl_gen_null(handle); break; default: VERIFY(!"Invalid variant type."); } } String icinga::JsonEncode(const Value& value, bool pretty_print) { #if YAJL_MAJOR < 2 yajl_gen_config conf = { pretty_print, "" }; yajl_gen handle = yajl_gen_alloc(&conf, NULL); #else /* YAJL_MAJOR */ yajl_gen handle = yajl_gen_alloc(NULL); if (pretty_print) yajl_gen_config(handle, yajl_gen_beautify, 1); #endif /* YAJL_MAJOR */ Encode(handle, value); const unsigned char *buf; yajl_size len; yajl_gen_get_buf(handle, &buf, &len); String result = String(buf, buf + len); yajl_gen_free(handle); return result; } struct JsonElement { String Key; bool KeySet; Value EValue; JsonElement(void) : KeySet(false) { } }; struct JsonContext { public: void Push(const Value& value) { JsonElement element; element.EValue = value; m_Stack.push(element); } JsonElement Pop(void) { JsonElement value = m_Stack.top(); m_Stack.pop(); return value; } void AddValue(const Value& value) { if (m_Stack.empty()) { JsonElement element; element.EValue = value; m_Stack.push(element); return; } JsonElement& element = m_Stack.top(); if (element.EValue.IsObjectType()) { if (!element.KeySet) { element.Key = value; element.KeySet = true; } else { Dictionary::Ptr dict = element.EValue; dict->Set(element.Key, value); element.KeySet = false; } } else if (element.EValue.IsObjectType()) { Array::Ptr arr = element.EValue; arr->Add(value); } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot add value to JSON element.")); } } Value GetValue(void) const { ASSERT(m_Stack.size() == 1); return m_Stack.top().EValue; } void SaveException(void) { m_Exception = boost::current_exception(); } void ThrowException(void) const { if (m_Exception) boost::rethrow_exception(m_Exception); } private: std::stack m_Stack; Value m_Key; boost::exception_ptr m_Exception; }; static int DecodeNull(void *ctx) { JsonContext *context = static_cast(ctx); try { context->AddValue(Empty); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeBoolean(void *ctx, int value) { JsonContext *context = static_cast(ctx); try { context->AddValue(static_cast(value)); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeNumber(void *ctx, const char *str, yajl_size len) { JsonContext *context = static_cast(ctx); try { String jstr = String(str, str + len); context->AddValue(Convert::ToDouble(jstr)); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeString(void *ctx, const unsigned char *str, yajl_size len) { JsonContext *context = static_cast(ctx); try { context->AddValue(String(str, str + len)); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeStartMap(void *ctx) { JsonContext *context = static_cast(ctx); try { context->Push(new Dictionary()); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeEndMapOrArray(void *ctx) { JsonContext *context = static_cast(ctx); try { context->AddValue(context->Pop().EValue); } catch (...) { context->SaveException(); return 0; } return 1; } static int DecodeStartArray(void *ctx) { JsonContext *context = static_cast(ctx); try { context->Push(new Array()); } catch (...) { context->SaveException(); return 0; } return 1; } Value icinga::JsonDecode(const String& data) { static const yajl_callbacks callbacks = { DecodeNull, DecodeBoolean, NULL, NULL, DecodeNumber, DecodeString, DecodeStartMap, DecodeString, DecodeEndMapOrArray, DecodeStartArray, DecodeEndMapOrArray }; yajl_handle handle; #if YAJL_MAJOR < 2 yajl_parser_config cfg = { 1, 0 }; #endif /* YAJL_MAJOR */ JsonContext context; #if YAJL_MAJOR < 2 handle = yajl_alloc(&callbacks, &cfg, NULL, &context); #else /* YAJL_MAJOR */ handle = yajl_alloc(&callbacks, NULL, &context); yajl_config(handle, yajl_dont_validate_strings, 1); yajl_config(handle, yajl_allow_comments, 1); #endif /* YAJL_MAJOR */ yajl_parse(handle, reinterpret_cast(data.CStr()), data.GetLength()); #if YAJL_MAJOR < 2 if (yajl_parse_complete(handle) != yajl_status_ok) { #else /* YAJL_MAJOR */ if (yajl_complete_parse(handle) != yajl_status_ok) { #endif /* YAJL_MAJOR */ unsigned char *internal_err_str = yajl_get_error(handle, 1, reinterpret_cast(data.CStr()), data.GetLength()); String msg = reinterpret_cast(internal_err_str); yajl_free_error(handle, internal_err_str); yajl_free(handle); /* throw saved exception (if there is one) */ context.ThrowException(); BOOST_THROW_EXCEPTION(std::invalid_argument(msg)); } yajl_free(handle); return context.GetValue(); } icinga2-2.8.1/lib/base/json.hpp000066400000000000000000000032461322762156600162170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef JSON_H #define JSON_H #include "base/i2-base.hpp" namespace icinga { class String; class Value; I2_BASE_API String JsonEncode(const Value& value, bool pretty_print = false); I2_BASE_API Value JsonDecode(const String& data); } #endif /* JSON_H */ icinga2-2.8.1/lib/base/loader.cpp000066400000000000000000000065441322762156600165130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/loader.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/application.hpp" using namespace icinga; /** * Loads the specified library. * * @param library The name of the library. */ void Loader::LoadExtensionLibrary(const String& library) { String path; #if defined(_WIN32) path = library + ".dll"; #elif defined(__APPLE__) path = "lib" + library + "." + Application::GetAppSpecVersion() + ".dylib"; #else /* __APPLE__ */ path = "lib" + library + ".so." + Application::GetAppSpecVersion(); #endif /* _WIN32 */ Log(LogNotice, "Loader") << "Loading library '" << path << "'"; #ifdef _WIN32 HMODULE hModule = LoadLibrary(path.CStr()); if (hModule == NULL) { BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("LoadLibrary") << errinfo_win32_error(GetLastError()) << boost::errinfo_file_name(path)); } #else /* _WIN32 */ void *hModule = dlopen(path.CStr(), RTLD_NOW | RTLD_GLOBAL); if (hModule == NULL) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror())); } #endif /* _WIN32 */ ExecuteDeferredInitializers(); } boost::thread_specific_ptr >& Loader::GetDeferredInitializers(void) { static boost::thread_specific_ptr > initializers; return initializers; } void Loader::ExecuteDeferredInitializers(void) { if (!GetDeferredInitializers().get()) return; while (!GetDeferredInitializers().get()->empty()) { DeferredInitializer initializer = GetDeferredInitializers().get()->top(); GetDeferredInitializers().get()->pop(); initializer(); } } void Loader::AddDeferredInitializer(const boost::function& callback, int priority) { if (!GetDeferredInitializers().get()) GetDeferredInitializers().reset(new std::priority_queue()); GetDeferredInitializers().get()->push(DeferredInitializer(callback, priority)); } icinga2-2.8.1/lib/base/loader.hpp000066400000000000000000000047101322762156600165110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LOADER_H #define LOADER_H #include "base/i2-base.hpp" #include "base/string.hpp" #include #include #include namespace icinga { struct DeferredInitializer { public: DeferredInitializer(const boost::function& callback, int priority) : m_Callback(callback), m_Priority(priority) { } inline bool operator<(const DeferredInitializer& other) const { return m_Priority < other.m_Priority; } inline void operator()(void) { m_Callback(); } private: boost::function m_Callback; int m_Priority; }; /** * Loader helper functions. * * @ingroup base */ class I2_BASE_API Loader { public: static void LoadExtensionLibrary(const String& library); static void AddDeferredInitializer(const boost::function& callback, int priority = 0); static void ExecuteDeferredInitializers(void); private: Loader(void); static boost::thread_specific_ptr >& GetDeferredInitializers(void); }; } #endif /* LOADER_H */ icinga2-2.8.1/lib/base/logger.cpp000066400000000000000000000134761322762156600165260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/logger.hpp" #include "base/logger.tcpp" #include "base/application.hpp" #include "base/streamlogger.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include "base/context.hpp" #include "base/scriptglobal.hpp" #include using namespace icinga; REGISTER_TYPE(Logger); std::set Logger::m_Loggers; boost::mutex Logger::m_Mutex; bool Logger::m_ConsoleLogEnabled = true; bool Logger::m_TimestampEnabled = true; LogSeverity Logger::m_ConsoleLogSeverity = LogInformation; INITIALIZE_ONCE([]() { ScriptGlobal::Set("LogDebug", LogDebug); ScriptGlobal::Set("LogNotice", LogNotice); ScriptGlobal::Set("LogInformation", LogInformation); ScriptGlobal::Set("LogWarning", LogWarning); ScriptGlobal::Set("LogCritical", LogCritical); }); /** * Constructor for the Logger class. */ void Logger::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); boost::mutex::scoped_lock lock(m_Mutex); m_Loggers.insert(this); } void Logger::Stop(bool runtimeRemoved) { { boost::mutex::scoped_lock lock(m_Mutex); m_Loggers.erase(this); } ObjectImpl::Stop(runtimeRemoved); } std::set Logger::GetLoggers(void) { boost::mutex::scoped_lock lock(m_Mutex); return m_Loggers; } /** * Writes a message to the application's log. * * @param severity The message severity. * @param facility The log facility. * @param message The message. */ void icinga::IcingaLog(LogSeverity severity, const String& facility, const String& message) { LogEntry entry; entry.Timestamp = Utility::GetTime(); entry.Severity = severity; entry.Facility = facility; entry.Message = message; if (severity >= LogWarning) { ContextTrace context; if (context.GetLength() > 0) { std::ostringstream trace; trace << context; entry.Message += "\nContext:" + trace.str(); } } for (const Logger::Ptr& logger : Logger::GetLoggers()) { ObjectLock llock(logger); if (!logger->IsActive()) continue; if (entry.Severity >= logger->GetMinSeverity()) logger->ProcessLogEntry(entry); } if (Logger::IsConsoleLogEnabled() && entry.Severity >= Logger::GetConsoleLogSeverity()) StreamLogger::ProcessLogEntry(std::cout, entry); } /** * Retrieves the minimum severity for this logger. * * @returns The minimum severity. */ LogSeverity Logger::GetMinSeverity(void) const { String severity = GetSeverity(); if (severity.IsEmpty()) return LogInformation; else { LogSeverity ls = LogInformation; try { ls = Logger::StringToSeverity(severity); } catch (const std::exception&) { /* use the default level */ } return ls; } } /** * Converts a severity enum value to a string. * * @param severity The severity value. */ String Logger::SeverityToString(LogSeverity severity) { switch (severity) { case LogDebug: return "debug"; case LogNotice: return "notice"; case LogInformation: return "information"; case LogWarning: return "warning"; case LogCritical: return "critical"; default: BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid severity.")); } } /** * Converts a string to a severity enum value. * * @param severity The severity. */ LogSeverity Logger::StringToSeverity(const String& severity) { if (severity == "debug") return LogDebug; else if (severity == "notice") return LogNotice; else if (severity == "information") return LogInformation; else if (severity == "warning") return LogWarning; else if (severity == "critical") return LogCritical; else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid severity: " + severity)); } void Logger::DisableConsoleLog(void) { m_ConsoleLogEnabled = false; } void Logger::EnableConsoleLog(void) { m_ConsoleLogEnabled = true; } bool Logger::IsConsoleLogEnabled(void) { return m_ConsoleLogEnabled; } void Logger::SetConsoleLogSeverity(LogSeverity logSeverity) { m_ConsoleLogSeverity = logSeverity; } LogSeverity Logger::GetConsoleLogSeverity(void) { return m_ConsoleLogSeverity; } void Logger::DisableTimestamp(bool disable) { m_TimestampEnabled = !disable; } bool Logger::IsTimestampEnabled(void) { return m_TimestampEnabled; } void Logger::ValidateSeverity(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateSeverity(value, utils); try { StringToSeverity(value); } catch (...) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("severity"), "Invalid severity specified: " + value)); } } icinga2-2.8.1/lib/base/logger.hpp000066400000000000000000000077761322762156600165410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LOGGER_H #define LOGGER_H #include "base/i2-base.hpp" #include "base/logger.thpp" #include #include namespace icinga { /** * Log severity. * * @ingroup base */ enum LogSeverity { LogDebug, LogNotice, LogInformation, LogWarning, LogCritical }; /** * A log entry. * * @ingroup base */ struct LogEntry { double Timestamp; /**< The timestamp when this log entry was created. */ LogSeverity Severity; /**< The severity of this log entry. */ String Facility; /**< The facility this log entry belongs to. */ String Message; /**< The log entry's message. */ }; /** * A log provider. * * @ingroup base */ class I2_BASE_API Logger : public ObjectImpl { public: DECLARE_OBJECT(Logger); static String SeverityToString(LogSeverity severity); static LogSeverity StringToSeverity(const String& severity); LogSeverity GetMinSeverity(void) const; /** * Processes the log entry and writes it to the log that is * represented by this ILogger object. * * @param entry The log entry that is to be processed. */ virtual void ProcessLogEntry(const LogEntry& entry) = 0; virtual void Flush(void) = 0; static std::set GetLoggers(void); static void DisableConsoleLog(void); static void EnableConsoleLog(void); static bool IsConsoleLogEnabled(void); static void DisableTimestamp(bool); static bool IsTimestampEnabled(void); static void SetConsoleLogSeverity(LogSeverity logSeverity); static LogSeverity GetConsoleLogSeverity(void); virtual void ValidateSeverity(const String& value, const ValidationUtils& utils) override; protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: static boost::mutex m_Mutex; static std::set m_Loggers; static bool m_ConsoleLogEnabled; static bool m_TimestampEnabled; static LogSeverity m_ConsoleLogSeverity; }; I2_BASE_API void IcingaLog(LogSeverity severity, const String& facility, const String& message); class Log { public: inline Log(LogSeverity severity, const String& facility, const String& message) : m_Severity(severity), m_Facility(facility) { m_Buffer << message; } inline Log(LogSeverity severity, const String& facility) : m_Severity(severity), m_Facility(facility) { } inline ~Log(void) { IcingaLog(m_Severity, m_Facility, m_Buffer.str()); } template Log& operator<<(const T& val) { m_Buffer << val; return *this; } private: LogSeverity m_Severity; String m_Facility; std::ostringstream m_Buffer; Log(void); Log(const Log& other); Log& operator=(const Log& rhs); }; } #endif /* LOGGER_H */ icinga2-2.8.1/lib/base/logger.ti000066400000000000000000000030571322762156600163520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library base; namespace icinga { abstract class Logger : ConfigObject { [config] String severity; }; } icinga2-2.8.1/lib/base/math-script.cpp000066400000000000000000000132261322762156600174730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/initialize.hpp" #include #include using namespace icinga; static double MathAbs(double x) { return std::fabs(x); } static double MathAcos(double x) { return std::acos(x); } static double MathAsin(double x) { return std::asin(x); } static double MathAtan(double x) { return std::atan(x); } static double MathAtan2(double y, double x) { return std::atan2(y, x); } static double MathCeil(double x) { return std::ceil(x); } static double MathCos(double x) { return std::cos(x); } static double MathExp(double x) { return std::exp(x); } static double MathFloor(double x) { return std::floor(x); } static double MathLog(double x) { return std::log(x); } static Value MathMax(const std::vector& args) { bool first = true; Value result = -INFINITY; for (const Value& arg : args) { if (first || arg > result) { first = false; result = arg; } } return result; } static Value MathMin(const std::vector& args) { bool first = true; Value result = INFINITY; for (const Value& arg : args) { if (first || arg < result) { first = false; result = arg; } } return result; } static double MathPow(double x, double y) { return std::pow(x, y); } static double MathRandom(void) { return (double)std::rand() / RAND_MAX; } static double MathRound(double x) { return boost::math::round(x); } static double MathSin(double x) { return std::sin(x); } static double MathSqrt(double x) { return std::sqrt(x); } static double MathTan(double x) { return std::tan(x); } static bool MathIsnan(double x) { return boost::math::isnan(x); } static bool MathIsinf(double x) { return boost::math::isinf(x); } static double MathSign(double x) { if (x > 0) return 1; else if (x < 0) return -1; else return 0; } INITIALIZE_ONCE([]() { Dictionary::Ptr mathObj = new Dictionary(); /* Constants */ mathObj->Set("E", 2.71828182845904523536); mathObj->Set("LN2", 0.693147180559945309417); mathObj->Set("LN10", 2.30258509299404568402); mathObj->Set("LOG2E", 1.44269504088896340736); mathObj->Set("LOG10E", 0.434294481903251827651); mathObj->Set("PI", 3.14159265358979323846); mathObj->Set("SQRT1_2", 0.707106781186547524401); mathObj->Set("SQRT2", 1.41421356237309504880); /* Methods */ mathObj->Set("abs", new Function("Math#abs", WrapFunction(MathAbs), { "x" }, true)); mathObj->Set("acos", new Function("Math#acos", WrapFunction(MathAcos), { "x" }, true)); mathObj->Set("asin", new Function("Math#asin", WrapFunction(MathAsin), { "x" }, true)); mathObj->Set("atan", new Function("Math#atan", WrapFunction(MathAtan), { "x" }, true)); mathObj->Set("atan2", new Function("Math#atan2", WrapFunction(MathAtan2), { "x", "y" }, true)); mathObj->Set("ceil", new Function("Math#ceil", WrapFunction(MathCeil), { "x" }, true)); mathObj->Set("cos", new Function("Math#cos", WrapFunction(MathCos), { "x" }, true)); mathObj->Set("exp", new Function("Math#exp", WrapFunction(MathExp), { "x" }, true)); mathObj->Set("floor", new Function("Math#floor", WrapFunction(MathFloor), { "x" }, true)); mathObj->Set("log", new Function("Math#log", WrapFunction(MathLog), { "x" }, true)); mathObj->Set("max", new Function("Math#max", WrapFunction(MathMax), {}, true)); mathObj->Set("min", new Function("Math#min", WrapFunction(MathMin), {}, true)); mathObj->Set("pow", new Function("Math#pow", WrapFunction(MathPow), { "x", "y" }, true)); mathObj->Set("random", new Function("Math#random", WrapFunction(MathRandom), {}, true)); mathObj->Set("round", new Function("Math#round", WrapFunction(MathRound), { "x" }, true)); mathObj->Set("sin", new Function("Math#sin", WrapFunction(MathSin), { "x" }, true)); mathObj->Set("sqrt", new Function("Math#sqrt", WrapFunction(MathSqrt), { "x" }, true)); mathObj->Set("tan", new Function("Math#tan", WrapFunction(MathTan), { "x" }, true)); mathObj->Set("isnan", new Function("Math#isnan", WrapFunction(MathIsnan), { "x" }, true)); mathObj->Set("isinf", new Function("Math#isinf", WrapFunction(MathIsinf), { "x" }, true)); mathObj->Set("sign", new Function("Math#sign", WrapFunction(MathSign), { "x" }, true)); ScriptGlobal::Set("Math", mathObj); }); icinga2-2.8.1/lib/base/netstring.cpp000066400000000000000000000103451322762156600172540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/netstring.hpp" #include "base/debug.hpp" #include using namespace icinga; /** * Reads data from a stream in netstring format. * * @param stream The stream to read from. * @param[out] str The String that has been read from the IOQueue. * @returns true if a complete String was read from the IOQueue, false otherwise. * @exception invalid_argument The input stream is invalid. * @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c */ StreamReadStatus NetString::ReadStringFromStream(const Stream::Ptr& stream, String *str, StreamReadContext& context, bool may_wait) { if (context.Eof) return StatusEof; if (context.MustRead) { if (!context.FillFromStream(stream, may_wait)) { context.Eof = true; return StatusEof; } context.MustRead = false; } size_t header_length = 0; for (size_t i = 0; i < context.Size; i++) { if (context.Buffer[i] == ':') { header_length = i; /* make sure there's a header */ if (header_length == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (no length specifier)")); break; } else if (i > 16) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (missing :)")); } if (header_length == 0) { context.MustRead = true; return StatusNeedData; } /* no leading zeros allowed */ if (context.Buffer[0] == '0' && isdigit(context.Buffer[1])) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (leading zero)")); size_t len, i; len = 0; for (i = 0; i < header_length && isdigit(context.Buffer[i]); i++) { /* length specifier must have at most 9 characters */ if (i >= 9) BOOST_THROW_EXCEPTION(std::invalid_argument("Length specifier must not exceed 9 characters")); len = len * 10 + (context.Buffer[i] - '0'); } /* read the whole message */ size_t data_length = len + 1; char *data = context.Buffer + header_length + 1; if (context.Size < header_length + 1 + data_length) { context.MustRead = true; return StatusNeedData; } if (data[len] != ',') BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (missing ,)")); *str = String(&data[0], &data[len]); context.DropData(header_length + 1 + len + 1); return StatusNewItem; } /** * Writes data into a stream using the netstring format. * * @param stream The stream. * @param str The String that is to be written. */ void NetString::WriteStringToStream(const Stream::Ptr& stream, const String& str) { std::ostringstream msgbuf; WriteStringToStream(msgbuf, str); String msg = msgbuf.str(); stream->Write(msg.CStr(), msg.GetLength()); } /** * Writes data into a stream using the netstring format. * * @param stream The stream. * @param str The String that is to be written. */ void NetString::WriteStringToStream(std::ostream& stream, const String& str) { stream << str.GetLength() << ":" << str << ","; } icinga2-2.8.1/lib/base/netstring.hpp000066400000000000000000000041201322762156600172530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NETSTRING_H #define NETSTRING_H #include "base/i2-base.hpp" #include "base/stream.hpp" namespace icinga { class String; /** * Helper functions for reading/writing messages in the netstring format. * * @see https://cr.yp.to/proto/netstrings.txt * * @ingroup base */ class I2_BASE_API NetString { public: static StreamReadStatus ReadStringFromStream(const Stream::Ptr& stream, String *message, StreamReadContext& context, bool may_wait = false); static void WriteStringToStream(const Stream::Ptr& stream, const String& message); static void WriteStringToStream(std::ostream& stream, const String& message); private: NetString(void); }; } #endif /* NETSTRING_H */ icinga2-2.8.1/lib/base/networkstream.cpp000066400000000000000000000055321322762156600201460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/networkstream.hpp" using namespace icinga; NetworkStream::NetworkStream(const Socket::Ptr& socket) : m_Socket(socket), m_Eof(false) { } void NetworkStream::Close(void) { Stream::Close(); m_Socket->Close(); } /** * Reads data from the stream. * * @param buffer The buffer where data should be stored. May be NULL if you're * not actually interested in the data. * @param count The number of bytes to read from the queue. * @returns The number of bytes actually read. */ size_t NetworkStream::Read(void *buffer, size_t count, bool allow_partial) { size_t rc; ASSERT(allow_partial); if (m_Eof) BOOST_THROW_EXCEPTION(std::invalid_argument("Tried to read from closed socket.")); try { rc = m_Socket->Read(buffer, count); } catch (...) { m_Eof = true; throw; } if (rc == 0) m_Eof = true; return rc; } /** * Writes data to the stream. * * @param buffer The data that is to be written. * @param count The number of bytes to write. * @returns The number of bytes written */ void NetworkStream::Write(const void *buffer, size_t count) { size_t rc; if (m_Eof) BOOST_THROW_EXCEPTION(std::invalid_argument("Tried to write to closed socket.")); try { rc = m_Socket->Write(buffer, count); } catch (...) { m_Eof = true; throw; } if (rc < count) { m_Eof = true; BOOST_THROW_EXCEPTION(std::runtime_error("Short write for socket.")); } } bool NetworkStream::IsEof(void) const { return m_Eof; } icinga2-2.8.1/lib/base/networkstream.hpp000066400000000000000000000040611322762156600201470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NETWORKSTREAM_H #define NETWORKSTREAM_H #include "base/i2-base.hpp" #include "base/stream.hpp" #include "base/socket.hpp" namespace icinga { /** * A network stream. * * @ingroup base */ class I2_BASE_API NetworkStream : public Stream { public: DECLARE_PTR_TYPEDEFS(NetworkStream); NetworkStream(const Socket::Ptr& socket); virtual size_t Read(void *buffer, size_t count, bool allow_partial = false) override; virtual void Write(const void *buffer, size_t count) override; virtual void Close(void) override; virtual bool IsEof(void) const override; private: Socket::Ptr m_Socket; bool m_Eof; }; } #endif /* NETWORKSTREAM_H */ icinga2-2.8.1/lib/base/number-script.cpp000066400000000000000000000037141322762156600200330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/number.hpp" #include "base/convert.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static String NumberToString(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); return vframe->Self; } Object::Ptr Number::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("to_string", new Function("Number#to_string", WrapFunction(NumberToString), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/number.cpp000066400000000000000000000030611322762156600165240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/number.hpp" #include "base/primitivetype.hpp" using namespace icinga; REGISTER_BUILTIN_TYPE(Number, Number::GetPrototype()); icinga2-2.8.1/lib/base/number.hpp000066400000000000000000000032711322762156600165340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NUMBER_H #define NUMBER_H #include "base/i2-base.hpp" #include "base/object.hpp" namespace icinga { class Value; /** * Number class. */ class I2_BASE_API Number { public: static Object::Ptr GetPrototype(void); private: Number(void); }; } #endif /* NUMBER_H */ icinga2-2.8.1/lib/base/object-script.cpp000066400000000000000000000052461322762156600200130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/object.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static String ObjectToString(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Object::Ptr self = static_cast(vframe->Self); return self->ToString(); } static void ObjectNotifyAttribute(const String& attribute) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Object::Ptr self = static_cast(vframe->Self); self->NotifyField(self->GetReflectionType()->GetFieldId(attribute)); } static Object::Ptr ObjectClone(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Object::Ptr self = static_cast(vframe->Self); return self->Clone(); } Object::Ptr Object::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("to_string", new Function("Object#to_string", WrapFunction(ObjectToString), {}, true)); prototype->Set("notify_attribute", new Function("Object#notify_attribute", WrapFunction(ObjectNotifyAttribute), { "attribute" }, false)); prototype->Set("clone", new Function("Object#clone", WrapFunction(ObjectClone), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/object.cpp000066400000000000000000000165471322762156600165170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/object.hpp" #include "base/value.hpp" #include "base/dictionary.hpp" #include "base/primitivetype.hpp" #include "base/utility.hpp" #include "base/timer.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include using namespace icinga; DEFINE_TYPE_INSTANCE(Object); #ifdef I2_LEAK_DEBUG static boost::mutex l_ObjectCountLock; static std::map l_ObjectCounts; static Timer::Ptr l_ObjectCountTimer; #endif /* I2_LEAK_DEBUG */ /** * Default constructor for the Object class. */ Object::Object(void) : m_References(0), m_Mutex(0) #ifdef I2_DEBUG , m_LockOwner(0) #endif /* I2_DEBUG */ { } /** * Destructor for the Object class. */ Object::~Object(void) { delete reinterpret_cast(m_Mutex); } /** * Returns a string representation for the object. */ String Object::ToString(void) const { return "Object of type '" + GetReflectionType()->GetName() + "'"; } #ifdef I2_DEBUG /** * Checks if the calling thread owns the lock on this object. * * @returns True if the calling thread owns the lock, false otherwise. */ bool Object::OwnsLock(void) const { #ifdef _WIN32 DWORD tid = InterlockedExchangeAdd(&m_LockOwner, 0); return (tid == GetCurrentThreadId()); #else /* _WIN32 */ pthread_t tid = __sync_fetch_and_add(&m_LockOwner, 0); return (tid == pthread_self()); #endif /* _WIN32 */ } #endif /* I2_DEBUG */ void Object::SetField(int id, const Value&, bool, const Value&) { if (id == 0) BOOST_THROW_EXCEPTION(std::runtime_error("Type field cannot be set.")); else BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } Value Object::GetField(int id) const { if (id == 0) return GetReflectionType()->GetName(); else BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } bool Object::HasOwnField(const String& field) const { Type::Ptr type = GetReflectionType(); if (!type) return false; return type->GetFieldId(field) != -1; } bool Object::GetOwnField(const String& field, Value *result) const { Type::Ptr type = GetReflectionType(); if (!type) return false; int tid = type->GetFieldId(field); if (tid == -1) return false; *result = GetField(tid); return true; } Value Object::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const { Type::Ptr type = GetReflectionType(); if (!type) return Empty; int fid = type->GetFieldId(field); if (fid == -1) return GetPrototypeField(const_cast(this), field, true, debugInfo); if (sandboxed) { Field fieldInfo = type->GetFieldInfo(fid); if (fieldInfo.Attributes & FANoUserView) BOOST_THROW_EXCEPTION(ScriptError("Accessing the field '" + field + "' for type '" + type->GetName() + "' is not allowed in sandbox mode.", debugInfo)); } return GetField(fid); } void Object::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) { Type::Ptr type = GetReflectionType(); if (!type) BOOST_THROW_EXCEPTION(ScriptError("Cannot set field on object.", debugInfo)); int fid = type->GetFieldId(field); if (fid == -1) BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' does not exist.", debugInfo)); try { SetField(fid, value); } catch (const boost::bad_lexical_cast&) { Field fieldInfo = type->GetFieldInfo(fid); Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName); BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo)); } catch (const std::bad_cast&) { Field fieldInfo = type->GetFieldInfo(fid); Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName); BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo)); } } void Object::Validate(int types, const ValidationUtils& utils) { /* Nothing to do here. */ } void Object::ValidateField(int id, const Value& value, const ValidationUtils& utils) { /* Nothing to do here. */ } void Object::NotifyField(int id, const Value& cookie) { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } Object::Ptr Object::NavigateField(int id) const { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } Object::Ptr Object::Clone(void) const { BOOST_THROW_EXCEPTION(std::runtime_error("Object cannot be cloned.")); } Type::Ptr Object::GetReflectionType(void) const { return Object::TypeInstance; } Value icinga::GetPrototypeField(const Value& context, const String& field, bool not_found_error, const DebugInfo& debugInfo) { Type::Ptr ctype = context.GetReflectionType(); Type::Ptr type = ctype; do { Object::Ptr object = type->GetPrototype(); if (object && object->HasOwnField(field)) return object->GetFieldByName(field, false, debugInfo); type = type->GetBaseType(); } while (type); if (not_found_error) BOOST_THROW_EXCEPTION(ScriptError("Invalid field access (for value of type '" + ctype->GetName() + "'): '" + field + "'", debugInfo)); else return Empty; } #ifdef I2_LEAK_DEBUG void icinga::TypeAddObject(Object *object) { boost::mutex::scoped_lock lock(l_ObjectCountLock); String typeName = Utility::GetTypeName(typeid(*object)); l_ObjectCounts[typeName]++; } void icinga::TypeRemoveObject(Object *object) { boost::mutex::scoped_lock lock(l_ObjectCountLock); String typeName = Utility::GetTypeName(typeid(*object)); l_ObjectCounts[typeName]--; } static void TypeInfoTimerHandler(void) { boost::mutex::scoped_lock lock(l_ObjectCountLock); typedef std::map::value_type kv_pair; for (kv_pair& kv : l_ObjectCounts) { if (kv.second == 0) continue; Log(LogInformation, "TypeInfo") << kv.second << " " << kv.first << " objects"; kv.second = 0; } } INITIALIZE_ONCE([]() { l_ObjectCountTimer = new Timer(); l_ObjectCountTimer->SetInterval(10); l_ObjectCountTimer->OnTimerExpired.connect(boost::bind(TypeInfoTimerHandler)); l_ObjectCountTimer->Start(); }); #endif /* I2_LEAK_DEBUG */ icinga2-2.8.1/lib/base/object.hpp000066400000000000000000000133221322762156600165100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include "base/i2-base.hpp" #include "base/debug.hpp" #include #include #include #include using boost::intrusive_ptr; using boost::dynamic_pointer_cast; using boost::static_pointer_cast; #include using boost::tie; namespace icinga { class Value; class Object; class Type; class String; struct DebugInfo; class ValidationUtils; extern I2_BASE_API Value Empty; #define DECLARE_PTR_TYPEDEFS(klass) \ typedef intrusive_ptr Ptr #define IMPL_TYPE_LOOKUP_SUPER() \ #define IMPL_TYPE_LOOKUP() \ static intrusive_ptr TypeInstance; \ virtual intrusive_ptr GetReflectionType(void) const override \ { \ return TypeInstance; \ } #define DECLARE_OBJECT(klass) \ DECLARE_PTR_TYPEDEFS(klass); \ IMPL_TYPE_LOOKUP(); template intrusive_ptr DefaultObjectFactory(const std::vector& args) { if (!args.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Constructor does not take any arguments.")); return new T(); } template intrusive_ptr DefaultObjectFactoryVA(const std::vector& args) { return new T(args); } typedef intrusive_ptr (*ObjectFactory)(const std::vector&); template struct TypeHelper { }; template struct TypeHelper { static ObjectFactory GetFactory(void) { return DefaultObjectFactory; } }; template struct TypeHelper { static ObjectFactory GetFactory(void) { return DefaultObjectFactoryVA; } }; /** * Base class for all heap-allocated objects. At least one of its methods * has to be virtual for RTTI to work. * * @ingroup base */ class I2_BASE_API Object { public: DECLARE_PTR_TYPEDEFS(Object); Object(void); virtual ~Object(void); virtual String ToString(void) const; virtual intrusive_ptr GetReflectionType(void) const; virtual void Validate(int types, const ValidationUtils& utils); virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty); virtual Value GetField(int id) const; virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const; virtual void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo); virtual bool HasOwnField(const String& field) const; virtual bool GetOwnField(const String& field, Value *result) const; virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils); virtual void NotifyField(int id, const Value& cookie = Empty); virtual Object::Ptr NavigateField(int id) const; #ifdef I2_DEBUG bool OwnsLock(void) const; #endif /* I2_DEBUG */ static Object::Ptr GetPrototype(void); virtual Object::Ptr Clone(void) const; static intrusive_ptr TypeInstance; private: Object(const Object& other); Object& operator=(const Object& rhs); uintptr_t m_References; mutable uintptr_t m_Mutex; #ifdef I2_DEBUG # ifndef _WIN32 mutable pthread_t m_LockOwner; # else /* _WIN32 */ mutable DWORD m_LockOwner; # endif /* _WIN32 */ #endif /* I2_DEBUG */ friend struct ObjectLock; friend void intrusive_ptr_add_ref(Object *object); friend void intrusive_ptr_release(Object *object); }; I2_BASE_API Value GetPrototypeField(const Value& context, const String& field, bool not_found_error, const DebugInfo& debugInfo); I2_BASE_API void TypeAddObject(Object *object); I2_BASE_API void TypeRemoveObject(Object *object); inline void intrusive_ptr_add_ref(Object *object) { #ifdef I2_LEAK_DEBUG if (object->m_References == 0) TypeAddObject(object); #endif /* I2_LEAK_DEBUG */ #ifdef _WIN32 InterlockedIncrement(&object->m_References); #else /* _WIN32 */ __sync_add_and_fetch(&object->m_References, 1); #endif /* _WIN32 */ } inline void intrusive_ptr_release(Object *object) { uintptr_t refs; #ifdef _WIN32 refs = InterlockedDecrement(&object->m_References); #else /* _WIN32 */ refs = __sync_sub_and_fetch(&object->m_References, 1); #endif /* _WIN32 */ if (unlikely(refs == 0)) { #ifdef I2_LEAK_DEBUG TypeRemoveObject(object); #endif /* I2_LEAK_DEBUG */ delete object; } } template class ObjectImpl { }; } #endif /* OBJECT_H */ #include "base/type.hpp" icinga2-2.8.1/lib/base/objectlock.hpp000066400000000000000000000103511322762156600173600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTLOCK_H #define OBJECTLOCK_H #include "base/object.hpp" #define I2MUTEX_UNLOCKED 0 #define I2MUTEX_LOCKED 1 namespace icinga { /** * A scoped lock for Objects. */ struct I2_BASE_API ObjectLock { public: inline ObjectLock(void) : m_Object(NULL), m_Locked(false) { } inline ~ObjectLock(void) { Unlock(); } inline ObjectLock(const Object::Ptr& object) : m_Object(object.get()), m_Locked(false) { if (m_Object) Lock(); } inline ObjectLock(const Object *object) : m_Object(object), m_Locked(false) { if (m_Object) Lock(); } inline static void LockMutex(const Object *object) { unsigned int it = 0; #ifdef _WIN32 # ifdef _WIN64 while (likely(InterlockedCompareExchange64((LONGLONG *)&object->m_Mutex, I2MUTEX_LOCKED, I2MUTEX_UNLOCKED) != I2MUTEX_UNLOCKED)) { # else /* _WIN64 */ while (likely(InterlockedCompareExchange(&object->m_Mutex, I2MUTEX_LOCKED, I2MUTEX_UNLOCKED) != I2MUTEX_UNLOCKED)) { # endif /* _WIN64 */ #else /* _WIN32 */ while (likely(!__sync_bool_compare_and_swap(&object->m_Mutex, I2MUTEX_UNLOCKED, I2MUTEX_LOCKED))) { #endif /* _WIN32 */ if (likely(object->m_Mutex > I2MUTEX_LOCKED)) { boost::recursive_mutex *mtx = reinterpret_cast(object->m_Mutex); mtx->lock(); return; } Spin(it); it++; } boost::recursive_mutex *mtx = new boost::recursive_mutex(); mtx->lock(); #ifdef _WIN32 # ifdef _WIN64 InterlockedCompareExchange64((LONGLONG *)&object->m_Mutex, reinterpret_cast(mtx), I2MUTEX_LOCKED); # else /* _WIN64 */ InterlockedCompareExchange(&object->m_Mutex, reinterpret_cast(mtx), I2MUTEX_LOCKED); # endif /* _WIN64 */ #else /* _WIN32 */ __sync_bool_compare_and_swap(&object->m_Mutex, I2MUTEX_LOCKED, reinterpret_cast(mtx)); #endif /* _WIN32 */ } inline void Lock(void) { ASSERT(!m_Locked && m_Object != NULL); LockMutex(m_Object); m_Locked = true; #ifdef I2_DEBUG # ifdef _WIN32 InterlockedExchange(&m_Object->m_LockOwner, GetCurrentThreadId()); # else /* _WIN32 */ __sync_lock_test_and_set(&m_Object->m_LockOwner, pthread_self()); # endif /* _WIN32 */ #endif /* I2_DEBUG */ } inline static void Spin(unsigned int it) { if (it < 8) { /* Do nothing. */ } #ifdef SPIN_PAUSE else if (it < 16) { SPIN_PAUSE(); } #endif /* SPIN_PAUSE */ else { #ifdef _WIN32 Sleep(0); #else /* _WIN32 */ sched_yield(); #endif /* _WIN32 */ } } inline void Unlock(void) { #ifdef I2_DEBUG if (m_Locked) { # ifdef _WIN32 InterlockedExchange(&m_Object->m_LockOwner, 0); # else /* _WIN32 */ __sync_lock_release(&m_Object->m_LockOwner); # endif /* _WIN32 */ } #endif /* I2_DEBUG */ if (m_Locked) { reinterpret_cast(m_Object->m_Mutex)->unlock(); m_Locked = false; } } private: const Object *m_Object; bool m_Locked; }; } #endif /* OBJECTLOCK_H */ icinga2-2.8.1/lib/base/objecttype.cpp000066400000000000000000000045231322762156600174100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/objecttype.hpp" #include "base/initialize.hpp" using namespace icinga; INITIALIZE_ONCE_WITH_PRIORITY([]() { Type::Ptr type = new ObjectType(); type->SetPrototype(Object::GetPrototype()); Type::Register(type); Object::TypeInstance = type; }, 20); ObjectType::ObjectType(void) { } String ObjectType::GetName(void) const { return "Object"; } Type::Ptr ObjectType::GetBaseType(void) const { return Type::Ptr(); } int ObjectType::GetAttributes(void) const { return 0; } int ObjectType::GetFieldId(const String& name) const { if (name == "type") return 0; else return -1; } Field ObjectType::GetFieldInfo(int id) const { if (id == 0) return Field(1, "String", "type", NULL, NULL, 0, 0); else BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } int ObjectType::GetFieldCount(void) const { return 1; } ObjectFactory ObjectType::GetFactory(void) const { return DefaultObjectFactory; } icinga2-2.8.1/lib/base/objecttype.hpp000066400000000000000000000040311322762156600174070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTTYPE_H #define OBJECTTYPE_H #include "base/i2-base.hpp" #include "base/type.hpp" #include "base/initialize.hpp" namespace icinga { class I2_BASE_API ObjectType : public Type { public: ObjectType(void); virtual String GetName(void) const override; virtual Type::Ptr GetBaseType(void) const override; virtual int GetAttributes(void) const override; virtual int GetFieldId(const String& name) const override; virtual Field GetFieldInfo(int id) const override; virtual int GetFieldCount(void) const override; protected: virtual ObjectFactory GetFactory(void) const override; }; } #endif /* OBJECTTYPE_H */ icinga2-2.8.1/lib/base/perfdatavalue.cpp000066400000000000000000000135051322762156600200630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/perfdatavalue.hpp" #include "base/perfdatavalue.tcpp" #include "base/convert.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include "base/function.hpp" #include #include #include using namespace icinga; REGISTER_TYPE(PerfdataValue); REGISTER_SCRIPTFUNCTION_NS(System, parse_performance_data, PerfdataValue::Parse, "perfdata"); PerfdataValue::PerfdataValue(void) { } PerfdataValue::PerfdataValue(String label, double value, bool counter, const String& unit, const Value& warn, const Value& crit, const Value& min, const Value& max) { SetLabel(label, true); SetValue(value, true); SetCounter(counter, true); SetUnit(unit, true); SetWarn(warn, true); SetCrit(crit, true); SetMin(min, true); SetMax(max, true); } PerfdataValue::Ptr PerfdataValue::Parse(const String& perfdata) { size_t eqp = perfdata.FindLastOf('='); if (eqp == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid performance data value: " + perfdata)); String label = perfdata.SubStr(0, eqp); if (label.GetLength() > 2 && label[0] == '\'' && label[label.GetLength() - 1] == '\'') label = label.SubStr(1, label.GetLength() - 2); size_t spq = perfdata.FindFirstOf(' ', eqp); if (spq == String::NPos) spq = perfdata.GetLength(); String valueStr = perfdata.SubStr(eqp + 1, spq - eqp - 1); size_t pos = valueStr.FindFirstNotOf("+-0123456789.e"); double value = Convert::ToDouble(valueStr.SubStr(0, pos)); std::vector tokens; boost::algorithm::split(tokens, valueStr, boost::is_any_of(";")); bool counter = false; String unit; Value warn, crit, min, max; if (pos != String::NPos) unit = valueStr.SubStr(pos, tokens[0].GetLength() - pos); boost::algorithm::to_lower(unit); double base = 1.0; if (unit == "us") { base /= 1000.0 * 1000.0; unit = "seconds"; } else if (unit == "ms") { base /= 1000.0; unit = "seconds"; } else if (unit == "s") { unit = "seconds"; } else if (unit == "tb") { base *= 1024.0 * 1024.0 * 1024.0 * 1024.0; unit = "bytes"; } else if (unit == "gb") { base *= 1024.0 * 1024.0 * 1024.0; unit = "bytes"; } else if (unit == "mb") { base *= 1024.0 * 1024.0; unit = "bytes"; } else if (unit == "kb") { base *= 1024.0; unit = "bytes"; } else if (unit == "b") { unit = "bytes"; } else if (unit == "%") { unit = "percent"; } else if (unit == "c") { counter = true; unit = ""; } else if (unit != "") { BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid performance data unit: " + unit)); } warn = ParseWarnCritMinMaxToken(tokens, 1, "warning"); crit = ParseWarnCritMinMaxToken(tokens, 2, "critical"); min = ParseWarnCritMinMaxToken(tokens, 3, "minimum"); max = ParseWarnCritMinMaxToken(tokens, 4, "maximum"); value = value * base; if (!warn.IsEmpty()) warn = warn * base; if (!crit.IsEmpty()) crit = crit * base; if (!min.IsEmpty()) min = min * base; if (!max.IsEmpty()) max = max * base; return new PerfdataValue(label, value, counter, unit, warn, crit, min, max); } String PerfdataValue::Format(void) const { std::ostringstream result; if (GetLabel().FindFirstOf(" ") != String::NPos) result << "'" << GetLabel() << "'"; else result << GetLabel(); result << "=" << Convert::ToString(GetValue()); String unit; if (GetCounter()) unit = "c"; else if (GetUnit() == "seconds") unit = "s"; else if (GetUnit() == "percent") unit = "%"; else if (GetUnit() == "bytes") unit = "B"; result << unit; if (!GetWarn().IsEmpty()) { result << ";" << Convert::ToString(GetWarn()); if (!GetCrit().IsEmpty()) { result << ";" << Convert::ToString(GetCrit()); if (!GetMin().IsEmpty()) { result << ";" << Convert::ToString(GetMin()); if (!GetMax().IsEmpty()) { result << ";" << Convert::ToString(GetMax()); } } } } return result.str(); } Value PerfdataValue::ParseWarnCritMinMaxToken(const std::vector& tokens, std::vector::size_type index, const String& description) { if (tokens.size() > index && tokens[index] != "U" && tokens[index] != "" && tokens[index].FindFirstNotOf("+-0123456789.e") == String::NPos) return Convert::ToDouble(tokens[index]); else { if (tokens.size() > index && tokens[index] != "") Log(LogDebug, "PerfdataValue") << "Ignoring unsupported perfdata " << description << " range, value: '" << tokens[index] << "'."; return Empty; } } icinga2-2.8.1/lib/base/perfdatavalue.hpp000066400000000000000000000043111322762156600200630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PERFDATAVALUE_H #define PERFDATAVALUE_H #include "base/i2-base.hpp" #include "base/perfdatavalue.thpp" namespace icinga { /** * A performance data value. * * @ingroup base */ class I2_BASE_API PerfdataValue : public ObjectImpl { public: DECLARE_OBJECT(PerfdataValue); PerfdataValue(void); PerfdataValue(String label, double value, bool counter = false, const String& unit = "", const Value& warn = Empty, const Value& crit = Empty, const Value& min = Empty, const Value& max = Empty); static PerfdataValue::Ptr Parse(const String& perfdata); String Format(void) const; private: static Value ParseWarnCritMinMaxToken(const std::vector& tokens, std::vector::size_type index, const String& description); }; } #endif /* PERFDATA_VALUE */ icinga2-2.8.1/lib/base/perfdatavalue.ti000066400000000000000000000032161322762156600177130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ library base; namespace icinga { class PerfdataValue { [state] String label; [state] double value; [state] bool counter; [state] String unit; [state] Value crit; [state] Value warn; [state] Value min; [state] Value max; }; } icinga2-2.8.1/lib/base/primitivetype.cpp000066400000000000000000000047431322762156600201560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/primitivetype.hpp" #include "base/dictionary.hpp" using namespace icinga; PrimitiveType::PrimitiveType(const String& name, const String& base, const ObjectFactory& factory) : m_Name(name), m_Base(base), m_Factory(factory) { } String PrimitiveType::GetName(void) const { return m_Name; } Type::Ptr PrimitiveType::GetBaseType(void) const { if (m_Base == "None") return Type::Ptr(); else return Type::GetByName(m_Base); } int PrimitiveType::GetAttributes(void) const { return 0; } int PrimitiveType::GetFieldId(const String& name) const { Type::Ptr base = GetBaseType(); if (base) return base->GetFieldId(name); else return -1; } Field PrimitiveType::GetFieldInfo(int id) const { Type::Ptr base = GetBaseType(); if (base) return base->GetFieldInfo(id); else throw std::runtime_error("Invalid field ID."); } int PrimitiveType::GetFieldCount(void) const { Type::Ptr base = GetBaseType(); if (base) return Object::TypeInstance->GetFieldCount(); else return 0; } ObjectFactory PrimitiveType::GetFactory(void) const { return m_Factory; } icinga2-2.8.1/lib/base/primitivetype.hpp000066400000000000000000000062471322762156600201640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PRIMITIVETYPE_H #define PRIMITIVETYPE_H #include "base/i2-base.hpp" #include "base/type.hpp" #include "base/initialize.hpp" namespace icinga { class I2_BASE_API PrimitiveType : public Type { public: PrimitiveType(const String& name, const String& base, const ObjectFactory& factory = ObjectFactory()); virtual String GetName(void) const override; virtual Type::Ptr GetBaseType(void) const override; virtual int GetAttributes(void) const override; virtual int GetFieldId(const String& name) const override; virtual Field GetFieldInfo(int id) const override; virtual int GetFieldCount(void) const override; protected: virtual ObjectFactory GetFactory(void) const override; private: String m_Name; String m_Base; ObjectFactory m_Factory; }; #define REGISTER_BUILTIN_TYPE(type, prototype) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ icinga::Type::Ptr t = new PrimitiveType(#type, "None"); \ t->SetPrototype(prototype); \ icinga::Type::Register(t); \ }, 15) #define REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, factory) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ icinga::Type::Ptr t = new PrimitiveType(#type, #base, factory); \ t->SetPrototype(prototype); \ icinga::Type::Register(t); \ type::TypeInstance = t; \ }, 15); \ DEFINE_TYPE_INSTANCE(type) #define REGISTER_PRIMITIVE_TYPE(type, base, prototype) \ REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, DefaultObjectFactory) #define REGISTER_PRIMITIVE_TYPE_VA(type, base, prototype) \ REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, DefaultObjectFactoryVA) #define REGISTER_PRIMITIVE_TYPE_NOINST(type, base, prototype) \ REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, NULL) } #endif /* PRIMITIVETYPE_H */ icinga2-2.8.1/lib/base/process.cpp000066400000000000000000000704431322762156600167220ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/process.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/initialize.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/scriptglobal.hpp" #include "base/json.hpp" #include #include #include #ifndef _WIN32 # include # include # include # ifndef __APPLE__ extern char **environ; # else /* __APPLE__ */ # include # define environ (*_NSGetEnviron()) # endif /* __APPLE__ */ #endif /* _WIN32 */ using namespace icinga; #define IOTHREADS 4 static boost::mutex l_ProcessMutex[IOTHREADS]; static std::map l_Processes[IOTHREADS]; #ifdef _WIN32 static HANDLE l_Events[IOTHREADS]; #else /* _WIN32 */ static int l_EventFDs[IOTHREADS][2]; static std::map l_FDs[IOTHREADS]; static boost::mutex l_ProcessControlMutex; static int l_ProcessControlFD = -1; static pid_t l_ProcessControlPID; #endif /* _WIN32 */ static boost::once_flag l_ProcessOnceFlag = BOOST_ONCE_INIT; static boost::once_flag l_SpawnHelperOnceFlag = BOOST_ONCE_INIT; Process::Process(const Process::Arguments& arguments, const Dictionary::Ptr& extraEnvironment) : m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment), m_Timeout(600), m_AdjustPriority(false) #ifdef _WIN32 , m_ReadPending(false), m_ReadFailed(false), m_Overlapped() #endif /* _WIN32 */ { #ifdef _WIN32 m_Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); #endif /* _WIN32 */ } Process::~Process(void) { #ifdef _WIN32 CloseHandle(m_Overlapped.hEvent); #endif /* _WIN32 */ } #ifndef _WIN32 static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& request) { struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_len != CMSG_LEN(sizeof(int) * 3)) { std::cerr << "Invalid 'spawn' request: FDs missing" << std::endl; return Empty; } int *fds = (int *)CMSG_DATA(cmsg); Array::Ptr arguments = request->Get("arguments"); Dictionary::Ptr extraEnvironment = request->Get("extraEnvironment"); bool adjustPriority = request->Get("adjustPriority"); // build argv char **argv = new char *[arguments->GetLength() + 1]; for (unsigned int i = 0; i < arguments->GetLength(); i++) { String arg = arguments->Get(i); argv[i] = strdup(arg.CStr()); } argv[arguments->GetLength()] = NULL; // build envp int envc = 0; /* count existing environment variables */ while (environ[envc] != NULL) envc++; char **envp = new char *[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0) + 2]; for (int i = 0; i < envc; i++) envp[i] = strdup(environ[i]); if (extraEnvironment) { ObjectLock olock(extraEnvironment); int index = envc; for (const Dictionary::Pair& kv : extraEnvironment) { String skv = kv.first + "=" + Convert::ToString(kv.second); envp[index] = strdup(skv.CStr()); index++; } } envp[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0)] = strdup("LC_NUMERIC=C"); envp[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0) + 1] = NULL; extraEnvironment.reset(); pid_t pid = fork(); int errorCode = 0; if (pid < 0) errorCode = errno; if (pid == 0) { // child process (void)close(l_ProcessControlFD); if (setsid() < 0) { perror("setsid() failed"); _exit(128); } if (dup2(fds[0], STDIN_FILENO) < 0 || dup2(fds[1], STDOUT_FILENO) < 0 || dup2(fds[2], STDERR_FILENO) < 0) { perror("dup2() failed"); _exit(128); } (void)close(fds[0]); (void)close(fds[1]); (void)close(fds[2]); #ifdef HAVE_NICE if (adjustPriority) nice(5); #endif /* HAVE_NICE */ sigset_t mask; sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, NULL); if (icinga2_execvpe(argv[0], argv, envp) < 0) { char errmsg[512]; strcpy(errmsg, "execvpe("); strncat(errmsg, argv[0], sizeof(errmsg) - strlen(errmsg) - 1); strncat(errmsg, ") failed", sizeof(errmsg) - strlen(errmsg) - 1); errmsg[sizeof(errmsg) - 1] = '\0'; perror(errmsg); _exit(128); } _exit(128); } (void)close(fds[0]); (void)close(fds[1]); (void)close(fds[2]); // free arguments for (int i = 0; argv[i] != NULL; i++) free(argv[i]); delete[] argv; // free environment for (int i = 0; envp[i] != NULL; i++) free(envp[i]); delete[] envp; Dictionary::Ptr response = new Dictionary(); response->Set("rc", pid); if (errorCode) response->Set("errno", errorCode); return response; } static Value ProcessKillImpl(struct msghdr *msgh, const Dictionary::Ptr& request) { pid_t pid = request->Get("pid"); int signum = request->Get("signum"); errno = 0; kill(pid, signum); int error = errno; Dictionary::Ptr response = new Dictionary(); response->Set("errno", error); return response; } static Value ProcessWaitPIDImpl(struct msghdr *msgh, const Dictionary::Ptr& request) { pid_t pid = request->Get("pid"); int status; int rc = waitpid(pid, &status, 0); Dictionary::Ptr response = new Dictionary(); response->Set("status", status); response->Set("rc", rc); return response; } static void ProcessHandler(void) { sigset_t mask; sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, NULL); rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { rlim_t maxfds = rl.rlim_max; if (maxfds == RLIM_INFINITY) maxfds = 65536; for (rlim_t i = 3; i < maxfds; i++) if (i != static_cast(l_ProcessControlFD)) (void)close(i); } for (;;) { size_t length; struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec io; io.iov_base = &length; io.iov_len = sizeof(length); msg.msg_iov = &io; msg.msg_iovlen = 1; char cbuf[4096]; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); int rc = recvmsg(l_ProcessControlFD, &msg, 0); if (rc <= 0) { if (rc < 0 && (errno == EINTR || errno == EAGAIN)) continue; break; } char *mbuf = new char[length]; size_t count = 0; while (count < length) { rc = recv(l_ProcessControlFD, mbuf + count, length - count, 0); if (rc <= 0) { if (rc < 0 && (errno == EINTR || errno == EAGAIN)) continue; delete [] mbuf; _exit(0); } count += rc; if (rc == 0) break; } String jrequest = String(mbuf, mbuf + count); delete [] mbuf; Dictionary::Ptr request = JsonDecode(jrequest); String command = request->Get("command"); Value response; if (command == "spawn") response = ProcessSpawnImpl(&msg, request); else if (command == "waitpid") response = ProcessWaitPIDImpl(&msg, request); else if (command == "kill") response = ProcessKillImpl(&msg, request); else response = Empty; String jresponse = JsonEncode(response); if (send(l_ProcessControlFD, jresponse.CStr(), jresponse.GetLength(), 0) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("send") << boost::errinfo_errno(errno)); } } _exit(0); } static void StartSpawnProcessHelper(void) { if (l_ProcessControlFD != -1) { (void)close(l_ProcessControlFD); int status; (void)waitpid(l_ProcessControlPID, &status, 0); } int controlFDs[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, controlFDs) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("socketpair") << boost::errinfo_errno(errno)); } pid_t pid = fork(); if (pid < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fork") << boost::errinfo_errno(errno)); } if (pid == 0) { (void)close(controlFDs[1]); l_ProcessControlFD = controlFDs[0]; ProcessHandler(); _exit(1); } (void)close(controlFDs[0]); l_ProcessControlFD = controlFDs[1]; l_ProcessControlPID = pid; } static pid_t ProcessSpawn(const std::vector& arguments, const Dictionary::Ptr& extraEnvironment, bool adjustPriority, int fds[3]) { Dictionary::Ptr request = new Dictionary(); request->Set("command", "spawn"); request->Set("arguments", Array::FromVector(arguments)); request->Set("extraEnvironment", extraEnvironment); request->Set("adjustPriority", adjustPriority); String jrequest = JsonEncode(request); size_t length = jrequest.GetLength(); boost::mutex::scoped_lock lock(l_ProcessControlMutex); struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec io; io.iov_base = &length; io.iov_len = sizeof(length); msg.msg_iov = &io; msg.msg_iovlen = 1; char cbuf[CMSG_SPACE(sizeof(int) * 3)]; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 3); memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * 3); msg.msg_controllen = cmsg->cmsg_len; send_message: while (sendmsg(l_ProcessControlFD, &msg, 0) < 0) StartSpawnProcessHelper(); if (send(l_ProcessControlFD, jrequest.CStr(), jrequest.GetLength(), 0) < 0) goto send_message; char buf[4096]; ssize_t rc = recv(l_ProcessControlFD, buf, sizeof(buf), 0); if (rc <= 0) return -1; String jresponse = String(buf, buf + rc); Dictionary::Ptr response = JsonDecode(jresponse); if (response->Get("rc") == -1) errno = response->Get("errno"); return response->Get("rc"); } static int ProcessKill(pid_t pid, int signum) { Dictionary::Ptr request = new Dictionary(); request->Set("command", "kill"); request->Set("pid", pid); request->Set("signum", signum); String jrequest = JsonEncode(request); size_t length = jrequest.GetLength(); boost::mutex::scoped_lock lock(l_ProcessControlMutex); send_message: while (send(l_ProcessControlFD, &length, sizeof(length), 0) < 0) StartSpawnProcessHelper(); if (send(l_ProcessControlFD, jrequest.CStr(), jrequest.GetLength(), 0) < 0) goto send_message; char buf[4096]; ssize_t rc = recv(l_ProcessControlFD, buf, sizeof(buf), 0); if (rc <= 0) return -1; String jresponse = String(buf, buf + rc); Dictionary::Ptr response = JsonDecode(jresponse); return response->Get("errno"); } static int ProcessWaitPID(pid_t pid, int *status) { Dictionary::Ptr request = new Dictionary(); request->Set("command", "waitpid"); request->Set("pid", pid); String jrequest = JsonEncode(request); size_t length = jrequest.GetLength(); boost::mutex::scoped_lock lock(l_ProcessControlMutex); send_message: while (send(l_ProcessControlFD, &length, sizeof(length), 0) < 0) StartSpawnProcessHelper(); if (send(l_ProcessControlFD, jrequest.CStr(), jrequest.GetLength(), 0) < 0) goto send_message; char buf[4096]; ssize_t rc = recv(l_ProcessControlFD, buf, sizeof(buf), 0); if (rc <= 0) return -1; String jresponse = String(buf, buf + rc); Dictionary::Ptr response = JsonDecode(jresponse); *status = response->Get("status"); return response->Get("rc"); } void Process::InitializeSpawnHelper(void) { if (l_ProcessControlFD == -1) StartSpawnProcessHelper(); } #endif /* _WIN32 */ static void InitializeProcess(void) { for (int tid = 0; tid < IOTHREADS; tid++) { #ifdef _WIN32 l_Events[tid] = CreateEvent(NULL, TRUE, FALSE, NULL); #else /* _WIN32 */ # ifdef HAVE_PIPE2 if (pipe2(l_EventFDs[tid], O_CLOEXEC) < 0) { if (errno == ENOSYS) { # endif /* HAVE_PIPE2 */ if (pipe(l_EventFDs[tid]) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("pipe") << boost::errinfo_errno(errno)); } Utility::SetCloExec(l_EventFDs[tid][0]); Utility::SetCloExec(l_EventFDs[tid][1]); # ifdef HAVE_PIPE2 } else { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("pipe2") << boost::errinfo_errno(errno)); } } # endif /* HAVE_PIPE2 */ #endif /* _WIN32 */ } } INITIALIZE_ONCE(InitializeProcess); void Process::ThreadInitialize(void) { /* Note to self: Make sure this runs _after_ we've daemonized. */ for (int tid = 0; tid < IOTHREADS; tid++) { boost::thread t(boost::bind(&Process::IOThreadProc, tid)); t.detach(); } } Process::Arguments Process::PrepareCommand(const Value& command) { #ifdef _WIN32 String args; #else /* _WIN32 */ std::vector args; #endif /* _WIN32 */ if (command.IsObjectType()) { Array::Ptr arguments = command; ObjectLock olock(arguments); for (const Value& argument : arguments) { #ifdef _WIN32 if (args != "") args += " "; args += Utility::EscapeCreateProcessArg(argument); #else /* _WIN32 */ args.push_back(argument); #endif /* _WIN32 */ } return args; } #ifdef _WIN32 return command; #else /* _WIN32 */ args.push_back("sh"); args.push_back("-c"); args.push_back(command); return args; #endif } void Process::SetTimeout(double timeout) { m_Timeout = timeout; } double Process::GetTimeout(void) const { return m_Timeout; } void Process::SetAdjustPriority(bool adjust) { m_AdjustPriority = adjust; } bool Process::GetAdjustPriority(void) const { return m_AdjustPriority; } void Process::IOThreadProc(int tid) { #ifdef _WIN32 HANDLE *handles = NULL; HANDLE *fhandles = NULL; #else /* _WIN32 */ pollfd *pfds = NULL; #endif /* _WIN32 */ int count = 0; double now; Utility::SetThreadName("ProcessIO"); for (;;) { double timeout = -1; now = Utility::GetTime(); { boost::mutex::scoped_lock lock(l_ProcessMutex[tid]); count = 1 + l_Processes[tid].size(); #ifdef _WIN32 handles = reinterpret_cast(realloc(handles, sizeof(HANDLE) * count)); fhandles = reinterpret_cast(realloc(fhandles, sizeof(HANDLE) * count)); fhandles[0] = l_Events[tid]; #else /* _WIN32 */ pfds = reinterpret_cast(realloc(pfds, sizeof(pollfd) * count)); pfds[0].fd = l_EventFDs[tid][0]; pfds[0].events = POLLIN; pfds[0].revents = 0; #endif /* _WIN32 */ int i = 1; typedef std::pair kv_pair; for (const kv_pair& kv : l_Processes[tid]) { const Process::Ptr& process = kv.second; #ifdef _WIN32 handles[i] = kv.first; if (!process->m_ReadPending) { process->m_ReadPending = true; BOOL res = ReadFile(process->m_FD, process->m_ReadBuffer, sizeof(process->m_ReadBuffer), 0, &process->m_Overlapped); if (res || GetLastError() != ERROR_IO_PENDING) { process->m_ReadFailed = !res; SetEvent(process->m_Overlapped.hEvent); } } fhandles[i] = process->m_Overlapped.hEvent; #else /* _WIN32 */ pfds[i].fd = process->m_FD; pfds[i].events = POLLIN; pfds[i].revents = 0; #endif /* _WIN32 */ if (process->m_Timeout != 0) { double delta = process->m_Timeout - (now - process->m_Result.ExecutionStart); if (timeout == -1 || delta < timeout) timeout = delta; } i++; } } if (timeout < 0.01) timeout = 0.5; timeout *= 1000; #ifdef _WIN32 DWORD rc = WaitForMultipleObjects(count, fhandles, FALSE, timeout == -1 ? INFINITE : static_cast(timeout)); #else /* _WIN32 */ int rc = poll(pfds, count, timeout); if (rc < 0) continue; #endif /* _WIN32 */ now = Utility::GetTime(); { boost::mutex::scoped_lock lock(l_ProcessMutex[tid]); #ifdef _WIN32 if (rc == WAIT_OBJECT_0) ResetEvent(l_Events[tid]); #else /* _WIN32 */ if (pfds[0].revents & (POLLIN | POLLHUP | POLLERR)) { char buffer[512]; if (read(l_EventFDs[tid][0], buffer, sizeof(buffer)) < 0) Log(LogCritical, "base", "Read from event FD failed."); } #endif /* _WIN32 */ for (int i = 1; i < count; i++) { #ifdef _WIN32 auto it = l_Processes[tid].find(handles[i]); #else /* _WIN32 */ auto it2 = l_FDs[tid].find(pfds[i].fd); if (it2 == l_FDs[tid].end()) continue; /* This should never happen. */ auto it = l_Processes[tid].find(it2->second); #endif /* _WIN32 */ if (it == l_Processes[tid].end()) continue; /* This should never happen. */ bool is_timeout = false; if (it->second->m_Timeout != 0) { double timeout = it->second->m_Result.ExecutionStart + it->second->m_Timeout; if (timeout < now) is_timeout = true; } #ifdef _WIN32 if (rc == WAIT_OBJECT_0 + i || is_timeout) { #else /* _WIN32 */ if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR) || is_timeout) { #endif /* _WIN32 */ if (!it->second->DoEvents()) { #ifdef _WIN32 CloseHandle(it->first); CloseHandle(it->second->m_FD); #else /* _WIN32 */ l_FDs[tid].erase(it->second->m_FD); (void)close(it->second->m_FD); #endif /* _WIN32 */ l_Processes[tid].erase(it); } } } } } } String Process::PrettyPrintArguments(const Process::Arguments& arguments) { #ifdef _WIN32 return "'" + arguments + "'"; #else /* _WIN32 */ return "'" + boost::algorithm::join(arguments, "' '") + "'"; #endif /* _WIN32 */ } #ifdef _WIN32 static BOOL CreatePipeOverlapped(HANDLE *outReadPipe, HANDLE *outWritePipe, SECURITY_ATTRIBUTES *securityAttributes, DWORD size, DWORD readMode, DWORD writeMode) { static LONG pipeIndex = 0; if (size == 0) size = 8192; LONG currentIndex = InterlockedIncrement(&pipeIndex); char pipeName[128]; sprintf(pipeName, "\\\\.\\Pipe\\OverlappedPipe.%d.%d", (int)GetCurrentProcessId(), (int)currentIndex); *outReadPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND | readMode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, size, size, 60 * 1000, securityAttributes); if (*outReadPipe == INVALID_HANDLE_VALUE) return FALSE; *outWritePipe = CreateFile(pipeName, GENERIC_WRITE, 0, securityAttributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | writeMode, NULL); if (*outWritePipe == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); CloseHandle(*outReadPipe); SetLastError(error); return FALSE; } return TRUE; } #endif /* _WIN32 */ void Process::Run(const boost::function& callback) { #ifndef _WIN32 boost::call_once(l_SpawnHelperOnceFlag, &Process::InitializeSpawnHelper); #endif /* _WIN32 */ boost::call_once(l_ProcessOnceFlag, &Process::ThreadInitialize); m_Result.ExecutionStart = Utility::GetTime(); #ifdef _WIN32 SECURITY_ATTRIBUTES sa = {}; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; HANDLE outReadPipe, outWritePipe; if (!CreatePipeOverlapped(&outReadPipe, &outWritePipe, &sa, 0, FILE_FLAG_OVERLAPPED, 0)) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("CreatePipe") << errinfo_win32_error(GetLastError())); if (!SetHandleInformation(outReadPipe, HANDLE_FLAG_INHERIT, 0)) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("SetHandleInformation") << errinfo_win32_error(GetLastError())); HANDLE outWritePipeDup; if (!DuplicateHandle(GetCurrentProcess(), outWritePipe, GetCurrentProcess(), &outWritePipeDup, 0, TRUE, DUPLICATE_SAME_ACCESS)) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("DuplicateHandle") << errinfo_win32_error(GetLastError())); /* LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; SIZE_T cbSize; if (!InitializeProcThreadAttributeList(NULL, 1, 0, &cbSize) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("InitializeProcThreadAttributeList") << errinfo_win32_error(GetLastError())); lpAttributeList = reinterpret_cast(new char[cbSize]); if (!InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &cbSize)) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("InitializeProcThreadAttributeList") << errinfo_win32_error(GetLastError())); HANDLE rgHandles[3]; rgHandles[0] = outWritePipe; rgHandles[1] = outWritePipeDup; rgHandles[2] = GetStdHandle(STD_INPUT_HANDLE); if (!UpdateProcThreadAttribute(lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, rgHandles, sizeof(rgHandles), NULL, NULL)) BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("UpdateProcThreadAttribute") << errinfo_win32_error(GetLastError())); */ STARTUPINFOEX si = {}; si.StartupInfo.cb = sizeof(si); si.StartupInfo.hStdError = outWritePipe; si.StartupInfo.hStdOutput = outWritePipeDup; si.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; // si.lpAttributeList = lpAttributeList; PROCESS_INFORMATION pi; char *args = new char[m_Arguments.GetLength() + 1]; strncpy(args, m_Arguments.CStr(), m_Arguments.GetLength() + 1); args[m_Arguments.GetLength()] = '\0'; LPCH pEnvironment = GetEnvironmentStrings(); size_t ioffset = 0, offset = 0; char *envp = NULL; for (;;) { size_t len = strlen(pEnvironment + ioffset); if (len == 0) break; char *eqp = strchr(pEnvironment + ioffset, '='); if (eqp && m_ExtraEnvironment && m_ExtraEnvironment->Contains(String(pEnvironment + ioffset, eqp))) { ioffset += len + 1; continue; } envp = static_cast(realloc(envp, offset + len + 1)); if (envp == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); strcpy(envp + offset, pEnvironment + ioffset); offset += len + 1; ioffset += len + 1; } FreeEnvironmentStrings(pEnvironment); if (m_ExtraEnvironment) { ObjectLock olock(m_ExtraEnvironment); for (const Dictionary::Pair& kv : m_ExtraEnvironment) { String skv = kv.first + "=" + Convert::ToString(kv.second); envp = static_cast(realloc(envp, offset + skv.GetLength() + 1)); if (envp == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); strcpy(envp + offset, skv.CStr()); offset += skv.GetLength() + 1; } } envp = static_cast(realloc(envp, offset + 1)); if (envp == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); envp[offset] = '\0'; if (!CreateProcess(NULL, args, NULL, NULL, TRUE, 0 /*EXTENDED_STARTUPINFO_PRESENT*/, envp, NULL, &si.StartupInfo, &pi)) { DWORD error = GetLastError(); CloseHandle(outWritePipe); CloseHandle(outWritePipeDup); free(envp); /* DeleteProcThreadAttributeList(lpAttributeList); delete [] reinterpret_cast(lpAttributeList); */ m_Result.PID = 0; m_Result.ExecutionEnd = Utility::GetTime(); m_Result.ExitStatus = 127; m_Result.Output = "Command " + String(args) + " failed to execute: " + Utility::FormatErrorNumber(error); delete [] args; if (callback) Utility::QueueAsyncCallback(boost::bind(callback, m_Result)); return; } delete [] args; free(envp); /* DeleteProcThreadAttributeList(lpAttributeList); delete [] reinterpret_cast(lpAttributeList); */ CloseHandle(outWritePipe); CloseHandle(outWritePipeDup); CloseHandle(pi.hThread); m_Process = pi.hProcess; m_FD = outReadPipe; m_PID = pi.dwProcessId; Log(LogNotice, "Process") << "Running command " << PrettyPrintArguments(m_Arguments) << ": PID " << m_PID; #else /* _WIN32 */ int outfds[2]; #ifdef HAVE_PIPE2 if (pipe2(outfds, O_CLOEXEC) < 0) { if (errno == ENOSYS) { #endif /* HAVE_PIPE2 */ if (pipe(outfds) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("pipe") << boost::errinfo_errno(errno)); } Utility::SetCloExec(outfds[0]); Utility::SetCloExec(outfds[1]); #ifdef HAVE_PIPE2 } else { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("pipe2") << boost::errinfo_errno(errno)); } } #endif /* HAVE_PIPE2 */ int fds[3]; fds[0] = STDIN_FILENO; fds[1] = outfds[1]; fds[2] = outfds[1]; m_Process = ProcessSpawn(m_Arguments, m_ExtraEnvironment, m_AdjustPriority, fds); m_PID = m_Process; if (m_PID == -1) { m_OutputStream << "Fork failed with error code " << errno << " (" << Utility::FormatErrorNumber(errno) << ")"; Log(LogCritical, "Process", m_OutputStream.str()); } Log(LogNotice, "Process") << "Running command " << PrettyPrintArguments(m_Arguments) << ": PID " << m_PID; (void)close(outfds[1]); Utility::SetNonBlocking(outfds[0]); m_FD = outfds[0]; #endif /* _WIN32 */ m_Callback = callback; int tid = GetTID(); { boost::mutex::scoped_lock lock(l_ProcessMutex[tid]); l_Processes[tid][m_Process] = this; #ifndef _WIN32 l_FDs[tid][m_FD] = m_Process; #endif /* _WIN32 */ } #ifdef _WIN32 SetEvent(l_Events[tid]); #else /* _WIN32 */ if (write(l_EventFDs[tid][1], "T", 1) < 0 && errno != EINTR && errno != EAGAIN) Log(LogCritical, "base", "Write to event FD failed."); #endif /* _WIN32 */ } bool Process::DoEvents(void) { bool is_timeout = false; #ifndef _WIN32 bool could_not_kill = false; #endif /* _WIN32 */ if (m_Timeout != 0) { double timeout = m_Result.ExecutionStart + m_Timeout; if (timeout < Utility::GetTime()) { Log(LogWarning, "Process") << "Killing process group " << m_PID << " (" << PrettyPrintArguments(m_Arguments) << ") after timeout of " << m_Timeout << " seconds"; m_OutputStream << ""; #ifdef _WIN32 TerminateProcess(m_Process, 1); #else /* _WIN32 */ int error = ProcessKill(-m_Process, SIGKILL); if (error) { Log(LogWarning, "Process") << "Couldn't kill the process group " << m_PID << " (" << PrettyPrintArguments(m_Arguments) << "): [errno " << error << "] " << strerror(error); could_not_kill = true; } #endif /* _WIN32 */ is_timeout = true; } } if (!is_timeout) { #ifdef _WIN32 m_ReadPending = false; DWORD rc; if (!m_ReadFailed && GetOverlappedResult(m_FD, &m_Overlapped, &rc, TRUE) && rc > 0) { m_OutputStream.write(m_ReadBuffer, rc); return true; } #else /* _WIN32 */ char buffer[512]; for (;;) { int rc = read(m_FD, buffer, sizeof(buffer)); if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return true; if (rc > 0) { m_OutputStream.write(buffer, rc); continue; } break; } #endif /* _WIN32 */ } String output = m_OutputStream.str(); #ifdef _WIN32 WaitForSingleObject(m_Process, INFINITE); DWORD exitcode; GetExitCodeProcess(m_Process, &exitcode); Log(LogNotice, "Process") << "PID " << m_PID << " (" << PrettyPrintArguments(m_Arguments) << ") terminated with exit code " << exitcode; #else /* _WIN32 */ int status, exitcode; if (could_not_kill || m_PID == -1) { exitcode = 128; } else if (ProcessWaitPID(m_Process, &status) != m_Process) { exitcode = 128; Log(LogWarning, "Process") << "PID " << m_PID << " (" << PrettyPrintArguments(m_Arguments) << ") died mysteriously: waitpid failed"; } else if (WIFEXITED(status)) { exitcode = WEXITSTATUS(status); Log(LogNotice, "Process") << "PID " << m_PID << " (" << PrettyPrintArguments(m_Arguments) << ") terminated with exit code " << exitcode; } else if (WIFSIGNALED(status)) { int signum = WTERMSIG(status); const char *zsigname = strsignal(signum); String signame = Convert::ToString(signum); if (zsigname) { signame += " ("; signame += zsigname; signame += ")"; } Log(LogWarning, "Process") << "PID " << m_PID << " was terminated by signal " << signame; std::ostringstream outputbuf; outputbuf << ""; output = output + outputbuf.str(); exitcode = 128; } else { exitcode = 128; } #endif /* _WIN32 */ m_Result.PID = m_PID; m_Result.ExecutionEnd = Utility::GetTime(); m_Result.ExitStatus = exitcode; m_Result.Output = output; if (m_Callback) Utility::QueueAsyncCallback(boost::bind(m_Callback, m_Result)); return false; } pid_t Process::GetPID(void) const { return m_PID; } int Process::GetTID(void) const { return (reinterpret_cast(this) / sizeof(void *)) % IOTHREADS; } icinga2-2.8.1/lib/base/process.hpp000066400000000000000000000067261322762156600167320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PROCESS_H #define PROCESS_H #include "base/i2-base.hpp" #include "base/dictionary.hpp" #include #include #include #include namespace icinga { /** * The result of a Process task. * * @ingroup base */ struct ProcessResult { pid_t PID; double ExecutionStart; double ExecutionEnd; long ExitStatus; String Output; }; /** * A process task. Executes an external application and returns the exit * code and console output. * * @ingroup base */ class I2_BASE_API Process : public Object { public: DECLARE_PTR_TYPEDEFS(Process); #ifdef _WIN32 typedef String Arguments; typedef HANDLE ProcessHandle; typedef HANDLE ConsoleHandle; #else /* _WIN32 */ typedef std::vector Arguments; typedef pid_t ProcessHandle; typedef int ConsoleHandle; #endif /* _WIN32 */ static const std::deque::size_type MaxTasksPerThread = 512; Process(const Arguments& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr()); ~Process(void); void SetTimeout(double timeout); double GetTimeout(void) const; void SetAdjustPriority(bool adjust); bool GetAdjustPriority(void) const; void Run(const boost::function& callback = boost::function()); pid_t GetPID(void) const; static Arguments PrepareCommand(const Value& command); static void ThreadInitialize(void); static String PrettyPrintArguments(const Arguments& arguments); #ifndef _WIN32 static void InitializeSpawnHelper(void); #endif /* _WIN32 */ private: Arguments m_Arguments; Dictionary::Ptr m_ExtraEnvironment; double m_Timeout; bool m_AdjustPriority; ProcessHandle m_Process; pid_t m_PID; ConsoleHandle m_FD; #ifdef _WIN32 bool m_ReadPending; bool m_ReadFailed; OVERLAPPED m_Overlapped; char m_ReadBuffer[1024]; #endif /* _WIN32 */ std::ostringstream m_OutputStream; boost::function m_Callback; ProcessResult m_Result; static void IOThreadProc(int tid); bool DoEvents(void); int GetTID(void) const; }; } #endif /* PROCESS_H */ icinga2-2.8.1/lib/base/registry.hpp000066400000000000000000000065561322762156600171250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef REGISTRY_H #define REGISTRY_H #include "base/i2-base.hpp" #include "base/string.hpp" #include #include #include namespace icinga { /** * A registry. * * @ingroup base */ template class Registry { public: typedef std::map ItemMap; void RegisterIfNew(const String& name, const T& item) { boost::mutex::scoped_lock lock(m_Mutex); if (m_Items.find(name) != m_Items.end()) return; RegisterInternal(name, item, lock); } void Register(const String& name, const T& item) { boost::mutex::scoped_lock lock(m_Mutex); RegisterInternal(name, item, lock); } void Unregister(const String& name) { size_t erased; { boost::mutex::scoped_lock lock(m_Mutex); erased = m_Items.erase(name); } if (erased > 0) OnUnregistered(name); } void Clear(void) { typename Registry::ItemMap items; { boost::mutex::scoped_lock lock(m_Mutex); items = m_Items; } for (const auto& kv : items) { OnUnregistered(kv.first); } { boost::mutex::scoped_lock lock(m_Mutex); m_Items.clear(); } } T GetItem(const String& name) const { boost::mutex::scoped_lock lock(m_Mutex); auto it = m_Items.find(name); if (it == m_Items.end()) return T(); return it->second; } ItemMap GetItems(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_Items; /* Makes a copy of the map. */ } boost::signals2::signal OnRegistered; boost::signals2::signal OnUnregistered; private: mutable boost::mutex m_Mutex; typename Registry::ItemMap m_Items; void RegisterInternal(const String& name, const T& item, boost::mutex::scoped_lock& lock) { bool old_item = false; if (m_Items.erase(name) > 0) old_item = true; m_Items[name] = item; lock.unlock(); if (old_item) OnUnregistered(name); OnRegistered(name, item); } }; } #endif /* REGISTRY_H */ icinga2-2.8.1/lib/base/ringbuffer.cpp000066400000000000000000000047651322762156600174010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/ringbuffer.hpp" #include "base/objectlock.hpp" using namespace icinga; RingBuffer::RingBuffer(RingBuffer::SizeType slots) : Object(), m_Slots(slots, 0), m_TimeValue(0) { } RingBuffer::SizeType RingBuffer::GetLength(void) const { ObjectLock olock(this); return m_Slots.size(); } void RingBuffer::InsertValue(RingBuffer::SizeType tv, int num) { ObjectLock olock(this); RingBuffer::SizeType offsetTarget = tv % m_Slots.size(); if (tv > m_TimeValue) { RingBuffer::SizeType offset = m_TimeValue % m_Slots.size(); /* walk towards the target offset, resetting slots to 0 */ while (offset != offsetTarget) { offset++; if (offset >= m_Slots.size()) offset = 0; m_Slots[offset] = 0; } m_TimeValue = tv; } m_Slots[offsetTarget] += num; } int RingBuffer::GetValues(RingBuffer::SizeType span) const { ObjectLock olock(this); if (span > m_Slots.size()) span = m_Slots.size(); int off = m_TimeValue % m_Slots.size();; int sum = 0; while (span > 0) { sum += m_Slots[off]; if (off == 0) off = m_Slots.size(); off--; span--; } return sum; } icinga2-2.8.1/lib/base/ringbuffer.hpp000066400000000000000000000037721322762156600174030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef RINGBUFFER_H #define RINGBUFFER_H #include "base/i2-base.hpp" #include "base/object.hpp" #include namespace icinga { /** * A ring buffer that holds a pre-defined number of integers. * * @ingroup base */ class I2_BASE_API RingBuffer : public Object { public: DECLARE_PTR_TYPEDEFS(RingBuffer); typedef std::vector::size_type SizeType; RingBuffer(SizeType slots); SizeType GetLength(void) const; void InsertValue(SizeType tv, int num); int GetValues(SizeType span) const; private: std::vector m_Slots; SizeType m_TimeValue; }; } #endif /* RINGBUFFER_H */ icinga2-2.8.1/lib/base/scriptframe.cpp000066400000000000000000000075521322762156600175640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/scriptframe.hpp" #include "base/scriptglobal.hpp" #include "base/exception.hpp" using namespace icinga; boost::thread_specific_ptr > ScriptFrame::m_ScriptFrames; Array::Ptr ScriptFrame::m_Imports; INITIALIZE_ONCE_WITH_PRIORITY([]() { Dictionary::Ptr systemNS = new Dictionary(); ScriptGlobal::Set("System", systemNS); ScriptFrame::AddImport(systemNS); Dictionary::Ptr typesNS = new Dictionary(); ScriptGlobal::Set("Types", typesNS); ScriptFrame::AddImport(typesNS); Dictionary::Ptr deprecatedNS = new Dictionary(); ScriptGlobal::Set("Deprecated", deprecatedNS); ScriptFrame::AddImport(deprecatedNS); }, 50); ScriptFrame::ScriptFrame(void) : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0) { InitializeFrame(); } ScriptFrame::ScriptFrame(const Value& self) : Locals(new Dictionary()), Self(self), Sandboxed(false), Depth(0) { InitializeFrame(); } void ScriptFrame::InitializeFrame(void) { std::stack *frames = m_ScriptFrames.get(); if (frames && !frames->empty()) { ScriptFrame *frame = frames->top(); Sandboxed = frame->Sandboxed; } PushFrame(this); } ScriptFrame::~ScriptFrame(void) { ScriptFrame *frame = PopFrame(); ASSERT(frame == this); } void ScriptFrame::IncreaseStackDepth(void) { if (Depth + 1 > 300) BOOST_THROW_EXCEPTION(ScriptError("Stack overflow while evaluating expression: Recursion level too deep.")); Depth++; } void ScriptFrame::DecreaseStackDepth(void) { Depth--; } ScriptFrame *ScriptFrame::GetCurrentFrame(void) { std::stack *frames = m_ScriptFrames.get(); ASSERT(!frames->empty()); return frames->top(); } ScriptFrame *ScriptFrame::PopFrame(void) { std::stack *frames = m_ScriptFrames.get(); ASSERT(!frames->empty()); ScriptFrame *frame = frames->top(); frames->pop(); return frame; } void ScriptFrame::PushFrame(ScriptFrame *frame) { std::stack *frames = m_ScriptFrames.get(); if (!frames) { frames = new std::stack(); m_ScriptFrames.reset(frames); } if (!frames->empty()) { ScriptFrame *parent = frames->top(); frame->Depth += parent->Depth; } frames->push(frame); } Array::Ptr ScriptFrame::GetImports(void) { return m_Imports; } void ScriptFrame::AddImport(const Object::Ptr& import) { Array::Ptr imports; if (!m_Imports) imports = new Array(); else imports = m_Imports->ShallowClone(); imports->Add(import); m_Imports = imports; } icinga2-2.8.1/lib/base/scriptframe.hpp000066400000000000000000000043671322762156600175720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCRIPTFRAME_H #define SCRIPTFRAME_H #include "base/i2-base.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include #include namespace icinga { struct I2_BASE_API ScriptFrame { Dictionary::Ptr Locals; Value Self; bool Sandboxed; int Depth; ScriptFrame(void); ScriptFrame(const Value& self); ~ScriptFrame(void); void IncreaseStackDepth(void); void DecreaseStackDepth(void); static ScriptFrame *GetCurrentFrame(void); static Array::Ptr GetImports(void); static void AddImport(const Object::Ptr& import); private: static boost::thread_specific_ptr > m_ScriptFrames; static Array::Ptr m_Imports; inline static void PushFrame(ScriptFrame *frame); inline static ScriptFrame *PopFrame(void); void InitializeFrame(void); }; } #endif /* SCRIPTFRAME_H */ icinga2-2.8.1/lib/base/scriptglobal.cpp000066400000000000000000000101371322762156600177230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/scriptglobal.hpp" #include "base/singleton.hpp" #include "base/logger.hpp" #include "base/stdiostream.hpp" #include "base/netstring.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" #include #include using namespace icinga; Dictionary::Ptr ScriptGlobal::m_Globals = new Dictionary(); Value ScriptGlobal::Get(const String& name, const Value *defaultValue) { Value result; if (!m_Globals->Get(name, &result)) { if (defaultValue) return *defaultValue; BOOST_THROW_EXCEPTION(std::invalid_argument("Tried to access undefined script variable '" + name + "'")); } return result; } void ScriptGlobal::Set(const String& name, const Value& value) { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of(".")); if (tokens.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Name must not be empty")); { ObjectLock olock(m_Globals); Dictionary::Ptr parent = m_Globals; for (std::vector::size_type i = 0; i < tokens.size(); i++) { const String& token = tokens[i]; if (i + 1 != tokens.size()) { Value vparent; if (!parent->Get(token, &vparent)) { Dictionary::Ptr dict = new Dictionary(); parent->Set(token, dict); parent = dict; } else { parent = vparent; } } } parent->Set(tokens[tokens.size() - 1], value); } } bool ScriptGlobal::Exists(const String& name) { return m_Globals->Contains(name); } Dictionary::Ptr ScriptGlobal::GetGlobals(void) { return m_Globals; } void ScriptGlobal::WriteToFile(const String& filename) { Log(LogInformation, "ScriptGlobal") << "Dumping variables to file '" << filename << "'"; std::fstream fp; String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", 0600, fp); if (!fp) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); StdioStream::Ptr sfp = new StdioStream(&fp, false); ObjectLock olock(m_Globals); for (const Dictionary::Pair& kv : m_Globals) { Dictionary::Ptr persistentVariable = new Dictionary(); persistentVariable->Set("name", kv.first); Value value = kv.second; if (value.IsObject()) value = Convert::ToString(value); persistentVariable->Set("value", value); String json = JsonEncode(persistentVariable); NetString::WriteStringToStream(sfp, json); } sfp->Close(); fp.close(); #ifdef _WIN32 _unlink(filename.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), filename.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } } icinga2-2.8.1/lib/base/scriptglobal.hpp000066400000000000000000000037341322762156600177350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCRIPTGLOBAL_H #define SCRIPTGLOBAL_H #include "base/i2-base.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Global script variables. * * @ingroup base */ class I2_BASE_API ScriptGlobal { public: static Value Get(const String& name, const Value *defaultValue = NULL); static void Set(const String& name, const Value& value); static bool Exists(const String& name); static void WriteToFile(const String& filename); static Dictionary::Ptr GetGlobals(void); private: static Dictionary::Ptr m_Globals; }; } #endif /* SCRIPTGLOBAL_H */ icinga2-2.8.1/lib/base/scriptutils.cpp000066400000000000000000000330041322762156600176210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/scriptutils.hpp" #include "base/function.hpp" #include "base/scriptframe.hpp" #include "base/exception.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include "base/json.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/configtype.hpp" #include "base/application.hpp" #include "base/dependencygraph.hpp" #include "base/initialize.hpp" #include #include #include #ifdef _WIN32 #include #endif /* _WIN32 */ using namespace icinga; REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex, "pattern:text:mode"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &ScriptUtils::Match, "pattern:text:mode"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, cidr_match, &ScriptUtils::CidrMatch, "pattern:ip:mode"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, len, &ScriptUtils::Len, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, union, &ScriptUtils::Union, ""); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, intersection, &ScriptUtils::Intersection, ""); REGISTER_SCRIPTFUNCTION_NS(System, log, &ScriptUtils::Log, "severity:facility:value"); REGISTER_SCRIPTFUNCTION_NS(System, range, &ScriptUtils::Range, "start:end:increment"); REGISTER_SCRIPTFUNCTION_NS(System, exit, &Application::Exit, "status"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, typeof, &ScriptUtils::TypeOf, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, keys, &ScriptUtils::Keys, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, random, &Utility::Random, ""); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_object, &ScriptUtils::GetObject, "type:name"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_objects, &ScriptUtils::GetObjects, "type"); REGISTER_SCRIPTFUNCTION_NS(System, assert, &ScriptUtils::Assert, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, string, &ScriptUtils::CastString, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, number, &ScriptUtils::CastNumber, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, bool, &ScriptUtils::CastBool, "value"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_time, &Utility::GetTime, ""); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, basename, &Utility::BaseName, "path"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, dirname, &Utility::DirName, "path"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, msi_get_component_path, &ScriptUtils::MsiGetComponentPathShim, "component"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, track_parents, &ScriptUtils::TrackParents, "child"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_shell_cmd, &Utility::EscapeShellCmd, "cmd"); REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_shell_arg, &Utility::EscapeShellArg, "arg"); #ifdef _WIN32 REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_create_process_arg, &Utility::EscapeCreateProcessArg, "arg"); #endif /* _WIN32 */ REGISTER_SCRIPTFUNCTION_NS(System, ptr, &ScriptUtils::Ptr, "object"); REGISTER_SCRIPTFUNCTION_NS(System, sleep, &Utility::Sleep, "interval"); REGISTER_SCRIPTFUNCTION_NS(System, path_exists, &Utility::PathExists, "path"); REGISTER_SCRIPTFUNCTION_NS(System, glob, &ScriptUtils::Glob, "pathspec:callback:type"); REGISTER_SCRIPTFUNCTION_NS(System, glob_recursive, &ScriptUtils::GlobRecursive, "pathspec:callback:type"); INITIALIZE_ONCE(&ScriptUtils::StaticInitialize); enum MatchType { MatchAll, MatchAny }; void ScriptUtils::StaticInitialize(void) { ScriptGlobal::Set("MatchAll", MatchAll); ScriptGlobal::Set("MatchAny", MatchAny); ScriptGlobal::Set("GlobFile", GlobFile); ScriptGlobal::Set("GlobDirectory", GlobDirectory); } String ScriptUtils::CastString(const Value& value) { return value; } double ScriptUtils::CastNumber(const Value& value) { return value; } bool ScriptUtils::CastBool(const Value& value) { return value.ToBool(); } bool ScriptUtils::Regex(const std::vector& args) { if (args.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Regular expression and text must be specified.")); Array::Ptr texts = new Array(); String pattern = args[0]; Value argTexts = args[1]; MatchType mode; if (args.size() > 2) mode = static_cast(static_cast(args[2])); else mode = MatchAll; if (argTexts.IsObjectType()) texts = argTexts; else { texts = new Array(); texts->Add(argTexts); } if (texts->GetLength() == 0) return false; ObjectLock olock(texts); for (const String& text : texts) { bool res = false; try { boost::regex expr(pattern.GetData()); boost::smatch what; res = boost::regex_search(text.GetData(), what, expr); } catch (boost::exception&) { res = false; /* exception means something went terribly wrong */ } if (mode == MatchAny && res) return true; else if (mode == MatchAll && !res) return false; } return mode == MatchAll; } bool ScriptUtils::Match(const std::vector& args) { if (args.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Pattern and text must be specified.")); Array::Ptr texts = new Array(); String pattern = args[0]; Value argTexts = args[1]; MatchType mode; if (args.size() > 2) mode = static_cast(static_cast(args[2])); else mode = MatchAll; if (argTexts.IsObjectType()) texts = argTexts; else { texts = new Array(); texts->Add(argTexts); } if (texts->GetLength() == 0) return false; ObjectLock olock(texts); for (const String& text : texts) { bool res = Utility::Match(pattern, text); if (mode == MatchAny && res) return true; else if (mode == MatchAll && !res) return false; } return mode == MatchAll; } bool ScriptUtils::CidrMatch(const std::vector& args) { if (args.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("CIDR and IP address must be specified.")); Array::Ptr ips = new Array(); String pattern = args[0]; Value argIps = args[1]; MatchType mode; if (args.size() > 2) mode = static_cast(static_cast(args[2])); else mode = MatchAll; if (argIps.IsObjectType()) ips = argIps; else { ips = new Array(); ips->Add(argIps); } if (ips->GetLength() == 0) return false; ObjectLock olock(ips); for (const String& ip : ips) { bool res = Utility::CidrMatch(pattern, ip); if (mode == MatchAny && res) return true; else if (mode == MatchAll && !res) return false; } return mode == MatchAll; } double ScriptUtils::Len(const Value& value) { if (value.IsObjectType()) { Dictionary::Ptr dict = value; return dict->GetLength(); } else if (value.IsObjectType()) { Array::Ptr array = value; return array->GetLength(); } else if (value.IsString()) { return Convert::ToString(value).GetLength(); } else { return 0; } } Array::Ptr ScriptUtils::Union(const std::vector& arguments) { std::set values; for (const Value& varr : arguments) { Array::Ptr arr = varr; if (arr) { ObjectLock olock(arr); for (const Value& value : arr) { values.insert(value); } } } Array::Ptr result = new Array(); for (const Value& value : values) { result->Add(value); } return result; } Array::Ptr ScriptUtils::Intersection(const std::vector& arguments) { if (arguments.size() == 0) return new Array(); Array::Ptr result = new Array(); Array::Ptr arg1 = arguments[0]; if (!arg1) return result; Array::Ptr arr1 = arg1->ShallowClone(); for (std::vector::size_type i = 1; i < arguments.size(); i++) { { ObjectLock olock(arr1); std::sort(arr1->Begin(), arr1->End()); } Array::Ptr arg2 = arguments[i]; if (!arg2) return result; Array::Ptr arr2 = arg2->ShallowClone(); { ObjectLock olock(arr2); std::sort(arr2->Begin(), arr2->End()); } result->Resize(std::max(arr1->GetLength(), arr2->GetLength())); Array::SizeType len; { ObjectLock olock(arr1), xlock(arr2), ylock(result); Array::Iterator it = std::set_intersection(arr1->Begin(), arr1->End(), arr2->Begin(), arr2->End(), result->Begin()); len = it - result->Begin(); } result->Resize(len); arr1 = result; } return result; } void ScriptUtils::Log(const std::vector& arguments) { if (arguments.size() != 1 && arguments.size() != 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid number of arguments for log()")); LogSeverity severity; String facility; Value message; if (arguments.size() == 1) { severity = LogInformation; facility = "config"; message = arguments[0]; } else { int sval = static_cast(arguments[0]); severity = static_cast(sval); facility = arguments[1]; message = arguments[2]; } if (message.IsString() || (!message.IsObjectType() && !message.IsObjectType())) ::Log(severity, facility, message); else ::Log(severity, facility, JsonEncode(message)); } Array::Ptr ScriptUtils::Range(const std::vector& arguments) { double start, end, increment; switch (arguments.size()) { case 1: start = 0; end = arguments[0]; increment = 1; break; case 2: start = arguments[0]; end = arguments[1]; increment = 1; break; case 3: start = arguments[0]; end = arguments[1]; increment = arguments[2]; break; default: BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid number of arguments for range()")); } Array::Ptr result = new Array(); if ((start < end && increment <= 0) || (start > end && increment >= 0)) return result; for (double i = start; (increment > 0 ? i < end : i > end); i += increment) result->Add(i); return result; } Type::Ptr ScriptUtils::TypeOf(const Value& value) { return value.GetReflectionType(); } Array::Ptr ScriptUtils::Keys(const Dictionary::Ptr& dict) { Array::Ptr result = new Array(); if (dict) { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { result->Add(kv.first); } } return result; } ConfigObject::Ptr ScriptUtils::GetObject(const Value& vtype, const String& name) { Type::Ptr ptype; if (vtype.IsObjectType()) ptype = vtype; else ptype = Type::GetByName(vtype); ConfigType *ctype = dynamic_cast(ptype.get()); if (!ctype) return ConfigObject::Ptr(); return ctype->GetObject(name); } Array::Ptr ScriptUtils::GetObjects(const Type::Ptr& type) { if (!type) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type: Must not be null")); ConfigType *ctype = dynamic_cast(type.get()); if (!ctype) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type: Type must inherit from 'ConfigObject'")); Array::Ptr result = new Array(); for (const ConfigObject::Ptr& object : ctype->GetObjects()) result->Add(object); return result; } void ScriptUtils::Assert(const Value& arg) { if (!arg.ToBool()) BOOST_THROW_EXCEPTION(std::runtime_error("Assertion failed")); } String ScriptUtils::MsiGetComponentPathShim(const String& component) { #ifdef _WIN32 TCHAR productCode[39]; if (MsiGetProductCode(component.CStr(), productCode) != ERROR_SUCCESS) return ""; TCHAR path[2048]; DWORD szPath = sizeof(path); path[0] = '\0'; MsiGetComponentPath(productCode, component.CStr(), path, &szPath); return path; #else /* _WIN32 */ return String(); #endif /* _WIN32 */ } Array::Ptr ScriptUtils::TrackParents(const Object::Ptr& child) { return Array::FromVector(DependencyGraph::GetParents(child)); } double ScriptUtils::Ptr(const Object::Ptr& object) { return reinterpret_cast(object.get()); } static void GlobCallbackHelper(std::vector& paths, const String& path) { paths.push_back(path); } Value ScriptUtils::Glob(const std::vector& args) { if (args.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Path must be specified.")); String pathSpec = args[0]; int type = GlobFile | GlobDirectory; if (args.size() > 1) type = args[1]; std::vector paths; Utility::Glob(pathSpec, boost::bind(&GlobCallbackHelper, boost::ref(paths), _1), type); return Array::FromVector(paths); } Value ScriptUtils::GlobRecursive(const std::vector& args) { if (args.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Path and pattern must be specified.")); String path = args[0]; String pattern = args[1]; int type = GlobFile | GlobDirectory; if (args.size() > 2) type = args[2]; std::vector paths; Utility::GlobRecursive(path, pattern, boost::bind(&GlobCallbackHelper, boost::ref(paths), _1), type); return Array::FromVector(paths); } icinga2-2.8.1/lib/base/scriptutils.hpp000066400000000000000000000056521322762156600176360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCRIPTUTILS_H #define SCRIPTUTILS_H #include "base/i2-base.hpp" #include "base/string.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/type.hpp" #include "base/configobject.hpp" namespace icinga { /** * @ingroup base */ class I2_BASE_API ScriptUtils { public: static void StaticInitialize(void); static String CastString(const Value& value); static double CastNumber(const Value& value); static bool CastBool(const Value& value); static bool Regex(const std::vector& args); static bool Match(const std::vector& args); static bool CidrMatch(const std::vector& args); static double Len(const Value& value); static Array::Ptr Union(const std::vector& arguments); static Array::Ptr Intersection(const std::vector& arguments); static void Log(const std::vector& arguments); static Array::Ptr Range(const std::vector& arguments); static Type::Ptr TypeOf(const Value& value); static Array::Ptr Keys(const Dictionary::Ptr& dict); static ConfigObject::Ptr GetObject(const Value& type, const String& name); static Array::Ptr GetObjects(const Type::Ptr& type); static void Assert(const Value& arg); static String MsiGetComponentPathShim(const String& component); static Array::Ptr TrackParents(const Object::Ptr& parent); static double Ptr(const Object::Ptr& object); static Value Glob(const std::vector& args); static Value GlobRecursive(const std::vector& args); private: ScriptUtils(void); }; } #endif /* SCRIPTUTILS_H */ icinga2-2.8.1/lib/base/serializer.cpp000066400000000000000000000125721322762156600174140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/serializer.hpp" #include "base/type.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" using namespace icinga; static Array::Ptr SerializeArray(const Array::Ptr& input, int attributeTypes) { Array::Ptr result = new Array(); ObjectLock olock(input); for (const Value& value : input) { result->Add(Serialize(value, attributeTypes)); } return result; } static Dictionary::Ptr SerializeDictionary(const Dictionary::Ptr& input, int attributeTypes) { Dictionary::Ptr result = new Dictionary(); ObjectLock olock(input); for (const Dictionary::Pair& kv : input) { result->Set(kv.first, Serialize(kv.second, attributeTypes)); } return result; } static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes) { Type::Ptr type = input->GetReflectionType(); if (!type) return Object::Ptr(); Dictionary::Ptr fields = new Dictionary(); for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); if (attributeTypes != 0 && (field.Attributes & attributeTypes) == 0) continue; fields->Set(field.Name, Serialize(input->GetField(i), attributeTypes)); } fields->Set("type", type->GetName()); return fields; } static Array::Ptr DeserializeArray(const Array::Ptr& input, bool safe_mode, int attributeTypes) { Array::Ptr result = new Array(); ObjectLock olock(input); for (const Value& value : input) { result->Add(Deserialize(value, safe_mode, attributeTypes)); } return result; } static Dictionary::Ptr DeserializeDictionary(const Dictionary::Ptr& input, bool safe_mode, int attributeTypes) { Dictionary::Ptr result = new Dictionary(); ObjectLock olock(input); for (const Dictionary::Pair& kv : input) { result->Set(kv.first, Deserialize(kv.second, safe_mode, attributeTypes)); } return result; } static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary::Ptr& input, bool safe_mode, int attributeTypes) { if (!object && safe_mode) BOOST_THROW_EXCEPTION(std::runtime_error("Tried to instantiate object while safe mode is enabled.")); Type::Ptr type; if (object) type = object->GetReflectionType(); else type = Type::GetByName(input->Get("type")); if (!type) return object; Object::Ptr instance; if (object) instance = object; else instance = type->Instantiate(std::vector()); ObjectLock olock(input); for (const Dictionary::Pair& kv : input) { if (kv.first.IsEmpty()) continue; int fid = type->GetFieldId(kv.first); if (fid < 0) continue; Field field = type->GetFieldInfo(fid); if ((field.Attributes & attributeTypes) == 0) continue; try { instance->SetField(fid, Deserialize(kv.second, safe_mode, attributeTypes), true); } catch (const std::exception&) { instance->SetField(fid, Empty); } } return instance; } Value icinga::Serialize(const Value& value, int attributeTypes) { if (!value.IsObject()) return value; Object::Ptr input = value; Array::Ptr array = dynamic_pointer_cast(input); if (array != NULL) return SerializeArray(array, attributeTypes); Dictionary::Ptr dict = dynamic_pointer_cast(input); if (dict != NULL) return SerializeDictionary(dict, attributeTypes); return SerializeObject(input, attributeTypes); } Value icinga::Deserialize(const Value& value, bool safe_mode, int attributeTypes) { return Deserialize(Object::Ptr(), value, safe_mode, attributeTypes); } Value icinga::Deserialize(const Object::Ptr& object, const Value& value, bool safe_mode, int attributeTypes) { if (!value.IsObject()) return value; Object::Ptr input = value; Array::Ptr array = dynamic_pointer_cast(input); if (array != NULL) return DeserializeArray(array, safe_mode, attributeTypes); Dictionary::Ptr dict = dynamic_pointer_cast(input); ASSERT(dict != NULL); if ((safe_mode && !object) || !dict->Contains("type")) return DeserializeDictionary(dict, safe_mode, attributeTypes); else return DeserializeObject(object, dict, safe_mode, attributeTypes); } icinga2-2.8.1/lib/base/serializer.hpp000066400000000000000000000036131322762156600174150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERIALIZER_H #define SERIALIZER_H #include "base/i2-base.hpp" #include "base/type.hpp" #include "base/value.hpp" namespace icinga { I2_BASE_API Value Serialize(const Value& value, int attributeTypes = FAState); I2_BASE_API Value Deserialize(const Value& value, bool safe_mode = false, int attributeTypes = FAState); I2_BASE_API Value Deserialize(const Object::Ptr& object, const Value& value, bool safe_mode = false, int attributeTypes = FAState); } #endif /* SERIALIZER_H */ icinga2-2.8.1/lib/base/singleton.hpp000066400000000000000000000036671322762156600172570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SINGLETON_H #define SINGLETON_H #include "base/i2-base.hpp" #include namespace icinga { /** * A singleton. * * @ingroup base */ template class Singleton { public: static T *GetInstance(void) { /* FIXME: This relies on static initializers being atomic. */ static boost::mutex mutex; boost::mutex::scoped_lock lock(mutex); static T *instance; if (!instance) instance = new T(); return instance; } private: static T *m_Instance; }; } #endif /* SINGLETON_H */ icinga2-2.8.1/lib/base/socket.cpp000066400000000000000000000263051322762156600165320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/socket.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include #include #include #include #include #ifndef _WIN32 # include #endif /* _WIN32 */ using namespace icinga; /** * Constructor for the Socket class. */ Socket::Socket(void) : m_FD(INVALID_SOCKET) { } /** * Constructor for the Socket class. */ Socket::Socket(SOCKET fd) : m_FD(INVALID_SOCKET) { SetFD(fd); } /** * Destructor for the Socket class. */ Socket::~Socket(void) { Close(); } /** * Sets the file descriptor for this socket object. * * @param fd The file descriptor. */ void Socket::SetFD(SOCKET fd) { if (fd != INVALID_SOCKET) { #ifndef _WIN32 /* mark the socket as close-on-exec */ Utility::SetCloExec(fd); #endif /* _WIN32 */ } ObjectLock olock(this); m_FD = fd; } /** * Retrieves the file descriptor for this socket object. * * @returns The file descriptor. */ SOCKET Socket::GetFD(void) const { ObjectLock olock(this); return m_FD; } /** * Closes the socket. */ void Socket::Close(void) { ObjectLock olock(this); if (m_FD != INVALID_SOCKET) { closesocket(m_FD); m_FD = INVALID_SOCKET; } } /** * Retrieves the last error that occured for the socket. * * @returns An error code. */ int Socket::GetError(void) const { int opt; socklen_t optlen = sizeof(opt); int rc = getsockopt(GetFD(), SOL_SOCKET, SO_ERROR, (char *)&opt, &optlen); if (rc >= 0) return opt; return 0; } /** * Formats a sockaddr in a human-readable way. * * @returns A String describing the sockaddr. */ String Socket::GetAddressFromSockaddr(sockaddr *address, socklen_t len) { char host[NI_MAXHOST]; char service[NI_MAXSERV]; if (getnameinfo(address, len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "getnameinfo() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getnameinfo") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "getnameinfo() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getnameinfo") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } std::ostringstream s; s << "[" << host << "]:" << service; return s.str(); } /** * Returns a String describing the local address of the socket. * * @returns A String describing the local address. */ String Socket::GetClientAddress(void) { boost::mutex::scoped_lock lock(m_SocketMutex); sockaddr_storage sin; socklen_t len = sizeof(sin); if (getsockname(GetFD(), (sockaddr *)&sin, &len) < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "getsockname() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getsockname") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "getsockname() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getsockname") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } String address; try { address = GetAddressFromSockaddr((sockaddr *)&sin, len); } catch (const std::exception&) { /* already logged */ } return address; } /** * Returns a String describing the peer address of the socket. * * @returns A String describing the peer address. */ String Socket::GetPeerAddress(void) { boost::mutex::scoped_lock lock(m_SocketMutex); sockaddr_storage sin; socklen_t len = sizeof(sin); if (getpeername(GetFD(), (sockaddr *)&sin, &len) < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "getpeername() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getpeername") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "getpeername() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getpeername") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } String address; try { address = GetAddressFromSockaddr((sockaddr *)&sin, len); } catch (const std::exception&) { /* already logged */ } return address; } /** * Starts listening for incoming client connections. */ void Socket::Listen(void) { if (listen(GetFD(), SOMAXCONN) < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "listen() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("listen") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "listen() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("listen") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } } /** * Sends data for the socket. */ size_t Socket::Write(const void *buffer, size_t count) { int rc; #ifndef _WIN32 rc = write(GetFD(), (const char *)buffer, count); #else /* _WIN32 */ rc = send(GetFD(), (const char *)buffer, count, 0); #endif /* _WIN32 */ if (rc < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "send() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("send") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "send() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("send") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } return rc; } /** * Processes data that can be written for this socket. */ size_t Socket::Read(void *buffer, size_t count) { int rc; #ifndef _WIN32 rc = read(GetFD(), (char *)buffer, count); #else /* _WIN32 */ rc = recv(GetFD(), (char *)buffer, count, 0); #endif /* _WIN32 */ if (rc < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "recv() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("recv") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "recv() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("recv") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } return rc; } /** * Accepts a new client and creates a new client object for it. */ Socket::Ptr Socket::Accept(void) { int fd; sockaddr_storage addr; socklen_t addrlen = sizeof(addr); fd = accept(GetFD(), (sockaddr *)&addr, &addrlen); if (fd < 0) { #ifndef _WIN32 Log(LogCritical, "Socket") << "accept() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("accept") << boost::errinfo_errno(errno)); #else /* _WIN32 */ Log(LogCritical, "Socket") << "accept() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("accept") << errinfo_win32_error(WSAGetLastError())); #endif /* _WIN32 */ } return new Socket(fd); } bool Socket::Poll(bool read, bool write, struct timeval *timeout) { int rc; #ifdef _WIN32 fd_set readfds, writefds, exceptfds; FD_ZERO(&readfds); if (read) FD_SET(GetFD(), &readfds); FD_ZERO(&writefds); if (write) FD_SET(GetFD(), &writefds); FD_ZERO(&exceptfds); FD_SET(GetFD(), &exceptfds); rc = select(GetFD() + 1, &readfds, &writefds, &exceptfds, timeout); if (rc < 0) { Log(LogCritical, "Socket") << "select() failed with error code " << WSAGetLastError() << ", \"" << Utility::FormatErrorNumber(WSAGetLastError()) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("select") << errinfo_win32_error(WSAGetLastError())); } #else /* _WIN32 */ pollfd pfd; pfd.fd = GetFD(); pfd.events = (read ? POLLIN : 0) | (write ? POLLOUT : 0); pfd.revents = 0; rc = poll(&pfd, 1, timeout ? (timeout->tv_sec + 1000 + timeout->tv_usec / 1000) : -1); if (rc < 0) { Log(LogCritical, "Socket") << "poll() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("poll") << boost::errinfo_errno(errno)); } #endif /* _WIN32 */ return (rc != 0); } void Socket::MakeNonBlocking(void) { #ifdef _WIN32 Utility::SetNonBlockingSocket(GetFD()); #else /* _WIN32 */ Utility::SetNonBlocking(GetFD()); #endif /* _WIN32 */ } void Socket::SocketPair(SOCKET s[2]) { if (dumb_socketpair(s, 0) < 0) BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("socketpair") << boost::errinfo_errno(errno)); } icinga2-2.8.1/lib/base/socket.hpp000066400000000000000000000047021322762156600165340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SOCKET_H #define SOCKET_H #include "base/i2-base.hpp" #include "base/object.hpp" namespace icinga { /** * Base class for connection-oriented sockets. * * @ingroup base */ class I2_BASE_API Socket : public Object { public: DECLARE_PTR_TYPEDEFS(Socket); Socket(void); Socket(SOCKET fd); ~Socket(void); SOCKET GetFD(void) const; void Close(void); String GetClientAddress(void); String GetPeerAddress(void); size_t Read(void *buffer, size_t size); size_t Write(const void *buffer, size_t size); void Listen(void); Socket::Ptr Accept(void); bool Poll(bool read, bool write, struct timeval *timeout = NULL); void MakeNonBlocking(void); static void SocketPair(SOCKET s[2]); protected: void SetFD(SOCKET fd); int GetError(void) const; mutable boost::mutex m_SocketMutex; private: SOCKET m_FD; /**< The socket descriptor. */ static String GetAddressFromSockaddr(sockaddr *address, socklen_t len); }; class socket_error : virtual public std::exception, virtual public boost::exception { }; } #endif /* SOCKET_H */ icinga2-2.8.1/lib/base/socketevents-epoll.cpp000066400000000000000000000131621322762156600210650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/socketevents.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include #include #ifdef __linux__ # include using namespace icinga; void SocketEventEngineEpoll::InitializeThread(int tid) { m_PollFDs[tid] = epoll_create(128); Utility::SetCloExec(m_PollFDs[tid]); SocketEventDescriptor sed; m_Sockets[tid][m_EventFDs[tid][0]] = sed; m_FDChanged[tid] = true; epoll_event event; memset(&event, 0, sizeof(event)); event.data.fd = m_EventFDs[tid][0]; event.events = EPOLLIN; epoll_ctl(m_PollFDs[tid], EPOLL_CTL_ADD, m_EventFDs[tid][0], &event); } int SocketEventEngineEpoll::PollToEpoll(int events) { int result = 0; if (events & POLLIN) result |= EPOLLIN; if (events & POLLOUT) result |= EPOLLOUT; return events; } int SocketEventEngineEpoll::EpollToPoll(int events) { int result = 0; if (events & EPOLLIN) result |= POLLIN; if (events & EPOLLOUT) result |= POLLOUT; return events; } void SocketEventEngineEpoll::ThreadProc(int tid) { Utility::SetThreadName("SocketIO"); for (;;) { { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (m_FDChanged[tid]) { m_FDChanged[tid] = false; m_CV[tid].notify_all(); } } epoll_event pevents[64]; int ready = epoll_wait(m_PollFDs[tid], pevents, sizeof(pevents) / sizeof(pevents[0]), -1); std::vector events; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (m_FDChanged[tid]) { m_FDChanged[tid] = false; continue; } for (int i = 0; i < ready; i++) { if (pevents[i].data.fd == m_EventFDs[tid][0]) { char buffer[512]; if (recv(m_EventFDs[tid][0], buffer, sizeof(buffer), 0) < 0) Log(LogCritical, "SocketEvents", "Read from event FD failed."); continue; } if ((pevents[i].events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR)) == 0) continue; EventDescription event; event.REvents = SocketEventEngineEpoll::EpollToPoll(pevents[i].events); event.Descriptor = m_Sockets[tid][pevents[i].data.fd]; event.LifesupportReference = event.Descriptor.LifesupportObject; VERIFY(event.LifesupportReference); events.push_back(event); } } for (const EventDescription& event : events) { try { event.Descriptor.EventInterface->OnEvent(event.REvents); } catch (const std::exception& ex) { Log(LogCritical, "SocketEvents") << "Exception thrown in socket I/O handler:\n" << DiagnosticInformation(ex); } catch (...) { Log(LogCritical, "SocketEvents", "Exception of unknown type thrown in socket I/O handler."); } } } } void SocketEventEngineEpoll::Register(SocketEvents *se, Object *lifesupportObject) { int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); VERIFY(se->m_FD != INVALID_SOCKET); SocketEventDescriptor desc; desc.EventInterface = se; desc.LifesupportObject = lifesupportObject; VERIFY(m_Sockets[tid].find(se->m_FD) == m_Sockets[tid].end()); m_Sockets[tid][se->m_FD] = desc; epoll_event event; memset(&event, 0, sizeof(event)); event.data.fd = se->m_FD; event.events = 0; epoll_ctl(m_PollFDs[tid], EPOLL_CTL_ADD, se->m_FD, &event); se->m_Events = true; } } void SocketEventEngineEpoll::Unregister(SocketEvents *se) { int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (se->m_FD == INVALID_SOCKET) return; m_Sockets[tid].erase(se->m_FD); m_FDChanged[tid] = true; epoll_ctl(m_PollFDs[tid], EPOLL_CTL_DEL, se->m_FD, NULL); se->m_FD = INVALID_SOCKET; se->m_Events = false; } WakeUpThread(tid, true); } void SocketEventEngineEpoll::ChangeEvents(SocketEvents *se, int events) { if (se->m_FD == INVALID_SOCKET) BOOST_THROW_EXCEPTION(std::runtime_error("Tried to read/write from a closed socket.")); int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); auto it = m_Sockets[tid].find(se->m_FD); if (it == m_Sockets[tid].end()) return; epoll_event event; memset(&event, 0, sizeof(event)); event.data.fd = se->m_FD; event.events = SocketEventEngineEpoll::PollToEpoll(events); epoll_ctl(m_PollFDs[tid], EPOLL_CTL_MOD, se->m_FD, &event); } } #endif /* __linux__ */ icinga2-2.8.1/lib/base/socketevents-poll.cpp000066400000000000000000000126661322762156600207300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/socketevents.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include #include using namespace icinga; void SocketEventEnginePoll::InitializeThread(int tid) { SocketEventDescriptor sed; sed.Events = POLLIN; m_Sockets[tid][m_EventFDs[tid][0]] = sed; m_FDChanged[tid] = true; } void SocketEventEnginePoll::ThreadProc(int tid) { Utility::SetThreadName("SocketIO"); std::vector pfds; std::vector descriptors; for (;;) { { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (m_FDChanged[tid]) { pfds.resize(m_Sockets[tid].size()); descriptors.resize(m_Sockets[tid].size()); int i = 0; typedef std::map::value_type kv_pair; for (const kv_pair& desc : m_Sockets[tid]) { if (desc.second.Events == 0) continue; if (desc.second.EventInterface) desc.second.EventInterface->m_EnginePrivate = &pfds[i]; pfds[i].fd = desc.first; pfds[i].events = desc.second.Events; descriptors[i] = desc.second; i++; } pfds.resize(i); m_FDChanged[tid] = false; m_CV[tid].notify_all(); } } ASSERT(!pfds.empty()); #ifdef _WIN32 (void) WSAPoll(&pfds[0], pfds.size(), -1); #else /* _WIN32 */ (void) poll(&pfds[0], pfds.size(), -1); #endif /* _WIN32 */ std::vector events; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (m_FDChanged[tid]) continue; for (std::vector::size_type i = 0; i < pfds.size(); i++) { if ((pfds[i].revents & (POLLIN | POLLOUT | POLLHUP | POLLERR)) == 0) continue; if (pfds[i].fd == m_EventFDs[tid][0]) { char buffer[512]; if (recv(m_EventFDs[tid][0], buffer, sizeof(buffer), 0) < 0) Log(LogCritical, "SocketEvents", "Read from event FD failed."); continue; } EventDescription event; event.REvents = pfds[i].revents; event.Descriptor = descriptors[i]; event.LifesupportReference = event.Descriptor.LifesupportObject; VERIFY(event.LifesupportReference); events.push_back(event); } } for (const EventDescription& event : events) { try { event.Descriptor.EventInterface->OnEvent(event.REvents); } catch (const std::exception& ex) { Log(LogCritical, "SocketEvents") << "Exception thrown in socket I/O handler:\n" << DiagnosticInformation(ex); } catch (...) { Log(LogCritical, "SocketEvents", "Exception of unknown type thrown in socket I/O handler."); } } } } void SocketEventEnginePoll::Register(SocketEvents *se, Object *lifesupportObject) { int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); VERIFY(se->m_FD != INVALID_SOCKET); SocketEventDescriptor desc; desc.Events = 0; desc.EventInterface = se; desc.LifesupportObject = lifesupportObject; VERIFY(m_Sockets[tid].find(se->m_FD) == m_Sockets[tid].end()); m_Sockets[tid][se->m_FD] = desc; m_FDChanged[tid] = true; se->m_Events = true; } WakeUpThread(tid, true); } void SocketEventEnginePoll::Unregister(SocketEvents *se) { int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); if (se->m_FD == INVALID_SOCKET) return; m_Sockets[tid].erase(se->m_FD); m_FDChanged[tid] = true; se->m_FD = INVALID_SOCKET; se->m_Events = false; } WakeUpThread(tid, true); } void SocketEventEnginePoll::ChangeEvents(SocketEvents *se, int events) { if (se->m_FD == INVALID_SOCKET) BOOST_THROW_EXCEPTION(std::runtime_error("Tried to read/write from a closed socket.")); int tid = se->m_ID % SOCKET_IOTHREADS; { boost::mutex::scoped_lock lock(m_EventMutex[tid]); auto it = m_Sockets[tid].find(se->m_FD); if (it == m_Sockets[tid].end()) return; if (it->second.Events == events) return; it->second.Events = events; if (se->m_EnginePrivate && boost::this_thread::get_id() == m_Threads[tid].get_id()) ((pollfd *)se->m_EnginePrivate)->events = events; else m_FDChanged[tid] = true; } WakeUpThread(tid, false); } icinga2-2.8.1/lib/base/socketevents.cpp000066400000000000000000000110101322762156600177420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/socketevents.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/scriptglobal.hpp" #include #include #ifdef __linux__ # include #endif /* __linux__ */ using namespace icinga; static boost::once_flag l_SocketIOOnceFlag = BOOST_ONCE_INIT; static SocketEventEngine *l_SocketIOEngine; int SocketEvents::m_NextID = 0; void SocketEventEngine::Start(void) { for (int tid = 0; tid < SOCKET_IOTHREADS; tid++) { Socket::SocketPair(m_EventFDs[tid]); Utility::SetNonBlockingSocket(m_EventFDs[tid][0]); Utility::SetNonBlockingSocket(m_EventFDs[tid][1]); #ifndef _WIN32 Utility::SetCloExec(m_EventFDs[tid][0]); Utility::SetCloExec(m_EventFDs[tid][1]); #endif /* _WIN32 */ InitializeThread(tid); m_Threads[tid] = boost::thread(boost::bind(&SocketEventEngine::ThreadProc, this, tid)); } } void SocketEventEngine::WakeUpThread(int sid, bool wait) { int tid = sid % SOCKET_IOTHREADS; if (boost::this_thread::get_id() == m_Threads[tid].get_id()) return; if (wait) { boost::mutex::scoped_lock lock(m_EventMutex[tid]); m_FDChanged[tid] = true; while (m_FDChanged[tid]) { (void) send(m_EventFDs[tid][1], "T", 1, 0); boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(50); m_CV[tid].timed_wait(lock, timeout); } } else { (void) send(m_EventFDs[tid][1], "T", 1, 0); } } void SocketEvents::InitializeEngine(void) { String eventEngine = ScriptGlobal::Get("EventEngine", &Empty); if (eventEngine.IsEmpty()) #ifdef __linux__ eventEngine = "epoll"; #else /* __linux__ */ eventEngine = "poll"; #endif /* __linux__ */ if (eventEngine == "poll") l_SocketIOEngine = new SocketEventEnginePoll(); #ifdef __linux__ else if (eventEngine == "epoll") l_SocketIOEngine = new SocketEventEngineEpoll(); #endif /* __linux__ */ else { Log(LogWarning, "SocketEvents") << "Invalid event engine selected: " << eventEngine << " - Falling back to 'poll'"; eventEngine = "poll"; l_SocketIOEngine = new SocketEventEnginePoll(); } l_SocketIOEngine->Start(); ScriptGlobal::Set("EventEngine", eventEngine); } /** * Constructor for the SocketEvents class. */ SocketEvents::SocketEvents(const Socket::Ptr& socket, Object *lifesupportObject) : m_ID(m_NextID++), m_FD(socket->GetFD()), m_EnginePrivate(NULL) { boost::call_once(l_SocketIOOnceFlag, &SocketEvents::InitializeEngine); Register(lifesupportObject); } SocketEvents::~SocketEvents(void) { VERIFY(m_FD == INVALID_SOCKET); } void SocketEvents::Register(Object *lifesupportObject) { l_SocketIOEngine->Register(this, lifesupportObject); } void SocketEvents::Unregister(void) { l_SocketIOEngine->Unregister(this); } void SocketEvents::ChangeEvents(int events) { l_SocketIOEngine->ChangeEvents(this, events); } boost::mutex& SocketEventEngine::GetMutex(int tid) { return m_EventMutex[tid]; } bool SocketEvents::IsHandlingEvents(void) const { int tid = m_ID % SOCKET_IOTHREADS; boost::mutex::scoped_lock lock(l_SocketIOEngine->GetMutex(tid)); return m_Events; } void SocketEvents::OnEvent(int revents) { } icinga2-2.8.1/lib/base/socketevents.hpp000066400000000000000000000103371322762156600177620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SOCKETEVENTS_H #define SOCKETEVENTS_H #include "base/i2-base.hpp" #include "base/socket.hpp" #include #ifndef _WIN32 # include #endif /* _WIN32 */ namespace icinga { /** * Socket event interface * * @ingroup base */ class I2_BASE_API SocketEvents { public: ~SocketEvents(void); virtual void OnEvent(int revents); void Unregister(void); void ChangeEvents(int events); bool IsHandlingEvents(void) const; void *GetEnginePrivate(void) const; void SetEnginePrivate(void *priv); protected: SocketEvents(const Socket::Ptr& socket, Object *lifesupportObject); private: int m_ID; SOCKET m_FD; bool m_Events; void *m_EnginePrivate; static int m_NextID; static void InitializeEngine(void); void WakeUpThread(bool wait = false); void Register(Object *lifesupportObject); friend class SocketEventEnginePoll; friend class SocketEventEngineEpoll; }; #define SOCKET_IOTHREADS 8 struct SocketEventDescriptor { int Events; SocketEvents *EventInterface; Object *LifesupportObject; SocketEventDescriptor(void) : Events(POLLIN), EventInterface(NULL), LifesupportObject(NULL) { } }; struct EventDescription { int REvents; SocketEventDescriptor Descriptor; Object::Ptr LifesupportReference; }; class I2_BASE_API SocketEventEngine { public: void Start(void); void WakeUpThread(int sid, bool wait); boost::mutex& GetMutex(int tid); protected: virtual void InitializeThread(int tid) = 0; virtual void ThreadProc(int tid) = 0; virtual void Register(SocketEvents *se, Object *lifesupportObject) = 0; virtual void Unregister(SocketEvents *se) = 0; virtual void ChangeEvents(SocketEvents *se, int events) = 0; boost::thread m_Threads[SOCKET_IOTHREADS]; SOCKET m_EventFDs[SOCKET_IOTHREADS][2]; bool m_FDChanged[SOCKET_IOTHREADS]; boost::mutex m_EventMutex[SOCKET_IOTHREADS]; boost::condition_variable m_CV[SOCKET_IOTHREADS]; std::map m_Sockets[SOCKET_IOTHREADS]; friend class SocketEvents; }; class I2_BASE_API SocketEventEnginePoll : public SocketEventEngine { public: virtual void Register(SocketEvents *se, Object *lifesupportObject); virtual void Unregister(SocketEvents *se); virtual void ChangeEvents(SocketEvents *se, int events); protected: virtual void InitializeThread(int tid); virtual void ThreadProc(int tid); }; #ifdef __linux__ class I2_BASE_API SocketEventEngineEpoll : public SocketEventEngine { public: virtual void Register(SocketEvents *se, Object *lifesupportObject); virtual void Unregister(SocketEvents *se); virtual void ChangeEvents(SocketEvents *se, int events); protected: virtual void InitializeThread(int tid); virtual void ThreadProc(int tid); private: SOCKET m_PollFDs[SOCKET_IOTHREADS]; static int PollToEpoll(int events); static int EpollToPoll(int events); }; #endif /* __linux__ */ } #endif /* SOCKETEVENTS_H */ icinga2-2.8.1/lib/base/stacktrace.cpp000066400000000000000000000116371322762156600173700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/stacktrace.hpp" #include "base/utility.hpp" #include "base/initialize.hpp" #ifdef HAVE_BACKTRACE_SYMBOLS # include #endif /* HAVE_BACKTRACE_SYMBOLS */ using namespace icinga; #ifdef _MSC_VER # pragma optimize("", off) #endif /* _MSC_VER */ StackTrace::StackTrace(void) { #ifdef HAVE_BACKTRACE_SYMBOLS m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0])); #else /* HAVE_BACKTRACE_SYMBOLS */ # ifdef _WIN32 m_Count = CaptureStackBackTrace(0, sizeof(m_Frames) / sizeof(m_Frames), m_Frames, NULL); # else /* _WIN32 */ m_Count = 0; # endif /* _WIN32 */ #endif /* HAVE_BACKTRACE_SYMBOLS */ } #ifdef _MSC_VER # pragma optimize("", on) #endif /* _MSC_VER */ #ifdef _WIN32 StackTrace::StackTrace(PEXCEPTION_POINTERS exi) { STACKFRAME64 frame; int architecture; #ifdef _WIN64 architecture = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = exi->ContextRecord->Rip; frame.AddrFrame.Offset = exi->ContextRecord->Rbp; frame.AddrStack.Offset = exi->ContextRecord->Rsp; #else /* _WIN64 */ architecture = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = exi->ContextRecord->Eip; frame.AddrFrame.Offset = exi->ContextRecord->Ebp; frame.AddrStack.Offset = exi->ContextRecord->Esp; #endif /* _WIN64 */ frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; m_Count = 0; while (StackWalk64(architecture, GetCurrentProcess(), GetCurrentThread(), &frame, exi->ContextRecord, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL) && m_Count < sizeof(m_Frames) / sizeof(m_Frames[0])) { m_Frames[m_Count] = reinterpret_cast(frame.AddrPC.Offset); m_Count++; } } #endif /* _WIN32 */ #ifdef _WIN32 INITIALIZE_ONCE([]() { (void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); (void) SymInitialize(GetCurrentProcess(), NULL, TRUE); }); #endif /* _WIN32 */ /** * Prints a stacktrace to the specified stream. * * @param fp The stream. * @param ignoreFrames The number of stackframes to ignore (in addition to * the one this function is executing in). * @returns true if the stacktrace was printed, false otherwise. */ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const { fp << std::endl; #ifndef _WIN32 # ifdef HAVE_BACKTRACE_SYMBOLS char **messages = backtrace_symbols(m_Frames, m_Count); for (int i = ignoreFrames + 1; i < m_Count && messages != NULL; ++i) { String message = messages[i]; char *sym_begin = strchr(messages[i], '('); if (sym_begin) { char *sym_end = strchr(sym_begin, '+'); if (sym_end != NULL) { String sym = String(sym_begin + 1, sym_end); String sym_demangled = Utility::DemangleSymbolName(sym); if (sym_demangled.IsEmpty()) sym_demangled = ""; String path = String(messages[i], sym_begin); size_t slashp = path.RFind("/"); if (slashp != String::NPos) path = path.SubStr(slashp + 1); message = path + ": " + sym_demangled + " (" + String(sym_end); } } fp << "\t(" << i - ignoreFrames - 1 << ") " << message << std::endl; } std::free(messages); fp << std::endl; # else /* HAVE_BACKTRACE_SYMBOLS */ fp << "(not available)" << std::endl; # endif /* HAVE_BACKTRACE_SYMBOLS */ #else /* _WIN32 */ for (int i = ignoreFrames + 1; i < m_Count; i++) { fp << "\t(" << i - ignoreFrames - 1 << "): " << Utility::GetSymbolName(m_Frames[i]) << std::endl; } #endif /* _WIN32 */ } std::ostream& icinga::operator<<(std::ostream& stream, const StackTrace& trace) { trace.Print(stream, 1); return stream; } icinga2-2.8.1/lib/base/stacktrace.hpp000066400000000000000000000037141322762156600173720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STACKTRACE_H #define STACKTRACE_H #include "base/i2-base.hpp" #include namespace icinga { /** * A stacktrace. * * @ingroup base */ class I2_BASE_API StackTrace { public: StackTrace(void); #ifdef _WIN32 explicit StackTrace(PEXCEPTION_POINTERS exi); #endif /* _WIN32 */ void Print(std::ostream& fp, int ignoreFrames = 0) const; static void StaticInitialize(void); private: void *m_Frames[64]; int m_Count; }; I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace); } #endif /* UTILITY_H */ icinga2-2.8.1/lib/base/statsfunction.cpp000066400000000000000000000035451322762156600201470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/statsfunction.hpp" #include "base/registry.hpp" #include "base/singleton.hpp" using namespace icinga; StatsFunction::StatsFunction(const Callback& function) : m_Callback(function) { } void StatsFunction::Invoke(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { m_Callback(status, perfdata); } StatsFunctionRegistry *StatsFunctionRegistry::GetInstance(void) { return Singleton::GetInstance(); } icinga2-2.8.1/lib/base/statsfunction.hpp000066400000000000000000000050321322762156600201450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STATSFUNCTION_H #define STATSFUNCTION_H #include "base/i2-base.hpp" #include "base/registry.hpp" #include "base/value.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include namespace icinga { /** * A stats function that can be used to execute a stats task. * * @ingroup base */ class I2_BASE_API StatsFunction : public Object { public: DECLARE_PTR_TYPEDEFS(StatsFunction); typedef boost::function Callback; StatsFunction(const Callback& function); void Invoke(const Dictionary::Ptr& status, const Array::Ptr& perfdata); private: Callback m_Callback; }; /** * A registry for script functions. * * @ingroup base */ class I2_BASE_API StatsFunctionRegistry : public Registry { public: static StatsFunctionRegistry *GetInstance(void); }; #define REGISTER_STATSFUNCTION(name, callback) \ INITIALIZE_ONCE([]() { \ StatsFunction::Ptr stf = new StatsFunction(callback); \ StatsFunctionRegistry::GetInstance()->Register(#name, stf); \ }) } #endif /* STATSFUNCTION_H */ icinga2-2.8.1/lib/base/stdiostream.cpp000066400000000000000000000047631322762156600176040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/stdiostream.hpp" #include "base/objectlock.hpp" using namespace icinga; /** * Constructor for the StdioStream class. * * @param innerStream The inner stream. * @param ownsStream Whether the new object owns the inner stream. If true * the stream's destructor deletes the inner stream. */ StdioStream::StdioStream(std::iostream *innerStream, bool ownsStream) : m_InnerStream(innerStream), m_OwnsStream(ownsStream) { } StdioStream::~StdioStream(void) { Close(); } size_t StdioStream::Read(void *buffer, size_t size, bool allow_partial) { ObjectLock olock(this); m_InnerStream->read(static_cast(buffer), size); return m_InnerStream->gcount(); } void StdioStream::Write(const void *buffer, size_t size) { ObjectLock olock(this); m_InnerStream->write(static_cast(buffer), size); } void StdioStream::Close(void) { Stream::Close(); if (m_OwnsStream) { delete m_InnerStream; m_OwnsStream = false; } } bool StdioStream::IsDataAvailable(void) const { return !IsEof(); } bool StdioStream::IsEof(void) const { return !m_InnerStream->good(); } icinga2-2.8.1/lib/base/stdiostream.hpp000066400000000000000000000041251322762156600176010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STDIOSTREAM_H #define STDIOSTREAM_H #include "base/i2-base.hpp" #include "base/stream.hpp" #include namespace icinga { class I2_BASE_API StdioStream : public Stream { public: DECLARE_PTR_TYPEDEFS(StdioStream); StdioStream(std::iostream *innerStream, bool ownsStream); ~StdioStream(void); virtual size_t Read(void *buffer, size_t size, bool allow_partial = false) override; virtual void Write(const void *buffer, size_t size) override; virtual void Close(void) override; virtual bool IsDataAvailable(void) const override; virtual bool IsEof(void) const override; private: std::iostream *m_InnerStream; bool m_OwnsStream; }; } #endif /* STDIOSTREAM_H */ icinga2-2.8.1/lib/base/stream.cpp000066400000000000000000000106301322762156600165270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/stream.hpp" #include using namespace icinga; void Stream::RegisterDataHandler(const boost::function& handler) { if (SupportsWaiting()) OnDataAvailable.connect(handler); else BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support waiting.")); } bool Stream::SupportsWaiting(void) const { return false; } bool Stream::IsDataAvailable(void) const { return false; } void Stream::Shutdown(void) { BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support Shutdown().")); } size_t Stream::Peek(void *buffer, size_t count, bool allow_partial) { BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support Peek().")); } void Stream::SignalDataAvailable(void) { OnDataAvailable(this); { boost::mutex::scoped_lock lock(m_Mutex); m_CV.notify_all(); } } bool Stream::WaitForData(int timeout) { if (!SupportsWaiting()) BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support waiting.")); boost::mutex::scoped_lock lock(m_Mutex); while (!IsDataAvailable() && !IsEof()) if (timeout < 0) m_CV.wait(lock); else m_CV.timed_wait(lock, boost::posix_time::milliseconds(timeout * 1000)); return IsDataAvailable() || IsEof(); } static void StreamDummyCallback(void) { } void Stream::Close(void) { OnDataAvailable.disconnect_all_slots(); /* Force signals2 to remove the slots, see https://stackoverflow.com/questions/2049291/force-deletion-of-slot-in-boostsignals2 * for details. */ OnDataAvailable.connect(boost::bind(&StreamDummyCallback)); } StreamReadStatus Stream::ReadLine(String *line, StreamReadContext& context, bool may_wait) { if (context.Eof) return StatusEof; if (context.MustRead) { if (!context.FillFromStream(this, may_wait)) { context.Eof = true; *line = String(context.Buffer, &(context.Buffer[context.Size])); boost::algorithm::trim_right(*line); return StatusNewItem; } } int count = 0; size_t first_newline; for (size_t i = 0; i < context.Size; i++) { if (context.Buffer[i] == '\n') { count++; if (count == 1) first_newline = i; else if (count > 1) break; } } context.MustRead = (count <= 1); if (count > 0) { *line = String(context.Buffer, &(context.Buffer[first_newline])); boost::algorithm::trim_right(*line); context.DropData(first_newline + 1); return StatusNewItem; } return StatusNeedData; } bool StreamReadContext::FillFromStream(const Stream::Ptr& stream, bool may_wait) { if (may_wait && stream->SupportsWaiting()) stream->WaitForData(); size_t count = 0; do { Buffer = (char *)realloc(Buffer, Size + 4096); if (!Buffer) throw std::bad_alloc(); size_t rc = stream->Read(Buffer + Size, 4096, true); Size += rc; count += rc; } while (count < 64 * 1024 && stream->IsDataAvailable()); if (count == 0 && stream->IsEof()) return false; else return true; } void StreamReadContext::DropData(size_t count) { ASSERT(count <= Size); memmove(Buffer, Buffer + count, Size - count); Size -= count; } icinga2-2.8.1/lib/base/stream.hpp000066400000000000000000000102251322762156600165340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STREAM_H #define STREAM_H #include "base/i2-base.hpp" #include "base/object.hpp" #include namespace icinga { class String; class Stream; enum ConnectionRole { RoleClient, RoleServer }; struct I2_BASE_API StreamReadContext { StreamReadContext(void) : Buffer(NULL), Size(0), MustRead(true), Eof(false) { } ~StreamReadContext(void) { free(Buffer); } bool FillFromStream(const intrusive_ptr& stream, bool may_wait); void DropData(size_t count); char *Buffer; size_t Size; bool MustRead; bool Eof; }; enum StreamReadStatus { StatusNewItem, StatusNeedData, StatusEof }; /** * A stream. * * @ingroup base */ class I2_BASE_API Stream : public Object { public: DECLARE_PTR_TYPEDEFS(Stream); /** * Reads data from the stream without removing it from the stream buffer. * * @param buffer The buffer where data should be stored. May be NULL if you're * not actually interested in the data. * @param count The number of bytes to read from the queue. * @param allow_partial Whether to allow partial reads. * @returns The number of bytes actually read. */ virtual size_t Peek(void *buffer, size_t count, bool allow_partial = false); /** * Reads data from the stream. * * @param buffer The buffer where data should be stored. May be NULL if you're * not actually interested in the data. * @param count The number of bytes to read from the queue. * @param allow_partial Whether to allow partial reads. * @returns The number of bytes actually read. */ virtual size_t Read(void *buffer, size_t count, bool allow_partial = false) = 0; /** * Writes data to the stream. * * @param buffer The data that is to be written. * @param count The number of bytes to write. * @returns The number of bytes written */ virtual void Write(const void *buffer, size_t count) = 0; /** * Causes the stream to be closed (via Close()) once all pending data has been * written. */ virtual void Shutdown(void); /** * Closes the stream and releases resources. */ virtual void Close(void); /** * Checks whether we've reached the end-of-file condition. * * @returns true if EOF. */ virtual bool IsEof(void) const = 0; /** * Waits until data can be read from the stream. */ bool WaitForData(int timeout = -1); virtual bool SupportsWaiting(void) const; virtual bool IsDataAvailable(void) const; void RegisterDataHandler(const boost::function& handler); StreamReadStatus ReadLine(String *line, StreamReadContext& context, bool may_wait = false); protected: void SignalDataAvailable(void); private: boost::signals2::signal OnDataAvailable; boost::mutex m_Mutex; boost::condition_variable m_CV; }; } #endif /* STREAM_H */ icinga2-2.8.1/lib/base/streamlogger.cpp000066400000000000000000000076141322762156600177370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/streamlogger.hpp" #include "base/streamlogger.tcpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include "base/console.hpp" #include using namespace icinga; REGISTER_TYPE(StreamLogger); boost::mutex StreamLogger::m_Mutex; /** * Constructor for the StreamLogger class. */ StreamLogger::StreamLogger(void) : m_Stream(NULL), m_OwnsStream(false) { } void StreamLogger::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); // make sure we flush the log data on shutdown, even if we don't call the destructor if (m_Stream) m_Stream->flush(); } /** * Destructor for the StreamLogger class. */ StreamLogger::~StreamLogger(void) { if (m_FlushLogTimer) m_FlushLogTimer->Stop(); if (m_OwnsStream) delete m_Stream; } void StreamLogger::FlushLogTimerHandler(void) { Flush(); } void StreamLogger::Flush(void) { if (m_Stream) m_Stream->flush(); } void StreamLogger::BindStream(std::ostream *stream, bool ownsStream) { ObjectLock olock(this); if (m_OwnsStream) delete m_Stream; m_Stream = stream; m_OwnsStream = ownsStream; m_FlushLogTimer = new Timer(); m_FlushLogTimer->SetInterval(1); m_FlushLogTimer->OnTimerExpired.connect(boost::bind(&StreamLogger::FlushLogTimerHandler, this)); m_FlushLogTimer->Start(); } /** * Processes a log entry and outputs it to a stream. * * @param stream The output stream. * @param entry The log entry. */ void StreamLogger::ProcessLogEntry(std::ostream& stream, const LogEntry& entry) { String timestamp = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", entry.Timestamp); boost::mutex::scoped_lock lock(m_Mutex); if (Logger::IsTimestampEnabled()) stream << "[" << timestamp << "] "; int color; switch (entry.Severity) { case LogDebug: color = Console_ForegroundCyan; break; case LogNotice: color = Console_ForegroundBlue; break; case LogInformation: color = Console_ForegroundGreen; break; case LogWarning: color = Console_ForegroundYellow | Console_Bold; break; case LogCritical: color = Console_ForegroundRed | Console_Bold; break; default: return; } stream << ConsoleColorTag(color); stream << Logger::SeverityToString(entry.Severity); stream << ConsoleColorTag(Console_Normal); stream << "/" << entry.Facility << ": " << entry.Message << "\n"; } /** * Processes a log entry and outputs it to a stream. * * @param entry The log entry. */ void StreamLogger::ProcessLogEntry(const LogEntry& entry) { ProcessLogEntry(*m_Stream, entry); } icinga2-2.8.1/lib/base/streamlogger.hpp000066400000000000000000000044121322762156600177350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STREAMLOGGER_H #define STREAMLOGGER_H #include "base/i2-base.hpp" #include "base/streamlogger.thpp" #include "base/timer.hpp" #include namespace icinga { /** * A logger that logs to an iostream. * * @ingroup base */ class I2_BASE_API StreamLogger : public ObjectImpl { public: DECLARE_OBJECT(StreamLogger); StreamLogger(void); virtual void Stop(bool runtimeRemoved) override; ~StreamLogger(void); void BindStream(std::ostream *stream, bool ownsStream); static void ProcessLogEntry(std::ostream& stream, const LogEntry& entry); protected: virtual void ProcessLogEntry(const LogEntry& entry) override; virtual void Flush(void) override; private: static boost::mutex m_Mutex; std::ostream *m_Stream; bool m_OwnsStream; Timer::Ptr m_FlushLogTimer; void FlushLogTimerHandler(void); }; } #endif /* STREAMLOGGER_H */ icinga2-2.8.1/lib/base/streamlogger.ti000066400000000000000000000030161322762156600175610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/logger.hpp" library base; namespace icinga { abstract class StreamLogger : Logger { }; } icinga2-2.8.1/lib/base/string-script.cpp000066400000000000000000000130211322762156600200410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/object.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" #include "base/exception.hpp" #include using namespace icinga; static int StringLen(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return self.GetLength(); } static String StringToString(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); return vframe->Self; } static String StringSubstr(const std::vector& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; if (args.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments")); if (static_cast(args[0]) < 0 || static_cast(args[0]) >= self.GetLength()) BOOST_THROW_EXCEPTION(std::invalid_argument("String index is out of range")); if (args.size() > 1) return self.SubStr(args[0], args[1]); else return self.SubStr(args[0]); } static String StringUpper(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return boost::to_upper_copy(self); } static String StringLower(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return boost::to_lower_copy(self); } static Array::Ptr StringSplit(const String& delims) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; std::vector tokens; boost::algorithm::split(tokens, self, boost::is_any_of(delims)); Array::Ptr result = new Array(); for (const String& token : tokens) { result->Add(token); } return result; } static int StringFind(const std::vector& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; if (args.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments")); String::SizeType result; if (args.size() > 1) { if (static_cast(args[1]) < 0) BOOST_THROW_EXCEPTION(std::invalid_argument("String index is out of range")); result = self.Find(args[0], args[1]); } else result = self.Find(args[0]); if (result == String::NPos) return -1; else return result; } static bool StringContains(const String& str) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return self.Contains(str); } static Value StringReplace(const String& search, const String& replacement) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; boost::algorithm::replace_all(self, search, replacement); return self; } static String StringReverse(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return self.Reverse(); } static String StringTrim(void) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); String self = vframe->Self; return self.Trim(); } Object::Ptr String::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("len", new Function("String#len", WrapFunction(StringLen), {}, true)); prototype->Set("to_string", new Function("String#to_string", WrapFunction(StringToString), {}, true)); prototype->Set("substr", new Function("String#substr", WrapFunction(StringSubstr), { "start", "len" }, true)); prototype->Set("upper", new Function("String#upper", WrapFunction(StringUpper), {}, true)); prototype->Set("lower", new Function("String#lower", WrapFunction(StringLower), {}, true)); prototype->Set("split", new Function("String#split", WrapFunction(StringSplit), { "delims" }, true)); prototype->Set("find", new Function("String#find", WrapFunction(StringFind), { "str", "start" }, true)); prototype->Set("contains", new Function("String#contains", WrapFunction(StringContains), { "str" }, true)); prototype->Set("replace", new Function("String#replace", WrapFunction(StringReplace), { "search", "replacement" }, true)); prototype->Set("reverse", new Function("String#reverse", WrapFunction(StringReverse), {}, true)); prototype->Set("trim", new Function("String#trim", WrapFunction(StringTrim), {}, true)); } return prototype; } icinga2-2.8.1/lib/base/string.cpp000066400000000000000000000040561322762156600165470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/string.hpp" #include "base/value.hpp" #include "base/primitivetype.hpp" #include "base/dictionary.hpp" #include using namespace icinga; REGISTER_BUILTIN_TYPE(String, String::GetPrototype()); const String::SizeType String::NPos = std::string::npos; #ifndef _MSC_VER String::String(Value&& other) { *this = std::move(other); } #endif /* _MSC_VER */ String& String::operator=(Value&& other) { if (other.IsString()) m_Data = std::move(other.Get()); else *this = static_cast(other); return *this; } String& String::operator+=(const Value& rhs) { m_Data += static_cast(rhs); return *this; } icinga2-2.8.1/lib/base/string.hpp000066400000000000000000000251251322762156600165540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STRING_H #define STRING_H #include "base/i2-base.hpp" #include "base/object.hpp" #include #include #include #include #include #include #include #include namespace icinga { class Value; /** * String class. * * Rationale for having this: The std::string class has an ambiguous assignment * operator when used in conjunction with the Value class. */ class I2_BASE_API String { public: typedef std::string::iterator Iterator; typedef std::string::const_iterator ConstIterator; typedef std::string::iterator iterator; typedef std::string::const_iterator const_iterator; typedef std::string::reverse_iterator ReverseIterator; typedef std::string::const_reverse_iterator ConstReverseIterator; typedef std::string::reverse_iterator reverse_iterator; typedef std::string::const_reverse_iterator const_reverse_iterator; typedef std::string::size_type SizeType; inline String(void) : m_Data() { } inline String(const char *data) : m_Data(data) { } inline String(const std::string& data) : m_Data(data) { } inline String(std::string&& data) : m_Data(data) { } inline String(String::SizeType n, char c) : m_Data(n, c) { } String(const String& other) : m_Data(other) { } String(String&& other) : m_Data(std::move(other.m_Data)) { } #ifndef _MSC_VER String(Value&& other); #endif /* _MSC_VER */ inline ~String(void) { } template String(InputIterator begin, InputIterator end) : m_Data(begin, end) { } String& operator=(const String& rhs) { m_Data = rhs.m_Data; return *this; } String& operator=(String&& rhs) { m_Data = std::move(rhs.m_Data); return *this; } String& operator=(Value&& rhs); inline String& operator=(const std::string& rhs) { m_Data = rhs; return *this; } inline String& operator=(const char *rhs) { m_Data = rhs; return *this; } inline const char& operator[](SizeType pos) const { return m_Data[pos]; } inline char& operator[](SizeType pos) { return m_Data[pos]; } inline String& operator+=(const String& rhs) { m_Data += rhs.m_Data; return *this; } inline String& operator+=(const char *rhs) { m_Data += rhs; return *this; } String& operator+=(const Value& rhs); inline String& operator+=(char rhs) { m_Data += rhs; return *this; } inline bool IsEmpty(void) const { return m_Data.empty(); } inline bool operator<(const String& rhs) const { return m_Data < rhs.m_Data; } inline operator const std::string&(void) const { return m_Data; } inline const char *CStr(void) const { return m_Data.c_str(); } inline void Clear(void) { m_Data.clear(); } inline SizeType GetLength(void) const { return m_Data.size(); } inline std::string& GetData(void) { return m_Data; } inline const std::string& GetData(void) const { return m_Data; } inline SizeType Find(const String& str, SizeType pos = 0) const { return m_Data.find(str, pos); } inline SizeType RFind(const String& str, SizeType pos = NPos) const { return m_Data.rfind(str, pos); } inline SizeType FindFirstOf(const char *s, SizeType pos = 0) const { return m_Data.find_first_of(s, pos); } inline SizeType FindFirstOf(char ch, SizeType pos = 0) const { return m_Data.find_first_of(ch, pos); } inline SizeType FindFirstNotOf(const char *s, SizeType pos = 0) const { return m_Data.find_first_not_of(s, pos); } inline SizeType FindFirstNotOf(char ch, SizeType pos = 0) const { return m_Data.find_first_not_of(ch, pos); } inline SizeType FindLastOf(const char *s, SizeType pos = NPos) const { return m_Data.find_last_of(s, pos); } inline SizeType FindLastOf(char ch, SizeType pos = NPos) const { return m_Data.find_last_of(ch, pos); } inline String SubStr(SizeType first, SizeType len = NPos) const { return m_Data.substr(first, len); } inline std::vector Split(const char *separators) const { std::vector result; boost::algorithm::split(result, m_Data, boost::is_any_of(separators)); return result; } inline void Replace(SizeType first, SizeType second, const String& str) { m_Data.replace(first, second, str); } inline String Trim(void) const { String t = m_Data; boost::algorithm::trim(t); return t; } inline String ToLower(void) const { String t = m_Data; boost::algorithm::to_lower(t); return t; } inline String ToUpper(void) const { String t = m_Data; boost::algorithm::to_upper(t); return t; } inline String Reverse(void) const { String t = m_Data; std::reverse(t.m_Data.begin(), t.m_Data.end()); return t; } inline void Append(int count, char ch) { m_Data.append(count, ch); } inline bool Contains(const String& str) const { return (m_Data.find(str) != std::string::npos); } inline void swap(String& str) { m_Data.swap(str.m_Data); } inline Iterator erase(Iterator first, Iterator last) { return m_Data.erase(first, last); } template void insert(Iterator p, InputIterator first, InputIterator last) { m_Data.insert(p, first, last); } inline Iterator Begin(void) { return m_Data.begin(); } inline ConstIterator Begin(void) const { return m_Data.begin(); } inline Iterator End(void) { return m_Data.end(); } inline ConstIterator End(void) const { return m_Data.end(); } inline ReverseIterator RBegin(void) { return m_Data.rbegin(); } inline ConstReverseIterator RBegin(void) const { return m_Data.rbegin(); } inline ReverseIterator REnd(void) { return m_Data.rend(); } inline ConstReverseIterator REnd(void) const { return m_Data.rend(); } static const SizeType NPos; static Object::Ptr GetPrototype(void); private: std::string m_Data; }; inline std::ostream& operator<<(std::ostream& stream, const String& str) { stream << str.GetData(); return stream; } inline std::istream& operator>>(std::istream& stream, String& str) { std::string tstr; stream >> tstr; str = tstr; return stream; } inline String operator+(const String& lhs, const String& rhs) { return lhs.GetData() + rhs.GetData(); } inline String operator+(const String& lhs, const char *rhs) { return lhs.GetData() + rhs; } inline String operator+(const char *lhs, const String& rhs) { return lhs + rhs.GetData(); } inline bool operator==(const String& lhs, const String& rhs) { return lhs.GetData() == rhs.GetData(); } inline bool operator==(const String& lhs, const char *rhs) { return lhs.GetData() == rhs; } inline bool operator==(const char *lhs, const String& rhs) { return lhs == rhs.GetData(); } inline bool operator<(const String& lhs, const char *rhs) { return lhs.GetData() < rhs; } inline bool operator<(const char *lhs, const String& rhs) { return lhs < rhs.GetData(); } inline bool operator>(const String& lhs, const String& rhs) { return lhs.GetData() > rhs.GetData(); } inline bool operator>(const String& lhs, const char *rhs) { return lhs.GetData() > rhs; } inline bool operator>(const char *lhs, const String& rhs) { return lhs > rhs.GetData(); } inline bool operator<=(const String& lhs, const String& rhs) { return lhs.GetData() <= rhs.GetData(); } inline bool operator<=(const String& lhs, const char *rhs) { return lhs.GetData() <= rhs; } inline bool operator<=(const char *lhs, const String& rhs) { return lhs <= rhs.GetData(); } inline bool operator>=(const String& lhs, const String& rhs) { return lhs.GetData() >= rhs.GetData(); } inline bool operator>=(const String& lhs, const char *rhs) { return lhs.GetData() >= rhs; } inline bool operator>=(const char *lhs, const String& rhs) { return lhs >= rhs.GetData(); } inline bool operator!=(const String& lhs, const String& rhs) { return lhs.GetData() != rhs.GetData(); } inline bool operator!=(const String& lhs, const char *rhs) { return lhs.GetData() != rhs; } inline bool operator!=(const char *lhs, const String& rhs) { return lhs != rhs.GetData(); } inline String::Iterator begin(String& x) { return x.Begin(); } inline String::ConstIterator begin(const String& x) { return x.Begin(); } inline String::Iterator end(String& x) { return x.End(); } inline String::ConstIterator end(const String& x) { return x.End(); } inline String::Iterator range_begin(String& x) { return x.Begin(); } inline String::ConstIterator range_begin(const String& x) { return x.Begin(); } inline String::Iterator range_end(String& x) { return x.End(); } inline String::ConstIterator range_end(const String& x) { return x.End(); } struct string_iless : std::binary_function { bool operator()(const String& s1, const String& s2) const { return strcasecmp(s1.CStr(), s2.CStr()) < 0; /* The "right" way would be to do this - however the * overhead is _massive_ due to the repeated non-inlined * function calls: return lexicographical_compare(s1.Begin(), s1.End(), s2.Begin(), s2.End(), boost::algorithm::is_iless()); */ } }; } namespace boost { template<> struct range_mutable_iterator { typedef icinga::String::Iterator type; }; template<> struct range_const_iterator { typedef icinga::String::ConstIterator type; }; } #endif /* STRING_H */ icinga2-2.8.1/lib/base/sysloglogger.cpp000066400000000000000000000123271322762156600177610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef _WIN32 #include "base/sysloglogger.hpp" #include "base/configtype.hpp" #include "base/statsfunction.hpp" #include "base/sysloglogger.tcpp" using namespace icinga; REGISTER_TYPE(SyslogLogger); REGISTER_STATSFUNCTION(SyslogLogger, &SyslogLogger::StatsFunc); INITIALIZE_ONCE(&SyslogLogger::StaticInitialize); std::map SyslogLogger::m_FacilityMap; void SyslogLogger::StaticInitialize(void) { ScriptGlobal::Set("FacilityAuth", "LOG_AUTH"); ScriptGlobal::Set("FacilityAuthPriv", "LOG_AUTHPRIV"); ScriptGlobal::Set("FacilityCron", "LOG_CRON"); ScriptGlobal::Set("FacilityDaemon", "LOG_DAEMON"); ScriptGlobal::Set("FacilityFtp", "LOG_FTP"); ScriptGlobal::Set("FacilityKern", "LOG_KERN"); ScriptGlobal::Set("FacilityLocal0", "LOG_LOCAL0"); ScriptGlobal::Set("FacilityLocal1", "LOG_LOCAL1"); ScriptGlobal::Set("FacilityLocal2", "LOG_LOCAL2"); ScriptGlobal::Set("FacilityLocal3", "LOG_LOCAL3"); ScriptGlobal::Set("FacilityLocal4", "LOG_LOCAL4"); ScriptGlobal::Set("FacilityLocal5", "LOG_LOCAL5"); ScriptGlobal::Set("FacilityLocal6", "LOG_LOCAL6"); ScriptGlobal::Set("FacilityLocal7", "LOG_LOCAL7"); ScriptGlobal::Set("FacilityLpr", "LOG_LPR"); ScriptGlobal::Set("FacilityMail", "LOG_MAIL"); ScriptGlobal::Set("FacilityNews", "LOG_NEWS"); ScriptGlobal::Set("FacilitySyslog", "LOG_SYSLOG"); ScriptGlobal::Set("FacilityUser", "LOG_USER"); ScriptGlobal::Set("FacilityUucp", "LOG_UUCP"); m_FacilityMap["LOG_AUTH"] = LOG_AUTH; m_FacilityMap["LOG_AUTHPRIV"] = LOG_AUTHPRIV; m_FacilityMap["LOG_CRON"] = LOG_CRON; m_FacilityMap["LOG_DAEMON"] = LOG_DAEMON; m_FacilityMap["LOG_FTP"] = LOG_FTP; m_FacilityMap["LOG_KERN"] = LOG_KERN; m_FacilityMap["LOG_LOCAL0"] = LOG_LOCAL0; m_FacilityMap["LOG_LOCAL1"] = LOG_LOCAL1; m_FacilityMap["LOG_LOCAL2"] = LOG_LOCAL2; m_FacilityMap["LOG_LOCAL3"] = LOG_LOCAL3; m_FacilityMap["LOG_LOCAL4"] = LOG_LOCAL4; m_FacilityMap["LOG_LOCAL5"] = LOG_LOCAL5; m_FacilityMap["LOG_LOCAL6"] = LOG_LOCAL6; m_FacilityMap["LOG_LOCAL7"] = LOG_LOCAL7; m_FacilityMap["LOG_LPR"] = LOG_LPR; m_FacilityMap["LOG_MAIL"] = LOG_MAIL; m_FacilityMap["LOG_NEWS"] = LOG_NEWS; m_FacilityMap["LOG_SYSLOG"] = LOG_SYSLOG; m_FacilityMap["LOG_USER"] = LOG_USER; m_FacilityMap["LOG_UUCP"] = LOG_UUCP; } void SyslogLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const SyslogLogger::Ptr& sysloglogger : ConfigType::GetObjectsByType()) { nodes->Set(sysloglogger->GetName(), 1); //add more stats } status->Set("sysloglogger", nodes); } void SyslogLogger::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); String facilityString = GetFacility(); auto it = m_FacilityMap.find(facilityString); if (it != m_FacilityMap.end()) m_Facility = it->second; else m_Facility = Convert::ToLong(facilityString); } void SyslogLogger::ValidateFacility(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateFacility(value, utils); if (m_FacilityMap.find(value) == m_FacilityMap.end()) { try { Convert::ToLong(value); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("facility"), "Invalid facility specified.")); } } } /** * Processes a log entry and outputs it to syslog. * * @param entry The log entry. */ void SyslogLogger::ProcessLogEntry(const LogEntry& entry) { int severity; switch (entry.Severity) { case LogDebug: severity = LOG_DEBUG; break; case LogNotice: severity = LOG_NOTICE; break; case LogWarning: severity = LOG_WARNING; break; case LogCritical: severity = LOG_CRIT; break; case LogInformation: default: severity = LOG_INFO; break; } syslog(severity | m_Facility, "%s", entry.Message.CStr()); } void SyslogLogger::Flush(void) { /* Nothing to do here. */ } #endif /* _WIN32 */ icinga2-2.8.1/lib/base/sysloglogger.hpp000066400000000000000000000043451322762156600177670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SYSLOGLOGGER_H #define SYSLOGLOGGER_H #ifndef _WIN32 #include "base/i2-base.hpp" #include "base/sysloglogger.thpp" namespace icinga { /** * A logger that logs to syslog. * * @ingroup base */ class I2_BASE_API SyslogLogger : public ObjectImpl { public: DECLARE_OBJECT(SyslogLogger); DECLARE_OBJECTNAME(SyslogLogger); static void StaticInitialize(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void OnConfigLoaded(void) override; virtual void ValidateFacility(const String& value, const ValidationUtils& utils) override; protected: static std::map m_FacilityMap; int m_Facility; virtual void ProcessLogEntry(const LogEntry& entry) override; virtual void Flush(void) override; }; } #endif /* _WIN32 */ #endif /* SYSLOGLOGGER_H */ icinga2-2.8.1/lib/base/sysloglogger.ti000066400000000000000000000031121322762156600176030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/logger.hpp" library base; namespace icinga { class SyslogLogger : Logger { [config] String facility { default {{{ return "LOG_USER"; }}} }; }; } icinga2-2.8.1/lib/base/tcpsocket.cpp000066400000000000000000000143131322762156600172350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/tcpsocket.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include #include #include using namespace icinga; /** * Creates a socket and binds it to the specified service. * * @param service The service. * @param family The address family for the socket. */ void TcpSocket::Bind(const String& service, int family) { Bind(String(), service, family); } /** * Creates a socket and binds it to the specified node and service. * * @param node The node. * @param service The service. * @param family The address family for the socket. */ void TcpSocket::Bind(const String& node, const String& service, int family) { addrinfo hints; addrinfo *result; int error; const char *func; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; int rc = getaddrinfo(node.IsEmpty() ? NULL : node.CStr(), service.CStr(), &hints, &result); if (rc != 0) { Log(LogCritical, "TcpSocket") << "getaddrinfo() failed with error code " << rc << ", \"" << gai_strerror(rc) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getaddrinfo") << errinfo_getaddrinfo_error(rc)); } int fd = INVALID_SOCKET; for (addrinfo *info = result; info != NULL; info = info->ai_next) { fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); if (fd == INVALID_SOCKET) { #ifdef _WIN32 error = WSAGetLastError(); #else /* _WIN32 */ error = errno; #endif /* _WIN32 */ func = "socket"; continue; } const int optFalse = 0; setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&optFalse), sizeof(optFalse)); #ifndef _WIN32 const int optTrue = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optTrue), sizeof(optTrue)); #endif /* _WIN32 */ int rc = bind(fd, info->ai_addr, info->ai_addrlen); if (rc < 0) { #ifdef _WIN32 error = WSAGetLastError(); #else /* _WIN32 */ error = errno; #endif /* _WIN32 */ func = "bind"; closesocket(fd); continue; } SetFD(fd); break; } freeaddrinfo(result); if (GetFD() == INVALID_SOCKET) { Log(LogCritical, "TcpSocket") << "Invalid socket: " << Utility::FormatErrorNumber(error); #ifndef _WIN32 BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function(func) << boost::errinfo_errno(error)); #else /* _WIN32 */ BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function(func) << errinfo_win32_error(error)); #endif /* _WIN32 */ } } /** * Creates a socket and connects to the specified node and service. * * @param node The node. * @param service The service. */ void TcpSocket::Connect(const String& node, const String& service) { addrinfo hints; addrinfo *result; int error; const char *func; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; int rc = getaddrinfo(node.CStr(), service.CStr(), &hints, &result); if (rc != 0) { Log(LogCritical, "TcpSocket") << "getaddrinfo() failed with error code " << rc << ", \"" << gai_strerror(rc) << "\""; BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function("getaddrinfo") << errinfo_getaddrinfo_error(rc)); } int fd = INVALID_SOCKET; for (addrinfo *info = result; info != NULL; info = info->ai_next) { fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); if (fd == INVALID_SOCKET) { #ifdef _WIN32 error = WSAGetLastError(); #else /* _WIN32 */ error = errno; #endif /* _WIN32 */ func = "socket"; continue; } const int optTrue = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast(&optTrue), sizeof(optTrue)) != 0) { #ifdef _WIN32 error = WSAGetLastError(); #else /* _WIN32 */ error = errno; #endif /* _WIN32 */ Log(LogWarning, "TcpSocket") << "setsockopt() unable to enable TCP keep-alives with error code " << rc; } rc = connect(fd, info->ai_addr, info->ai_addrlen); if (rc < 0) { #ifdef _WIN32 error = WSAGetLastError(); #else /* _WIN32 */ error = errno; #endif /* _WIN32 */ func = "connect"; closesocket(fd); continue; } SetFD(fd); break; } freeaddrinfo(result); if (GetFD() == INVALID_SOCKET) { Log(LogCritical, "TcpSocket") << "Invalid socket: " << Utility::FormatErrorNumber(error); #ifndef _WIN32 BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function(func) << boost::errinfo_errno(error)); #else /* _WIN32 */ BOOST_THROW_EXCEPTION(socket_error() << boost::errinfo_api_function(func) << errinfo_win32_error(error)); #endif /* _WIN32 */ } } icinga2-2.8.1/lib/base/tcpsocket.hpp000066400000000000000000000035521322762156600172450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TCPSOCKET_H #define TCPSOCKET_H #include "base/i2-base.hpp" #include "base/socket.hpp" namespace icinga { /** * A TCP socket. * * @ingroup base */ class I2_BASE_API TcpSocket : public Socket { public: DECLARE_PTR_TYPEDEFS(TcpSocket); void Bind(const String& service, int family); void Bind(const String& node, const String& service, int family); void Connect(const String& node, const String& service); }; } #endif /* TCPSOCKET_H */ icinga2-2.8.1/lib/base/threadpool.cpp000066400000000000000000000251051322762156600174000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/threadpool.hpp" #include "base/logger.hpp" #include "base/debug.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/application.hpp" #include #include using namespace icinga; int ThreadPool::m_NextID = 1; ThreadPool::ThreadPool(size_t max_threads) : m_ID(m_NextID++), m_MaxThreads(max_threads), m_Stopped(true) { if (m_MaxThreads != UINT_MAX && m_MaxThreads < sizeof(m_Queues) / sizeof(m_Queues[0])) m_MaxThreads = sizeof(m_Queues) / sizeof(m_Queues[0]); Start(); } ThreadPool::~ThreadPool(void) { Stop(); } void ThreadPool::Start(void) { if (!m_Stopped) return; m_Stopped = false; for (size_t i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) m_Queues[i].SpawnWorker(m_ThreadGroup); m_MgmtThread = boost::thread(boost::bind(&ThreadPool::ManagerThreadProc, this)); } void ThreadPool::Stop(void) { if (m_Stopped) return; { boost::mutex::scoped_lock lock(m_MgmtMutex); m_Stopped = true; m_MgmtCV.notify_all(); } if (m_MgmtThread.joinable()) m_MgmtThread.join(); for (size_t i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) { boost::mutex::scoped_lock lock(m_Queues[i].Mutex); m_Queues[i].Stopped = true; m_Queues[i].CV.notify_all(); } m_ThreadGroup.join_all(); m_ThreadGroup.~thread_group(); new (&m_ThreadGroup) boost::thread_group(); for (size_t i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) m_Queues[i].Stopped = false; m_Stopped = true; } /** * Waits for work items and processes them. */ void ThreadPool::WorkerThread::ThreadProc(Queue& queue) { std::ostringstream idbuf; idbuf << "Q #" << &queue << " W #" << this; Utility::SetThreadName(idbuf.str()); for (;;) { WorkItem wi; { boost::mutex::scoped_lock lock(queue.Mutex); UpdateUtilization(ThreadIdle); while (queue.Items.empty() && !queue.Stopped && !Zombie) { if (queue.Items.empty()) queue.CVStarved.notify_all(); queue.CV.wait(lock); } if (Zombie) break; if (queue.Items.empty() && queue.Stopped) break; wi = queue.Items.front(); queue.Items.pop_front(); UpdateUtilization(ThreadBusy); } double st = Utility::GetTime();; #ifdef I2_DEBUG # ifdef RUSAGE_THREAD struct rusage usage_start, usage_end; (void) getrusage(RUSAGE_THREAD, &usage_start); # endif /* RUSAGE_THREAD */ #endif /* I2_DEBUG */ try { if (wi.Callback) wi.Callback(); } catch (const std::exception& ex) { Log(LogCritical, "ThreadPool") << "Exception thrown in event handler:\n" << DiagnosticInformation(ex); } catch (...) { Log(LogCritical, "ThreadPool", "Exception of unknown type thrown in event handler."); } double et = Utility::GetTime(); double latency = st - wi.Timestamp; { boost::mutex::scoped_lock lock(queue.Mutex); queue.WaitTime += latency; queue.ServiceTime += et - st; queue.TaskCount++; } #ifdef I2_DEBUG # ifdef RUSAGE_THREAD (void) getrusage(RUSAGE_THREAD, &usage_end); double duser = (usage_end.ru_utime.tv_sec - usage_start.ru_utime.tv_sec) + (usage_end.ru_utime.tv_usec - usage_start.ru_utime.tv_usec) / 1000000.0; double dsys = (usage_end.ru_stime.tv_sec - usage_start.ru_stime.tv_sec) + (usage_end.ru_stime.tv_usec - usage_start.ru_stime.tv_usec) / 1000000.0; double dwait = (et - st) - (duser + dsys); int dminfaults = usage_end.ru_minflt - usage_start.ru_minflt; int dmajfaults = usage_end.ru_majflt - usage_start.ru_majflt; int dvctx = usage_end.ru_nvcsw - usage_start.ru_nvcsw; int divctx = usage_end.ru_nivcsw - usage_start.ru_nivcsw; # endif /* RUSAGE_THREAD */ if (et - st > 0.5) { Log(LogWarning, "ThreadPool") # ifdef RUSAGE_THREAD << "Event call took user:" << duser << "s, system:" << dsys << "s, wait:" << dwait << "s, minor_faults:" << dminfaults << ", major_faults:" << dmajfaults << ", voluntary_csw:" << dvctx << ", involuntary_csw:" << divctx; # else << "Event call took " << (et - st) << "s"; # endif /* RUSAGE_THREAD */ } #endif /* I2_DEBUG */ } boost::mutex::scoped_lock lock(queue.Mutex); UpdateUtilization(ThreadDead); Zombie = false; } /** * Appends a work item to the work queue. Work items will be processed in FIFO order. * * @param callback The callback function for the work item. * @param policy The scheduling policy * @returns true if the item was queued, false otherwise. */ bool ThreadPool::Post(const ThreadPool::WorkFunction& callback, SchedulerPolicy policy) { WorkItem wi; wi.Callback = callback; wi.Timestamp = Utility::GetTime(); Queue& queue = m_Queues[Utility::Random() % (sizeof(m_Queues) / sizeof(m_Queues[0]))]; { boost::mutex::scoped_lock lock(queue.Mutex); if (queue.Stopped) return false; if (policy == LowLatencyScheduler) queue.SpawnWorker(m_ThreadGroup); queue.Items.push_back(wi); queue.CV.notify_one(); } return true; } void ThreadPool::ManagerThreadProc(void) { std::ostringstream idbuf; idbuf << "TP #" << m_ID << " Manager"; Utility::SetThreadName(idbuf.str()); double lastStats = 0; for (;;) { size_t total_pending = 0, total_alive = 0; double total_avg_latency = 0; double total_utilization = 0; { boost::mutex::scoped_lock lock(m_MgmtMutex); if (!m_Stopped) m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(500)); if (m_Stopped) break; } for (size_t i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) { size_t pending, alive = 0; double avg_latency; double utilization = 0; Queue& queue = m_Queues[i]; boost::mutex::scoped_lock lock(queue.Mutex); for (size_t i = 0; i < sizeof(queue.Threads) / sizeof(queue.Threads[0]); i++) queue.Threads[i].UpdateUtilization(); pending = queue.Items.size(); for (size_t i = 0; i < sizeof(queue.Threads) / sizeof(queue.Threads[0]); i++) { if (queue.Threads[i].State != ThreadDead && !queue.Threads[i].Zombie) { alive++; utilization += queue.Threads[i].Utilization * 100; } } utilization /= alive; if (queue.TaskCount > 0) avg_latency = queue.WaitTime / (queue.TaskCount * 1.0); else avg_latency = 0; if (utilization < 60 || utilization > 80 || alive < 8) { double wthreads = std::ceil((utilization * alive) / 80.0); int tthreads = wthreads - alive; /* Make sure there is at least one thread per queue */ if (alive + tthreads < 1) tthreads = 1 - alive; /* Don't kill more than 2 threads at once. */ if (tthreads < -2) tthreads = -2; /* Spawn more workers if there are outstanding work items. */ if (tthreads > 0 && pending > 0) tthreads = 2; if (m_MaxThreads != UINT_MAX && (alive + tthreads) * (sizeof(m_Queues) / sizeof(m_Queues[0])) > m_MaxThreads) tthreads = m_MaxThreads / (sizeof(m_Queues) / sizeof(m_Queues[0])) - alive; if (tthreads != 0) { Log(LogNotice, "ThreadPool") << "Thread pool; current: " << alive << "; adjustment: " << tthreads; } for (int i = 0; i < -tthreads; i++) queue.KillWorker(m_ThreadGroup); for (int i = 0; i < tthreads; i++) queue.SpawnWorker(m_ThreadGroup); } queue.WaitTime = 0; queue.ServiceTime = 0; queue.TaskCount = 0; total_pending += pending; total_alive += alive; total_avg_latency += avg_latency; total_utilization += utilization; } double now = Utility::GetTime(); if (lastStats < now - 15) { lastStats = now; Log(LogNotice, "ThreadPool") << "Pool #" << m_ID << ": Pending tasks: " << total_pending << "; Average latency: " << (long)(total_avg_latency * 1000 / (sizeof(m_Queues) / sizeof(m_Queues[0]))) << "ms" << "; Threads: " << total_alive << "; Pool utilization: " << (total_utilization / (sizeof(m_Queues) / sizeof(m_Queues[0]))) << "%"; } } } /** * Note: Caller must hold m_Mutex */ void ThreadPool::Queue::SpawnWorker(boost::thread_group& group) { for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) { if (Threads[i].State == ThreadDead) { Log(LogDebug, "ThreadPool", "Spawning worker thread."); Threads[i] = WorkerThread(ThreadIdle); Threads[i].Thread = group.create_thread(boost::bind(&ThreadPool::WorkerThread::ThreadProc, boost::ref(Threads[i]), boost::ref(*this))); break; } } } /** * Note: Caller must hold Mutex. */ void ThreadPool::Queue::KillWorker(boost::thread_group& group) { for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) { if (Threads[i].State == ThreadIdle && !Threads[i].Zombie) { Log(LogDebug, "ThreadPool", "Killing worker thread."); group.remove_thread(Threads[i].Thread); Threads[i].Thread->detach(); delete Threads[i].Thread; Threads[i].Zombie = true; CV.notify_all(); break; } } } /** * Note: Caller must hold queue Mutex. */ void ThreadPool::WorkerThread::UpdateUtilization(ThreadState state) { double utilization; switch (State) { case ThreadDead: return; case ThreadIdle: utilization = 0; break; case ThreadBusy: utilization = 1; break; default: VERIFY(0); } double now = Utility::GetTime(); double time = now - LastUpdate; const double avg_time = 5.0; if (time > avg_time) time = avg_time; Utilization = (Utilization * (avg_time - time) + utilization * time) / avg_time; LastUpdate = now; if (state != ThreadUnspecified) State = state; } icinga2-2.8.1/lib/base/threadpool.hpp000066400000000000000000000064741322762156600174150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef THREADPOOL_H #define THREADPOOL_H #include "base/i2-base.hpp" #include #include #include #include #include namespace icinga { #define QUEUECOUNT 4U enum SchedulerPolicy { DefaultScheduler, LowLatencyScheduler }; /** * A thread pool. * * @ingroup base */ class I2_BASE_API ThreadPool { public: typedef boost::function WorkFunction; ThreadPool(size_t max_threads = UINT_MAX); ~ThreadPool(void); void Start(void); void Stop(void); bool Post(const WorkFunction& callback, SchedulerPolicy policy = DefaultScheduler); private: enum ThreadState { ThreadUnspecified, ThreadDead, ThreadIdle, ThreadBusy }; struct WorkItem { WorkFunction Callback; double Timestamp; }; struct Queue; struct WorkerThread { ThreadState State; bool Zombie; double Utilization; double LastUpdate; boost::thread *Thread; WorkerThread(ThreadState state = ThreadDead) : State(state), Zombie(false), Utilization(0), LastUpdate(0), Thread(NULL) { } void UpdateUtilization(ThreadState state = ThreadUnspecified); void ThreadProc(Queue& queue); }; struct Queue { boost::mutex Mutex; boost::condition_variable CV; boost::condition_variable CVStarved; std::deque Items; double WaitTime; double ServiceTime; int TaskCount; bool Stopped; WorkerThread Threads[16]; Queue(void) : WaitTime(0), ServiceTime(0), TaskCount(0), Stopped(false) { } void SpawnWorker(boost::thread_group& group); void KillWorker(boost::thread_group& group); }; int m_ID; static int m_NextID; size_t m_MaxThreads; boost::thread_group m_ThreadGroup; boost::thread m_MgmtThread; boost::mutex m_MgmtMutex; boost::condition_variable m_MgmtCV; bool m_Stopped; Queue m_Queues[QUEUECOUNT]; void ManagerThreadProc(void); }; } #endif /* EVENTQUEUE_H */ icinga2-2.8.1/lib/base/timer.cpp000066400000000000000000000156411322762156600163630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/timer.hpp" #include "base/debug.hpp" #include "base/utility.hpp" #include #include #include #include #include #include #include using namespace icinga; typedef boost::multi_index_container< Timer::Holder, boost::multi_index::indexed_by< boost::multi_index::ordered_unique >, boost::multi_index::ordered_non_unique > > > TimerSet; static boost::mutex l_TimerMutex; static boost::condition_variable l_TimerCV; static boost::thread l_TimerThread; static bool l_StopTimerThread; static TimerSet l_Timers; /** * Constructor for the Timer class. */ Timer::Timer(void) : m_Interval(0), m_Next(0), m_Started(false), m_Running(false) { } /** * Destructor for the Timer class. */ Timer::~Timer(void) { Stop(true); } /** * Initializes the timer sub-system. */ void Timer::Initialize(void) { boost::mutex::scoped_lock lock(l_TimerMutex); l_StopTimerThread = false; l_TimerThread = boost::thread(&Timer::TimerThreadProc); } /** * Disables the timer sub-system. */ void Timer::Uninitialize(void) { { boost::mutex::scoped_lock lock(l_TimerMutex); l_StopTimerThread = true; l_TimerCV.notify_all(); } if (l_TimerThread.joinable()) l_TimerThread.join(); } /** * Calls this timer. */ void Timer::Call(void) { try { OnTimerExpired(Timer::Ptr(this)); } catch (...) { InternalReschedule(true); throw; } InternalReschedule(true); } /** * Sets the interval for this timer. * * @param interval The new interval. */ void Timer::SetInterval(double interval) { boost::mutex::scoped_lock lock(l_TimerMutex); m_Interval = interval; } /** * Retrieves the interval for this timer. * * @returns The interval. */ double Timer::GetInterval(void) const { boost::mutex::scoped_lock lock(l_TimerMutex); return m_Interval; } /** * Registers the timer and starts processing events for it. */ void Timer::Start(void) { { boost::mutex::scoped_lock lock(l_TimerMutex); m_Started = true; } InternalReschedule(false); } /** * Unregisters the timer and stops processing events for it. */ void Timer::Stop(bool wait) { if (l_StopTimerThread) return; boost::mutex::scoped_lock lock(l_TimerMutex); m_Started = false; l_Timers.erase(this); /* Notify the worker thread that we've disabled a timer. */ l_TimerCV.notify_all(); while (wait && m_Running) l_TimerCV.wait(lock); } void Timer::Reschedule(double next) { InternalReschedule(false, next); } /** * Reschedules this timer. * * @param completed Whether the timer has just completed its callback. * @param next The time when this timer should be called again. Use -1 to let * the timer figure out a suitable time based on the interval. */ void Timer::InternalReschedule(bool completed, double next) { boost::mutex::scoped_lock lock(l_TimerMutex); if (completed) m_Running = false; if (next < 0) { /* Don't schedule the next call if this is not a periodic timer. */ if (m_Interval <= 0) return; next = Utility::GetTime() + m_Interval; } m_Next = next; if (m_Started && !m_Running) { /* Remove and re-add the timer to update the index. */ l_Timers.erase(this); l_Timers.insert(this); /* Notify the worker that we've rescheduled a timer. */ l_TimerCV.notify_all(); } } /** * Retrieves when the timer is next due. * * @returns The timestamp. */ double Timer::GetNext(void) const { boost::mutex::scoped_lock lock(l_TimerMutex); return m_Next; } /** * Adjusts all timers by adding the specified amount of time to their * next scheduled timestamp. * * @param adjustment The adjustment. */ void Timer::AdjustTimers(double adjustment) { boost::mutex::scoped_lock lock(l_TimerMutex); double now = Utility::GetTime(); typedef boost::multi_index::nth_index::type TimerView; TimerView& idx = boost::get<1>(l_Timers); std::vector timers; for (Timer *timer : idx) { if (std::fabs(now - (timer->m_Next + adjustment)) < std::fabs(now - timer->m_Next)) { timer->m_Next += adjustment; timers.push_back(timer); } } for (Timer *timer : timers) { l_Timers.erase(timer); l_Timers.insert(timer); } /* Notify the worker that we've rescheduled some timers. */ l_TimerCV.notify_all(); } /** * Worker thread proc for Timer objects. */ void Timer::TimerThreadProc(void) { Utility::SetThreadName("Timer Thread"); for (;;) { boost::mutex::scoped_lock lock(l_TimerMutex); typedef boost::multi_index::nth_index::type NextTimerView; NextTimerView& idx = boost::get<1>(l_Timers); /* Wait until there is at least one timer. */ while (idx.empty() && !l_StopTimerThread) l_TimerCV.wait(lock); if (l_StopTimerThread) break; auto it = idx.begin(); Timer *timer = *it; double wait = timer->m_Next - Utility::GetTime(); if (wait > 0.01) { /* Wait for the next timer. */ l_TimerCV.timed_wait(lock, boost::posix_time::milliseconds(wait * 1000)); continue; } Timer::Ptr ptimer = timer; /* Remove the timer from the list so it doesn't get called again * until the current call is completed. */ l_Timers.erase(timer); timer->m_Running = true; lock.unlock(); /* Asynchronously call the timer. */ Utility::QueueAsyncCallback(boost::bind(&Timer::Call, ptimer)); } } icinga2-2.8.1/lib/base/timer.hpp000066400000000000000000000054571322762156600163740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TIMER_H #define TIMER_H #include "base/i2-base.hpp" #include "base/object.hpp" #include namespace icinga { /** * A timer that periodically triggers an event. * * @ingroup base */ class I2_BASE_API Timer : public Object { public: DECLARE_PTR_TYPEDEFS(Timer); Timer(void); ~Timer(void); void SetInterval(double interval); double GetInterval(void) const; static void AdjustTimers(double adjustment); void Start(void); void Stop(bool wait = false); void Reschedule(double next = -1); double GetNext(void) const; boost::signals2::signal OnTimerExpired; class Holder { public: Holder(Timer *timer) : m_Timer(timer) { } inline Timer *GetObject(void) const { return m_Timer; } inline double GetNextUnlocked(void) const { return m_Timer->m_Next; } operator Timer *(void) const { return m_Timer; } private: Timer *m_Timer; }; private: double m_Interval; /**< The interval of the timer. */ double m_Next; /**< When the next event should happen. */ bool m_Started; /**< Whether the timer is enabled. */ bool m_Running; /**< Whether the timer proc is currently running. */ void Call(); void InternalReschedule(bool completed, double next = -1); static void TimerThreadProc(void); static void Initialize(void); static void Uninitialize(void); friend class Application; }; } #endif /* TIMER_H */ icinga2-2.8.1/lib/base/tlsstream.cpp000066400000000000000000000222021322762156600172500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/tlsstream.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include #include #ifndef _WIN32 # include #endif /* _WIN32 */ using namespace icinga; int I2_EXPORT TlsStream::m_SSLIndex; bool I2_EXPORT TlsStream::m_SSLIndexInitialized = false; /** * Constructor for the TlsStream class. * * @param role The role of the client. * @param sslContext The SSL context for the client. */ TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr& sslContext) : SocketEvents(socket, this), m_Eof(false), m_HandshakeOK(false), m_VerifyOK(true), m_ErrorCode(0), m_ErrorOccurred(false), m_Socket(socket), m_Role(role), m_SendQ(new FIFO()), m_RecvQ(new FIFO()), m_CurrentAction(TlsActionNone), m_Retry(false), m_Shutdown(false) { std::ostringstream msgbuf; char errbuf[120]; m_SSL = boost::shared_ptr(SSL_new(sslContext.get()), SSL_free); if (!m_SSL) { msgbuf << "SSL_new() failed with code " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; Log(LogCritical, "TlsStream", msgbuf.str()); BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_new") << errinfo_openssl_error(ERR_peek_error())); } if (!m_SSLIndexInitialized) { m_SSLIndex = SSL_get_ex_new_index(0, const_cast("TlsStream"), NULL, NULL, NULL); m_SSLIndexInitialized = true; } SSL_set_ex_data(m_SSL.get(), m_SSLIndex, this); SSL_set_verify(m_SSL.get(), SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, &TlsStream::ValidateCertificate); socket->MakeNonBlocking(); SSL_set_fd(m_SSL.get(), socket->GetFD()); if (m_Role == RoleServer) SSL_set_accept_state(m_SSL.get()); else { #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (!hostname.IsEmpty()) SSL_set_tlsext_host_name(m_SSL.get(), hostname.CStr()); #endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */ SSL_set_connect_state(m_SSL.get()); } } TlsStream::~TlsStream(void) { CloseInternal(true); } int TlsStream::ValidateCertificate(int preverify_ok, X509_STORE_CTX *ctx) { SSL *ssl = static_cast(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); TlsStream *stream = static_cast(SSL_get_ex_data(ssl, m_SSLIndex)); if (!preverify_ok) { stream->m_VerifyOK = false; std::ostringstream msgbuf; int err = X509_STORE_CTX_get_error(ctx); msgbuf << "code " << err << ": " << X509_verify_cert_error_string(err); stream->m_VerifyError = msgbuf.str(); } return 1; } bool TlsStream::IsVerifyOK(void) const { return m_VerifyOK; } String TlsStream::GetVerifyError(void) const { return m_VerifyError; } /** * Retrieves the X509 certficate for this client. * * @returns The X509 certificate. */ boost::shared_ptr TlsStream::GetClientCertificate(void) const { boost::mutex::scoped_lock lock(m_Mutex); return boost::shared_ptr(SSL_get_certificate(m_SSL.get()), &Utility::NullDeleter); } /** * Retrieves the X509 certficate for the peer. * * @returns The X509 certificate. */ boost::shared_ptr TlsStream::GetPeerCertificate(void) const { boost::mutex::scoped_lock lock(m_Mutex); return boost::shared_ptr(SSL_get_peer_certificate(m_SSL.get()), X509_free); } void TlsStream::OnEvent(int revents) { int rc; size_t count; boost::mutex::scoped_lock lock(m_Mutex); if (!m_SSL) return; char buffer[64 * 1024]; if (m_CurrentAction == TlsActionNone) { if (revents & (POLLIN | POLLERR | POLLHUP)) m_CurrentAction = TlsActionRead; else if (m_SendQ->GetAvailableBytes() > 0 && (revents & POLLOUT)) m_CurrentAction = TlsActionWrite; else { ChangeEvents(POLLIN); return; } } bool success = false; /* Clear error queue for this thread before using SSL_{read,write,do_handshake}. * Otherwise SSL_*_error() does not work reliably. */ ERR_clear_error(); switch (m_CurrentAction) { case TlsActionRead: do { rc = SSL_read(m_SSL.get(), buffer, sizeof(buffer)); if (rc > 0) { m_RecvQ->Write(buffer, rc); success = true; } } while (rc > 0); if (success) m_CV.notify_all(); break; case TlsActionWrite: count = m_SendQ->Peek(buffer, sizeof(buffer), true); rc = SSL_write(m_SSL.get(), buffer, count); if (rc > 0) { m_SendQ->Read(NULL, rc, true); success = true; } break; case TlsActionHandshake: rc = SSL_do_handshake(m_SSL.get()); if (rc > 0) { success = true; m_HandshakeOK = true; m_CV.notify_all(); } break; default: VERIFY(!"Invalid TlsAction"); } if (rc <= 0) { int err = SSL_get_error(m_SSL.get(), rc); switch (err) { case SSL_ERROR_WANT_READ: m_Retry = true; ChangeEvents(POLLIN); break; case SSL_ERROR_WANT_WRITE: m_Retry = true; ChangeEvents(POLLOUT); break; case SSL_ERROR_ZERO_RETURN: lock.unlock(); Close(); return; default: m_ErrorCode = ERR_peek_error(); m_ErrorOccurred = true; if (m_ErrorCode != 0) { Log(LogWarning, "TlsStream") << "OpenSSL error: " << ERR_error_string(m_ErrorCode, NULL); } else { Log(LogWarning, "TlsStream", "TLS stream was disconnected."); } lock.unlock(); Close(); return; } } if (success) { m_CurrentAction = TlsActionNone; if (!m_Eof) { if (m_SendQ->GetAvailableBytes() > 0) ChangeEvents(POLLIN|POLLOUT); else ChangeEvents(POLLIN); } lock.unlock(); while (m_RecvQ->IsDataAvailable() && IsHandlingEvents()) SignalDataAvailable(); } if (m_Shutdown && !m_SendQ->IsDataAvailable()) { if (!success) lock.unlock(); Close(); } } void TlsStream::HandleError(void) const { if (m_ErrorOccurred) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("TlsStream::OnEvent") << errinfo_openssl_error(m_ErrorCode)); } } void TlsStream::Handshake(void) { boost::mutex::scoped_lock lock(m_Mutex); m_CurrentAction = TlsActionHandshake; ChangeEvents(POLLOUT); while (!m_HandshakeOK && !m_ErrorOccurred && !m_Eof) m_CV.wait(lock); if (m_Eof) BOOST_THROW_EXCEPTION(std::runtime_error("Socket was closed during TLS handshake.")); HandleError(); } /** * Processes data for the stream. */ size_t TlsStream::Peek(void *buffer, size_t count, bool allow_partial) { boost::mutex::scoped_lock lock(m_Mutex); if (!allow_partial) while (m_RecvQ->GetAvailableBytes() < count && !m_ErrorOccurred && !m_Eof) m_CV.wait(lock); HandleError(); return m_RecvQ->Peek(buffer, count, true); } size_t TlsStream::Read(void *buffer, size_t count, bool allow_partial) { boost::mutex::scoped_lock lock(m_Mutex); if (!allow_partial) while (m_RecvQ->GetAvailableBytes() < count && !m_ErrorOccurred && !m_Eof) m_CV.wait(lock); HandleError(); return m_RecvQ->Read(buffer, count, true); } void TlsStream::Write(const void *buffer, size_t count) { boost::mutex::scoped_lock lock(m_Mutex); m_SendQ->Write(buffer, count); ChangeEvents(POLLIN|POLLOUT); } void TlsStream::Shutdown(void) { m_Shutdown = true; ChangeEvents(POLLOUT); } /** * Closes the stream. */ void TlsStream::Close(void) { CloseInternal(false); } void TlsStream::CloseInternal(bool inDestructor) { if (m_Eof) return; m_Eof = true; if (!inDestructor) SignalDataAvailable(); SocketEvents::Unregister(); Stream::Close(); boost::mutex::scoped_lock lock(m_Mutex); if (!m_SSL) return; (void)SSL_shutdown(m_SSL.get()); m_SSL.reset(); m_Socket->Close(); m_Socket.reset(); m_CV.notify_all(); } bool TlsStream::IsEof(void) const { return m_Eof; } bool TlsStream::SupportsWaiting(void) const { return true; } bool TlsStream::IsDataAvailable(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_RecvQ->GetAvailableBytes() > 0; } Socket::Ptr TlsStream::GetSocket(void) const { return m_Socket; } icinga2-2.8.1/lib/base/tlsstream.hpp000066400000000000000000000066761322762156600172760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TLSSTREAM_H #define TLSSTREAM_H #include "base/i2-base.hpp" #include "base/socket.hpp" #include "base/socketevents.hpp" #include "base/stream.hpp" #include "base/tlsutility.hpp" #include "base/fifo.hpp" namespace icinga { enum TlsAction { TlsActionNone, TlsActionRead, TlsActionWrite, TlsActionHandshake }; /** * A TLS stream. * * @ingroup base */ class I2_BASE_API TlsStream : public Stream, private SocketEvents { public: DECLARE_PTR_TYPEDEFS(TlsStream); TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr& sslContext = MakeSSLContext()); ~TlsStream(void); Socket::Ptr GetSocket(void) const; boost::shared_ptr GetClientCertificate(void) const; boost::shared_ptr GetPeerCertificate(void) const; void Handshake(void); virtual void Close(void) override; virtual void Shutdown(void) override; virtual size_t Peek(void *buffer, size_t count, bool allow_partial = false) override; virtual size_t Read(void *buffer, size_t count, bool allow_partial = false) override; virtual void Write(const void *buffer, size_t count) override; virtual bool IsEof(void) const override; virtual bool SupportsWaiting(void) const override; virtual bool IsDataAvailable(void) const override; bool IsVerifyOK(void) const; String GetVerifyError(void) const; private: boost::shared_ptr m_SSL; bool m_Eof; mutable boost::mutex m_Mutex; mutable boost::condition_variable m_CV; bool m_HandshakeOK; bool m_VerifyOK; String m_VerifyError; int m_ErrorCode; bool m_ErrorOccurred; Socket::Ptr m_Socket; ConnectionRole m_Role; FIFO::Ptr m_SendQ; FIFO::Ptr m_RecvQ; TlsAction m_CurrentAction; bool m_Retry; bool m_Shutdown; static int m_SSLIndex; static bool m_SSLIndexInitialized; virtual void OnEvent(int revents) override; void HandleError(void) const; static int ValidateCertificate(int preverify_ok, X509_STORE_CTX *ctx); static void NullCertificateDeleter(X509 *certificate); void CloseInternal(bool inDestructor); }; } #endif /* TLSSTREAM_H */ icinga2-2.8.1/lib/base/tlsutility.cpp000066400000000000000000000602441322762156600174700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/tlsutility.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/utility.hpp" #include "base/application.hpp" #include "base/exception.hpp" #include namespace icinga { static bool l_SSLInitialized = false; static boost::mutex *l_Mutexes; #ifdef CRYPTO_LOCK static void OpenSSLLockingCallback(int mode, int type, const char *, int) { if (mode & CRYPTO_LOCK) l_Mutexes[type].lock(); else l_Mutexes[type].unlock(); } static unsigned long OpenSSLIDCallback(void) { #ifdef _WIN32 return (unsigned long)GetCurrentThreadId(); #else /* _WIN32 */ return (unsigned long)pthread_self(); #endif /* _WIN32 */ } #endif /* CRYPTO_LOCK */ /** * Initializes the OpenSSL library. */ void InitializeOpenSSL(void) { if (l_SSLInitialized) return; SSL_library_init(); SSL_load_error_strings(); SSL_COMP_get_compression_methods(); #ifdef CRYPTO_LOCK l_Mutexes = new boost::mutex[CRYPTO_num_locks()]; CRYPTO_set_locking_callback(&OpenSSLLockingCallback); CRYPTO_set_id_callback(&OpenSSLIDCallback); #endif /* CRYPTO_LOCK */ l_SSLInitialized = true; } /** * Initializes an SSL context using the specified certificates. * * @param pubkey The public key. * @param privkey The matching private key. * @param cakey CA certificate chain file. * @returns An SSL context. */ boost::shared_ptr MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey) { char errbuf[120]; InitializeOpenSSL(); boost::shared_ptr sslContext = boost::shared_ptr(SSL_CTX_new(SSLv23_method()), SSL_CTX_free); long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE; #ifdef SSL_OP_NO_COMPRESSION flags |= SSL_OP_NO_COMPRESSION; #endif /* SSL_OP_NO_COMPRESSION */ SSL_CTX_set_options(sslContext.get(), flags); SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_session_id_context(sslContext.get(), (const unsigned char *)"Icinga 2", 8); if (!pubkey.IsEmpty()) { if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) { Log(LogCritical, "SSL") << "Error with public key file '" << pubkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_use_certificate_chain_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(pubkey)); } } if (!privkey.IsEmpty()) { if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) { Log(LogCritical, "SSL") << "Error with private key file '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_use_PrivateKey_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(privkey)); } if (!SSL_CTX_check_private_key(sslContext.get())) { Log(LogCritical, "SSL") << "Error checking private key '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_check_private_key") << errinfo_openssl_error(ERR_peek_error())); } } if (!cakey.IsEmpty()) { if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) { Log(LogCritical, "SSL") << "Error loading and verifying locations in ca key file '" << cakey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_load_verify_locations") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(cakey)); } STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file(cakey.CStr()); if (cert_names == NULL) { Log(LogCritical, "SSL") << "Error loading client ca key file '" << cakey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_load_client_CA_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(cakey)); } SSL_CTX_set_client_CA_list(sslContext.get(), cert_names); } return sslContext; } /** * Set the cipher list to the specified SSL context. * @param context The ssl context. * @param cipherList The ciper list. **/ void SetCipherListToSSLContext(const boost::shared_ptr& context, const String& cipherList) { char errbuf[256]; if (SSL_CTX_set_cipher_list(context.get(), cipherList.CStr()) == 0) { Log(LogCritical, "SSL") << "Cipher list '" << cipherList << "' does not specify any usable ciphers: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_set_cipher_list") << errinfo_openssl_error(ERR_peek_error())); } } /** * Set the minimum TLS protocol version to the specified SSL context. * * @param context The ssl context. * @param tlsProtocolmin The minimum TLS protocol version. */ void SetTlsProtocolminToSSLContext(const boost::shared_ptr& context, const String& tlsProtocolmin) { long flags = SSL_CTX_get_options(context.get()); flags |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; #ifdef SSL_TXT_TLSV1_1 if (tlsProtocolmin == SSL_TXT_TLSV1_1) flags |= SSL_OP_NO_TLSv1; else #endif /* SSL_TXT_TLSV1_1 */ #ifdef SSL_TXT_TLSV1_2 if (tlsProtocolmin == SSL_TXT_TLSV1_2) flags |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1; else #endif /* SSL_TXT_TLSV1_2 */ if (tlsProtocolmin != SSL_TXT_TLSV1) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid TLS protocol version specified.")); SSL_CTX_set_options(context.get(), flags); } /** * Loads a CRL and appends its certificates to the specified SSL context. * * @param context The SSL context. * @param crlPath The path to the CRL file. */ void AddCRLToSSLContext(const boost::shared_ptr& context, const String& crlPath) { char errbuf[120]; X509_STORE *x509_store = SSL_CTX_get_cert_store(context.get()); X509_LOOKUP *lookup; lookup = X509_STORE_add_lookup(x509_store, X509_LOOKUP_file()); if (!lookup) { Log(LogCritical, "SSL") << "Error adding X509 store lookup: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_STORE_add_lookup") << errinfo_openssl_error(ERR_peek_error())); } if (X509_LOOKUP_load_file(lookup, crlPath.CStr(), X509_FILETYPE_PEM) != 1) { Log(LogCritical, "SSL") << "Error loading crl file '" << crlPath << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_LOOKUP_load_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(crlPath)); } X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); X509_STORE_set1_param(x509_store, param); X509_VERIFY_PARAM_free(param); } static String GetX509NameCN(X509_NAME *name) { char errbuf[120]; char buffer[256]; int rc = X509_NAME_get_text_by_NID(name, NID_commonName, buffer, sizeof(buffer)); if (rc == -1) { Log(LogCritical, "SSL") << "Error with x509 NAME getting text by NID: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_NAME_get_text_by_NID") << errinfo_openssl_error(ERR_peek_error())); } return buffer; } /** * Retrieves the common name for an X509 certificate. * * @param certificate The X509 certificate. * @returns The common name. */ String GetCertificateCN(const boost::shared_ptr& certificate) { return GetX509NameCN(X509_get_subject_name(certificate.get())); } /** * Retrieves an X509 certificate from the specified file. * * @param pemfile The filename. * @returns An X509 certificate. */ boost::shared_ptr GetX509Certificate(const String& pemfile) { char errbuf[120]; X509 *cert; BIO *fpcert = BIO_new(BIO_s_file()); if (fpcert == NULL) { Log(LogCritical, "SSL") << "Error creating new BIO: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_new") << errinfo_openssl_error(ERR_peek_error())); } if (BIO_read_filename(fpcert, pemfile.CStr()) < 0) { Log(LogCritical, "SSL") << "Error reading pem file '" << pemfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_read_filename") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(pemfile)); } cert = PEM_read_bio_X509_AUX(fpcert, NULL, NULL, NULL); if (cert == NULL) { Log(LogCritical, "SSL") << "Error on bio X509 AUX reading pem file '" << pemfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("PEM_read_bio_X509_AUX") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(pemfile)); } BIO_free(fpcert); return boost::shared_ptr(cert, X509_free); } int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile, const String& certfile, bool ca) { char errbuf[120]; InitializeOpenSSL(); RSA *rsa = RSA_generate_key(4096, RSA_F4, NULL, NULL); Log(LogInformation, "base") << "Writing private key to '" << keyfile << "'."; BIO *bio = BIO_new_file(const_cast(keyfile.CStr()), "w"); if (!bio) { Log(LogCritical, "SSL") << "Error while opening private RSA key file '" << keyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_new_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(keyfile)); } if (!PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL)) { Log(LogCritical, "SSL") << "Error while writing private RSA key to file '" << keyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("PEM_write_bio_RSAPrivateKey") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(keyfile)); } BIO_free(bio); #ifndef _WIN32 chmod(keyfile.CStr(), 0600); #endif /* _WIN32 */ EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_assign_RSA(key, rsa); if (!certfile.IsEmpty()) { X509_NAME *subject = X509_NAME_new(); X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0); boost::shared_ptr cert = CreateCert(key, subject, subject, key, ca); X509_NAME_free(subject); Log(LogInformation, "base") << "Writing X509 certificate to '" << certfile << "'."; bio = BIO_new_file(const_cast(certfile.CStr()), "w"); if (!bio) { Log(LogCritical, "SSL") << "Error while opening certificate file '" << certfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_new_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(certfile)); } if (!PEM_write_bio_X509(bio, cert.get())) { Log(LogCritical, "SSL") << "Error while writing certificate to file '" << certfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("PEM_write_bio_X509") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(certfile)); } BIO_free(bio); } if (!csrfile.IsEmpty()) { X509_REQ *req = X509_REQ_new(); if (!req) return 0; X509_REQ_set_version(req, 0); X509_REQ_set_pubkey(req, key); X509_NAME *name = X509_REQ_get_subject_name(req); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0); if (!ca) { String san = "DNS:" + cn; X509_EXTENSION *subjectAltNameExt = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, const_cast(san.CStr())); if (subjectAltNameExt) { /* OpenSSL 0.9.8 requires STACK_OF(X509_EXTENSION), otherwise we would just use stack_st_X509_EXTENSION. */ STACK_OF(X509_EXTENSION) *exts = sk_X509_EXTENSION_new_null(); sk_X509_EXTENSION_push(exts, subjectAltNameExt); X509_REQ_add_extensions(req, exts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); } } X509_REQ_sign(req, key, EVP_sha256()); Log(LogInformation, "base") << "Writing certificate signing request to '" << csrfile << "'."; bio = BIO_new_file(const_cast(csrfile.CStr()), "w"); if (!bio) { Log(LogCritical, "SSL") << "Error while opening CSR file '" << csrfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_new_file") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(csrfile)); } if (!PEM_write_bio_X509_REQ(bio, req)) { Log(LogCritical, "SSL") << "Error while writing CSR to file '" << csrfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("PEM_write_bio_X509") << errinfo_openssl_error(ERR_peek_error()) << boost::errinfo_file_name(csrfile)); } BIO_free(bio); X509_REQ_free(req); } EVP_PKEY_free(key); return 1; } boost::shared_ptr CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca) { X509 *cert = X509_new(); X509_set_version(cert, 2); X509_gmtime_adj(X509_get_notBefore(cert), 0); X509_gmtime_adj(X509_get_notAfter(cert), 365 * 24 * 60 * 60 * 15); X509_set_pubkey(cert, pubkey); X509_set_subject_name(cert, subject); X509_set_issuer_name(cert, issuer); String id = Utility::NewUniqueID(); char errbuf[120]; SHA_CTX context; unsigned char digest[SHA_DIGEST_LENGTH]; if (!SHA1_Init(&context)) { Log(LogCritical, "SSL") << "Error on SHA1 Init: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Init") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA1_Update(&context, (unsigned char*)id.CStr(), id.GetLength())) { Log(LogCritical, "SSL") << "Error on SHA1 Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Update") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA1_Final(digest, &context)) { Log(LogCritical, "SSL") << "Error on SHA1 Final: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Final") << errinfo_openssl_error(ERR_peek_error())); } BIGNUM *bn = BN_new(); BN_bin2bn(digest, sizeof(digest), bn); BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert)); BN_free(bn); X509V3_CTX ctx; X509V3_set_ctx_nodb(&ctx); X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); const char *attr; if (ca) attr = "critical,CA:TRUE"; else attr = "critical,CA:FALSE"; X509_EXTENSION *basicConstraintsExt = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, const_cast(attr)); if (basicConstraintsExt) { X509_add_ext(cert, basicConstraintsExt, -1); X509_EXTENSION_free(basicConstraintsExt); } String cn = GetX509NameCN(subject); if (!ca) { String san = "DNS:" + cn; X509_EXTENSION *subjectAltNameExt = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_alt_name, const_cast(san.CStr())); if (subjectAltNameExt) { X509_add_ext(cert, subjectAltNameExt, -1); X509_EXTENSION_free(subjectAltNameExt); } } X509_sign(cert, cakey, EVP_sha256()); return boost::shared_ptr(cert, X509_free); } String GetIcingaCADir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/ca"; } boost::shared_ptr CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject) { char errbuf[120]; String cadir = GetIcingaCADir(); String cakeyfile = cadir + "/ca.key"; RSA *rsa; BIO *cakeybio = BIO_new_file(const_cast(cakeyfile.CStr()), "r"); if (!cakeybio) { Log(LogCritical, "SSL") << "Could not open CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; return boost::shared_ptr(); } rsa = PEM_read_bio_RSAPrivateKey(cakeybio, NULL, NULL, NULL); if (!rsa) { Log(LogCritical, "SSL") << "Could not read RSA key from CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; return boost::shared_ptr(); } BIO_free(cakeybio); String cacertfile = cadir + "/ca.crt"; boost::shared_ptr cacert = GetX509Certificate(cacertfile); EVP_PKEY *privkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(privkey, rsa); return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false); } boost::shared_ptr CreateCertIcingaCA(const boost::shared_ptr& cert) { boost::shared_ptr pkey = boost::shared_ptr(X509_get_pubkey(cert.get()), EVP_PKEY_free); return CreateCertIcingaCA(pkey.get(), X509_get_subject_name(cert.get())); } String CertificateToString(const boost::shared_ptr& cert) { BIO *mem = BIO_new(BIO_s_mem()); PEM_write_bio_X509(mem, cert.get()); char *data; long len = BIO_get_mem_data(mem, &data); String result = String(data, data + len); BIO_free(mem); return result; } boost::shared_ptr StringToCertificate(const String& cert) { BIO *bio = BIO_new(BIO_s_mem()); BIO_write(bio, (const void *)cert.CStr(), cert.GetLength()); X509 *rawCert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); BIO_free(bio); if (!rawCert) BOOST_THROW_EXCEPTION(std::invalid_argument("The specified X509 certificate is invalid.")); return boost::shared_ptr(rawCert, X509_free); } String PBKDF2_SHA1(const String& password, const String& salt, int iterations) { unsigned char digest[SHA_DIGEST_LENGTH]; PKCS5_PBKDF2_HMAC_SHA1(password.CStr(), password.GetLength(), reinterpret_cast(salt.CStr()), salt.GetLength(), iterations, sizeof(digest), digest); char output[SHA_DIGEST_LENGTH*2+1]; for (int i = 0; i < SHA_DIGEST_LENGTH; i++) sprintf(output + 2 * i, "%02x", digest[i]); return output; } String SHA1(const String& s, bool binary) { char errbuf[120]; SHA_CTX context; unsigned char digest[SHA_DIGEST_LENGTH]; if (!SHA1_Init(&context)) { Log(LogCritical, "SSL") << "Error on SHA Init: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Init") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA1_Update(&context, (unsigned char*)s.CStr(), s.GetLength())) { Log(LogCritical, "SSL") << "Error on SHA Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Update") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA1_Final(digest, &context)) { Log(LogCritical, "SSL") << "Error on SHA Final: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA1_Final") << errinfo_openssl_error(ERR_peek_error())); } if (binary) return String(reinterpret_cast(digest), reinterpret_cast(digest + SHA_DIGEST_LENGTH)); char output[SHA_DIGEST_LENGTH*2+1]; for (int i = 0; i < 20; i++) sprintf(output + 2 * i, "%02x", digest[i]); return output; } String SHA256(const String& s) { char errbuf[120]; SHA256_CTX context; unsigned char digest[SHA256_DIGEST_LENGTH]; if (!SHA256_Init(&context)) { Log(LogCritical, "SSL") << "Error on SHA256 Init: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Init") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA256_Update(&context, (unsigned char*)s.CStr(), s.GetLength())) { Log(LogCritical, "SSL") << "Error on SHA256 Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Update") << errinfo_openssl_error(ERR_peek_error())); } if (!SHA256_Final(digest, &context)) { Log(LogCritical, "SSL") << "Error on SHA256 Final: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Final") << errinfo_openssl_error(ERR_peek_error())); } char output[SHA256_DIGEST_LENGTH*2+1]; for (int i = 0; i < 32; i++) sprintf(output + 2 * i, "%02x", digest[i]); return output; } String RandomString(int length) { unsigned char *bytes = new unsigned char[length]; if (!RAND_bytes(bytes, length)) { delete [] bytes; char errbuf[120]; Log(LogCritical, "SSL") << "Error for RAND_bytes: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("RAND_bytes") << errinfo_openssl_error(ERR_peek_error())); } char *output = new char[length * 2 + 1]; for (int i = 0; i < length; i++) sprintf(output + 2 * i, "%02x", bytes[i]); String result = output; delete [] bytes; delete [] output; return result; } bool VerifyCertificate(const boost::shared_ptr& caCertificate, const boost::shared_ptr& certificate) { X509_STORE *store = X509_STORE_new(); if (!store) return false; X509_STORE_add_cert(store, caCertificate.get()); X509_STORE_CTX *csc = X509_STORE_CTX_new(); X509_STORE_CTX_init(csc, store, certificate.get(), NULL); int rc = X509_verify_cert(csc); X509_STORE_CTX_free(csc); X509_STORE_free(store); return rc == 1; } } icinga2-2.8.1/lib/base/tlsutility.hpp000066400000000000000000000101531322762156600174670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TLSUTILITY_H #define TLSUTILITY_H #include "base/i2-base.hpp" #include "base/object.hpp" #include "base/string.hpp" #include #include #include #include #include #include #include #include #include #include namespace icinga { void I2_BASE_API InitializeOpenSSL(void); boost::shared_ptr I2_BASE_API MakeSSLContext(const String& pubkey = String(), const String& privkey = String(), const String& cakey = String()); void I2_BASE_API AddCRLToSSLContext(const boost::shared_ptr& context, const String& crlPath); void I2_BASE_API SetCipherListToSSLContext(const boost::shared_ptr& context, const String& cipherList); void I2_BASE_API SetTlsProtocolminToSSLContext(const boost::shared_ptr& context, const String& tlsProtocolmin); String I2_BASE_API GetCertificateCN(const boost::shared_ptr& certificate); boost::shared_ptr I2_BASE_API GetX509Certificate(const String& pemfile); int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), bool ca = false); boost::shared_ptr I2_BASE_API CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca); String I2_BASE_API GetIcingaCADir(void); String I2_BASE_API CertificateToString(const boost::shared_ptr& cert); boost::shared_ptr I2_BASE_API StringToCertificate(const String& cert); boost::shared_ptr I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject); boost::shared_ptr I2_BASE_API CreateCertIcingaCA(const boost::shared_ptr& cert); String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations); String I2_BASE_API SHA1(const String& s, bool binary = false); String I2_BASE_API SHA256(const String& s); String I2_BASE_API RandomString(int length); bool I2_BASE_API VerifyCertificate(const boost::shared_ptr& caCertificate, const boost::shared_ptr& certificate); class I2_BASE_API openssl_error : virtual public std::exception, virtual public boost::exception { }; struct errinfo_openssl_error_; typedef boost::error_info errinfo_openssl_error; inline std::string to_string(const errinfo_openssl_error& e) { std::ostringstream tmp; int code = e.value(); char errbuf[120]; const char *message = ERR_error_string(code, errbuf); if (message == NULL) message = "Unknown error."; tmp << code << ", \"" << message << "\""; return "[errinfo_openssl_error]" + tmp.str() + "\n"; } } #endif /* TLSUTILITY_H */ icinga2-2.8.1/lib/base/type.cpp000066400000000000000000000124671322762156600162270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/type.hpp" #include "base/scriptglobal.hpp" #include "base/objectlock.hpp" using namespace icinga; Type::Ptr Type::TypeInstance; INITIALIZE_ONCE_WITH_PRIORITY([]() { Type::Ptr type = new TypeType(); type->SetPrototype(TypeType::GetPrototype()); Type::TypeInstance = type; Type::Register(type); }, 20); String Type::ToString(void) const { return "type '" + GetName() + "'"; } void Type::Register(const Type::Ptr& type) { VERIFY(GetByName(type->GetName()) == NULL); ScriptGlobal::Set("Types." + type->GetName(), type); } Type::Ptr Type::GetByName(const String& name) { Dictionary::Ptr typesNS = ScriptGlobal::Get("Types", &Empty); if (!typesNS) return Type::Ptr(); Value ptype = typesNS->Get(name); if (!ptype.IsObjectType()) return Type::Ptr(); return ptype; } std::vector Type::GetAllTypes(void) { std::vector types; Dictionary::Ptr typesNS = ScriptGlobal::Get("Types", &Empty); if (typesNS) { ObjectLock olock(typesNS); for (const Dictionary::Pair& kv : typesNS) { if (kv.second.IsObjectType()) types.push_back(kv.second); } } return types; } String Type::GetPluralName(void) const { String name = GetName(); if (name.GetLength() >= 2 && name[name.GetLength() - 1] == 'y' && name.SubStr(name.GetLength() - 2, 1).FindFirstOf("aeiou") == String::NPos) return name.SubStr(0, name.GetLength() - 1) + "ies"; else return name + "s"; } Object::Ptr Type::Instantiate(const std::vector& args) const { ObjectFactory factory = GetFactory(); if (!factory) BOOST_THROW_EXCEPTION(std::runtime_error("Type does not have a factory function.")); return factory(args); } bool Type::IsAbstract(void) const { return ((GetAttributes() & TAAbstract) != 0); } bool Type::IsAssignableFrom(const Type::Ptr& other) const { for (Type::Ptr t = other; t; t = t->GetBaseType()) { if (t.get() == this) return true; } return false; } Object::Ptr Type::GetPrototype(void) const { return m_Prototype; } void Type::SetPrototype(const Object::Ptr& object) { m_Prototype = object; } void Type::SetField(int id, const Value& value, bool suppress_events, const Value& cookie) { if (id == 1) { SetPrototype(value); return; } Object::SetField(id, value, suppress_events, cookie); } Value Type::GetField(int id) const { int real_id = id - Object::TypeInstance->GetFieldCount(); if (real_id < 0) return Object::GetField(id); if (real_id == 0) return GetName(); else if (real_id == 1) return GetPrototype(); else if (real_id == 2) return GetBaseType(); BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } std::vector Type::GetLoadDependencies(void) const { return std::vector(); } void Type::RegisterAttributeHandler(int fieldId, const AttributeHandler& callback) { throw std::runtime_error("Invalid field ID."); } String TypeType::GetName(void) const { return "Type"; } Type::Ptr TypeType::GetBaseType(void) const { return Object::TypeInstance; } int TypeType::GetAttributes(void) const { return 0; } int TypeType::GetFieldId(const String& name) const { int base_field_count = GetBaseType()->GetFieldCount(); if (name == "name") return base_field_count + 0; else if (name == "prototype") return base_field_count + 1; else if (name == "base") return base_field_count + 2; return GetBaseType()->GetFieldId(name); } Field TypeType::GetFieldInfo(int id) const { int real_id = id - GetBaseType()->GetFieldCount(); if (real_id < 0) return GetBaseType()->GetFieldInfo(id); if (real_id == 0) return Field(0, "String", "name", "", NULL, 0, 0); else if (real_id == 1) return Field(1, "Object", "prototype", "", NULL, 0, 0); else if (real_id == 2) return Field(2, "Type", "base", "", NULL, 0, 0); throw std::runtime_error("Invalid field ID."); } int TypeType::GetFieldCount(void) const { return GetBaseType()->GetFieldCount() + 3; } ObjectFactory TypeType::GetFactory(void) const { return NULL; } icinga2-2.8.1/lib/base/type.hpp000066400000000000000000000115501322762156600162240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TYPE_H #define TYPE_H #include "base/i2-base.hpp" #include "base/string.hpp" #include "base/object.hpp" #include "base/initialize.hpp" #include #include namespace icinga { /* keep this in sync with tools/mkclass/classcompiler.hpp */ enum FieldAttribute { FAEphemeral = 1, FAConfig = 2, FAState = 4, FARequired = 256, FANavigation = 512, FANoUserModify = 1024, FANoUserView = 2048, FADeprecated = 4096, }; class Type; struct Field { int ID; const char *TypeName; const char *Name; const char *NavigationName; const char *RefTypeName; int Attributes; int ArrayRank; Field(int id, const char *type, const char *name, const char *navigationName, const char *reftype, int attributes, int arrayRank) : ID(id), TypeName(type), Name(name), NavigationName(navigationName), RefTypeName(reftype), Attributes(attributes), ArrayRank(arrayRank) { } }; enum TypeAttribute { TAAbstract = 1 }; class ValidationUtils { public: virtual bool ValidateName(const String& type, const String& name) const = 0; }; class I2_BASE_API Type : public Object { public: DECLARE_OBJECT(Type); virtual String ToString(void) const override; virtual String GetName(void) const = 0; virtual Type::Ptr GetBaseType(void) const = 0; virtual int GetAttributes(void) const = 0; virtual int GetFieldId(const String& name) const = 0; virtual Field GetFieldInfo(int id) const = 0; virtual int GetFieldCount(void) const = 0; String GetPluralName(void) const; Object::Ptr Instantiate(const std::vector& args) const; bool IsAssignableFrom(const Type::Ptr& other) const; bool IsAbstract(void) const; Object::Ptr GetPrototype(void) const; void SetPrototype(const Object::Ptr& object); static void Register(const Type::Ptr& type); static Type::Ptr GetByName(const String& name); static std::vector GetAllTypes(void); virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty) override; virtual Value GetField(int id) const override; virtual std::vector GetLoadDependencies(void) const; typedef boost::function AttributeHandler; virtual void RegisterAttributeHandler(int fieldId, const AttributeHandler& callback); protected: virtual ObjectFactory GetFactory(void) const = 0; private: Object::Ptr m_Prototype; }; class I2_BASE_API TypeType : public Type { public: DECLARE_PTR_TYPEDEFS(Type); virtual String GetName(void) const override; virtual Type::Ptr GetBaseType(void) const override; virtual int GetAttributes(void) const override; virtual int GetFieldId(const String& name) const override; virtual Field GetFieldInfo(int id) const override; virtual int GetFieldCount(void) const override; static Object::Ptr GetPrototype(void); protected: virtual ObjectFactory GetFactory(void) const override; }; template class I2_BASE_API TypeImpl { }; #define REGISTER_TYPE(type) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ icinga::Type::Ptr t = new TypeImpl(); \ type::TypeInstance = t; \ icinga::Type::Register(t); \ }, 10); \ DEFINE_TYPE_INSTANCE(type) #define REGISTER_TYPE_WITH_PROTOTYPE(type, prototype) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ icinga::Type::Ptr t = new TypeImpl(); \ t->SetPrototype(prototype); \ type::TypeInstance = t; \ icinga::Type::Register(t); \ }, 10); \ DEFINE_TYPE_INSTANCE(type) #define DEFINE_TYPE_INSTANCE(type) \ Type::Ptr type::TypeInstance } #endif /* TYPE_H */ icinga2-2.8.1/lib/base/typetype-script.cpp000066400000000000000000000047351322762156600204320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/type.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static void InvokeAttributeHandlerHelper(const Function::Ptr& callback, const Object::Ptr& object, const Value& cookie) { std::vector arguments; arguments.push_back(object); callback->Invoke(arguments); } static void TypeRegisterAttributeHandler(const String& fieldName, const Function::Ptr& callback) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Type::Ptr self = static_cast(vframe->Self); int fid = self->GetFieldId(fieldName); self->RegisterAttributeHandler(fid, boost::bind(&InvokeAttributeHandlerHelper, callback, _1, _2)); } Object::Ptr TypeType::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("register_attribute_handler", new Function("Type#register_attribute_handler", WrapFunction(TypeRegisterAttributeHandler), { "field", "callback" }, false)); } return prototype; } icinga2-2.8.1/lib/base/unix.hpp000066400000000000000000000044611322762156600162310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef UNIX_H #define UNIX_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef int SOCKET; #define INVALID_SOCKET (-1) #define closesocket close #define ioctlsocket ioctl #ifndef SUN_LEN /* TODO: Ideally this should take into the account how long the socket path really is. */ # define SUN_LEN(sun) (sizeof(sockaddr_un)) #endif /* SUN_LEN */ #ifndef PATH_MAX # define PATH_MAX 1024 #endif /* PATH_MAX */ #ifndef MAXPATHLEN # define MAXPATHLEN PATH_MAX #endif /* MAXPATHLEN */ #endif /* UNIX_H */ icinga2-2.8.1/lib/base/unixsocket.cpp000066400000000000000000000052161322762156600174340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/unixsocket.hpp" #include "base/exception.hpp" #ifndef _WIN32 using namespace icinga; UnixSocket::UnixSocket(void) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("socket") << boost::errinfo_errno(errno)); } SetFD(fd); } void UnixSocket::Bind(const String& path) { unlink(path.CStr()); sockaddr_un s_un; memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; strncpy(s_un.sun_path, path.CStr(), sizeof(s_un.sun_path)); s_un.sun_path[sizeof(s_un.sun_path) - 1] = '\0'; if (bind(GetFD(), (sockaddr *)&s_un, SUN_LEN(&s_un)) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("bind") << boost::errinfo_errno(errno)); } } void UnixSocket::Connect(const String& path) { sockaddr_un s_un; memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; strncpy(s_un.sun_path, path.CStr(), sizeof(s_un.sun_path)); s_un.sun_path[sizeof(s_un.sun_path) - 1] = '\0'; if (connect(GetFD(), (sockaddr *)&s_un, SUN_LEN(&s_un)) < 0 && errno != EINPROGRESS) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("connect") << boost::errinfo_errno(errno)); } } #endif /* _WIN32 */ icinga2-2.8.1/lib/base/unixsocket.hpp000066400000000000000000000033641322762156600174430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef UNIXSOCKET_H #define UNIXSOCKET_H #include "base/socket.hpp" #ifndef _WIN32 namespace icinga { class I2_BASE_API UnixSocket : public Socket { public: DECLARE_PTR_TYPEDEFS(UnixSocket); UnixSocket(void); void Bind(const String& path); void Connect(const String& path); }; } #endif /* _WIN32 */ #endif /* UNIXSOCKET_H */ icinga2-2.8.1/lib/base/utility.cpp000066400000000000000000001300701322762156600167400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/utility.hpp" #include "base/convert.hpp" #include "base/application.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/socket.hpp" #include "base/utility.hpp" #include "base/json.hpp" #include "base/objectlock.hpp" #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ # include #endif /* __FreeBSD__ */ #ifdef HAVE_CXXABI_H # include #endif /* HAVE_CXXABI_H */ #ifndef _WIN32 # include # include # include # include #endif /* _WIN32 */ #ifdef _WIN32 # include # include # include # include # include #endif /*_WIN32*/ using namespace icinga; boost::thread_specific_ptr Utility::m_ThreadName; boost::thread_specific_ptr Utility::m_RandSeed; #ifdef I2_DEBUG double Utility::m_DebugTime = -1; #endif /* I2_DEBUG */ /** * Demangles a symbol name. * * @param sym The symbol name. * @returns A human-readable version of the symbol name. */ String Utility::DemangleSymbolName(const String& sym) { String result = sym; #ifdef HAVE_CXXABI_H int status; char *realname = abi::__cxa_demangle(sym.CStr(), 0, 0, &status); if (realname != NULL) { result = String(realname); free(realname); } #elif defined(_MSC_VER) /* HAVE_CXXABI_H */ CHAR output[256]; if (UnDecorateSymbolName(sym.CStr(), output, sizeof(output), UNDNAME_COMPLETE) > 0) result = output; #else /* _MSC_VER */ /* We're pretty much out of options here. */ #endif /* _MSC_VER */ return result; } /** * Returns a human-readable type name of a type_info object. * * @param ti A type_info object. * @returns The type name of the object. */ String Utility::GetTypeName(const std::type_info& ti) { return DemangleSymbolName(ti.name()); } String Utility::GetSymbolName(const void *addr) { #ifdef HAVE_DLADDR Dl_info dli; if (dladdr(const_cast(addr), &dli) > 0) return dli.dli_sname; #endif /* HAVE_DLADDR */ #ifdef _WIN32 char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD64 dwAddress = (DWORD64)addr; DWORD64 dwDisplacement; IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement, pSymbol)) { char output[256]; if (UnDecorateSymbolName(pSymbol->Name, output, sizeof(output), UNDNAME_COMPLETE)) return String(output) + "+" + Convert::ToString(dwDisplacement); else return String(pSymbol->Name) + "+" + Convert::ToString(dwDisplacement); } #endif /* _WIN32 */ return "(unknown function)"; } /** * Performs wildcard pattern matching. * * @param pattern The wildcard pattern. * @param text The String that should be checked. * @returns true if the wildcard pattern matches, false otherwise. */ bool Utility::Match(const String& pattern, const String& text) { return (match(pattern.CStr(), text.CStr()) == 0); } static bool ParseIp(const String& ip, char addr[16], int *proto) { if (inet_pton(AF_INET, ip.CStr(), addr + 12) == 1) { /* IPv4-mapped IPv6 address (::ffff:) */ memset(addr, 0, 10); memset(addr + 10, 0xff, 2); *proto = AF_INET; return true; } if (inet_pton(AF_INET6, ip.CStr(), addr) == 1) { *proto = AF_INET6; return true; } return false; } static void ParseIpMask(const String& ip, char mask[16], int *bits) { String::SizeType slashp = ip.FindFirstOf("/"); String uip; if (slashp == String::NPos) { uip = ip; *bits = 0; } else { uip = ip.SubStr(0, slashp); *bits = Convert::ToLong(ip.SubStr(slashp + 1)); } int proto; if (!ParseIp(uip, mask, &proto)) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid IP address specified.")); if (proto == AF_INET) { if (*bits > 32 || *bits < 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Mask must be between 0 and 32 for IPv4 CIDR masks.")); *bits += 96; } if (slashp == String::NPos) *bits = 128; if (*bits > 128 || *bits < 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Mask must be between 0 and 128 for IPv6 CIDR masks.")); for (int i = 0; i < 16; i++) { int lbits = std::max(0, *bits - i * 8); if (lbits >= 8) continue; if (mask[i] & (0xff >> lbits)) BOOST_THROW_EXCEPTION(std::invalid_argument("Masked-off bits must all be zero.")); } } static bool IpMaskCheck(char addr[16], char mask[16], int bits) { for (int i = 0; i < 16; i++) { if (bits < 8) return !((addr[i] ^ mask[i]) >> (8 - bits)); if (mask[i] != addr[i]) return false; bits -= 8; if (bits == 0) return true; } return true; } bool Utility::CidrMatch(const String& pattern, const String& ip) { char mask[16]; int bits; ParseIpMask(pattern, mask, &bits); char addr[16]; int proto; if (!ParseIp(ip, addr, &proto)) return false; return IpMaskCheck(addr, mask, bits); } /** * Returns the directory component of a path. See dirname(3) for details. * * @param path The full path. * @returns The directory. */ String Utility::DirName(const String& path) { char *dir; #ifdef _WIN32 String dupPath = path; /* PathRemoveFileSpec doesn't properly handle forward slashes. */ for (char& ch : dupPath) { if (ch == '/') ch = '\\'; } dir = strdup(dupPath.CStr()); #else /* _WIN32 */ dir = strdup(path.CStr()); #endif /* _WIN32 */ if (dir == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); String result; #ifndef _WIN32 result = dirname(dir); #else /* _WIN32 */ if (dir[0] != 0 && !PathRemoveFileSpec(dir)) { free(dir); BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("PathRemoveFileSpec") << errinfo_win32_error(GetLastError())); } result = dir; if (result.IsEmpty()) result = "."; #endif /* _WIN32 */ free(dir); return result; } /** * Returns the file component of a path. See basename(3) for details. * * @param path The full path. * @returns The filename. */ String Utility::BaseName(const String& path) { char *dir = strdup(path.CStr()); String result; if (dir == NULL) BOOST_THROW_EXCEPTION(std::bad_alloc()); #ifndef _WIN32 result = basename(dir); #else /* _WIN32 */ result = PathFindFileName(dir); #endif /* _WIN32 */ free(dir); return result; } /** * Null deleter. Used as a parameter for the shared_ptr constructor. * * @param - The object that should be deleted. */ void Utility::NullDeleter(void *) { /* Nothing to do here. */ } #ifdef I2_DEBUG /** * (DEBUG / TESTING ONLY) Sets the current system time to a static value, * that will be be retrieved by any component of Icinga, when using GetTime(). * * This should be only used for testing purposes, e.g. unit tests and debugging of certain functionalities. */ void Utility::SetTime(double time) { m_DebugTime = time; } /** * (DEBUG / TESTING ONLY) Increases the set debug system time by X seconds. * * This should be only used for testing purposes, e.g. unit tests and debugging of certain functionalities. */ void Utility::IncrementTime(double diff) { m_DebugTime += diff; } #endif /* I2_DEBUG */ /** * Returns the current UNIX timestamp including fractions of seconds. * * @returns The current time. */ double Utility::GetTime(void) { #ifdef I2_DEBUG if (m_DebugTime >= 0) { // (DEBUG / TESTING ONLY) this will return a *STATIC* system time, if the value has been set! return m_DebugTime; } #endif /* I2_DEBUG */ #ifdef _WIN32 FILETIME cft; GetSystemTimeAsFileTime(&cft); ULARGE_INTEGER ucft; ucft.HighPart = cft.dwHighDateTime; ucft.LowPart = cft.dwLowDateTime; SYSTEMTIME est = { 1970, 1, 4, 1, 0, 0, 0, 0}; FILETIME eft; SystemTimeToFileTime(&est, &eft); ULARGE_INTEGER ueft; ueft.HighPart = eft.dwHighDateTime; ueft.LowPart = eft.dwLowDateTime; return ((ucft.QuadPart - ueft.QuadPart) / 10000) / 1000.0; #else /* _WIN32 */ struct timeval tv; int rc = gettimeofday(&tv, NULL); VERIFY(rc >= 0); return tv.tv_sec + tv.tv_usec / 1000000.0; #endif /* _WIN32 */ } /** * Returns the ID of the current process. * * @returns The PID. */ pid_t Utility::GetPid(void) { #ifndef _WIN32 return getpid(); #else /* _WIN32 */ return GetCurrentProcessId(); #endif /* _WIN32 */ } /** * Sleeps for the specified amount of time. * * @param timeout The timeout in seconds. */ void Utility::Sleep(double timeout) { #ifndef _WIN32 unsigned long micros = timeout * 1000000u; if (timeout >= 1.0) sleep((unsigned)timeout); usleep(micros % 1000000u); #else /* _WIN32 */ ::Sleep(timeout * 1000); #endif /* _WIN32 */ } /** * Generates a new unique ID. * * @returns The new unique ID. */ String Utility::NewUniqueID(void) { static boost::mutex mutex; static int next_id = 0; /* I'd much rather use UUIDs but RHEL is way too cool to have * a semi-recent version of boost. Yay. */ String id; char buf[128]; if (gethostname(buf, sizeof(buf)) == 0) id = String(buf) + "-"; id += Convert::ToString((long)Utility::GetTime()) + "-"; { boost::mutex::scoped_lock lock(mutex); id += Convert::ToString(next_id); next_id++; } return id; } #ifdef _WIN32 static bool GlobHelper(const String& pathSpec, int type, std::vector& files, std::vector& dirs) { HANDLE handle; WIN32_FIND_DATA wfd; handle = FindFirstFile(pathSpec.CStr(), &wfd); if (handle == INVALID_HANDLE_VALUE) { DWORD errorCode = GetLastError(); if (errorCode == ERROR_FILE_NOT_FOUND) return false; BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("FindFirstFile") << errinfo_win32_error(errorCode) << boost::errinfo_file_name(pathSpec)); } do { if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0) continue; String path = Utility::DirName(pathSpec) + "/" + wfd.cFileName; if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobDirectory)) dirs.push_back(path); else if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobFile)) files.push_back(path); } while (FindNextFile(handle, &wfd)); if (!FindClose(handle)) { BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("FindClose") << errinfo_win32_error(GetLastError())); } return true; } #endif /* _WIN32 */ #ifndef _WIN32 static int GlobErrorHandler(const char *epath, int eerrno) { if (eerrno == ENOTDIR) return 0; return eerrno; } #endif /* _WIN32 */ /** * Calls the specified callback for each file matching the path specification. * * @param pathSpec The path specification. * @param callback The callback which is invoked for each matching file. * @param type The file type (a combination of GlobFile and GlobDirectory) */ bool Utility::Glob(const String& pathSpec, const boost::function& callback, int type) { std::vector files, dirs; #ifdef _WIN32 std::vector tokens; boost::algorithm::split(tokens, pathSpec, boost::is_any_of("\\/")); String part1; for (std::vector::size_type i = 0; i < tokens.size() - 1; i++) { const String& token = tokens[i]; if (!part1.IsEmpty()) part1 += "/"; part1 += token; if (token.FindFirstOf("?*") != String::NPos) { String part2; for (std::vector::size_type k = i + 1; k < tokens.size(); k++) { if (!part2.IsEmpty()) part2 += "/"; part2 += tokens[k]; } std::vector files2, dirs2; if (!GlobHelper(part1, GlobDirectory, files2, dirs2)) return false; for (const String& dir : dirs2) { if (!Utility::Glob(dir + "/" + part2, callback, type)) return false; } return true; } } if (!GlobHelper(part1 + "/" + tokens[tokens.size() - 1], type, files, dirs)) return false; #else /* _WIN32 */ glob_t gr; int rc = glob(pathSpec.CStr(), GLOB_NOSORT, GlobErrorHandler, &gr); if (rc < 0) { if (rc == GLOB_NOMATCH) return false; BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("glob") << boost::errinfo_errno(errno) << boost::errinfo_file_name(pathSpec)); } if (gr.gl_pathc == 0) { globfree(&gr); return false; } size_t left; char **gp; for (gp = gr.gl_pathv, left = gr.gl_pathc; left > 0; gp++, left--) { struct stat statbuf; if (stat(*gp, &statbuf) < 0) continue; if (!S_ISDIR(statbuf.st_mode) && !S_ISREG(statbuf.st_mode)) continue; if (S_ISDIR(statbuf.st_mode) && (type & GlobDirectory)) dirs.push_back(*gp); else if (!S_ISDIR(statbuf.st_mode) && (type & GlobFile)) files.push_back(*gp); } globfree(&gr); #endif /* _WIN32 */ std::sort(files.begin(), files.end()); for (const String& cpath : files) { callback(cpath); } std::sort(dirs.begin(), dirs.end()); for (const String& cpath : dirs) { callback(cpath); } return true; } /** * Calls the specified callback for each file in the specified directory * or any of its child directories if the file name matches the specified * pattern. * * @param path The path. * @param pattern The pattern. * @param callback The callback which is invoked for each matching file. * @param type The file type (a combination of GlobFile and GlobDirectory) */ bool Utility::GlobRecursive(const String& path, const String& pattern, const boost::function& callback, int type) { std::vector files, dirs, alldirs; #ifdef _WIN32 HANDLE handle; WIN32_FIND_DATA wfd; String pathSpec = path + "/*"; handle = FindFirstFile(pathSpec.CStr(), &wfd); if (handle == INVALID_HANDLE_VALUE) { DWORD errorCode = GetLastError(); if (errorCode == ERROR_FILE_NOT_FOUND) return false; BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("FindFirstFile") << errinfo_win32_error(errorCode) << boost::errinfo_file_name(pathSpec)); } do { if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0) continue; String cpath = path + "/" + wfd.cFileName; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) alldirs.push_back(cpath); if (!Utility::Match(pattern, wfd.cFileName)) continue; if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobFile)) files.push_back(cpath); if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobDirectory)) dirs.push_back(cpath); } while (FindNextFile(handle, &wfd)); if (!FindClose(handle)) { BOOST_THROW_EXCEPTION(win32_error() << boost::errinfo_api_function("FindClose") << errinfo_win32_error(GetLastError())); } #else /* _WIN32 */ DIR *dirp; dirp = opendir(path.CStr()); if (dirp == NULL) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("opendir") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); while (dirp) { dirent *pent; errno = 0; pent = readdir(dirp); if (!pent && errno != 0) { closedir(dirp); BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("readdir") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } if (!pent) break; if (strcmp(pent->d_name, ".") == 0 || strcmp(pent->d_name, "..") == 0) continue; String cpath = path + "/" + pent->d_name; struct stat statbuf; if (stat(cpath.CStr(), &statbuf) < 0) continue; if (S_ISDIR(statbuf.st_mode)) alldirs.push_back(cpath); if (!Utility::Match(pattern, pent->d_name)) continue; if (S_ISDIR(statbuf.st_mode) && (type & GlobDirectory)) dirs.push_back(cpath); if (!S_ISDIR(statbuf.st_mode) && (type & GlobFile)) files.push_back(cpath); } closedir(dirp); #endif /* _WIN32 */ std::sort(files.begin(), files.end()); for (const String& cpath : files) { callback(cpath); } std::sort(dirs.begin(), dirs.end()); for (const String& cpath : dirs) { callback(cpath); } std::sort(alldirs.begin(), alldirs.end()); for (const String& cpath : alldirs) { GlobRecursive(cpath, pattern, callback, type); } return true; } void Utility::MkDir(const String& path, int mode) { #ifndef _WIN32 if (mkdir(path.CStr(), mode) < 0 && errno != EEXIST) { #else /*_ WIN32 */ if (mkdir(path.CStr()) < 0 && errno != EEXIST) { #endif /* _WIN32 */ BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("mkdir") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } } void Utility::MkDirP(const String& path, int mode) { size_t pos = 0; while (pos != String::NPos) { #ifndef _WIN32 pos = path.Find("/", pos + 1); #else /*_ WIN32 */ pos = path.FindFirstOf("/\\", pos + 1); #endif /* _WIN32 */ String spath = path.SubStr(0, pos + 1); struct stat statbuf; if (stat(spath.CStr(), &statbuf) < 0 && errno == ENOENT) MkDir(path.SubStr(0, pos), mode); } } void Utility::RemoveDirRecursive(const String& path) { std::vector paths; Utility::GlobRecursive(path, "*", boost::bind(&Utility::CollectPaths, _1, boost::ref(paths)), GlobFile | GlobDirectory); /* This relies on the fact that GlobRecursive lists the parent directory first before recursing into subdirectories. */ std::reverse(paths.begin(), paths.end()); for (const String& path : paths) { if (remove(path.CStr()) < 0) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("remove") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } #ifndef _WIN32 if (rmdir(path.CStr()) < 0) #else /* _WIN32 */ if (_rmdir(path.CStr()) < 0) #endif /* _WIN32 */ BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rmdir") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } void Utility::CollectPaths(const String& path, std::vector& paths) { paths.push_back(path); } /* * Copies a source file to a target location. * Caller must ensure that the target's base directory exists and is writable. */ void Utility::CopyFile(const String& source, const String& target) { std::ifstream ifs(source.CStr(), std::ios::binary); std::ofstream ofs(target.CStr(), std::ios::binary | std::ios::trunc); ofs << ifs.rdbuf(); } /* * Set file permissions */ bool Utility::SetFileOwnership(const String& file, const String& user, const String& group) { #ifndef _WIN32 errno = 0; struct passwd *pw = getpwnam(user.CStr()); if (!pw) { if (errno == 0) { Log(LogCritical, "cli") << "Invalid user specified: " << user; return false; } else { Log(LogCritical, "cli") << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return false; } } errno = 0; struct group *gr = getgrnam(group.CStr()); if (!gr) { if (errno == 0) { Log(LogCritical, "cli") << "Invalid group specified: " << group; return false; } else { Log(LogCritical, "cli") << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return false; } } if (chown(file.CStr(), pw->pw_uid, gr->gr_gid) < 0) { Log(LogCritical, "cli") << "chown() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return false; } #endif /* _WIN32 */ return true; } #ifndef _WIN32 void Utility::SetNonBlocking(int fd, bool nb) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fcntl") << boost::errinfo_errno(errno)); } if (nb) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fcntl") << boost::errinfo_errno(errno)); } } void Utility::SetCloExec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD, 0); if (flags < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fcntl") << boost::errinfo_errno(errno)); } if (cloexec) flags |= FD_CLOEXEC; else flags &= ~FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("fcntl") << boost::errinfo_errno(errno)); } } #endif /* _WIN32 */ void Utility::SetNonBlockingSocket(SOCKET s, bool nb) { #ifndef _WIN32 SetNonBlocking(s, nb); #else /* _WIN32 */ unsigned long lflag = nb; ioctlsocket(s, FIONBIO, &lflag); #endif /* _WIN32 */ } void Utility::QueueAsyncCallback(const boost::function& callback, SchedulerPolicy policy) { Application::GetTP().Post(callback, policy); } String Utility::NaturalJoin(const std::vector& tokens) { String result; for (std::vector::size_type i = 0; i < tokens.size(); i++) { result += tokens[i]; if (tokens.size() > i + 1) { if (i < tokens.size() - 2) result += ", "; else if (i == tokens.size() - 2) result += " and "; } } return result; } String Utility::Join(const Array::Ptr& tokens, char separator, bool escapeSeparator) { String result; bool first = true; ObjectLock olock(tokens); for (const Value& vtoken : tokens) { String token = Convert::ToString(vtoken); if (escapeSeparator) { boost::algorithm::replace_all(token, "\\", "\\\\"); char sep_before[2], sep_after[3]; sep_before[0] = separator; sep_before[1] = '\0'; sep_after[0] = '\\'; sep_after[1] = separator; sep_after[2] = '\0'; boost::algorithm::replace_all(token, sep_before, sep_after); } if (first) first = false; else result += String(1, separator); result += token; } return result; } String Utility::FormatDuration(double duration) { std::vector tokens; String result; if (duration >= 86400) { int days = duration / 86400; tokens.push_back(Convert::ToString(days) + (days != 1 ? " days" : " day")); duration = static_cast(duration) % 86400; } if (duration >= 3600) { int hours = duration / 3600; tokens.push_back(Convert::ToString(hours) + (hours != 1 ? " hours" : " hour")); duration = static_cast(duration) % 3600; } if (duration >= 60) { int minutes = duration / 60; tokens.push_back(Convert::ToString(minutes) + (minutes != 1 ? " minutes" : " minute")); duration = static_cast(duration) % 60; } if (duration >= 1) { int seconds = duration; tokens.push_back(Convert::ToString(seconds) + (seconds != 1 ? " seconds" : " second")); } if (tokens.size() == 0) { int milliseconds = std::floor(duration * 1000); if (milliseconds >= 1) tokens.push_back(Convert::ToString(milliseconds) + (milliseconds != 1 ? " milliseconds" : " millisecond")); else tokens.push_back("less than 1 millisecond"); } return NaturalJoin(tokens); } String Utility::FormatDateTime(const char *format, double ts) { char timestamp[128]; time_t tempts = (time_t)ts; /* We don't handle sub-second timestamps here just yet. */ tm tmthen; #ifdef _MSC_VER tm *temp = localtime(&tempts); if (temp == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime") << boost::errinfo_errno(errno)); } tmthen = *temp; #else /* _MSC_VER */ if (localtime_r(&tempts, &tmthen) == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime_r") << boost::errinfo_errno(errno)); } #endif /* _MSC_VER */ strftime(timestamp, sizeof(timestamp), format, &tmthen); return timestamp; } String Utility::FormatErrorNumber(int code) { std::ostringstream msgbuf; #ifdef _WIN32 char *message; String result = "Unknown error."; DWORD rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, 0, (char *)&message, 0, NULL); if (rc != 0) { result = String(message); LocalFree(message); /* remove trailing new-line characters */ boost::algorithm::trim_right(result); } msgbuf << code << ", \"" << result << "\""; #else msgbuf << strerror(code); #endif return msgbuf.str(); } String Utility::EscapeShellCmd(const String& s) { String result; size_t prev_quote = String::NPos; int index = -1; for (char ch : s) { bool escape = false; index++; #ifdef _WIN32 if (ch == '%' || ch == '"' || ch == '\'') escape = true; #else /* _WIN32 */ if (ch == '"' || ch == '\'') { /* Find a matching closing quotation character. */ if (prev_quote == String::NPos && (prev_quote = s.FindFirstOf(ch, index + 1)) != String::NPos) ; /* Empty statement. */ else if (prev_quote != String::NPos && s[prev_quote] == ch) prev_quote = String::NPos; else escape = true; } #endif /* _WIN32 */ if (ch == '#' || ch == '&' || ch == ';' || ch == '`' || ch == '|' || ch == '*' || ch == '?' || ch == '~' || ch == '<' || ch == '>' || ch == '^' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}' || ch == '$' || ch == '\\' || ch == '\x0A' || ch == '\xFF') escape = true; if (escape) #ifdef _WIN32 result += '^'; #else /* _WIN32 */ result += '\\'; #endif /* _WIN32 */ result += ch; } return result; } String Utility::EscapeShellArg(const String& s) { String result; #ifdef _WIN32 result = "\""; #else /* _WIN32 */ result = "'"; #endif /* _WIN32 */ for (char ch : s) { #ifdef _WIN32 if (ch == '"' || ch == '%') { result += ' '; } #else /* _WIN32 */ if (ch == '\'') result += "'\\'"; #endif result += ch; } #ifdef _WIN32 result += '"'; #else /* _WIN32 */ result += '\''; #endif /* _WIN32 */ return result; } #ifdef _WIN32 String Utility::EscapeCreateProcessArg(const String& arg) { if (arg.FindFirstOf(" \t\n\v\"") == String::NPos) return arg; String result = "\""; for (String::ConstIterator it = arg.Begin(); ; it++) { int numBackslashes = 0; while (it != arg.End() && *it == '\\') { it++; numBackslashes++; } if (it == arg.End()) { result.Append(numBackslashes * 2, '\\'); break; } else if (*it == '"') { result.Append(numBackslashes * 2, '\\'); result.Append(1, *it); } else { result.Append(numBackslashes, '\\'); result.Append(1, *it); } } result += "\""; return result; } #endif /* _WIN32 */ #ifdef _WIN32 static void WindowsSetThreadName(const char *name) { THREADNAME_INFO info; info.dwType = 0x1000; info.szName = name; info.dwThreadID = -1; info.dwFlags = 0; __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); } __except(EXCEPTION_EXECUTE_HANDLER) { /* Nothing to do here. */ } } #endif /* _WIN32 */ void Utility::SetThreadName(const String& name, bool os) { m_ThreadName.reset(new String(name)); if (!os) return; #ifdef _WIN32 WindowsSetThreadName(name.CStr()); #endif /* _WIN32 */ #ifdef HAVE_PTHREAD_SET_NAME_NP pthread_set_name_np(pthread_self(), name.CStr()); #endif /* HAVE_PTHREAD_SET_NAME_NP */ #ifdef HAVE_PTHREAD_SETNAME_NP # ifdef __APPLE__ pthread_setname_np(name.CStr()); # else /* __APPLE__ */ String tname = name.SubStr(0, 15); pthread_setname_np(pthread_self(), tname.CStr()); # endif /* __APPLE__ */ #endif /* HAVE_PTHREAD_SETNAME_NP */ } String Utility::GetThreadName(void) { String *name = m_ThreadName.get(); if (!name) { std::ostringstream idbuf; idbuf << boost::this_thread::get_id(); return idbuf.str(); } return *name; } unsigned long Utility::SDBM(const String& str, size_t len) { unsigned long hash = 0; size_t current = 0; for (char c : str) { if (current >= len) break; hash = c + (hash << 6) + (hash << 16) - hash; current++; } return hash; } int Utility::CompareVersion(const String& v1, const String& v2) { std::vector tokensv1, tokensv2; boost::algorithm::split(tokensv1, v1, boost::is_any_of(".")); boost::algorithm::split(tokensv2, v2, boost::is_any_of(".")); for (std::vector::size_type i = 0; i < tokensv2.size() - tokensv1.size(); i++) tokensv1.push_back("0"); for (std::vector::size_type i = 0; i < tokensv1.size() - tokensv2.size(); i++) tokensv2.push_back("0"); for (std::vector::size_type i = 0; i < tokensv1.size(); i++) { if (Convert::ToLong(tokensv2[i]) > Convert::ToLong(tokensv1[i])) return 1; else if (Convert::ToLong(tokensv2[i]) < Convert::ToLong(tokensv1[i])) return -1; } return 0; } String Utility::GetHostName(void) { char name[255]; if (gethostname(name, sizeof(name)) < 0) return "localhost"; return name; } /** * Returns the fully-qualified domain name for the host * we're running on. * * @returns The FQDN. */ String Utility::GetFQDN(void) { String hostname = GetHostName(); addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_CANONNAME; addrinfo *result; int rc = getaddrinfo(hostname.CStr(), NULL, &hints, &result); if (rc != 0) result = NULL; if (result) { if (strcmp(result->ai_canonname, "localhost") != 0) hostname = result->ai_canonname; freeaddrinfo(result); } return hostname; } int Utility::Random(void) { #ifdef _WIN32 return rand(); #else /* _WIN32 */ unsigned int *seed = m_RandSeed.get(); if (!seed) { seed = new unsigned int(Utility::GetTime()); m_RandSeed.reset(seed); } return rand_r(seed); #endif /* _WIN32 */ } tm Utility::LocalTime(time_t ts) { #ifdef _MSC_VER tm *result = localtime(&ts); if (result == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime") << boost::errinfo_errno(errno)); } return *result; #else /* _MSC_VER */ tm result; if (localtime_r(&ts, &result) == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime_r") << boost::errinfo_errno(errno)); } return result; #endif /* _MSC_VER */ } bool Utility::PathExists(const String& path) { #ifndef _WIN32 struct stat statbuf; return (lstat(path.CStr(), &statbuf) >= 0); #else /* _WIN32 */ struct _stat statbuf; return (_stat(path.CStr(), &statbuf) >= 0); #endif /* _WIN32 */ } Value Utility::LoadJsonFile(const String& path) { std::ifstream fp; fp.open(path.CStr()); String json((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); fp.close(); if (fp.fail()) BOOST_THROW_EXCEPTION(std::runtime_error("Could not read JSON file '" + path + "'.")); return JsonDecode(json); } void Utility::SaveJsonFile(const String& path, int mode, const Value& value) { std::fstream fp; String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", mode, fp); fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); fp << JsonEncode(value); fp.close(); #ifdef _WIN32 _unlink(path.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } } static void HexEncode(char ch, std::ostream& os) { const char *hex_chars = "0123456789ABCDEF"; os << hex_chars[ch >> 4 & 0x0f]; os << hex_chars[ch & 0x0f]; } static int HexDecode(char hc) { if (hc >= '0' && hc <= '9') return hc - '0'; else if (hc >= 'a' && hc <= 'f') return hc - 'a' + 10; else if (hc >= 'A' && hc <= 'F') return hc - 'A' + 10; else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid hex character.")); } String Utility::EscapeString(const String& s, const String& chars, const bool illegal) { std::ostringstream result; if (illegal) { for (char ch : s) { if (chars.FindFirstOf(ch) != String::NPos || ch == '%') { result << '%'; HexEncode(ch, result); } else result << ch; } } else { for (char ch : s) { if (chars.FindFirstOf(ch) == String::NPos || ch == '%') { result << '%'; HexEncode(ch, result); } else result << ch; } } return result.str(); } String Utility::UnescapeString(const String& s) { std::ostringstream result; for (String::SizeType i = 0; i < s.GetLength(); i++) { if (s[i] == '%') { if (i + 2 > s.GetLength() - 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid escape sequence.")); char ch = HexDecode(s[i + 1]) * 16 + HexDecode(s[i + 2]); result << ch; i += 2; } else result << s[i]; } return result.str(); } #ifndef _WIN32 static String UnameHelper(char type) { /* Unfortunately the uname() system call doesn't support some of the * query types we're interested in - so we're using popen() instead. */ char cmd[] = "uname -X 2>&1"; cmd[7] = type; FILE *fp = popen(cmd, "r"); if (!fp) return "Unknown"; char line[1024]; std::ostringstream msgbuf; while (fgets(line, sizeof(line), fp) != NULL) msgbuf << line; pclose(fp); String result = msgbuf.str(); return result.Trim(); } #endif /* _WIN32 */ static bool ReleaseHelper(String *platformName, String *platformVersion) { #ifdef _WIN32 if (platformName) *platformName = "Windows"; if (platformVersion) { *platformVersion = "Vista"; if (IsWindowsVistaSP1OrGreater()) *platformVersion = "Vista SP1"; if (IsWindowsVistaSP2OrGreater()) *platformVersion = "Vista SP2"; if (IsWindows7OrGreater()) *platformVersion = "7"; if (IsWindows7SP1OrGreater()) *platformVersion = "7 SP1"; if (IsWindows8OrGreater()) *platformVersion = "8"; if (IsWindows8Point1OrGreater()) *platformVersion = "8.1 or greater"; if (IsWindowsServer()) *platformVersion += " (Server)"; } return true; #else /* _WIN32 */ if (platformName) *platformName = "Unknown"; if (platformVersion) *platformVersion = "Unknown"; /* You have systemd or Ubuntu etc. */ std::ifstream release("/etc/os-release"); if (release.is_open()) { std::string release_line; while (getline(release, release_line)) { std::string::size_type pos = release_line.find("="); if (pos == std::string::npos) continue; std::string key = release_line.substr(0, pos); std::string value = release_line.substr(pos + 1); std::string::size_type firstQuote = value.find("\""); if (firstQuote != std::string::npos) value.erase(0, firstQuote + 1); std::string::size_type lastQuote = value.rfind("\""); if (lastQuote != std::string::npos) value.erase(lastQuote); if (platformName && key == "NAME") *platformName = value; if (platformVersion && key == "VERSION") *platformVersion = value; } return true; } /* You are using a distribution which supports LSB. */ FILE *fp = popen("type lsb_release >/dev/null 2>&1 && lsb_release -s -i 2>&1", "r"); if (fp != NULL) { std::ostringstream msgbuf; char line[1024]; while (fgets(line, sizeof(line), fp) != NULL) msgbuf << line; int status = pclose(fp); if (WEXITSTATUS(status) == 0) { if (platformName) *platformName = msgbuf.str(); } } fp = popen("type lsb_release >/dev/null 2>&1 && lsb_release -s -r 2>&1", "r"); if (fp != NULL) { std::ostringstream msgbuf; char line[1024]; while (fgets(line, sizeof(line), fp) != NULL) msgbuf << line; int status = pclose(fp); if (WEXITSTATUS(status) == 0) { if (platformVersion) *platformVersion = msgbuf.str(); } } /* OS X */ fp = popen("type sw_vers >/dev/null 2>&1 && sw_vers -productName 2>&1", "r"); if (fp != NULL) { std::ostringstream msgbuf; char line[1024]; while (fgets(line, sizeof(line), fp) != NULL) msgbuf << line; int status = pclose(fp); if (WEXITSTATUS(status) == 0) { String info = msgbuf.str(); info = info.Trim(); if (platformName) *platformName = info; } } fp = popen("type sw_vers >/dev/null 2>&1 && sw_vers -productVersion 2>&1", "r"); if (fp != NULL) { std::ostringstream msgbuf; char line[1024]; while (fgets(line, sizeof(line), fp) != NULL) msgbuf << line; int status = pclose(fp); if (WEXITSTATUS(status) == 0) { String info = msgbuf.str(); info = info.Trim(); if (platformVersion) *platformVersion = info; return true; } } /* Centos/RHEL < 7 */ release.close(); release.open("/etc/redhat-release"); if (release.is_open()) { std::string release_line; getline(release, release_line); String info = release_line; /* example: Red Hat Enterprise Linux Server release 6.7 (Santiago) */ if (platformName) *platformName = info.SubStr(0, info.Find("release") - 1); if (platformVersion) *platformVersion = info.SubStr(info.Find("release") + 8); return true; } /* sles 11 sp3, opensuse w/e */ release.close(); release.open("/etc/SuSE-release"); if (release.is_open()) { std::string release_line; getline(release, release_line); String info = release_line; if (platformName) *platformName = info.SubStr(0, info.FindFirstOf(" ")); if (platformVersion) *platformVersion = info.SubStr(info.FindFirstOf(" ") + 1); return true; } /* Just give up */ return false; #endif /* _WIN32 */ } String Utility::GetPlatformKernel(void) { #ifdef _WIN32 return "Windows"; #else /* _WIN32 */ return UnameHelper('s'); #endif /* _WIN32 */ } String Utility::GetPlatformKernelVersion(void) { #ifdef _WIN32 OSVERSIONINFO info; info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&info); std::ostringstream msgbuf; msgbuf << info.dwMajorVersion << "." << info.dwMinorVersion; return msgbuf.str(); #else /* _WIN32 */ return UnameHelper('r'); #endif /* _WIN32 */ } String Utility::GetPlatformName(void) { String platformName; if (!ReleaseHelper(&platformName, NULL)) return "Unknown"; return platformName; } String Utility::GetPlatformVersion(void) { String platformVersion; if (!ReleaseHelper(NULL, &platformVersion)) return "Unknown"; return platformVersion; } String Utility::GetPlatformArchitecture(void) { #ifdef _WIN32 SYSTEM_INFO info; GetNativeSystemInfo(&info); switch (info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: return "x86_64"; case PROCESSOR_ARCHITECTURE_ARM: return "arm"; case PROCESSOR_ARCHITECTURE_INTEL: return "x86"; default: return "unknown"; } #else /* _WIN32 */ return UnameHelper('m'); #endif /* _WIN32 */ } String Utility::ValidateUTF8(const String& input) { String output; size_t length = input.GetLength(); for (size_t i = 0; i < length; i++) { if ((input[i] & 0x80) == 0) { output += input[i]; continue; } if ((input[i] & 0xE0) == 0xC0 && length > i + 1 && (input[i + 1] & 0xC0) == 0x80) { output += input[i]; output += input[i + 1]; i++; continue; } if ((input[i] & 0xF0) == 0xE0 && length > i + 2 && (input[i + 1] & 0xC0) == 0x80 && (input[i + 2] & 0xC0) == 0x80) { output += input[i]; output += input[i + 1]; output += input[i + 2]; i += 2; continue; } output += '\xEF'; output += '\xBF'; output += '\xBD'; } return output; } String Utility::CreateTempFile(const String& path, int mode, std::fstream& fp) { std::vector targetPath(path.Begin(), path.End()); targetPath.push_back('\0'); int fd; #ifndef _WIN32 fd = mkstemp(&targetPath[0]); #else /* _WIN32 */ fd = MksTemp(&targetPath[0]); #endif /*_WIN32*/ if (fd < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("mkstemp") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } try { fp.open(&targetPath[0], std::ios_base::trunc | std::ios_base::out); } catch (const std::fstream::failure& e) { close(fd); throw; } close(fd); String resultPath = String(targetPath.begin(), targetPath.end() - 1); if (chmod(resultPath.CStr(), mode) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("chmod") << boost::errinfo_errno(errno) << boost::errinfo_file_name(resultPath)); } return resultPath; } #ifdef _WIN32 /* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. */ #define _O_EXCL 0x0400 #define _O_CREAT 0x0100 #define _O_RDWR 0x0002 #define O_EXCL _O_EXCL #define O_CREAT _O_CREAT #define O_RDWR _O_RDWR static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /* Generate a temporary file name based on TMPL. TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed does not exist at the time of the call to mkstemp. TMPL is overwritten with the result. */ int Utility::MksTemp(char *tmpl) { int len; char *XXXXXX; static unsigned long long value; unsigned long long random_time_bits; unsigned int count; int fd = -1; int save_errno = errno; /* A lower bound on the number of temporary files to attempt to generate. The maximum total number of temporary file names that can exist for a given template is 62**6. It should never be necessary to try all these combinations. Instead if a reasonable number of names is tried (we define reasonable as 62**3) fail to give the system administrator the chance to remove the problems. */ #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX unsigned int attempts = TMP_MAX; #else unsigned int attempts = ATTEMPTS_MIN; #endif len = strlen (tmpl); if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) { errno = EINVAL; return -1; } /* This is where the Xs start. */ XXXXXX = &tmpl[len - 6]; /* Get some more or less random data. */ { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) | (unsigned long long)ftNow.dwLowDateTime); } value += random_time_bits ^ (unsigned long long)GetCurrentThreadId(); for (count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = letters[v % 62]; v /= 62; XXXXXX[1] = letters[v % 62]; v /= 62; XXXXXX[2] = letters[v % 62]; v /= 62; XXXXXX[3] = letters[v % 62]; v /= 62; XXXXXX[4] = letters[v % 62]; v /= 62; XXXXXX[5] = letters[v % 62]; fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE); if (fd >= 0) { errno = save_errno; return fd; } else if (errno != EEXIST) return -1; } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } String Utility::GetIcingaInstallPath(void) { char szProduct[39]; for (int i = 0; MsiEnumProducts(i, szProduct) == ERROR_SUCCESS; i++) { char szName[128]; DWORD cbName = sizeof(szName); if (MsiGetProductInfo(szProduct, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, szName, &cbName) != ERROR_SUCCESS) continue; if (strcmp(szName, "Icinga 2") != 0) continue; char szLocation[1024]; DWORD cbLocation = sizeof(szLocation); if (MsiGetProductInfo(szProduct, INSTALLPROPERTY_INSTALLLOCATION, szLocation, &cbLocation) == ERROR_SUCCESS) return szLocation; } return ""; } String Utility::GetIcingaDataPath(void) { char path[MAX_PATH]; if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path))) return ""; return String(path) + "\\icinga2"; } #endif /* _WIN32 */ icinga2-2.8.1/lib/base/utility.hpp000066400000000000000000000130301322762156600167410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef UTILITY_H #define UTILITY_H #include "base/i2-base.hpp" #include "base/string.hpp" #include "base/array.hpp" #include "base/threadpool.hpp" #include #include #include #include namespace icinga { #ifdef _WIN32 #define MS_VC_EXCEPTION 0x406D1388 # pragma pack(push, 8) struct THREADNAME_INFO { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; }; # pragma pack(pop) #endif enum GlobType { GlobFile = 1, GlobDirectory = 2 }; /** * Helper functions. * * @ingroup base */ class I2_BASE_API Utility { public: static String DemangleSymbolName(const String& sym); static String GetTypeName(const std::type_info& ti); static String GetSymbolName(const void *addr); static bool Match(const String& pattern, const String& text); static bool CidrMatch(const String& pattern, const String& ip); static String DirName(const String& path); static String BaseName(const String& path); static void NullDeleter(void *); static double GetTime(void); static pid_t GetPid(void); static void Sleep(double timeout); static String NewUniqueID(void); static bool Glob(const String& pathSpec, const boost::function& callback, int type = GlobFile | GlobDirectory); static bool GlobRecursive(const String& path, const String& pattern, const boost::function& callback, int type = GlobFile | GlobDirectory); static void MkDir(const String& path, int mode); static void MkDirP(const String& path, int mode); static bool SetFileOwnership(const String& file, const String& user, const String& group); static void QueueAsyncCallback(const boost::function& callback, SchedulerPolicy policy = DefaultScheduler); static String NaturalJoin(const std::vector& tokens); static String Join(const Array::Ptr& tokens, char separator, bool escapeSeparator = true); static String FormatDuration(double duration); static String FormatDateTime(const char *format, double ts); static String FormatErrorNumber(int code); #ifndef _WIN32 static void SetNonBlocking(int fd, bool nb = true); static void SetCloExec(int fd, bool cloexec = true); #endif /* _WIN32 */ static void SetNonBlockingSocket(SOCKET s, bool nb = true); static String EscapeShellCmd(const String& s); static String EscapeShellArg(const String& s); #ifdef _WIN32 static String EscapeCreateProcessArg(const String& arg); #endif /* _WIN32 */ static String EscapeString(const String& s, const String& chars, const bool illegal); static String UnescapeString(const String& s); static void SetThreadName(const String& name, bool os = true); static String GetThreadName(void); static unsigned long SDBM(const String& str, size_t len = String::NPos); static int CompareVersion(const String& v1, const String& v2); static int Random(void); static String GetHostName(void); static String GetFQDN(void); static tm LocalTime(time_t ts); static bool PathExists(const String& path); static void RemoveDirRecursive(const String& path); static void CopyFile(const String& source, const String& target); static Value LoadJsonFile(const String& path); static void SaveJsonFile(const String& path, int mode, const Value& value); static String GetPlatformKernel(void); static String GetPlatformKernelVersion(void); static String GetPlatformName(void); static String GetPlatformVersion(void); static String GetPlatformArchitecture(void); static String ValidateUTF8(const String& input); static String CreateTempFile(const String& path, int mode, std::fstream& fp); #ifdef _WIN32 static String GetIcingaInstallPath(void); static String GetIcingaDataPath(void); #endif /* _WIN32 */ #ifdef I2_DEBUG static void SetTime(double); static void IncrementTime(double); #endif /* I2_DEBUG */ private: Utility(void); static void CollectPaths(const String& path, std::vector& paths); #ifdef _WIN32 static int MksTemp (char *tmpl); #endif /* _WIN32 */ #ifdef I2_DEBUG static double m_DebugTime; #endif /* I2_DEBUG */ static boost::thread_specific_ptr m_ThreadName; static boost::thread_specific_ptr m_RandSeed; }; } #endif /* UTILITY_H */ icinga2-2.8.1/lib/base/value-operators.cpp000066400000000000000000000516641322762156600204000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/value.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/datetime.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include using namespace icinga; Value::operator double(void) const { const double *value = boost::get(&m_Value); if (value) return *value; const bool *fvalue = boost::get(&m_Value); if (fvalue) return *fvalue; if (IsEmpty()) return 0; try { return boost::lexical_cast(m_Value); } catch (const std::exception&) { std::ostringstream msgbuf; msgbuf << "Can't convert '" << *this << "' to a floating point number."; BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); } } Value::operator String(void) const { Object *object; switch (GetType()) { case ValueEmpty: return String(); case ValueNumber: return Convert::ToString(boost::get(m_Value)); case ValueBoolean: if (boost::get(m_Value)) return "true"; else return "false"; case ValueString: return boost::get(m_Value); case ValueObject: object = boost::get(m_Value).get(); return object->ToString(); default: BOOST_THROW_EXCEPTION(std::runtime_error("Unknown value type.")); } } std::ostream& icinga::operator<<(std::ostream& stream, const Value& value) { if (value.IsBoolean()) stream << static_cast(value); else stream << static_cast(value); return stream; } std::istream& icinga::operator>>(std::istream& stream, Value& value) { String tstr; stream >> tstr; value = tstr; return stream; } bool Value::operator==(bool rhs) const { return *this == Value(rhs); } bool Value::operator!=(bool rhs) const { return !(*this == rhs); } bool Value::operator==(int rhs) const { return *this == Value(rhs); } bool Value::operator!=(int rhs) const { return !(*this == rhs); } bool Value::operator==(double rhs) const { return *this == Value(rhs); } bool Value::operator!=(double rhs) const { return !(*this == rhs); } bool Value::operator==(const char *rhs) const { return static_cast(*this) == rhs; } bool Value::operator!=(const char *rhs) const { return !(*this == rhs); } bool Value::operator==(const String& rhs) const { return static_cast(*this) == rhs; } bool Value::operator!=(const String& rhs) const { return !(*this == rhs); } bool Value::operator==(const Value& rhs) const { if (IsNumber() && rhs.IsNumber()) return Get() == rhs.Get(); else if ((IsBoolean() || IsNumber()) && (rhs.IsBoolean() || rhs.IsNumber()) && !(IsEmpty() && rhs.IsEmpty())) return static_cast(*this) == static_cast(rhs); if (IsString() && rhs.IsString()) return Get() == rhs.Get(); else if ((IsString() || IsEmpty()) && (rhs.IsString() || rhs.IsEmpty()) && !(IsEmpty() && rhs.IsEmpty())) return static_cast(*this) == static_cast(rhs); if (IsEmpty() != rhs.IsEmpty()) return false; if (IsEmpty()) return true; if (IsObject() != rhs.IsObject()) return false; if (IsObject()) { if (IsObjectType() && rhs.IsObjectType()) { DateTime::Ptr dt1 = *this; DateTime::Ptr dt2 = rhs; return dt1->GetValue() == dt2->GetValue(); } if (IsObjectType() && rhs.IsObjectType()) { Array::Ptr arr1 = *this; Array::Ptr arr2 = rhs; if (arr1 == arr2) return true; if (arr1->GetLength() != arr2->GetLength()) return false; for (Array::SizeType i = 0; i < arr1->GetLength(); i++) { if (arr1->Get(i) != arr2->Get(i)) return false; } return true; } return Get() == rhs.Get(); } return false; } bool Value::operator!=(const Value& rhs) const { return !(*this == rhs); } Value icinga::operator+(const Value& lhs, const char *rhs) { return lhs + Value(rhs); } Value icinga::operator+(const char *lhs, const Value& rhs) { return Value(lhs) + rhs; } Value icinga::operator+(const Value& lhs, const String& rhs) { return lhs + Value(rhs); } Value icinga::operator+(const String& lhs, const Value& rhs) { return Value(lhs) + rhs; } Value icinga::operator+(const Value& lhs, const Value& rhs) { if ((lhs.IsEmpty() || lhs.IsNumber()) && !lhs.IsString() && (rhs.IsEmpty() || rhs.IsNumber()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) + static_cast(rhs); if ((lhs.IsString() || lhs.IsEmpty() || lhs.IsNumber()) && (rhs.IsString() || rhs.IsEmpty() || rhs.IsNumber()) && (!(lhs.IsEmpty() && rhs.IsEmpty()) || lhs.IsString() || rhs.IsString())) return static_cast(lhs) + static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) + static_cast(rhs); else if (lhs.IsObjectType() && rhs.IsNumber()) return new DateTime(Convert::ToDateTimeValue(lhs) + rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { Array::Ptr result = new Array(); if (!lhs.IsEmpty()) static_cast(lhs)->CopyTo(result); if (!rhs.IsEmpty()) static_cast(rhs)->CopyTo(result); return result; } else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { Dictionary::Ptr result = new Dictionary(); if (!lhs.IsEmpty()) static_cast(lhs)->CopyTo(result); if (!rhs.IsEmpty()) static_cast(rhs)->CopyTo(result); return result; } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } } Value icinga::operator+(const Value& lhs, double rhs) { return lhs + Value(rhs); } Value icinga::operator+(double lhs, const Value& rhs) { return Value(lhs) + rhs; } Value icinga::operator+(const Value& lhs, int rhs) { return lhs + Value(rhs); } Value icinga::operator+(int lhs, const Value& rhs) { return Value(lhs) + rhs; } Value icinga::operator-(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && !lhs.IsString() && (rhs.IsNumber() || rhs.IsEmpty()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) - static_cast(rhs); else if (lhs.IsObjectType() && rhs.IsNumber()) return new DateTime(Convert::ToDateTimeValue(lhs) - rhs); else if (lhs.IsObjectType() && rhs.IsObjectType()) return Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return new DateTime(Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs)); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { if (lhs.IsEmpty()) return new Array(); Array::Ptr result = new Array(); Array::Ptr left = lhs; Array::Ptr right = rhs; ObjectLock olock(left); for (const Value& lv : left) { bool found = false; ObjectLock xlock(right); for (const Value& rv : right) { if (lv == rv) { found = true; break; } } if (found) continue; result->Add(lv); } return result; } else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator - cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator-(const Value& lhs, double rhs) { return lhs - Value(rhs); } Value icinga::operator-(double lhs, const Value& rhs) { return Value(lhs) - rhs; } Value icinga::operator-(const Value& lhs, int rhs) { return lhs - Value(rhs); } Value icinga::operator-(int lhs, const Value& rhs) { return Value(lhs) - rhs; } Value icinga::operator*(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) * static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator * cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator*(const Value& lhs, double rhs) { return lhs * Value(rhs); } Value icinga::operator*(double lhs, const Value& rhs) { return Value(lhs) * rhs; } Value icinga::operator*(const Value& lhs, int rhs) { return lhs * Value(rhs); } Value icinga::operator*(int lhs, const Value& rhs) { return Value(lhs) * rhs; } Value icinga::operator/(const Value& lhs, const Value& rhs) { if (rhs.IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is Empty.")); else if ((lhs.IsEmpty() || lhs.IsNumber()) && rhs.IsNumber()) { if (static_cast(rhs) == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator / is 0.")); return static_cast(lhs) / static_cast(rhs); } else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator / cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator/(const Value& lhs, double rhs) { return lhs / Value(rhs); } Value icinga::operator/(double lhs, const Value& rhs) { return Value(lhs) / rhs; } Value icinga::operator/(const Value& lhs, int rhs) { return lhs / Value(rhs); } Value icinga::operator/(int lhs, const Value& rhs) { return Value(lhs) / rhs; } Value icinga::operator%(const Value& lhs, const Value& rhs) { if (rhs.IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is Empty.")); else if ((rhs.IsNumber() || lhs.IsNumber()) && rhs.IsNumber()) { if (static_cast(rhs) == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Right-hand side argument for operator % is 0.")); return static_cast(lhs) % static_cast(rhs); } else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator % cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator%(const Value& lhs, double rhs) { return lhs % Value(rhs); } Value icinga::operator%(double lhs, const Value& rhs) { return Value(lhs) % rhs; } Value icinga::operator%(const Value& lhs, int rhs) { return lhs % Value(rhs); } Value icinga::operator%(int lhs, const Value& rhs) { return Value(lhs) % rhs; } Value icinga::operator^(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) ^ static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator^(const Value& lhs, double rhs) { return lhs ^ Value(rhs); } Value icinga::operator^(double lhs, const Value& rhs) { return Value(lhs) ^ rhs; } Value icinga::operator^(const Value& lhs, int rhs) { return lhs ^ Value(rhs); } Value icinga::operator^(int lhs, const Value& rhs) { return Value(lhs) ^ rhs; } Value icinga::operator&(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) & static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator & cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator&(const Value& lhs, double rhs) { return lhs & Value(rhs); } Value icinga::operator&(double lhs, const Value& rhs) { return Value(lhs) & rhs; } Value icinga::operator&(const Value& lhs, int rhs) { return lhs & Value(rhs); } Value icinga::operator&(int lhs, const Value& rhs) { return Value(lhs) & rhs; } Value icinga::operator|(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) | static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator | cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator|(const Value& lhs, double rhs) { return lhs | Value(rhs); } Value icinga::operator|(double lhs, const Value& rhs) { return Value(lhs) | rhs; } Value icinga::operator|(const Value& lhs, int rhs) { return lhs | Value(rhs); } Value icinga::operator|(int lhs, const Value& rhs) { return Value(lhs) | rhs; } Value icinga::operator<<(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) << static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator << cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator<<(const Value& lhs, double rhs) { return lhs << Value(rhs); } Value icinga::operator<<(double lhs, const Value& rhs) { return Value(lhs) << rhs; } Value icinga::operator<<(const Value& lhs, int rhs) { return lhs << Value(rhs); } Value icinga::operator<<(int lhs, const Value& rhs) { return Value(lhs) << rhs; } Value icinga::operator>>(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) >> static_cast(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >> cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } Value icinga::operator>>(const Value& lhs, double rhs) { return lhs >> Value(rhs); } Value icinga::operator>>(double lhs, const Value& rhs) { return Value(lhs) >> rhs; } Value icinga::operator>>(const Value& lhs, int rhs) { return lhs >> Value(rhs); } Value icinga::operator>>(int lhs, const Value& rhs) { return Value(lhs) >> rhs; } bool icinga::operator<(const Value& lhs, const Value& rhs) { if (lhs.IsString() && rhs.IsString()) return static_cast(lhs) < static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) < static_cast(rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return Convert::ToDateTimeValue(lhs) < Convert::ToDateTimeValue(rhs); else if (lhs.IsObjectType() && rhs.IsObjectType()) { Array::Ptr larr = lhs; Array::Ptr rarr = rhs; ObjectLock llock(larr); ObjectLock rlock(rarr); Array::SizeType llen = larr->GetLength(); Array::SizeType rlen = rarr->GetLength(); for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) { Value lval = (i >= llen) ? Empty : larr->Get(i); Value rval = (i >= rlen) ? Empty : rarr->Get(i); if (lval < rval) return true; else if (lval > rval) return false; } return false; } else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } bool icinga::operator<(const Value& lhs, double rhs) { return lhs < Value(rhs); } bool icinga::operator<(double lhs, const Value& rhs) { return Value(lhs) < rhs; } bool icinga::operator<(const Value& lhs, int rhs) { return lhs < Value(rhs); } bool icinga::operator<(int lhs, const Value& rhs) { return Value(lhs) < rhs; } bool icinga::operator>(const Value& lhs, const Value& rhs) { if (lhs.IsString() && rhs.IsString()) return static_cast(lhs) > static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) > static_cast(rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return Convert::ToDateTimeValue(lhs) > Convert::ToDateTimeValue(rhs); else if (lhs.IsObjectType() && rhs.IsObjectType()) { Array::Ptr larr = lhs; Array::Ptr rarr = rhs; ObjectLock llock(larr); ObjectLock rlock(rarr); Array::SizeType llen = larr->GetLength(); Array::SizeType rlen = rarr->GetLength(); for (Array::SizeType i = 0; i < std::max(llen, rlen); i++) { Value lval = (i >= llen) ? Empty : larr->Get(i); Value rval = (i >= rlen) ? Empty : rarr->Get(i); if (lval > rval) return true; else if (lval < rval) return false; } return false; } else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } bool icinga::operator>(const Value& lhs, double rhs) { return lhs > Value(rhs); } bool icinga::operator>(double lhs, const Value& rhs) { return Value(lhs) > rhs; } bool icinga::operator>(const Value& lhs, int rhs) { return lhs > Value(rhs); } bool icinga::operator>(int lhs, const Value& rhs) { return Value(lhs) > rhs; } bool icinga::operator<=(const Value& lhs, const Value& rhs) { if (lhs.IsString() && rhs.IsString()) return static_cast(lhs) <= static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) <= static_cast(rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return Convert::ToDateTimeValue(lhs) <= Convert::ToDateTimeValue(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } bool icinga::operator<=(const Value& lhs, double rhs) { return lhs <= Value(rhs); } bool icinga::operator<=(double lhs, const Value& rhs) { return Value(lhs) <= rhs; } bool icinga::operator<=(const Value& lhs, int rhs) { return lhs <= Value(rhs); } bool icinga::operator<=(int lhs, const Value& rhs) { return Value(lhs) <= rhs; } bool icinga::operator>=(const Value& lhs, const Value& rhs) { if (lhs.IsString() && rhs.IsString()) return static_cast(lhs) >= static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) >= static_cast(rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return Convert::ToDateTimeValue(lhs) >= Convert::ToDateTimeValue(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } bool icinga::operator>=(const Value& lhs, double rhs) { return lhs >= Value(rhs); } bool icinga::operator>=(double lhs, const Value& rhs) { return Value(lhs) >= rhs; } bool icinga::operator>=(const Value& lhs, int rhs) { return lhs >= Value(rhs); } bool icinga::operator>=(int lhs, const Value& rhs) { return Value(lhs) >= rhs; } icinga2-2.8.1/lib/base/value.cpp000066400000000000000000000064441322762156600163600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/value.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/type.hpp" using namespace icinga; Value icinga::Empty; bool Value::ToBool(void) const { switch (GetType()) { case ValueNumber: return static_cast(boost::get(m_Value)); case ValueBoolean: return boost::get(m_Value); case ValueString: return !boost::get(m_Value).IsEmpty(); case ValueObject: if (IsObjectType()) { Dictionary::Ptr dictionary = *this; return dictionary->GetLength() > 0; } else if (IsObjectType()) { Array::Ptr array = *this; return array->GetLength() > 0; } else { return true; } case ValueEmpty: return false; default: BOOST_THROW_EXCEPTION(std::runtime_error("Invalid variant type.")); } } String Value::GetTypeName(void) const { Type::Ptr t; switch (GetType()) { case ValueEmpty: return "Empty"; case ValueNumber: return "Number"; case ValueBoolean: return "Boolean"; case ValueString: return "String"; case ValueObject: t = boost::get(m_Value)->GetReflectionType(); if (!t) { if (IsObjectType()) return "Array"; else if (IsObjectType()) return "Dictionary"; else return "Object"; } else return t->GetName(); default: return "Invalid"; } } Type::Ptr Value::GetReflectionType(void) const { switch (GetType()) { case ValueEmpty: return Object::TypeInstance; case ValueNumber: return Type::GetByName("Number"); case ValueBoolean: return Type::GetByName("Boolean"); case ValueString: return Type::GetByName("String"); case ValueObject: return boost::get(m_Value)->GetReflectionType(); default: return Type::Ptr(); } } Value Value::Clone(void) const { if (IsObject()) return static_cast(*this)->Clone(); else return *this; } icinga2-2.8.1/lib/base/value.hpp000066400000000000000000000253261322762156600163650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VALUE_H #define VALUE_H #include "base/object.hpp" #include "base/string.hpp" #include #include namespace icinga { typedef double Timestamp; /** * The type of a Value. * * @ingroup base */ enum ValueType { ValueEmpty = 0, ValueNumber = 1, ValueBoolean = 2, ValueString = 3, ValueObject = 4 }; /** * A type that can hold an arbitrary value. * * @ingroup base */ class I2_BASE_API Value { public: inline Value(void) { } inline Value(int value) : m_Value(double(value)) { } inline Value(unsigned int value) : m_Value(double(value)) { } inline Value(long value) : m_Value(double(value)) { } inline Value(unsigned long value) : m_Value(double(value)) { } inline Value(long long value) : m_Value(double(value)) { } inline Value(unsigned long long value) : m_Value(double(value)) { } inline Value(double value) : m_Value(value) { } inline Value(bool value) : m_Value(value) { } inline Value(const String& value) : m_Value(value) { } inline Value(String&& value) : m_Value(value) { } inline Value(const char *value) : m_Value(String(value)) { } Value(const Value& other) : m_Value(other.m_Value) { } Value(Value&& other) { #if BOOST_VERSION >= 105400 m_Value = std::move(other.m_Value); #else /* BOOST_VERSION */ m_Value.swap(other.m_Value); #endif /* BOOST_VERSION */ } inline Value(Object *value) { if (!value) return; m_Value = Object::Ptr(value); } template inline Value(const intrusive_ptr& value) { if (!value) return; m_Value = static_pointer_cast(value); } bool ToBool(void) const; operator double(void) const; operator String(void) const; Value& operator=(const Value& other) { m_Value = other.m_Value; return *this; } Value& operator=(Value&& other) { #if BOOST_VERSION >= 105400 m_Value = std::move(other.m_Value); #else /* BOOST_VERSION */ m_Value.swap(other.m_Value); #endif /* BOOST_VERSION */ return *this; } bool operator==(bool rhs) const; bool operator!=(bool rhs) const; bool operator==(int rhs) const; bool operator!=(int rhs) const; bool operator==(double rhs) const; bool operator!=(double rhs) const; bool operator==(const char *rhs) const; bool operator!=(const char *rhs) const; bool operator==(const String& rhs) const; bool operator!=(const String& rhs) const; bool operator==(const Value& rhs) const; bool operator!=(const Value& rhs) const; template operator intrusive_ptr(void) const { if (IsEmpty() && !IsString()) return intrusive_ptr(); if (!IsObject()) BOOST_THROW_EXCEPTION(std::runtime_error("Cannot convert value of type '" + GetTypeName() + "' to an object.")); const Object::Ptr& object = boost::get(m_Value); ASSERT(object); intrusive_ptr tobject = dynamic_pointer_cast(object); if (!tobject) BOOST_THROW_EXCEPTION(std::bad_cast()); return tobject; } /** * Checks whether the variant is empty. * * @returns true if the variant is empty, false otherwise. */ inline bool IsEmpty(void) const { return (GetType() == ValueEmpty || (IsString() && boost::get(m_Value).IsEmpty())); } /** * Checks whether the variant is scalar (i.e. not an object and not empty). * * @returns true if the variant is scalar, false otherwise. */ inline bool IsScalar(void) const { return !IsEmpty() && !IsObject(); } /** * Checks whether the variant is a number. * * @returns true if the variant is a number. */ inline bool IsNumber(void) const { return (GetType() == ValueNumber); } /** * Checks whether the variant is a boolean. * * @returns true if the variant is a boolean. */ inline bool IsBoolean(void) const { return (GetType() == ValueBoolean); } /** * Checks whether the variant is a string. * * @returns true if the variant is a string. */ inline bool IsString(void) const { return (GetType() == ValueString); } /** * Checks whether the variant is a non-null object. * * @returns true if the variant is a non-null object, false otherwise. */ inline bool IsObject(void) const { return (GetType() == ValueObject); } template bool IsObjectType(void) const { if (!IsObject()) return false; return (dynamic_cast(boost::get(m_Value).get()) != NULL); } /** * Returns the type of the value. * * @returns The type. */ inline ValueType GetType(void) const { return static_cast(m_Value.which()); } inline void Swap(Value& other) { m_Value.swap(other.m_Value); } String GetTypeName(void) const; Type::Ptr GetReflectionType(void) const; Value Clone(void) const; template const T& Get(void) const { return boost::get(m_Value); } private: boost::variant m_Value; }; extern I2_BASE_API Value Empty; I2_BASE_API Value operator+(const Value& lhs, const char *rhs); I2_BASE_API Value operator+(const char *lhs, const Value& rhs); I2_BASE_API Value operator+(const Value& lhs, const String& rhs); I2_BASE_API Value operator+(const String& lhs, const Value& rhs); I2_BASE_API Value operator+(const Value& lhs, const Value& rhs); I2_BASE_API Value operator+(const Value& lhs, double rhs); I2_BASE_API Value operator+(double lhs, const Value& rhs); I2_BASE_API Value operator+(const Value& lhs, int rhs); I2_BASE_API Value operator+(int lhs, const Value& rhs); I2_BASE_API Value operator-(const Value& lhs, const Value& rhs); I2_BASE_API Value operator-(const Value& lhs, double rhs); I2_BASE_API Value operator-(double lhs, const Value& rhs); I2_BASE_API Value operator-(const Value& lhs, int rhs); I2_BASE_API Value operator-(int lhs, const Value& rhs); I2_BASE_API Value operator*(const Value& lhs, const Value& rhs); I2_BASE_API Value operator*(const Value& lhs, double rhs); I2_BASE_API Value operator*(double lhs, const Value& rhs); I2_BASE_API Value operator*(const Value& lhs, int rhs); I2_BASE_API Value operator*(int lhs, const Value& rhs); I2_BASE_API Value operator/(const Value& lhs, const Value& rhs); I2_BASE_API Value operator/(const Value& lhs, double rhs); I2_BASE_API Value operator/(double lhs, const Value& rhs); I2_BASE_API Value operator/(const Value& lhs, int rhs); I2_BASE_API Value operator/(int lhs, const Value& rhs); I2_BASE_API Value operator%(const Value& lhs, const Value& rhs); I2_BASE_API Value operator%(const Value& lhs, double rhs); I2_BASE_API Value operator%(double lhs, const Value& rhs); I2_BASE_API Value operator%(const Value& lhs, int rhs); I2_BASE_API Value operator%(int lhs, const Value& rhs); I2_BASE_API Value operator^(const Value& lhs, const Value& rhs); I2_BASE_API Value operator^(const Value& lhs, double rhs); I2_BASE_API Value operator^(double lhs, const Value& rhs); I2_BASE_API Value operator^(const Value& lhs, int rhs); I2_BASE_API Value operator^(int lhs, const Value& rhs); I2_BASE_API Value operator&(const Value& lhs, const Value& rhs); I2_BASE_API Value operator&(const Value& lhs, double rhs); I2_BASE_API Value operator&(double lhs, const Value& rhs); I2_BASE_API Value operator&(const Value& lhs, int rhs); I2_BASE_API Value operator&(int lhs, const Value& rhs); I2_BASE_API Value operator|(const Value& lhs, const Value& rhs); I2_BASE_API Value operator|(const Value& lhs, double rhs); I2_BASE_API Value operator|(double lhs, const Value& rhs); I2_BASE_API Value operator|(const Value& lhs, int rhs); I2_BASE_API Value operator|(int lhs, const Value& rhs); I2_BASE_API Value operator<<(const Value& lhs, const Value& rhs); I2_BASE_API Value operator<<(const Value& lhs, double rhs); I2_BASE_API Value operator<<(double lhs, const Value& rhs); I2_BASE_API Value operator<<(const Value& lhs, int rhs); I2_BASE_API Value operator<<(int lhs, const Value& rhs); I2_BASE_API Value operator>>(const Value& lhs, const Value& rhs); I2_BASE_API Value operator>>(const Value& lhs, double rhs); I2_BASE_API Value operator>>(double lhs, const Value& rhs); I2_BASE_API Value operator>>(const Value& lhs, int rhs); I2_BASE_API Value operator>>(int lhs, const Value& rhs); I2_BASE_API bool operator<(const Value& lhs, const Value& rhs); I2_BASE_API bool operator<(const Value& lhs, double rhs); I2_BASE_API bool operator<(double lhs, const Value& rhs); I2_BASE_API bool operator<(const Value& lhs, int rhs); I2_BASE_API bool operator<(int lhs, const Value& rhs); I2_BASE_API bool operator>(const Value& lhs, const Value& rhs); I2_BASE_API bool operator>(const Value& lhs, double rhs); I2_BASE_API bool operator>(double lhs, const Value& rhs); I2_BASE_API bool operator>(const Value& lhs, int rhs); I2_BASE_API bool operator>(int lhs, const Value& rhs); I2_BASE_API bool operator<=(const Value& lhs, const Value& rhs); I2_BASE_API bool operator<=(const Value& lhs, double rhs); I2_BASE_API bool operator<=(double lhs, const Value& rhs); I2_BASE_API bool operator<=(const Value& lhs, int rhs); I2_BASE_API bool operator<=(int lhs, const Value& rhs); I2_BASE_API bool operator>=(const Value& lhs, const Value& rhs); I2_BASE_API bool operator>=(const Value& lhs, double rhs); I2_BASE_API bool operator>=(double lhs, const Value& rhs); I2_BASE_API bool operator>=(const Value& lhs, int rhs); I2_BASE_API bool operator>=(int lhs, const Value& rhs); I2_BASE_API std::ostream& operator<<(std::ostream& stream, const Value& value); I2_BASE_API std::istream& operator>>(std::istream& stream, Value& value); } #endif /* VALUE_H */ icinga2-2.8.1/lib/base/visibility.hpp000066400000000000000000000036031322762156600174320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VISIBILITY_H #define VISIBILITY_H #ifndef _WIN32 # define I2_EXPORT __attribute__ ((visibility("default"))) # define I2_IMPORT __attribute__ ((visibility("default"))) #else /* _WIN32 */ # define I2_EXPORT __declspec(dllexport) # define I2_IMPORT __declspec(dllimport) # define I2_HIDDEN #endif /* _WIN32 */ #define TOKENPASTE(x, y) x ## y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) #define UNIQUE_NAME(prefix) TOKENPASTE2(prefix, __COUNTER__) #endif /* VISIBILITY_H */ icinga2-2.8.1/lib/base/win32.hpp000066400000000000000000000037371322762156600162150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef WIN32_H #define WIN32_H #define WIN32_LEAN_AND_MEAN #ifndef _WIN32_WINNT #define _WIN32_WINNT _WIN32_WINNT_VISTA #endif /* _WIN32_WINNT */ #define NOMINMAX #include #include #include #include #include #include #ifdef __MINGW32__ # ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 # endif /* IPV6_V6ONLY */ #endif /* __MINGW32__ */ typedef int socklen_t; #define MAXPATHLEN MAX_PATH #ifdef _MSC_VER typedef DWORD pid_t; #define strcasecmp stricmp #endif /* _MSC_VER */ #endif /* WIN32_H */ icinga2-2.8.1/lib/base/workqueue.cpp000066400000000000000000000177171322762156600173000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/workqueue.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/application.hpp" #include "base/exception.hpp" #include #include using namespace icinga; int WorkQueue::m_NextID = 1; boost::thread_specific_ptr l_ThreadWorkQueue; WorkQueue::WorkQueue(size_t maxItems, int threadCount) : m_ID(m_NextID++), m_ThreadCount(threadCount), m_Spawned(false), m_MaxItems(maxItems), m_Stopped(false), m_Processing(0), m_NextTaskID(0), m_TaskStats(15 * 60), m_PendingTasks(0), m_PendingTasksTimestamp(0) { /* Initialize logger. */ m_StatusTimerTimeout = Utility::GetTime(); m_StatusTimer = new Timer(); m_StatusTimer->SetInterval(10); m_StatusTimer->OnTimerExpired.connect(boost::bind(&WorkQueue::StatusTimerHandler, this)); m_StatusTimer->Start(); } WorkQueue::~WorkQueue(void) { m_StatusTimer->Stop(true); Join(true); } void WorkQueue::SetName(const String& name) { m_Name = name; } String WorkQueue::GetName(void) const { return m_Name; } /** * Enqueues a task. Tasks are guaranteed to be executed in the order * they were enqueued in except if there is more than one worker thread or when * allowInterleaved is true in which case the new task might be run * immediately if it's being enqueued from within the WorkQueue thread. */ void WorkQueue::Enqueue(boost::function&& function, WorkQueuePriority priority, bool allowInterleaved) { bool wq_thread = IsWorkerThread(); if (wq_thread && allowInterleaved) { function(); return; } boost::mutex::scoped_lock lock(m_Mutex); if (!m_Spawned) { Log(LogNotice, "WorkQueue") << "Spawning WorkQueue threads for '" << m_Name << "'"; for (int i = 0; i < m_ThreadCount; i++) { m_Threads.create_thread(boost::bind(&WorkQueue::WorkerThreadProc, this)); } m_Spawned = true; } if (!wq_thread) { while (m_Tasks.size() >= m_MaxItems && m_MaxItems != 0) m_CVFull.wait(lock); } m_Tasks.emplace(std::move(function), priority, ++m_NextTaskID); m_CVEmpty.notify_one(); } /** * Waits until all currently enqueued tasks have completed. This only works reliably * when no other thread is enqueuing new tasks when this method is called. * * @param stop Whether to stop the worker threads */ void WorkQueue::Join(bool stop) { boost::mutex::scoped_lock lock(m_Mutex); while (m_Processing || !m_Tasks.empty()) m_CVStarved.wait(lock); if (stop) { m_Stopped = true; m_CVEmpty.notify_all(); lock.unlock(); m_Threads.join_all(); m_Spawned = false; Log(LogNotice, "WorkQueue") << "Stopped WorkQueue threads for '" << m_Name << "'"; } } /** * Checks whether the calling thread is one of the worker threads * for this work queue. * * @returns true if called from one of the worker threads, false otherwise */ bool WorkQueue::IsWorkerThread(void) const { WorkQueue **pwq = l_ThreadWorkQueue.get(); if (!pwq) return false; return *pwq == this; } void WorkQueue::SetExceptionCallback(const ExceptionCallback& callback) { m_ExceptionCallback = callback; } /** * Checks whether any exceptions have occurred while executing tasks for this * work queue. When a custom exception callback is set this method will always * return false. */ bool WorkQueue::HasExceptions(void) const { boost::mutex::scoped_lock lock(m_Mutex); return !m_Exceptions.empty(); } /** * Returns all exceptions which have occurred for tasks in this work queue. When a * custom exception callback is set this method will always return an empty list. */ std::vector WorkQueue::GetExceptions(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_Exceptions; } void WorkQueue::ReportExceptions(const String& facility) const { std::vector exceptions = GetExceptions(); for (const auto& eptr : exceptions) { Log(LogCritical, facility) << DiagnosticInformation(eptr); } Log(LogCritical, facility) << exceptions.size() << " error" << (exceptions.size() != 1 ? "s" : ""); } size_t WorkQueue::GetLength(void) const { boost::mutex::scoped_lock lock(m_Mutex); return m_Tasks.size(); } void WorkQueue::StatusTimerHandler(void) { boost::mutex::scoped_lock lock(m_Mutex); ASSERT(!m_Name.IsEmpty()); int pending = m_Tasks.size(); double now = Utility::GetTime(); double gradient = (pending - m_PendingTasks) / (now - m_PendingTasksTimestamp); double timeToZero = pending / gradient; String timeInfo; if (pending > GetTaskCount(5)) { timeInfo = " empty in "; if (timeToZero < 0) timeInfo += "infinite time, your task handler isn't able to keep up"; else timeInfo += Utility::FormatDuration(timeToZero); } m_PendingTasks = pending; m_PendingTasksTimestamp = now; /* Log if there are pending items, or 5 minute timeout is reached. */ if (pending > 0 || m_StatusTimerTimeout < now) { Log(LogInformation, "WorkQueue") << "#" << m_ID << " (" << m_Name << ") " << "items: " << pending << ", " << "rate: " << std::setw(2) << GetTaskCount(60) / 60.0 << "/s " << "(" << GetTaskCount(60) << "/min " << GetTaskCount(60 * 5) << "/5min " << GetTaskCount(60 * 15) << "/15min);" << timeInfo; } /* Reschedule next log entry in 5 minutes. */ if (m_StatusTimerTimeout < now) { m_StatusTimerTimeout = now + 60 * 5; } } void WorkQueue::WorkerThreadProc(void) { std::ostringstream idbuf; idbuf << "WQ #" << m_ID; Utility::SetThreadName(idbuf.str()); l_ThreadWorkQueue.reset(new WorkQueue *(this)); boost::mutex::scoped_lock lock(m_Mutex); for (;;) { while (m_Tasks.empty() && !m_Stopped) m_CVEmpty.wait(lock); if (m_Stopped) break; if (m_Tasks.size() >= m_MaxItems && m_MaxItems != 0) m_CVFull.notify_all(); Task task = m_Tasks.top(); m_Tasks.pop(); m_Processing++; lock.unlock(); try { task.Function(); } catch (const std::exception&) { lock.lock(); if (!m_ExceptionCallback) m_Exceptions.push_back(boost::current_exception()); lock.unlock(); if (m_ExceptionCallback) m_ExceptionCallback(boost::current_exception()); } /* clear the task so whatever other resources it holds are released _before_ we re-acquire the mutex */ task = Task(); IncreaseTaskCount(); lock.lock(); m_Processing--; if (m_Tasks.empty()) m_CVStarved.notify_all(); } } void WorkQueue::IncreaseTaskCount(void) { double now = Utility::GetTime(); boost::mutex::scoped_lock lock(m_StatsMutex); m_TaskStats.InsertValue(now, 1); } int WorkQueue::GetTaskCount(RingBuffer::SizeType span) const { boost::mutex::scoped_lock lock(m_StatsMutex); return m_TaskStats.GetValues(span); } icinga2-2.8.1/lib/base/workqueue.hpp000066400000000000000000000076411322762156600173000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef WORKQUEUE_H #define WORKQUEUE_H #include "base/i2-base.hpp" #include "base/timer.hpp" #include "base/ringbuffer.hpp" #include #include #include #include #include #include #include namespace icinga { enum WorkQueuePriority { PriorityLow, PriorityNormal, PriorityHigh }; struct Task { Task(void) : Priority(PriorityNormal), ID(-1) { } Task(boost::function&& function, WorkQueuePriority priority, int id) : Function(std::move(function)), Priority(priority), ID(id) { } boost::function Function; WorkQueuePriority Priority; int ID; }; inline bool operator<(const Task& a, const Task& b) { if (a.Priority < b.Priority) return true; if (a.Priority == b.Priority) { if (a.ID > b.ID) return true; else return false; } return false; } /** * A workqueue. * * @ingroup base */ class I2_BASE_API WorkQueue { public: typedef boost::function ExceptionCallback; WorkQueue(size_t maxItems = 0, int threadCount = 1); ~WorkQueue(void); void SetName(const String& name); String GetName(void) const; void Enqueue(boost::function&& function, WorkQueuePriority priority = PriorityNormal, bool allowInterleaved = false); void Join(bool stop = false); bool IsWorkerThread(void) const; size_t GetLength(void) const; int GetTaskCount(RingBuffer::SizeType span) const; void SetExceptionCallback(const ExceptionCallback& callback); bool HasExceptions(void) const; std::vector GetExceptions(void) const; void ReportExceptions(const String& facility) const; protected: void IncreaseTaskCount(void); private: int m_ID; String m_Name; static int m_NextID; int m_ThreadCount; bool m_Spawned; mutable boost::mutex m_Mutex; boost::condition_variable m_CVEmpty; boost::condition_variable m_CVFull; boost::condition_variable m_CVStarved; boost::thread_group m_Threads; size_t m_MaxItems; bool m_Stopped; int m_Processing; std::priority_queue > m_Tasks; int m_NextTaskID; ExceptionCallback m_ExceptionCallback; std::vector m_Exceptions; Timer::Ptr m_StatusTimer; double m_StatusTimerTimeout; mutable boost::mutex m_StatsMutex; RingBuffer m_TaskStats; int m_PendingTasks; double m_PendingTasksTimestamp; void WorkerThreadProc(void); void StatusTimerHandler(void); }; } #endif /* WORKQUEUE_H */ icinga2-2.8.1/lib/checker/000077500000000000000000000000001322762156600152225ustar00rootroot00000000000000icinga2-2.8.1/lib/checker/CMakeLists.txt000066400000000000000000000042221322762156600177620ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(checkercomponent.ti checkercomponent.tcpp checkercomponent.thpp) set(checker_SOURCES checkercomponent.cpp checkercomponent.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(checker checker checker_SOURCES) endif() add_library(checker SHARED ${checker_SOURCES}) target_link_libraries(checker ${Boost_LIBRARIES} base config icinga remote) set_target_properties ( checker PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_CHECKER_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/checker.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) if(NOT WIN32) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")") install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/checker.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/checker.conf\")") else() install_if_not_exists(${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/checker.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() install( TARGETS checker RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/checker/checkercomponent.cpp000066400000000000000000000236401322762156600212620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "checker/checkercomponent.hpp" #include "checker/checkercomponent.tcpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "remote/apilistener.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/statsfunction.hpp" using namespace icinga; REGISTER_TYPE(CheckerComponent); REGISTER_STATSFUNCTION(CheckerComponent, &CheckerComponent::StatsFunc); void CheckerComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const CheckerComponent::Ptr& checker : ConfigType::GetObjectsByType()) { unsigned long idle = checker->GetIdleCheckables(); unsigned long pending = checker->GetPendingCheckables(); Dictionary::Ptr stats = new Dictionary(); stats->Set("idle", idle); stats->Set("pending", pending); nodes->Set(checker->GetName(), stats); String perfdata_prefix = "checkercomponent_" + checker->GetName() + "_"; perfdata->Add(new PerfdataValue(perfdata_prefix + "idle", Convert::ToDouble(idle))); perfdata->Add(new PerfdataValue(perfdata_prefix + "pending", Convert::ToDouble(pending))); } status->Set("checkercomponent", nodes); } CheckerComponent::CheckerComponent(void) : m_Stopped(false) { } void CheckerComponent::OnConfigLoaded(void) { ConfigObject::OnActiveChanged.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); ConfigObject::OnPausedChanged.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); Checkable::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1)); } void CheckerComponent::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "CheckerComponent") << "'" << GetName() << "' started."; m_Thread = boost::thread(boost::bind(&CheckerComponent::CheckThreadProc, this)); m_ResultTimer = new Timer(); m_ResultTimer->SetInterval(5); m_ResultTimer->OnTimerExpired.connect(boost::bind(&CheckerComponent::ResultTimerHandler, this)); m_ResultTimer->Start(); } void CheckerComponent::Stop(bool runtimeRemoved) { Log(LogInformation, "CheckerComponent") << "'" << GetName() << "' stopped."; { boost::mutex::scoped_lock lock(m_Mutex); m_Stopped = true; m_CV.notify_all(); } m_ResultTimer->Stop(); m_Thread.join(); ObjectImpl::Stop(runtimeRemoved); } void CheckerComponent::CheckThreadProc(void) { Utility::SetThreadName("Check Scheduler"); boost::mutex::scoped_lock lock(m_Mutex); for (;;) { typedef boost::multi_index::nth_index::type CheckTimeView; CheckTimeView& idx = boost::get<1>(m_IdleCheckables); while (idx.begin() == idx.end() && !m_Stopped) m_CV.wait(lock); if (m_Stopped) break; auto it = idx.begin(); CheckableScheduleInfo csi = *it; double wait = csi.NextCheck - Utility::GetTime(); if (Checkable::GetPendingChecks() >= GetConcurrentChecks()) wait = 0.5; if (wait > 0) { /* Wait for the next check. */ m_CV.timed_wait(lock, boost::posix_time::milliseconds(wait * 1000)); continue; } Checkable::Ptr checkable = csi.Object; m_IdleCheckables.erase(checkable); bool forced = checkable->GetForceNextCheck(); bool check = true; if (!forced) { if (!checkable->IsReachable(DependencyCheckExecution)) { Log(LogNotice, "CheckerComponent") << "Skipping check for object '" << checkable->GetName() << "': Dependency failed."; check = false; } Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); if (host && !service && (!checkable->GetEnableActiveChecks() || !IcingaApplication::GetInstance()->GetEnableHostChecks())) { Log(LogNotice, "CheckerComponent") << "Skipping check for host '" << host->GetName() << "': active host checks are disabled"; check = false; } if (host && service && (!checkable->GetEnableActiveChecks() || !IcingaApplication::GetInstance()->GetEnableServiceChecks())) { Log(LogNotice, "CheckerComponent") << "Skipping check for service '" << service->GetName() << "': active service checks are disabled"; check = false; } TimePeriod::Ptr tp = checkable->GetCheckPeriod(); if (tp && !tp->IsInside(Utility::GetTime())) { Log(LogNotice, "CheckerComponent") << "Skipping check for object '" << checkable->GetName() << "': not in check period '" << tp->GetName() << "'"; check = false; } } /* reschedule the checkable if checks are disabled */ if (!check) { m_IdleCheckables.insert(GetCheckableScheduleInfo(checkable)); lock.unlock(); checkable->UpdateNextCheck(); lock.lock(); continue; } m_PendingCheckables.insert(GetCheckableScheduleInfo(checkable)); lock.unlock(); if (forced) { ObjectLock olock(checkable); checkable->SetForceNextCheck(false); } Log(LogDebug, "CheckerComponent") << "Executing check for '" << checkable->GetName() << "'"; Checkable::IncreasePendingChecks(); Utility::QueueAsyncCallback(boost::bind(&CheckerComponent::ExecuteCheckHelper, CheckerComponent::Ptr(this), checkable)); lock.lock(); } } void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable) { try { checkable->ExecuteCheck(); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); String output = "Exception occured while checking '" + checkable->GetName() + "': " + DiagnosticInformation(ex); cr->SetOutput(output); double now = Utility::GetTime(); cr->SetScheduleStart(now); cr->SetScheduleEnd(now); cr->SetExecutionStart(now); cr->SetExecutionEnd(now); checkable->ProcessCheckResult(cr); Log(LogCritical, "checker", output); } Checkable::DecreasePendingChecks(); { boost::mutex::scoped_lock lock(m_Mutex); /* remove the object from the list of pending objects; if it's not in the * list this was a manual (i.e. forced) check and we must not re-add the * object to the list because it's already there. */ auto it = m_PendingCheckables.find(checkable); if (it != m_PendingCheckables.end()) { m_PendingCheckables.erase(it); if (checkable->IsActive()) m_IdleCheckables.insert(GetCheckableScheduleInfo(checkable)); m_CV.notify_all(); } } Log(LogDebug, "CheckerComponent") << "Check finished for object '" << checkable->GetName() << "'"; } void CheckerComponent::ResultTimerHandler(void) { std::ostringstream msgbuf; { boost::mutex::scoped_lock lock(m_Mutex); msgbuf << "Pending checkables: " << m_PendingCheckables.size() << "; Idle checkables: " << m_IdleCheckables.size() << "; Checks/s: " << (CIB::GetActiveHostChecksStatistics(60) + CIB::GetActiveServiceChecksStatistics(60)) / 60.0; } Log(LogNotice, "CheckerComponent", msgbuf.str()); } void CheckerComponent::ObjectHandler(const ConfigObject::Ptr& object) { Checkable::Ptr checkable = dynamic_pointer_cast(object); if (!checkable) return; Zone::Ptr zone = Zone::GetByName(checkable->GetZoneName()); bool same_zone = (!zone || Zone::GetLocalZone() == zone); { boost::mutex::scoped_lock lock(m_Mutex); if (object->IsActive() && !object->IsPaused() && same_zone) { if (m_PendingCheckables.find(checkable) != m_PendingCheckables.end()) return; m_IdleCheckables.insert(GetCheckableScheduleInfo(checkable)); } else { m_IdleCheckables.erase(checkable); m_PendingCheckables.erase(checkable); } m_CV.notify_all(); } } CheckableScheduleInfo CheckerComponent::GetCheckableScheduleInfo(const Checkable::Ptr& checkable) { CheckableScheduleInfo csi; csi.Object = checkable; csi.NextCheck = checkable->GetNextCheck(); return csi; } void CheckerComponent::NextCheckChangedHandler(const Checkable::Ptr& checkable) { boost::mutex::scoped_lock lock(m_Mutex); /* remove and re-insert the object from the set in order to force an index update */ typedef boost::multi_index::nth_index::type CheckableView; CheckableView& idx = boost::get<0>(m_IdleCheckables); auto it = idx.find(checkable); if (it == idx.end()) return; idx.erase(checkable); CheckableScheduleInfo csi = GetCheckableScheduleInfo(checkable); idx.insert(csi); m_CV.notify_all(); } unsigned long CheckerComponent::GetIdleCheckables(void) { boost::mutex::scoped_lock lock(m_Mutex); return m_IdleCheckables.size(); } unsigned long CheckerComponent::GetPendingCheckables(void) { boost::mutex::scoped_lock lock(m_Mutex); return m_PendingCheckables.size(); } icinga2-2.8.1/lib/checker/checkercomponent.hpp000066400000000000000000000072311322762156600212650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECKERCOMPONENT_H #define CHECKERCOMPONENT_H #include "checker/checkercomponent.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include #include #include #include #include #include namespace icinga { /** * @ingroup checker */ struct CheckableScheduleInfo { Checkable::Ptr Object; double NextCheck; }; /** * @ingroup checker */ struct CheckableNextCheckExtractor { typedef double result_type; /** * @threadsafety Always. */ double operator()(const CheckableScheduleInfo& csi) { return csi.NextCheck; } }; /** * @ingroup checker */ class CheckerComponent : public ObjectImpl { public: DECLARE_OBJECT(CheckerComponent); DECLARE_OBJECTNAME(CheckerComponent); typedef boost::multi_index_container< CheckableScheduleInfo, boost::multi_index::indexed_by< boost::multi_index::ordered_unique >, boost::multi_index::ordered_non_unique > > CheckableSet; CheckerComponent(void); virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); unsigned long GetIdleCheckables(void); unsigned long GetPendingCheckables(void); private: boost::mutex m_Mutex; boost::condition_variable m_CV; bool m_Stopped; boost::thread m_Thread; CheckableSet m_IdleCheckables; CheckableSet m_PendingCheckables; Timer::Ptr m_ResultTimer; void CheckThreadProc(void); void ResultTimerHandler(void); void ExecuteCheckHelper(const Checkable::Ptr& checkable); void AdjustCheckTimer(void); void ObjectHandler(const ConfigObject::Ptr& object); void NextCheckChangedHandler(const Checkable::Ptr& checkable); void RescheduleCheckTimer(void); static CheckableScheduleInfo GetCheckableScheduleInfo(const Checkable::Ptr& checkable); }; } #endif /* CHECKERCOMPONENT_H */ icinga2-2.8.1/lib/checker/checkercomponent.ti000066400000000000000000000031411322762156600211060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library checker; namespace icinga { class CheckerComponent : ConfigObject { [config] int concurrent_checks { default {{{ return 512; }}} }; }; } icinga2-2.8.1/lib/cli/000077500000000000000000000000001322762156600143655ustar00rootroot00000000000000icinga2-2.8.1/lib/cli/CMakeLists.txt000066400000000000000000000041001322762156600171200ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. set(cli_SOURCES apisetupcommand.cpp apisetuputility.cpp calistcommand.cpp casigncommand.cpp nodesetupcommand.cpp nodewizardcommand.cpp nodeutility.cpp clicommand.cpp consolecommand.cpp daemoncommand.cpp daemonutility.cpp featureenablecommand.cpp featuredisablecommand.cpp featurelistcommand.cpp featureutility.cpp objectlistcommand.cpp objectlistutility.cpp pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkisavecertcommand.cpp pkiticketcommand.cpp variablegetcommand.cpp variablelistcommand.cpp variableutility.cpp troubleshootcommand.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(cli cli cli_SOURCES) endif() add_library(cli SHARED ${cli_SOURCES}) target_link_libraries(cli ${Boost_LIBRARIES} base config remote) if(EDITLINE_FOUND) target_link_libraries(cli ${EDITLINE_LIBRARIES}) include_directories(${EDITLINE_INCLUDE_DIR}) endif() if(TERMCAP_FOUND) target_link_libraries(cli ${TERMCAP_LIBRARIES}) include_directories(${TERMCAP_INCLUDE_DIR}) endif() set_target_properties ( cli PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_CLI_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS cli RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/cli/apisetupcommand.cpp000066400000000000000000000046421322762156600202700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/apisetupcommand.hpp" #include "cli/apisetuputility.hpp" #include "cli/variableutility.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("api/setup", ApiSetupCommand); String ApiSetupCommand::GetDescription(void) const { return "Setup for Icinga 2 API."; } String ApiSetupCommand::GetShortDescription(void) const { return "setup for api"; } ImpersonationLevel ApiSetupCommand::GetImpersonationLevel(void) const { return ImpersonateRoot; } int ApiSetupCommand::GetMaxArguments(void) const { return -1; } /** * The entry point for the "api setup" CLI command. * * @returns An exit status. */ int ApiSetupCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { String cn = VariableUtility::GetVariable("NodeName"); if (cn.IsEmpty()) cn = Utility::GetFQDN(); if (!ApiSetupUtility::SetupMaster(cn, true)) return 1; return 0; } icinga2-2.8.1/lib/cli/apisetupcommand.hpp000066400000000000000000000040441322762156600202710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APISETUPCOMMAND_H #define APISETUPCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "api setup" command. * * @ingroup cli */ class ApiSetupCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(ApiSetupCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMaxArguments(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; }; } #endif /* APISETUPCOMMAND_H */ icinga2-2.8.1/lib/cli/apisetuputility.cpp000066400000000000000000000147761322762156600203660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/apisetuputility.hpp" #include "cli/nodeutility.hpp" #include "cli/featureutility.hpp" #include "remote/apilistener.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/scriptglobal.hpp" #include "base/exception.hpp" #include #include #include #include #include #include #include using namespace icinga; String ApiSetupUtility::GetConfdPath(void) { return Application::GetSysconfDir() + "/icinga2/conf.d"; } bool ApiSetupUtility::SetupMaster(const String& cn, bool prompt_restart) { if (!SetupMasterCertificates(cn)) return false; if (!SetupMasterApiUser()) return false; if (!SetupMasterEnableApi()) return false; if (prompt_restart) { std::cout << "Done.\n\n"; std::cout << "Now restart your Icinga 2 daemon to finish the installation!\n\n"; } return true; } bool ApiSetupUtility::SetupMasterCertificates(const String& cn) { Log(LogInformation, "cli", "Generating new CA."); if (PkiUtility::NewCa() > 0) Log(LogWarning, "cli", "Found CA, skipping and using the existing one."); String pki_path = ApiListener::GetCertsDir(); Utility::MkDirP(pki_path, 0700); String user = ScriptGlobal::Get("RunAsUser"); String group = ScriptGlobal::Get("RunAsGroup"); if (!Utility::SetFileOwnership(pki_path, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << pki_path << "'."; } String key = pki_path + "/" + cn + ".key"; String csr = pki_path + "/" + cn + ".csr"; if (Utility::PathExists(key)) { Log(LogInformation, "cli") << "Private key file '" << key << "' already exists, not generating new certificate."; return true; } Log(LogInformation, "cli") << "Generating new CSR in '" << csr << "'."; if (Utility::PathExists(key)) NodeUtility::CreateBackupFile(key, true); if (Utility::PathExists(csr)) NodeUtility::CreateBackupFile(csr); if (PkiUtility::NewCert(cn, key, csr, "") > 0) { Log(LogCritical, "cli", "Failed to create certificate signing request."); return false; } /* Sign the CSR with the CA key */ String cert = pki_path + "/" + cn + ".crt"; Log(LogInformation, "cli") << "Signing CSR with CA and writing certificate to '" << cert << "'."; if (Utility::PathExists(cert)) NodeUtility::CreateBackupFile(cert); if (PkiUtility::SignCsr(csr, cert) != 0) { Log(LogCritical, "cli", "Could not sign CSR."); return false; } /* Copy CA certificate to /etc/icinga2/pki */ String ca_path = ApiListener::GetCaDir(); String ca = ca_path + "/ca.crt"; String ca_key = ca_path + "/ca.key"; String target_ca = pki_path + "/ca.crt"; Log(LogInformation, "cli") << "Copying CA certificate to '" << target_ca << "'."; if (Utility::PathExists(target_ca)) NodeUtility::CreateBackupFile(target_ca); /* does not overwrite existing files! */ Utility::CopyFile(ca, target_ca); /* fix permissions: root -> icinga daemon user */ std::vector files; files.push_back(ca_path); files.push_back(ca); files.push_back(ca_key); files.push_back(target_ca); files.push_back(key); files.push_back(csr); files.push_back(cert); for (const String& file : files) { if (!Utility::SetFileOwnership(file, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << file << "'."; } } return true; } bool ApiSetupUtility::SetupMasterApiUser(void) { String api_username = "root"; // TODO make this available as cli parameter? String api_password = RandomString(8); String apiUsersPath = GetConfdPath() + "/api-users.conf"; if (Utility::PathExists(apiUsersPath)) { Log(LogInformation, "cli") << "API user config file '" << apiUsersPath << "' already exists, not creating config file."; return true; } Log(LogInformation, "cli") << "Adding new ApiUser '" << api_username << "' in '" << apiUsersPath << "'."; NodeUtility::CreateBackupFile(apiUsersPath); std::fstream fp; String tempFilename = Utility::CreateTempFile(apiUsersPath + ".XXXXXX", 0644, fp); fp << "/**\n" << " * The APIUser objects are used for authentication against the API.\n" << " */\n" << "object ApiUser \"" << api_username << "\" {\n" << " password = \"" << api_password << "\"\n" << " // client_cn = \"\"\n" << "\n" << " permissions = [ \"*\" ]\n" << "}\n"; fp.close(); #ifdef _WIN32 _unlink(apiUsersPath.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), apiUsersPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } return true; } bool ApiSetupUtility::SetupMasterEnableApi(void) { Log(LogInformation, "cli", "Enabling the 'api' feature."); std::vector features; features.push_back("api"); FeatureUtility::EnableFeatures(features); return true; } icinga2-2.8.1/lib/cli/apisetuputility.hpp000066400000000000000000000040431322762156600203550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APISETUPUTILITY_H #define APISETUPUTILITY_H #include "base/i2-base.hpp" #include "cli/i2-cli.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include "base/value.hpp" #include "base/string.hpp" #include namespace icinga { /** * @ingroup cli */ class I2_CLI_API ApiSetupUtility { public: static bool SetupMaster(const String& cn, bool prompt_restart = false); static bool SetupMasterCertificates(const String& cn); static bool SetupMasterApiUser(void); static bool SetupMasterEnableApi(void); static String GetConfdPath(void); private: ApiSetupUtility(void); }; } #endif /* APISETUPUTILITY_H */ icinga2-2.8.1/lib/cli/calistcommand.cpp000066400000000000000000000063151322762156600177140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/calistcommand.hpp" #include "remote/apilistener.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/json.hpp" #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("ca/list", CAListCommand); String CAListCommand::GetDescription(void) const { return "Lists all certificate signing requests."; } String CAListCommand::GetShortDescription(void) const { return "lists all certificate signing requests"; } void CAListCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("json", "encode output as JSON") ; } /** * The entry point for the "ca list" CLI command. * * @returns An exit status. */ int CAListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { Dictionary::Ptr requests = PkiUtility::GetCertificateRequests(); if (vm.count("json")) std::cout << JsonEncode(requests); else { ObjectLock olock(requests); std::cout << "Fingerprint | Timestamp | Signed | Subject\n"; std::cout << "-----------------------------------------------------------------|--------------------------|--------|--------\n"; for (auto& kv : requests) { Dictionary::Ptr request = kv.second; std::cout << kv.first << " | " /* << Utility::FormatDateTime("%Y/%m/%d %H:%M:%S", request->Get("timestamp")) */ << request->Get("timestamp") << " | " << (request->Contains("cert_response") ? "*" : " ") << " " << " | " << request->Get("subject") << "\n"; } } return 0; } icinga2-2.8.1/lib/cli/calistcommand.hpp000066400000000000000000000042021322762156600177120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CALISTCOMMAND_H #define CALISTCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "ca list" command. * * @ingroup cli */ class CAListCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(CAListCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; private: static void PrintRequest(const String& requestFile); }; } #endif /* CALISTCOMMAND_H */ icinga2-2.8.1/lib/cli/casigncommand.cpp000066400000000000000000000070151322762156600176770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/casigncommand.hpp" #include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" using namespace icinga; REGISTER_CLICOMMAND("ca/sign", CASignCommand); String CASignCommand::GetDescription(void) const { return "Signs an outstanding certificate request."; } String CASignCommand::GetShortDescription(void) const { return "signs an outstanding certificate request"; } int CASignCommand::GetMinArguments(void) const { return 1; } ImpersonationLevel CASignCommand::GetImpersonationLevel(void) const { return ImpersonateIcinga; } /** * The entry point for the "ca sign" CLI command. * * @returns An exit status. */ int CASignCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json"; if (!Utility::PathExists(requestFile)) { Log(LogCritical, "cli") << "No request exists for fingerprint '" << ap[0] << "'."; return 1; } Dictionary::Ptr request = Utility::LoadJsonFile(requestFile); if (!request) return 1; String certRequestText = request->Get("cert_request"); boost::shared_ptr certRequest = StringToCertificate(certRequestText); if (!certRequest) { Log(LogCritical, "cli", "Certificate request is invalid. Could not parse X.509 certificate for the 'cert_request' attribute."); return 1; } boost::shared_ptr certResponse = CreateCertIcingaCA(certRequest); BIO *out = BIO_new(BIO_s_mem()); X509_NAME_print_ex(out, X509_get_subject_name(certRequest.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB); char *data; long length; length = BIO_get_mem_data(out, &data); String subject = String(data, data + length); BIO_free(out); if (!certResponse) { Log(LogCritical, "cli") << "Could not sign certificate for '" << subject << "'."; return 1; } request->Set("cert_response", CertificateToString(certResponse)); Utility::SaveJsonFile(requestFile, 0600, request); Log(LogInformation, "cli") << "Signed certificate for '" << subject << "'."; return 0; } icinga2-2.8.1/lib/cli/casigncommand.hpp000066400000000000000000000040301322762156600176760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CASIGNCOMMAND_H #define CASIGNCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "ca sign" command. * * @ingroup cli */ class CASignCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(CASignCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMinArguments(void) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* CASIGNCOMMAND_H */ icinga2-2.8.1/lib/cli/clicommand.cpp000066400000000000000000000246051322762156600172060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/clicommand.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include "base/type.hpp" #include "base/serializer.hpp" #include #include #include #include #include using namespace icinga; namespace po = boost::program_options; std::vector icinga::GetBashCompletionSuggestions(const String& type, const String& word) { std::vector result; #ifndef _WIN32 String bashArg = "compgen -A " + Utility::EscapeShellArg(type) + " " + Utility::EscapeShellArg(word); String cmd = "bash -c " + Utility::EscapeShellArg(bashArg); FILE *fp = popen(cmd.CStr(), "r"); char line[4096]; while (fgets(line, sizeof(line), fp)) { String wline = line; boost::algorithm::trim_right_if(wline, boost::is_any_of("\r\n")); result.push_back(wline); } fclose(fp); /* Append a slash if there's only one suggestion and it's a directory */ if ((type == "file" || type == "directory") && result.size() == 1) { String path = result[0]; struct stat statbuf; if (lstat(path.CStr(), &statbuf) >= 0) { if (S_ISDIR(statbuf.st_mode)) { result.clear(), result.push_back(path + "/"); } } } #endif /* _WIN32 */ return result; } std::vector icinga::GetFieldCompletionSuggestions(const Type::Ptr& type, const String& word) { std::vector result; for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); if (field.Attributes & FANoUserView) continue; if (strcmp(field.TypeName, "int") != 0 && strcmp(field.TypeName, "double") != 0 && strcmp(field.TypeName, "bool") != 0 && strcmp(field.TypeName, "String") != 0) continue; String fname = field.Name; String suggestion = fname + "="; if (suggestion.Find(word) == 0) result.push_back(suggestion); } return result; } int CLICommand::GetMinArguments(void) const { return 0; } int CLICommand::GetMaxArguments(void) const { return GetMinArguments(); } bool CLICommand::IsHidden(void) const { return false; } bool CLICommand::IsDeprecated(void) const { return false; } boost::mutex& CLICommand::GetRegistryMutex(void) { static boost::mutex mtx; return mtx; } std::map, CLICommand::Ptr>& CLICommand::GetRegistry(void) { static std::map, CLICommand::Ptr> registry; return registry; } CLICommand::Ptr CLICommand::GetByName(const std::vector& name) { boost::mutex::scoped_lock lock(GetRegistryMutex()); auto it = GetRegistry().find(name); if (it == GetRegistry().end()) return CLICommand::Ptr(); return it->second; } void CLICommand::Register(const std::vector& name, const CLICommand::Ptr& function) { boost::mutex::scoped_lock lock(GetRegistryMutex()); GetRegistry()[name] = function; } void CLICommand::Unregister(const std::vector& name) { boost::mutex::scoped_lock lock(GetRegistryMutex()); GetRegistry().erase(name); } std::vector CLICommand::GetArgumentSuggestions(const String& argument, const String& word) const { return std::vector(); } std::vector CLICommand::GetPositionalSuggestions(const String& word) const { return std::vector(); } void CLICommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { } ImpersonationLevel CLICommand::GetImpersonationLevel(void) const { return ImpersonateIcinga; } bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& visibleDesc, po::options_description& hiddenDesc, po::positional_options_description& positionalDesc, po::variables_map& vm, String& cmdname, CLICommand::Ptr& command, bool autocomplete) { boost::mutex::scoped_lock lock(GetRegistryMutex()); typedef std::map, CLICommand::Ptr>::value_type CLIKeyValue; std::vector best_match; int arg_end = 0; bool tried_command = false; for (const CLIKeyValue& kv : GetRegistry()) { const std::vector& vname = kv.first; std::vector::size_type i; int k; for (i = 0, k = 1; i < vname.size() && k < argc; i++, k++) { if (strncmp(argv[k], "--", 2) == 0) { i--; continue; } tried_command = true; if (vname[i] != argv[k]) break; if (i >= best_match.size()) best_match.push_back(vname[i]); if (i == vname.size() - 1) { cmdname = boost::algorithm::join(vname, " "); command = kv.second; arg_end = k; goto found_command; } } } found_command: lock.unlock(); if (command) { po::options_description vdesc("Command options"); command->InitParameters(vdesc, hiddenDesc); visibleDesc.add(vdesc); } if (autocomplete || (tried_command && !command)) return true; po::options_description adesc; adesc.add(visibleDesc); adesc.add(hiddenDesc); if (command && command->IsDeprecated()) { std::cerr << ConsoleColorTag(Console_ForegroundRed | Console_Bold) << "Warning: CLI command '" << cmdname << "' is DEPRECATED! Please read the Changelog." << ConsoleColorTag(Console_Normal) << std::endl << std::endl; } po::store(po::command_line_parser(argc - arg_end, argv + arg_end).options(adesc).positional(positionalDesc).run(), vm); po::notify(vm); return true; } void CLICommand::ShowCommands(int argc, char **argv, po::options_description *visibleDesc, po::options_description *hiddenDesc, ArgumentCompletionCallback globalArgCompletionCallback, bool autocomplete, int autoindex) { boost::mutex::scoped_lock lock(GetRegistryMutex()); typedef std::map, CLICommand::Ptr>::value_type CLIKeyValue; std::vector best_match; int arg_begin = 0; CLICommand::Ptr command; for (const CLIKeyValue& kv : GetRegistry()) { const std::vector& vname = kv.first; arg_begin = 0; std::vector::size_type i; int k; for (i = 0, k = 1; i < vname.size() && k < argc; i++, k++) { if (strcmp(argv[k], "--no-stack-rlimit") == 0 || strcmp(argv[k], "--autocomplete") == 0 || strcmp(argv[k], "--scm") == 0) { i--; arg_begin++; continue; } if (autocomplete && static_cast(i) >= autoindex - 1) break; if (vname[i] != argv[k]) break; if (i >= best_match.size()) { best_match.push_back(vname[i]); } if (i == vname.size() - 1) { command = kv.second; break; } } } String aword; if (autocomplete) { if (autoindex < argc) aword = argv[autoindex]; if (autoindex - 1 > static_cast(best_match.size()) && !command) return; } else std::cout << "Supported commands: " << std::endl; for (const CLIKeyValue& kv : GetRegistry()) { const std::vector& vname = kv.first; if (vname.size() < best_match.size() || kv.second->IsHidden()) continue; bool match = true; for (std::vector::size_type i = 0; i < best_match.size(); i++) { if (vname[i] != best_match[i]) { match = false; break; } } if (!match) continue; if (autocomplete) { String cname; if (autoindex - 1 < static_cast(vname.size())) { cname = vname[autoindex - 1]; if (cname.Find(aword) == 0) std::cout << cname << "\n"; } } else { std::cout << " * " << boost::algorithm::join(vname, " ") << " (" << kv.second->GetShortDescription() << ")" << (kv.second->IsDeprecated() ? " (DEPRECATED)" : "") << std::endl; } } if (!autocomplete) std::cout << std::endl; if (command && autocomplete) { String aname, prefix, pword; const po::option_description *odesc; if (autoindex - 2 >= 0 && strcmp(argv[autoindex - 1], "=") == 0 && strstr(argv[autoindex - 2], "--") == argv[autoindex - 2]) { aname = argv[autoindex - 2] + 2; pword = aword; } else if (autoindex - 1 >= 0 && argv[autoindex - 1][0] == '-' && argv[autoindex - 1][1] == '-') { aname = argv[autoindex - 1] + 2; pword = aword; if (pword == "=") pword = ""; } else if (autoindex - 1 >= 0 && argv[autoindex - 1][0] == '-' && argv[autoindex - 1][1] != '-') { aname = argv[autoindex - 1]; pword = aword; if (pword == "=") pword = ""; } else if (aword.GetLength() > 1 && aword[0] == '-' && aword[1] != '-') { aname = aword.SubStr(0, 2); prefix = aname; pword = aword.SubStr(2); } else { goto complete_option; } odesc = visibleDesc->find_nothrow(aname, false); if (!odesc) return; if (odesc->semantic()->min_tokens() == 0) goto complete_option; for (const String& suggestion : globalArgCompletionCallback(odesc->long_name(), pword)) { std::cout << prefix << suggestion << "\n"; } for (const String& suggestion : command->GetArgumentSuggestions(odesc->long_name(), pword)) { std::cout << prefix << suggestion << "\n"; } return; complete_option: for (const boost::shared_ptr& odesc : visibleDesc->options()) { String cname = "--" + odesc->long_name(); if (cname.Find(aword) == 0) std::cout << cname << "\n"; } for (const String& suggestion : command->GetPositionalSuggestions(aword)) { std::cout << suggestion << "\n"; } } return; } icinga2-2.8.1/lib/cli/clicommand.hpp000066400000000000000000000103451322762156600172070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLICOMMAND_H #define CLICOMMAND_H #include "cli/i2-cli.hpp" #include "base/value.hpp" #include "base/utility.hpp" #include "base/type.hpp" #include #include #include #include namespace icinga { std::vector I2_CLI_API GetBashCompletionSuggestions(const String& type, const String& word); std::vector I2_CLI_API GetFieldCompletionSuggestions(const Type::Ptr& type, const String& word); enum ImpersonationLevel { ImpersonateNone, ImpersonateRoot, ImpersonateIcinga }; /** * A CLI command. * * @ingroup base */ class I2_CLI_API CLICommand : public Object { public: DECLARE_PTR_TYPEDEFS(CLICommand); typedef std::vector(*ArgumentCompletionCallback)(const String&, const String&); virtual String GetDescription(void) const = 0; virtual String GetShortDescription(void) const = 0; virtual int GetMinArguments(void) const; virtual int GetMaxArguments(void) const; virtual bool IsHidden(void) const; virtual bool IsDeprecated(void) const; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const; virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const = 0; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const; virtual std::vector GetPositionalSuggestions(const String& word) const; static CLICommand::Ptr GetByName(const std::vector& name); static void Register(const std::vector& name, const CLICommand::Ptr& command); static void Unregister(const std::vector& name); static bool ParseCommand(int argc, char **argv, boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc, boost::program_options::positional_options_description& positionalDesc, boost::program_options::variables_map& vm, String& cmdname, CLICommand::Ptr& command, bool autocomplete); static void ShowCommands(int argc, char **argv, boost::program_options::options_description *visibleDesc = NULL, boost::program_options::options_description *hiddenDesc = NULL, ArgumentCompletionCallback globalArgCompletionCallback = NULL, bool autocomplete = false, int autoindex = -1); private: static boost::mutex& GetRegistryMutex(void); static std::map, CLICommand::Ptr>& GetRegistry(void); }; #define REGISTER_CLICOMMAND(name, klass) \ INITIALIZE_ONCE([]() { \ std::vector vname; \ boost::algorithm::split(vname, name, boost::is_any_of("/")); \ CLICommand::Register(vname, new klass()); \ }) } #endif /* CLICOMMAND_H */ icinga2-2.8.1/lib/cli/consolecommand.cpp000066400000000000000000000344671322762156600201100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/consolecommand.hpp" #include "config/configcompiler.hpp" #include "remote/apiclient.hpp" #include "remote/consolehandler.hpp" #include "remote/url.hpp" #include "base/configwriter.hpp" #include "base/serializer.hpp" #include "base/json.hpp" #include "base/console.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" #include "base/unixsocket.hpp" #include "base/utility.hpp" #include "base/networkstream.hpp" #include "base/exception.hpp" #include #ifdef HAVE_EDITLINE #include "cli/editline.hpp" #endif /* HAVE_EDITLINE */ using namespace icinga; namespace po = boost::program_options; static ScriptFrame *l_ScriptFrame; static ApiClient::Ptr l_ApiClient; static String l_Session; REGISTER_CLICOMMAND("console", ConsoleCommand); INITIALIZE_ONCE(&ConsoleCommand::StaticInitialize); extern "C" void dbg_spawn_console(void) { ScriptFrame frame; ConsoleCommand::RunScriptConsole(frame); } extern "C" void dbg_inspect_value(const Value& value) { ConfigWriter::EmitValue(std::cout, 1, Serialize(value, 0)); std::cout << std::endl; } extern "C" void dbg_inspect_object(Object *obj) { Object::Ptr objr = obj; dbg_inspect_value(objr); } extern "C" void dbg_eval(const char *text) { Expression *expr = NULL; try { ScriptFrame frame; expr = ConfigCompiler::CompileText("", text); Value result = Serialize(expr->Evaluate(frame), 0); dbg_inspect_value(result); } catch (const std::exception& ex) { std::cout << "Error: " << DiagnosticInformation(ex) << "\n"; } delete expr; } extern "C" void dbg_eval_with_value(const Value& value, const char *text) { Expression *expr = NULL; try { ScriptFrame frame; frame.Locals = new Dictionary(); frame.Locals->Set("arg", value); expr = ConfigCompiler::CompileText("", text); Value result = Serialize(expr->Evaluate(frame), 0); dbg_inspect_value(result); } catch (const std::exception& ex) { std::cout << "Error: " << DiagnosticInformation(ex) << "\n"; } delete expr; } extern "C" void dbg_eval_with_object(Object *object, const char *text) { Expression *expr = NULL; try { ScriptFrame frame; frame.Locals = new Dictionary(); frame.Locals->Set("arg", object); expr = ConfigCompiler::CompileText("", text); Value result = Serialize(expr->Evaluate(frame), 0); dbg_inspect_value(result); } catch (const std::exception& ex) { std::cout << "Error: " << DiagnosticInformation(ex) << "\n"; } delete expr; } void ConsoleCommand::BreakpointHandler(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di) { static boost::mutex mutex; boost::mutex::scoped_lock lock(mutex); if (!Application::GetScriptDebuggerEnabled()) return; if (ex && ex->IsHandledByDebugger()) return; std::cout << "Breakpoint encountered.\n"; if (ex) { std::cout << "Exception: " << DiagnosticInformation(*ex) << "\n"; ex->SetHandledByDebugger(true); } else ShowCodeLocation(std::cout, di); std::cout << "You can inspect expressions (such as variables) by entering them at the prompt.\n" << "To leave the debugger and continue the program use \"$continue\".\n"; #ifdef HAVE_EDITLINE rl_completion_entry_function = ConsoleCommand::ConsoleCompleteHelper; rl_completion_append_character = '\0'; #endif /* HAVE_EDITLINE */ ConsoleCommand::RunScriptConsole(frame); } void ConsoleCommand::StaticInitialize(void) { Expression::OnBreakpoint.connect(&ConsoleCommand::BreakpointHandler); } String ConsoleCommand::GetDescription(void) const { return "Interprets Icinga script expressions."; } String ConsoleCommand::GetShortDescription(void) const { return "Icinga console"; } ImpersonationLevel ConsoleCommand::GetImpersonationLevel(void) const { return ImpersonateNone; } void ConsoleCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("connect,c", po::value(), "connect to an Icinga 2 instance") ("eval,e", po::value(), "evaluate expression and terminate") ("file,r", po::value(), "evaluate a file and terminate") ("syntax-only", "only validate syntax (requires --eval or --file)") ("sandbox", "enable sandbox mode") ; } #ifdef HAVE_EDITLINE char *ConsoleCommand::ConsoleCompleteHelper(const char *word, int state) { static std::vector matches; if (state == 0) { if (!l_ApiClient) matches = ConsoleHandler::GetAutocompletionSuggestions(word, *l_ScriptFrame); else { boost::mutex mutex; boost::condition_variable cv; bool ready = false; Array::Ptr suggestions; l_ApiClient->AutocompleteScript(l_Session, word, l_ScriptFrame->Sandboxed, boost::bind(&ConsoleCommand::AutocompleteScriptCompletionHandler, boost::ref(mutex), boost::ref(cv), boost::ref(ready), _1, _2, boost::ref(suggestions))); { boost::mutex::scoped_lock lock(mutex); while (!ready) cv.wait(lock); } matches.clear(); ObjectLock olock(suggestions); std::copy(suggestions->Begin(), suggestions->End(), std::back_inserter(matches)); } } if (state >= static_cast(matches.size())) return NULL; return strdup(matches[state].CStr()); } #endif /* HAVE_EDITLINE */ /** * The entry point for the "console" CLI command. * * @returns An exit status. */ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector& ap) const { #ifdef HAVE_EDITLINE rl_completion_entry_function = ConsoleCommand::ConsoleCompleteHelper; rl_completion_append_character = '\0'; #endif /* HAVE_EDITLINE */ String addr, session; ScriptFrame scriptFrame; session = Utility::NewUniqueID(); if (vm.count("sandbox")) scriptFrame.Sandboxed = true; scriptFrame.Self = scriptFrame.Locals; if (!vm.count("eval") && !vm.count("file")) std::cout << "Icinga 2 (version: " << Application::GetAppVersion() << ")\n"; const char *addrEnv = getenv("ICINGA2_API_URL"); if (addrEnv) addr = addrEnv; if (vm.count("connect")) addr = vm["connect"].as(); String command; bool syntaxOnly = false; if (vm.count("syntax-only")) { if (vm.count("eval") || vm.count("file")) syntaxOnly = true; else { std::cerr << "The option --syntax-only can only be used in combination with --eval or --file." << std::endl; return EXIT_FAILURE; } } if (vm.count("eval")) command = vm["eval"].as(); else if (vm.count("file")) { std::string fname = vm["file"].as(); try { std::ifstream fp(fname.c_str()); fp.exceptions(std::ifstream::failbit | std::ifstream::badbit); command = String(std::istreambuf_iterator(fp), std::istreambuf_iterator()); } catch (const std::exception&) { std::cerr << "Could not read file '" << fname << "'." << std::endl; return EXIT_FAILURE; } } return RunScriptConsole(scriptFrame, addr, session, command, syntaxOnly); } int ConsoleCommand::RunScriptConsole(ScriptFrame& scriptFrame, const String& addr, const String& session, const String& commandOnce, bool syntaxOnly) { std::map lines; int next_line = 1; #ifdef HAVE_EDITLINE String homeEnv = getenv("HOME"); String historyPath = homeEnv + "/.icinga2_history"; std::fstream historyfp; historyfp.open(historyPath.CStr(), std::fstream::in); String line; while (std::getline(historyfp, line.GetData())) add_history(line.CStr()); historyfp.close(); #endif /* HAVE_EDITLINE */ l_ScriptFrame = &scriptFrame; l_Session = session; if (!addr.IsEmpty()) { Url::Ptr url; try { url = new Url(addr); } catch (const std::exception& ex) { Log(LogCritical, "ConsoleCommand", ex.what()); return EXIT_FAILURE; } const char *usernameEnv = getenv("ICINGA2_API_USERNAME"); const char *passwordEnv = getenv("ICINGA2_API_PASSWORD"); if (usernameEnv) url->SetUsername(usernameEnv); if (passwordEnv) url->SetPassword(passwordEnv); if (url->GetPort().IsEmpty()) url->SetPort("5665"); l_ApiClient = new ApiClient(url->GetHost(), url->GetPort(), url->GetUsername(), url->GetPassword()); } while (std::cin.good()) { String fileName = "<" + Convert::ToString(next_line) + ">"; next_line++; bool continuation = false; std::string command; incomplete: std::string line; if (commandOnce.IsEmpty()) { #ifdef HAVE_EDITLINE std::ostringstream promptbuf; std::ostream& os = promptbuf; #else /* HAVE_EDITLINE */ std::ostream& os = std::cout; #endif /* HAVE_EDITLINE */ os << fileName; if (!continuation) os << " => "; else os << " .. "; #ifdef HAVE_EDITLINE String prompt = promptbuf.str(); char *cline; cline = readline(prompt.CStr()); if (!cline) break; if (commandOnce.IsEmpty() && cline[0] != '\0') { add_history(cline); historyfp.open(historyPath.CStr(), std::fstream::out | std::fstream::app); historyfp << cline << "\n"; historyfp.close(); } line = cline; free(cline); #else /* HAVE_EDITLINE */ std::getline(std::cin, line); #endif /* HAVE_EDITLINE */ } else line = commandOnce; if (!line.empty() && line[0] == '$') { if (line == "$continue") break; std::cout << "Unknown debugger command: " << line << "\n"; continue; } if (!command.empty()) command += "\n"; command += line; Expression *expr = NULL; try { lines[fileName] = command; Value result; if (!l_ApiClient) { expr = ConfigCompiler::CompileText(fileName, command); /* This relies on the fact that - for syntax errors - CompileText() * returns an AST where the top-level expression is a 'throw'. */ if (!syntaxOnly || dynamic_cast(expr)) { if (syntaxOnly) std::cerr << " => " << command << std::endl; result = Serialize(expr->Evaluate(scriptFrame), 0); } else result = true; } else { boost::mutex mutex; boost::condition_variable cv; bool ready = false; boost::exception_ptr eptr; l_ApiClient->ExecuteScript(l_Session, command, scriptFrame.Sandboxed, boost::bind(&ConsoleCommand::ExecuteScriptCompletionHandler, boost::ref(mutex), boost::ref(cv), boost::ref(ready), _1, _2, boost::ref(result), boost::ref(eptr))); { boost::mutex::scoped_lock lock(mutex); while (!ready) cv.wait(lock); } if (eptr) boost::rethrow_exception(eptr); } if (commandOnce.IsEmpty()) { std::cout << ConsoleColorTag(Console_ForegroundCyan); ConfigWriter::EmitValue(std::cout, 1, result); std::cout << ConsoleColorTag(Console_Normal) << "\n"; } else { std::cout << JsonEncode(result) << "\n"; break; } } catch (const ScriptError& ex) { if (ex.IsIncompleteExpression() && commandOnce.IsEmpty()) { continuation = true; goto incomplete; } DebugInfo di = ex.GetDebugInfo(); if (lines.find(di.Path) != lines.end()) { String text = lines[di.Path]; std::vector ulines; boost::algorithm::split(ulines, text, boost::is_any_of("\n")); for (int i = 1; i <= ulines.size(); i++) { int start, len; if (i == di.FirstLine) start = di.FirstColumn; else start = 0; if (i == di.LastLine) len = di.LastColumn - di.FirstColumn + 1; else len = ulines[i - 1].GetLength(); int offset; if (di.Path != fileName) { std::cout << di.Path << ": " << ulines[i - 1] << "\n"; offset = 2; } else offset = 4; if (i >= di.FirstLine && i <= di.LastLine) { std::cout << String(di.Path.GetLength() + offset, ' '); std::cout << String(start, ' ') << String(len, '^') << "\n"; } } } else { ShowCodeLocation(std::cout, di); } std::cout << ex.what() << "\n"; if (!commandOnce.IsEmpty()) return EXIT_FAILURE; } catch (const std::exception& ex) { std::cout << "Error: " << DiagnosticInformation(ex) << "\n"; if (!commandOnce.IsEmpty()) return EXIT_FAILURE; } delete expr; } return EXIT_SUCCESS; } void ConsoleCommand::ExecuteScriptCompletionHandler(boost::mutex& mutex, boost::condition_variable& cv, bool& ready, boost::exception_ptr eptr, const Value& result, Value& resultOut, boost::exception_ptr& eptrOut) { if (eptr) { try { boost::rethrow_exception(eptr); } catch (const ScriptError& ex) { eptrOut = boost::current_exception(); } catch (const std::exception& ex) { Log(LogCritical, "ConsoleCommand") << "HTTP query failed: " << ex.what(); Application::Exit(EXIT_FAILURE); } } resultOut = result; { boost::mutex::scoped_lock lock(mutex); ready = true; cv.notify_all(); } } void ConsoleCommand::AutocompleteScriptCompletionHandler(boost::mutex& mutex, boost::condition_variable& cv, bool& ready, boost::exception_ptr eptr, const Array::Ptr& result, Array::Ptr& resultOut) { if (eptr) { try { boost::rethrow_exception(eptr); } catch (const std::exception& ex) { Log(LogCritical, "ConsoleCommand") << "HTTP query failed: " << ex.what(); Application::Exit(EXIT_FAILURE); } } resultOut = result; { boost::mutex::scoped_lock lock(mutex); ready = true; cv.notify_all(); } } icinga2-2.8.1/lib/cli/consolecommand.hpp000066400000000000000000000061641322762156600201060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONSOLECOMMAND_H #define CONSOLECOMMAND_H #include "cli/clicommand.hpp" #include "base/exception.hpp" #include "base/scriptframe.hpp" namespace icinga { /** * The "console" CLI command. * * @ingroup cli */ class ConsoleCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(ConsoleCommand); static void StaticInitialize(void); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; static int RunScriptConsole(ScriptFrame& scriptFrame, const String& addr = String(), const String& session = String(), const String& commandOnce = String(), bool syntaxOnly = false); private: mutable boost::mutex m_Mutex; mutable boost::condition_variable m_CV; static void ExecuteScriptCompletionHandler(boost::mutex& mutex, boost::condition_variable& cv, bool& ready, boost::exception_ptr eptr, const Value& result, Value& resultOut, boost::exception_ptr& eptrOut); static void AutocompleteScriptCompletionHandler(boost::mutex& mutex, boost::condition_variable& cv, bool& ready, boost::exception_ptr eptr, const Array::Ptr& result, Array::Ptr& resultOut); #ifdef HAVE_EDITLINE static char *ConsoleCompleteHelper(const char *word, int state); #endif /* HAVE_EDITLINE */ static void BreakpointHandler(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di); }; } #endif /* CONSOLECOMMAND_H */ icinga2-2.8.1/lib/cli/daemoncommand.cpp000066400000000000000000000215641322762156600177030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/daemoncommand.hpp" #include "cli/daemonutility.hpp" #include "remote/apilistener.hpp" #include "remote/configobjectutility.hpp" #include "config/configcompiler.hpp" #include "config/configcompilercontext.hpp" #include "config/configitembuilder.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/scriptglobal.hpp" #include "base/context.hpp" #include "config.h" #include #include #include #include using namespace icinga; namespace po = boost::program_options; static po::variables_map g_AppParams; REGISTER_CLICOMMAND("daemon", DaemonCommand); #ifndef _WIN32 static void SigHupHandler(int) { Application::RequestRestart(); } #endif /* _WIN32 */ static bool Daemonize(void) { #ifndef _WIN32 Application::UninitializeBase(); pid_t pid = fork(); if (pid == -1) { return false; } if (pid) { // systemd requires that the pidfile of the daemon is written before the forking // process terminates. So wait till either the forked daemon has written a pidfile or died. int status; int ret; pid_t readpid; do { Utility::Sleep(0.1); readpid = Application::ReadPidFile(Application::GetPidPath()); ret = waitpid(pid, &status, WNOHANG); } while (readpid != pid && ret == 0); if (ret == pid) { Log(LogCritical, "cli", "The daemon could not be started. See log output for details."); _exit(EXIT_FAILURE); } else if (ret == -1) { Log(LogCritical, "cli") << "waitpid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; _exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); } Application::InitializeBase(); #endif /* _WIN32 */ return true; } static bool SetDaemonIO(const String& stderrFile) { #ifndef _WIN32 int fdnull = open("/dev/null", O_RDWR); if (fdnull >= 0) { if (fdnull != 0) dup2(fdnull, 0); if (fdnull != 1) dup2(fdnull, 1); if (fdnull > 1) close(fdnull); } const char *errPath = "/dev/null"; if (!stderrFile.IsEmpty()) errPath = stderrFile.CStr(); int fderr = open(errPath, O_WRONLY | O_APPEND); if (fderr < 0 && errno == ENOENT) fderr = open(errPath, O_CREAT | O_WRONLY | O_APPEND, 0600); if (fderr >= 0) { if (fderr != 2) dup2(fderr, 2); if (fderr > 2) close(fderr); } pid_t sid = setsid(); if (sid == -1) { return false; } #endif return true; } /** * Terminate another process and wait till it has ended * * @params target PID of the process to end */ static void TerminateAndWaitForEnd(pid_t target) { #ifndef _WIN32 // allow 30 seconds timeout double timeout = Utility::GetTime() + 30; int ret = kill(target, SIGTERM); while (Utility::GetTime() < timeout && (ret == 0 || errno != ESRCH)) { Utility::Sleep(0.1); ret = kill(target, 0); } // timeout and the process still seems to live: update pid and kill it if (ret == 0 || errno != ESRCH) { String pidFile = Application::GetPidPath(); std::ofstream fp(pidFile.CStr()); fp << Utility::GetPid(); fp.close(); kill(target, SIGKILL); } #else // TODO: implement this for Win32 #endif /* _WIN32 */ } String DaemonCommand::GetDescription(void) const { return "Starts Icinga 2."; } String DaemonCommand::GetShortDescription(void) const { return "starts Icinga 2"; } void DaemonCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("config,c", po::value >(), "parse a configuration file") ("no-config,z", "start without a configuration file") ("validate,C", "exit after validating the configuration") ("errorlog,e", po::value(), "log fatal errors to the specified log file (only works in combination with --daemonize)") #ifndef _WIN32 ("daemonize,d", "detach from the controlling terminal") #endif /* _WIN32 */ ; #ifndef _WIN32 hiddenDesc.add_options() ("reload-internal", po::value(), "used internally to implement config reload: do not call manually, send SIGHUP instead"); #endif /* _WIN32 */ } std::vector DaemonCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "config" || argument == "errorlog") return GetBashCompletionSuggestions("file", word); else return CLICommand::GetArgumentSuggestions(argument, word); } /** * The entry point for the "daemon" CLI command. * * @returns An exit status. */ int DaemonCommand::Run(const po::variables_map& vm, const std::vector& ap) const { if (!vm.count("validate")) Logger::DisableTimestamp(false); Log(LogInformation, "cli") << "Icinga application loader (version: " << Application::GetAppVersion() #ifdef I2_DEBUG << "; debug" #endif /* I2_DEBUG */ << ")"; if (!vm.count("validate") && !vm.count("reload-internal")) { pid_t runningpid = Application::ReadPidFile(Application::GetPidPath()); if (runningpid > 0) { Log(LogCritical, "cli") << "Another instance of Icinga already running with PID " << runningpid; return EXIT_FAILURE; } } std::vector configs; if (vm.count("config") > 0) configs = vm["config"].as < std::vector >() ; else if (!vm.count("no-config")) configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf"); Log(LogInformation, "cli", "Loading configuration file(s)."); std::vector newItems; if (!DaemonUtility::LoadConfigFiles(configs, newItems, Application::GetObjectsPath(), Application::GetVarsPath())) return EXIT_FAILURE; if (vm.count("validate")) { Log(LogInformation, "cli", "Finished validating the configuration file(s)."); return EXIT_SUCCESS; } if (vm.count("reload-internal")) { int parentpid = vm["reload-internal"].as(); Log(LogInformation, "cli") << "Terminating previous instance of Icinga (PID " << parentpid << ")"; TerminateAndWaitForEnd(parentpid); Log(LogInformation, "cli", "Previous instance has ended, taking over now."); } if (vm.count("daemonize")) { if (!vm.count("reload-internal")) { // no additional fork neccessary on reload try { Daemonize(); } catch (std::exception&) { Log(LogCritical, "cli", "Daemonize failed. Exiting."); return EXIT_FAILURE; } } } /* restore the previous program state */ try { ConfigObject::RestoreObjects(Application::GetStatePath()); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Failed to restore state file: " << DiagnosticInformation(ex); return EXIT_FAILURE; } { WorkQueue upq(25000, Application::GetConcurrency()); upq.SetName("DaemonCommand::Run"); // activate config only after daemonization: it starts threads and that is not compatible with fork() if (!ConfigItem::ActivateItems(upq, newItems, false, false, true)) { Log(LogCritical, "cli", "Error activating configuration."); return EXIT_FAILURE; } } if (vm.count("daemonize")) { String errorLog; if (vm.count("errorlog")) errorLog = vm["errorlog"].as(); SetDaemonIO(errorLog); Logger::DisableConsoleLog(); } /* Remove ignored Downtime/Comment objects. */ ConfigItem::RemoveIgnoredItems(ConfigObjectUtility::GetConfigDir()); #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = &SigHupHandler; sigaction(SIGHUP, &sa, NULL); #endif /* _WIN32 */ ApiListener::UpdateObjectAuthority(); return Application::GetInstance()->Run(); } icinga2-2.8.1/lib/cli/daemoncommand.hpp000066400000000000000000000042651322762156600177070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DAEMONCOMMAND_H #define DAEMONCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "daemon" CLI command. * * @ingroup cli */ class DaemonCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(DaemonCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* DAEMONCOMMAND_H */ icinga2-2.8.1/lib/cli/daemonutility.cpp000066400000000000000000000160031322762156600177600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/daemonutility.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "config/configcompiler.hpp" #include "config/configcompilercontext.hpp" #include "config/configitembuilder.hpp" using namespace icinga; static bool ExecuteExpression(Expression *expression) { if (!expression) return false; try { ScriptFrame frame; expression->Evaluate(frame); } catch (const std::exception& ex) { Log(LogCritical, "config", DiagnosticInformation(ex)); return false; } return true; } static void IncludeZoneDirRecursive(const String& path, const String& package, bool& success) { String zoneName = Utility::BaseName(path); /* register this zone path for cluster config sync */ ConfigCompiler::RegisterZoneDir("_etc", path, zoneName); std::vector expressions; Utility::GlobRecursive(path, "*.conf", boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName, package), GlobFile); DictExpression expr(expressions); if (!ExecuteExpression(&expr)) success = false; } static void IncludeNonLocalZone(const String& zonePath, const String& package, bool& success) { /* Note: This include function must not call RegisterZoneDir(). * We do not need to copy it for cluster config sync. */ String zoneName = Utility::BaseName(zonePath); /* Check whether this node already has an authoritative config version * from zones.d in etc or api package directory, or a local marker file) */ if (ConfigCompiler::HasZoneConfigAuthority(zoneName) || Utility::PathExists(zonePath + "/.authoritative")) { Log(LogNotice, "config") << "Ignoring non local config include for zone '" << zoneName << "': We already have an authoritative copy included."; return; } std::vector expressions; Utility::GlobRecursive(zonePath, "*.conf", boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName, package), GlobFile); DictExpression expr(expressions); if (!ExecuteExpression(&expr)) success = false; } static void IncludePackage(const String& packagePath, bool& success) { /* Note: Package includes will register their zones * for config sync inside their generated config. */ String packageName = Utility::BaseName(packagePath); if (Utility::PathExists(packagePath + "/include.conf")) { Expression *expr = ConfigCompiler::CompileFile(packagePath + "/include.conf", String(), packageName); if (!ExecuteExpression(expr)) success = false; delete expr; } } bool DaemonUtility::ValidateConfigFiles(const std::vector& configs, const String& objectsFile) { bool success; if (!objectsFile.IsEmpty()) ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile); if (!configs.empty()) { for (const String& configPath : configs) { try { Expression *expression = ConfigCompiler::CompileFile(configPath, String(), "_etc"); success = ExecuteExpression(expression); delete expression; if (!success) return false; } catch (const std::exception& ex) { Log(LogCritical, "cli", "Could not compile config files: " + DiagnosticInformation(ex, false)); Application::Exit(1); } } } /* Load cluster config files from /etc/icinga2/zones.d. * This should probably be in libremote but * unfortunately moving it there is somewhat non-trivial. */ success = true; String zonesEtcDir = Application::GetZonesDir(); if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir)) Utility::Glob(zonesEtcDir + "/*", boost::bind(&IncludeZoneDirRecursive, _1, "_etc", boost::ref(success)), GlobDirectory); if (!success) return false; /* Load package config files - they may contain additional zones which * are authoritative on this node and are checked in HasZoneConfigAuthority(). */ String packagesVarDir = Application::GetLocalStateDir() + "/lib/icinga2/api/packages"; if (Utility::PathExists(packagesVarDir)) Utility::Glob(packagesVarDir + "/*", boost::bind(&IncludePackage, _1, boost::ref(success)), GlobDirectory); if (!success) return false; /* Load cluster synchronized configuration files */ String zonesVarDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones"; if (Utility::PathExists(zonesVarDir)) Utility::Glob(zonesVarDir + "/*", boost::bind(&IncludeNonLocalZone, _1, "_cluster", boost::ref(success)), GlobDirectory); if (!success) return false; Type::Ptr appType = Type::GetByName(ScriptGlobal::Get("ApplicationType", &Empty)); if (ConfigItem::GetItems(appType).empty()) { ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(); builder->SetType(appType); builder->SetName("app"); builder->AddExpression(new ImportDefaultTemplatesExpression()); ConfigItem::Ptr item = builder->Compile(); item->Register(); } return true; } bool DaemonUtility::LoadConfigFiles(const std::vector& configs, std::vector& newItems, const String& objectsFile, const String& varsfile) { ActivationScope ascope; if (!DaemonUtility::ValidateConfigFiles(configs, objectsFile)) { ConfigCompilerContext::GetInstance()->CancelObjectsFile(); return false; } WorkQueue upq(25000, Application::GetConcurrency()); upq.SetName("DaemonUtility::LoadConfigFiles"); bool result = ConfigItem::CommitItems(ascope.GetContext(), upq, newItems); if (!result) { ConfigCompilerContext::GetInstance()->CancelObjectsFile(); return false; } ConfigCompilerContext::GetInstance()->FinishObjectsFile(); try { ScriptGlobal::WriteToFile(varsfile); } catch (const std::exception& ex) { Log(LogCritical, "cli", "Could not write vars file: " + DiagnosticInformation(ex, false)); Application::Exit(1); } return true; } icinga2-2.8.1/lib/cli/daemonutility.hpp000066400000000000000000000037651322762156600200000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DAEMONUTILITY_H #define DAEMONUTILITY_H #include "cli/i2-cli.hpp" #include "config/configitem.hpp" #include "base/string.hpp" #include namespace icinga { /** * @ingroup cli */ class I2_CLI_API DaemonUtility { public: static bool ValidateConfigFiles(const std::vector& configs, const String& objectsFile = String()); static bool LoadConfigFiles(const std::vector& configs, std::vector& newItems, const String& objectsFile = String(), const String& varsfile = String()); }; } #endif /* DAEMONULITIY_H */ icinga2-2.8.1/lib/cli/editline.hpp000066400000000000000000000033061322762156600166750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EDITLINE_H #define EDITLINE_H extern "C" { char *readline(const char *prompt); int add_history(const char *line); typedef char *ELFunction(const char *, int); extern char rl_completion_append_character; extern ELFunction *rl_completion_entry_function; } #endif /* EDITLINE_H */ icinga2-2.8.1/lib/cli/featuredisablecommand.cpp000066400000000000000000000051751322762156600214170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/featuredisablecommand.hpp" #include "cli/featureutility.hpp" #include "base/logger.hpp" using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("feature/disable", FeatureDisableCommand); String FeatureDisableCommand::GetDescription(void) const { return "Disables specified Icinga 2 feature."; } String FeatureDisableCommand::GetShortDescription(void) const { return "disables specified feature"; } std::vector FeatureDisableCommand::GetPositionalSuggestions(const String& word) const { return FeatureUtility::GetFieldCompletionSuggestions(word, false); } int FeatureDisableCommand::GetMinArguments(void) const { return 1; } int FeatureDisableCommand::GetMaxArguments(void) const { return -1; } ImpersonationLevel FeatureDisableCommand::GetImpersonationLevel(void) const { return ImpersonateRoot; } /** * The entry point for the "feature disable" CLI command. * * @returns An exit status. */ int FeatureDisableCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (ap.empty()) { Log(LogCritical, "cli", "Cannot disable feature(s). Name(s) are missing!"); return 0; } return FeatureUtility::DisableFeatures(ap); } icinga2-2.8.1/lib/cli/featuredisablecommand.hpp000066400000000000000000000043261322762156600214210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FEATUREDISABLECOMMAND_H #define FEATUREDISABLECOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "feature disable" command. * * @ingroup cli */ class FeatureDisableCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(FeatureDisableCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMinArguments(void) const override; virtual int GetMaxArguments(void) const override; virtual std::vector GetPositionalSuggestions(const String& word) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* FEATUREDISABLECOMMAND_H */ icinga2-2.8.1/lib/cli/featureenablecommand.cpp000066400000000000000000000047751322762156600212470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/featureenablecommand.hpp" #include "cli/featureutility.hpp" #include "base/logger.hpp" using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("feature/enable", FeatureEnableCommand); String FeatureEnableCommand::GetDescription(void) const { return "Enables specified Icinga 2 feature."; } String FeatureEnableCommand::GetShortDescription(void) const { return "enables specified feature"; } std::vector FeatureEnableCommand::GetPositionalSuggestions(const String& word) const { return FeatureUtility::GetFieldCompletionSuggestions(word, true); } int FeatureEnableCommand::GetMinArguments(void) const { return 1; } int FeatureEnableCommand::GetMaxArguments(void) const { return -1; } ImpersonationLevel FeatureEnableCommand::GetImpersonationLevel(void) const { return ImpersonateRoot; } /** * The entry point for the "feature enable" CLI command. * * @returns An exit status. */ int FeatureEnableCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { return FeatureUtility::EnableFeatures(ap); } icinga2-2.8.1/lib/cli/featureenablecommand.hpp000066400000000000000000000043171322762156600212440ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FEATUREENABLECOMMAND_H #define FEATUREENABLECOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "feature enable" command. * * @ingroup cli */ class FeatureEnableCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(FeatureEnableCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMinArguments(void) const override; virtual int GetMaxArguments(void) const override; virtual std::vector GetPositionalSuggestions(const String& word) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* FEATUREENABLECOMMAND_H */ icinga2-2.8.1/lib/cli/featurelistcommand.cpp000066400000000000000000000043151322762156600207620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/featurelistcommand.hpp" #include "cli/featureutility.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/console.hpp" #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("feature/list", FeatureListCommand); String FeatureListCommand::GetDescription(void) const { return "Lists all available Icinga 2 features."; } String FeatureListCommand::GetShortDescription(void) const { return "lists all available features"; } /** * The entry point for the "feature list" CLI command. * * @returns An exit status. */ int FeatureListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { return FeatureUtility::ListFeatures(); } icinga2-2.8.1/lib/cli/featurelistcommand.hpp000066400000000000000000000036731322762156600207750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FEATURELISTCOMMAND_H #define FEATURELISTCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "feature list" command. * * @ingroup cli */ class FeatureListCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(FeatureListCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* FEATURELISTCOMMAND_H */ icinga2-2.8.1/lib/cli/featureutility.cpp000066400000000000000000000206641322762156600201600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/featureutility.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include "base/application.hpp" #include #include #include #include using namespace icinga; String FeatureUtility::GetFeaturesAvailablePath(void) { return Application::GetSysconfDir() + "/icinga2/features-available"; } String FeatureUtility::GetFeaturesEnabledPath(void) { return Application::GetSysconfDir() + "/icinga2/features-enabled"; } std::vector FeatureUtility::GetFieldCompletionSuggestions(const String& word, bool enable) { std::vector cache; std::vector suggestions; GetFeatures(cache, enable); std::sort(cache.begin(), cache.end()); for (const String& suggestion : cache) { if (suggestion.Find(word) == 0) suggestions.push_back(suggestion); } return suggestions; } int FeatureUtility::EnableFeatures(const std::vector& features) { String features_available_dir = GetFeaturesAvailablePath(); String features_enabled_dir = GetFeaturesEnabledPath(); if (!Utility::PathExists(features_available_dir) ) { Log(LogCritical, "cli") << "Cannot parse available features. Path '" << features_available_dir << "' does not exist."; return 1; } if (!Utility::PathExists(features_enabled_dir) ) { Log(LogCritical, "cli") << "Cannot enable features. Path '" << features_enabled_dir << "' does not exist."; return 1; } std::vector errors; for (const String& feature : features) { String source = features_available_dir + "/" + feature + ".conf"; if (!Utility::PathExists(source) ) { Log(LogCritical, "cli") << "Cannot enable feature '" << feature << "'. Source file '" << source + "' does not exist."; errors.push_back(feature); continue; } String target = features_enabled_dir + "/" + feature + ".conf"; if (Utility::PathExists(target) ) { Log(LogWarning, "cli") << "Feature '" << feature << "' already enabled."; continue; } std::cout << "Enabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature << ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n"; #ifndef _WIN32 String relativeSource = "../features-available/" + feature + ".conf"; if (symlink(relativeSource.CStr(), target.CStr()) < 0) { Log(LogCritical, "cli") << "Cannot enable feature '" << feature << "'. Linking source '" << relativeSource << "' to target file '" << target << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"."; errors.push_back(feature); continue; } #else /* _WIN32 */ std::ofstream fp; fp.open(target.CStr()); fp << "include \"../features-available/" << feature << ".conf\"" << std::endl; fp.close(); if (fp.fail()) { Log(LogCritical, "cli") << "Cannot enable feature '" << feature << "'. Failed to open file '" << target << "'."; errors.push_back(feature); continue; } #endif /* _WIN32 */ } if (!errors.empty()) { Log(LogCritical, "cli") << "Cannot enable feature(s): " << boost::algorithm::join(errors, " "); errors.clear(); return 1; } return 0; } int FeatureUtility::DisableFeatures(const std::vector& features) { String features_enabled_dir = GetFeaturesEnabledPath(); if (!Utility::PathExists(features_enabled_dir) ) { Log(LogCritical, "cli") << "Cannot disable features. Path '" << features_enabled_dir << "' does not exist."; return 0; } std::vector errors; for (const String& feature : features) { String target = features_enabled_dir + "/" + feature + ".conf"; if (!Utility::PathExists(target) ) { Log(LogWarning, "cli") << "Feature '" << feature << "' already disabled."; continue; } if (unlink(target.CStr()) < 0) { Log(LogCritical, "cli") << "Cannot disable feature '" << feature << "'. Unlinking target file '" << target << "' failed with error code " << errno << ", \"" + Utility::FormatErrorNumber(errno) << "\"."; errors.push_back(feature); continue; } std::cout << "Disabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature << ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n"; } if (!errors.empty()) { Log(LogCritical, "cli") << "Cannot disable feature(s): " << boost::algorithm::join(errors, " "); errors.clear(); return 1; } return 0; } int FeatureUtility::ListFeatures(std::ostream& os) { std::vector disabled_features; std::vector enabled_features; if (!FeatureUtility::GetFeatures(disabled_features, true)) return 1; os << ConsoleColorTag(Console_ForegroundRed | Console_Bold) << "Disabled features: " << ConsoleColorTag(Console_Normal) << boost::algorithm::join(disabled_features, " ") << "\n"; if (!FeatureUtility::GetFeatures(enabled_features, false)) return 1; os << ConsoleColorTag(Console_ForegroundGreen | Console_Bold) << "Enabled features: " << ConsoleColorTag(Console_Normal) << boost::algorithm::join(enabled_features, " ") << "\n"; return 0; } bool FeatureUtility::GetFeatures(std::vector& features, bool get_disabled) { /* request all disabled features */ if (get_disabled) { /* disable = available-enabled */ String available_pattern = GetFeaturesAvailablePath() + "/*.conf"; std::vector available; Utility::Glob(available_pattern, boost::bind(&FeatureUtility::CollectFeatures, _1, boost::ref(available)), GlobFile); String enabled_pattern = GetFeaturesEnabledPath() + "/*.conf"; std::vector enabled; Utility::Glob(enabled_pattern, boost::bind(&FeatureUtility::CollectFeatures, _1, boost::ref(enabled)), GlobFile); std::sort(available.begin(), available.end()); std::sort(enabled.begin(), enabled.end()); std::set_difference( available.begin(), available.end(), enabled.begin(), enabled.end(), std::back_inserter(features) ); } else { /* all enabled features */ String enabled_pattern = GetFeaturesEnabledPath() + "/*.conf"; Utility::Glob(enabled_pattern, boost::bind(&FeatureUtility::CollectFeatures, _1, boost::ref(features)), GlobFile); } return true; } bool FeatureUtility::CheckFeatureEnabled(const String& feature) { return CheckFeatureInternal(feature, false); } bool FeatureUtility::CheckFeatureDisabled(const String& feature) { return CheckFeatureInternal(feature, true); } bool FeatureUtility::CheckFeatureInternal(const String& feature, bool check_disabled) { std::vector features; if (!FeatureUtility::GetFeatures(features, check_disabled)) return false; for (const String& check_feature : features) { if (check_feature == feature) return true; } return false; } void FeatureUtility::CollectFeatures(const String& feature_file, std::vector& features) { String feature = Utility::BaseName(feature_file); boost::algorithm::replace_all(feature, ".conf", ""); Log(LogDebug, "cli") << "Adding feature: " << feature; features.push_back(feature); } icinga2-2.8.1/lib/cli/featureutility.hpp000066400000000000000000000047121322762156600201610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FEATUREUTILITY_H #define FEATUREUTILITY_H #include "base/i2-base.hpp" #include "cli/i2-cli.hpp" #include "base/string.hpp" #include #include namespace icinga { /** * @ingroup cli */ class I2_CLI_API FeatureUtility { public: static String GetFeaturesAvailablePath(void); static String GetFeaturesEnabledPath(void); static std::vector GetFieldCompletionSuggestions(const String& word, bool enable); static int EnableFeatures(const std::vector& features); static int DisableFeatures(const std::vector& features); static int ListFeatures(std::ostream& os = std::cout); static bool GetFeatures(std::vector& features, bool enable); static bool CheckFeatureEnabled(const String& feature); static bool CheckFeatureDisabled(const String& feature); private: FeatureUtility(void); static void CollectFeatures(const String& feature_file, std::vector& features); static bool CheckFeatureInternal(const String& feature, bool check_disabled); }; } #endif /* FEATUREUTILITY_H */ icinga2-2.8.1/lib/cli/i2-cli.hpp000066400000000000000000000033501322762156600161560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2CLI_H #define I2CLI_H /** * @defgroup cli CLI commands * * The CLI library implements Icinga's command-line interface. */ #include "base/i2-base.hpp" #ifdef I2_CLI_BUILD # define I2_CLI_API I2_EXPORT #else /* I2_REMOTE_BUILD */ # define I2_CLI_API I2_IMPORT #endif /* I2_REMOTE_BUILD */ #endif /* I2CLI_H */ icinga2-2.8.1/lib/cli/nodesetupcommand.cpp000066400000000000000000000376561322762156600204570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/nodesetupcommand.hpp" #include "cli/nodeutility.hpp" #include "cli/featureutility.hpp" #include "cli/apisetuputility.hpp" #include "remote/apilistener.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/scriptglobal.hpp" #include "base/exception.hpp" #include #include #include #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("node/setup", NodeSetupCommand); String NodeSetupCommand::GetDescription(void) const { return "Sets up an Icinga 2 node."; } String NodeSetupCommand::GetShortDescription(void) const { return "set up node"; } void NodeSetupCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("zone", po::value(), "The name of the local zone") ("master_host", po::value(), "The name of the master host for auto-signing the csr; syntax: host[,port]") ("endpoint", po::value >(), "Connect to remote endpoint; syntax: cn[,host,port]") ("listen", po::value(), "Listen on host,port") ("ticket", po::value(), "Generated ticket number for this request (optional)") ("trustedcert", po::value(), "Trusted master certificate file") ("cn", po::value(), "The certificate's common name") ("accept-config", "Accept config from master") ("accept-commands", "Accept commands from master") ("master", "Use setup for a master instance"); hiddenDesc.add_options() ("master_zone", po::value(), "The name of the master zone"); } std::vector NodeSetupCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "key" || argument == "cert" || argument == "trustedcert") return GetBashCompletionSuggestions("file", word); else if (argument == "host") return GetBashCompletionSuggestions("hostname", word); else if (argument == "port") return GetBashCompletionSuggestions("service", word); else return CLICommand::GetArgumentSuggestions(argument, word); } ImpersonationLevel NodeSetupCommand::GetImpersonationLevel(void) const { return ImpersonateRoot; } /** * The entry point for the "node setup" CLI command. * * @returns An exit status. */ int NodeSetupCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!ap.empty()) { Log(LogWarning, "cli") << "Ignoring parameters: " << boost::algorithm::join(ap, " "); } if (vm.count("master")) return SetupMaster(vm, ap); else return SetupNode(vm, ap); } int NodeSetupCommand::SetupMaster(const boost::program_options::variables_map& vm, const std::vector& ap) { /* Ignore not required parameters */ if (vm.count("ticket")) Log(LogWarning, "cli", "Master for Node setup: Ignoring --ticket"); if (vm.count("endpoint")) Log(LogWarning, "cli", "Master for Node setup: Ignoring --endpoint"); if (vm.count("trustedcert")) Log(LogWarning, "cli", "Master for Node setup: Ignoring --trustedcert"); if (vm.count("accept-config")) Log(LogWarning, "cli", "Master for Node setup: Ignoring --accept-config"); if (vm.count("accept-commands")) Log(LogWarning, "cli", "Master for Node setup: Ignoring --accept-commands"); String cn = Utility::GetFQDN(); if (vm.count("cn")) cn = vm["cn"].as(); /* check whether the user wants to generate a new certificate or not */ String existingPath = ApiListener::GetCertsDir() + "/" + cn + ".crt"; Log(LogInformation, "cli") << "Checking in existing certificates for common name '" << cn << "'..."; if (Utility::PathExists(existingPath)) { Log(LogWarning, "cli") << "Certificate '" << existingPath << "' for CN '" << cn << "' already exists. Not generating new certificate."; } else { Log(LogInformation, "cli") << "Certificates not yet generated. Running 'api setup' now."; ApiSetupUtility::SetupMasterCertificates(cn); } Log(LogInformation, "cli", "Generating master configuration for Icinga 2."); ApiSetupUtility::SetupMasterApiUser(); if (!FeatureUtility::CheckFeatureEnabled("api")) { ApiSetupUtility::SetupMasterEnableApi(); } else { Log(LogInformation, "cli") << "'api' feature already enabled.\n"; } /* write zones.conf and update with zone + endpoint information */ Log(LogInformation, "cli", "Generating zone and object configuration."); std::vector globalZones; globalZones.push_back("global-templates"); globalZones.push_back("director-global"); NodeUtility::GenerateNodeMasterIcingaConfig(globalZones); /* update the ApiListener config - SetupMaster() will always enable it */ Log(LogInformation, "cli", "Updating the APIListener feature."); String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); std::fstream fp; String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", 0644, fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" << " */\n" << "object ApiListener \"api\" {\n"; if (vm.count("listen")) { std::vector tokens; boost::algorithm::split(tokens, vm["listen"].as(), boost::is_any_of(",")); if (tokens.size() > 0) fp << " bind_host = \"" << tokens[0] << "\"\n"; if (tokens.size() > 1) fp << " bind_port = " << tokens[1] << "\n"; } fp << "\n" << " ticket_salt = TicketSalt\n" << "}\n"; fp.close(); #ifdef _WIN32 _unlink(apipath.CStr()); #endif /* _WIN32 */ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempApiPath)); } /* update constants.conf with NodeName = CN + TicketSalt = random value */ if (cn != Utility::GetFQDN()) { Log(LogWarning, "cli") << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!"; } Log(LogInformation, "cli", "Updating constants.conf."); NodeUtility::CreateBackupFile(Application::GetSysconfDir() + "/icinga2/constants.conf"); NodeUtility::UpdateConstant("NodeName", cn); NodeUtility::UpdateConstant("ZoneName", cn); String salt = RandomString(16); NodeUtility::UpdateConstant("TicketSalt", salt); Log(LogInformation, "cli") << "Edit the api feature config file '" << apipath << "' and set a secure 'ticket_salt' attribute."; /* tell the user to reload icinga2 */ Log(LogInformation, "cli", "Make sure to restart Icinga 2."); return 0; } int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm, const std::vector& ap) { /* require at least one endpoint. Ticket is optional. */ if (!vm.count("endpoint")) { Log(LogCritical, "cli", "You need to specify at least one endpoint (--endpoint)."); return 1; } if (!vm.count("zone")) { Log(LogCritical, "cli", "You need to specify the local zone (--zone)."); return 1; } String ticket; if (vm.count("ticket")) ticket = vm["ticket"].as(); if (ticket.IsEmpty()) { Log(LogInformation, "cli") << "Requesting certificate without a ticket."; } else { Log(LogInformation, "cli") << "Requesting certificate with ticket '" << ticket << "'."; } /* require master host information for auto-signing requests */ if (!vm.count("master_host")) { Log(LogCritical, "cli", "Please pass the master host connection information for auto-signing using '--master_host '. This can also be a direct parent satellite since 2.8."); return 1; } std::vector tokens; boost::algorithm::split(tokens, vm["master_host"].as(), boost::is_any_of(",")); String master_host; String master_port = "5665"; if (tokens.size() == 1 || tokens.size() == 2) master_host = tokens[0]; if (tokens.size() == 2) master_port = tokens[1]; Log(LogInformation, "cli") << "Verifying parent host connection information: host '" << master_host << "', port '" << master_port << "'."; /* trusted cert must be passed (retrieved by the user with 'pki save-cert' before) */ if (!vm.count("trustedcert")) { Log(LogCritical, "cli") << "Please pass the trusted cert retrieved from the parent node (master or satellite)\n" << "(Hint: 'icinga2 pki save-cert --host --port <5665> --key local.key --cert local.crt --trustedcert master.crt')."; return 1; } boost::shared_ptr trustedcert = GetX509Certificate(vm["trustedcert"].as()); Log(LogInformation, "cli") << "Verifying trusted certificate file '" << vm["trustedcert"].as() << "'."; /* retrieve CN and pass it (defaults to FQDN) */ String cn = Utility::GetFQDN(); if (vm.count("cn")) cn = vm["cn"].as(); Log(LogInformation, "cli") << "Using the following CN (defaults to FQDN): '" << cn << "'."; /* pki request a signed certificate from the master */ String pki_path = ApiListener::GetCertsDir(); Utility::MkDirP(pki_path, 0700); String user = ScriptGlobal::Get("RunAsUser"); String group = ScriptGlobal::Get("RunAsGroup"); if (!Utility::SetFileOwnership(pki_path, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << pki_path << "'. Verify it yourself!"; } String key = pki_path + "/" + cn + ".key"; String cert = pki_path + "/" + cn + ".crt"; String ca = pki_path + "/ca.crt"; if (Utility::PathExists(key)) NodeUtility::CreateBackupFile(key, true); if (Utility::PathExists(cert)) NodeUtility::CreateBackupFile(cert); if (PkiUtility::NewCert(cn, key, String(), cert) != 0) { Log(LogCritical, "cli", "Failed to generate new self-signed certificate."); return 1; } /* fix permissions: root -> icinga daemon user */ if (!Utility::SetFileOwnership(key, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << key << "'. Verify it yourself!"; } Log(LogInformation, "cli", "Requesting a signed certificate from the parent Icinga node."); if (PkiUtility::RequestCertificate(master_host, master_port, key, cert, ca, trustedcert, ticket) > 0) { Log(LogCritical, "cli") << "Failed to fetch signed certificate from parent Icinga node '" << master_host << ", " << master_port << "'. Please try again."; return 1; } if (!Utility::SetFileOwnership(ca, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << ca << "'. Verify it yourself!"; } /* fix permissions (again) when updating the signed certificate */ if (!Utility::SetFileOwnership(cert, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << cert << "'. Verify it yourself!"; } /* disable the notifications feature */ Log(LogInformation, "cli", "Disabling the Notification feature."); std::vector disable; disable.push_back("notification"); FeatureUtility::DisableFeatures(disable); /* enable the ApiListener config */ Log(LogInformation, "cli", "Updating the ApiListener feature."); std::vector enable; enable.push_back("api"); FeatureUtility::EnableFeatures(enable); String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); std::fstream fp; String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", 0644, fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" << " */\n" << "object ApiListener \"api\" {\n"; if (vm.count("listen")) { std::vector tokens; boost::algorithm::split(tokens, vm["listen"].as(), boost::is_any_of(",")); if (tokens.size() > 0) fp << " bind_host = \"" << tokens[0] << "\"\n"; if (tokens.size() > 1) fp << " bind_port = " << tokens[1] << "\n"; } fp << "\n"; if (vm.count("accept-config")) fp << " accept_config = true\n"; else fp << " accept_config = false\n"; if (vm.count("accept-commands")) fp << " accept_commands = true\n"; else fp << " accept_commands = false\n"; fp << "\n" << "}\n"; fp.close(); #ifdef _WIN32 _unlink(apipath.CStr()); #endif /* _WIN32 */ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempApiPath)); } /* generate local zones.conf with zone+endpoint */ Log(LogInformation, "cli", "Generating zone and object configuration."); std::vector globalZones; globalZones.push_back("global-templates"); globalZones.push_back("director-global"); NodeUtility::GenerateNodeIcingaConfig(vm["endpoint"].as >(), globalZones); /* update constants.conf with NodeName = CN */ if (cn != Utility::GetFQDN()) { Log(LogWarning, "cli") << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires an update for the NodeName constant in constants.conf!"; } Log(LogInformation, "cli", "Updating constants.conf."); NodeUtility::CreateBackupFile(Application::GetSysconfDir() + "/icinga2/constants.conf"); NodeUtility::UpdateConstant("NodeName", cn); NodeUtility::UpdateConstant("ZoneName", vm["zone"].as()); if (!ticket.IsEmpty()) { String ticketPath = ApiListener::GetCertsDir() + "/ticket"; String tempTicketPath = Utility::CreateTempFile(ticketPath + ".XXXXXX", 0600, fp); if (!Utility::SetFileOwnership(tempTicketPath, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << tempTicketPath << "'. Verify it yourself!"; } fp << ticket; fp.close(); #ifdef _WIN32 _unlink(ticketPath.CStr()); #endif /* _WIN32 */ if (rename(tempTicketPath.CStr(), ticketPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempTicketPath)); } } /* tell the user to reload icinga2 */ Log(LogInformation, "cli", "Make sure to restart Icinga 2."); return 0; } icinga2-2.8.1/lib/cli/nodesetupcommand.hpp000066400000000000000000000047601322762156600204520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NODESETUPCOMMAND_H #define NODESETUPCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "node setup" command. * * @ingroup cli */ class NodeSetupCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(NodeSetupCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; private: static int SetupMaster(const boost::program_options::variables_map& vm, const std::vector& ap); static int SetupNode(const boost::program_options::variables_map& vm, const std::vector& ap); }; } #endif /* NODESETUPCOMMAND_H */ icinga2-2.8.1/lib/cli/nodeutility.cpp000066400000000000000000000227631322762156600174540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/nodeutility.hpp" #include "cli/clicommand.hpp" #include "cli/variableutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/scriptglobal.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/stdiostream.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/console.hpp" #include "base/exception.hpp" #include "base/configwriter.hpp" #include #include #include #include #include #include using namespace icinga; /* * Node Setup helpers */ int NodeUtility::GenerateNodeIcingaConfig(const std::vector& endpoints, const std::vector& globalZones) { Array::Ptr my_config = new Array(); Dictionary::Ptr my_master_zone = new Dictionary(); Array::Ptr my_master_zone_members = new Array(); String master_zone_name = "master"; //TODO: Find a better name. for (const std::string& endpoint : endpoints) { /* extract all --endpoint arguments and store host,port info */ std::vector tokens; boost::algorithm::split(tokens, endpoint, boost::is_any_of(",")); Dictionary::Ptr my_master_endpoint = new Dictionary(); if (tokens.size() > 1) { String host = tokens[1].Trim(); if (!host.IsEmpty()) my_master_endpoint->Set("host", host); } if (tokens.size() > 2) { String port = tokens[2].Trim(); if (!port.IsEmpty()) my_master_endpoint->Set("port", port); } String cn = tokens[0].Trim(); my_master_endpoint->Set("__name", cn); my_master_endpoint->Set("__type", "Endpoint"); /* save endpoint in master zone */ my_master_zone_members->Add(cn); my_config->Add(my_master_endpoint); } /* add the master zone to the config */ my_master_zone->Set("__name", master_zone_name); my_master_zone->Set("__type", "Zone"); my_master_zone->Set("endpoints", my_master_zone_members); my_config->Add(my_master_zone); /* store the local generated node configuration */ Dictionary::Ptr my_endpoint = new Dictionary(); Dictionary::Ptr my_zone = new Dictionary(); my_endpoint->Set("__name", new ConfigIdentifier("NodeName")); my_endpoint->Set("__type", "Endpoint"); Array::Ptr my_zone_members = new Array(); my_zone_members->Add(new ConfigIdentifier("NodeName")); my_zone->Set("__name", new ConfigIdentifier("ZoneName")); my_zone->Set("__type", "Zone"); my_zone->Set("parent", master_zone_name); //set the master zone as parent my_zone->Set("endpoints", my_zone_members); for (const String& globalzone : globalZones) { Dictionary::Ptr myGlobalZone = new Dictionary(); myGlobalZone->Set("__name", globalzone); myGlobalZone->Set("__type", "Zone"); myGlobalZone->Set("global", true); my_config->Add(myGlobalZone); } /* store the local config */ my_config->Add(my_endpoint); my_config->Add(my_zone); /* write the newly generated configuration */ String zones_path = Application::GetSysconfDir() + "/icinga2/zones.conf"; NodeUtility::WriteNodeConfigObjects(zones_path, my_config); return 0; } int NodeUtility::GenerateNodeMasterIcingaConfig(const std::vector& globalZones) { Array::Ptr my_config = new Array(); /* store the local generated node master configuration */ Dictionary::Ptr my_master_endpoint = new Dictionary(); Dictionary::Ptr my_master_zone = new Dictionary(); Array::Ptr my_master_zone_members = new Array(); my_master_endpoint->Set("__name", new ConfigIdentifier("NodeName")); my_master_endpoint->Set("__type", "Endpoint"); my_master_zone_members->Add(new ConfigIdentifier("NodeName")); my_master_zone->Set("__name", new ConfigIdentifier("ZoneName")); my_master_zone->Set("__type", "Zone"); my_master_zone->Set("endpoints", my_master_zone_members); /* store the local config */ my_config->Add(my_master_endpoint); my_config->Add(my_master_zone); for (const String& globalzone : globalZones) { Dictionary::Ptr myGlobalZone = new Dictionary(); myGlobalZone->Set("__name", globalzone); myGlobalZone->Set("__type", "Zone"); myGlobalZone->Set("global", true); my_config->Add(myGlobalZone); } /* write the newly generated configuration */ String zones_path = Application::GetSysconfDir() + "/icinga2/zones.conf"; NodeUtility::WriteNodeConfigObjects(zones_path, my_config); return 0; } bool NodeUtility::WriteNodeConfigObjects(const String& filename, const Array::Ptr& objects) { Log(LogInformation, "cli") << "Dumping config items to file '" << filename << "'."; /* create a backup first */ CreateBackupFile(filename); String path = Utility::DirName(filename); Utility::MkDirP(path, 0755); String user = ScriptGlobal::Get("RunAsUser"); String group = ScriptGlobal::Get("RunAsGroup"); if (!Utility::SetFileOwnership(path, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on path '" << path << "'. Verify it yourself!"; } if (!Utility::SetFileOwnership(filename, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on path '" << path << "'. Verify it yourself!"; } std::fstream fp; String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", 0644, fp); fp << "/*\n"; fp << " * Generated by Icinga 2 node setup commands\n"; fp << " * on " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n"; fp << " */\n\n"; ObjectLock olock(objects); for (const Dictionary::Ptr& object : objects) { SerializeObject(fp, object); } fp << std::endl; fp.close(); #ifdef _WIN32 _unlink(filename.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), filename.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } return true; } /* * We generally don't overwrite files without backup before */ bool NodeUtility::CreateBackupFile(const String& target, bool is_private) { if (!Utility::PathExists(target)) return false; String backup = target + ".orig"; if (Utility::PathExists(backup)) { Log(LogWarning, "cli") << "Backup file '" << backup << "' already exists. Skipping backup."; return false; } Utility::CopyFile(target, backup); #ifndef _WIN32 if (is_private) chmod(backup.CStr(), 0600); #endif /* _WIN32 */ Log(LogInformation, "cli") << "Created backup file '" << backup << "'."; return true; } void NodeUtility::SerializeObject(std::ostream& fp, const Dictionary::Ptr& object) { fp << "object "; ConfigWriter::EmitIdentifier(fp, object->Get("__type"), false); fp << " "; ConfigWriter::EmitValue(fp, 0, object->Get("__name")); fp << " {\n"; ObjectLock olock(object); for (const Dictionary::Pair& kv : object) { if (kv.first == "__type" || kv.first == "__name") continue; fp << "\t"; ConfigWriter::EmitIdentifier(fp, kv.first, true); fp << " = "; ConfigWriter::EmitValue(fp, 1, kv.second); fp << "\n"; } fp << "}\n\n"; } void NodeUtility::UpdateConstant(const String& name, const String& value) { String constantsFile = Application::GetSysconfDir() + "/icinga2/constants.conf"; std::ifstream ifp(constantsFile.CStr()); std::fstream ofp; String tempFile = Utility::CreateTempFile(constantsFile + ".XXXXXX", 0644, ofp); bool found = false; Log(LogInformation, "cli") << "Updating constants file '" << constantsFile << "'."; std::string line; while (std::getline(ifp, line)) { if (line.find("const " + name + " = ") != std::string::npos) { ofp << "const " + name + " = \"" + value + "\"\n"; found = true; } else ofp << line << "\n"; } if (!found) ofp << "const " + name + " = \"" + value + "\"\n"; ifp.close(); ofp.close(); #ifdef _WIN32 _unlink(constantsFile.CStr()); #endif /* _WIN32 */ if (rename(tempFile.CStr(), constantsFile.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(constantsFile)); } } icinga2-2.8.1/lib/cli/nodeutility.hpp000066400000000000000000000044771322762156600174630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NODEUTILITY_H #define NODEUTILITY_H #include "base/i2-base.hpp" #include "cli/i2-cli.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include "base/value.hpp" #include "base/string.hpp" #include namespace icinga { /** * @ingroup cli */ class I2_CLI_API NodeUtility { public: static bool CreateBackupFile(const String& target, bool is_private = false); static bool WriteNodeConfigObjects(const String& filename, const Array::Ptr& objects); static void UpdateConstant(const String& name, const String& value); /* node setup helpers */ static int GenerateNodeIcingaConfig(const std::vector& endpoints, const std::vector& globalZones); static int GenerateNodeMasterIcingaConfig(const std::vector& globalZones); private: NodeUtility(void); static void SerializeObject(std::ostream& fp, const Dictionary::Ptr& object); }; } #endif /* NODEUTILITY_H */ icinga2-2.8.1/lib/cli/nodewizardcommand.cpp000066400000000000000000000513711322762156600206050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/nodewizardcommand.hpp" #include "cli/nodeutility.hpp" #include "cli/featureutility.hpp" #include "cli/apisetuputility.hpp" #include "remote/apilistener.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/console.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/scriptglobal.hpp" #include "base/exception.hpp" #include #include #include #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("node/wizard", NodeWizardCommand); String NodeWizardCommand::GetDescription(void) const { return "Wizard for Icinga 2 node setup."; } String NodeWizardCommand::GetShortDescription(void) const { return "wizard for node setup"; } ImpersonationLevel NodeWizardCommand::GetImpersonationLevel(void) const { return ImpersonateRoot; } int NodeWizardCommand::GetMaxArguments(void) const { return -1; } void NodeWizardCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("verbose", "increase log level"); } /** * The entry point for the "node wizard" CLI command. * * @returns An exit status. */ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("verbose")) Logger::SetConsoleLogSeverity(LogCritical); /* * The wizard will get all information from the user, * and then call all required functions. */ std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundBlue) << "Welcome to the Icinga 2 Setup Wizard!\n" << "\n" << "We will guide you through all required configuration details.\n" << "\n" << ConsoleColorTag(Console_Normal); /* 0. master or node setup? * 1. Ticket * 2. Master information for autosigning * 3. Trusted cert location * 4. CN to use (defaults to FQDN) * 5. Local CA * 6. New self signed certificate * 7. Request signed certificate from master * 8. copy key information to /var/lib/icinga2/certs * 9. enable ApiListener feature * 10. generate zones.conf with endpoints and zone objects * 11. set NodeName = cn in constants.conf * 12. reload icinga2, or tell the user to */ std::string answer; /* master or satellite/client setup */ std::cout << ConsoleColorTag(Console_Bold) << "Please specify if this is a satellite/client setup " << "('n' installs a master setup)" << ConsoleColorTag(Console_Normal) << " [Y/n]: "; std::getline (std::cin, answer); boost::algorithm::to_lower(answer); String choice = answer; std::cout << "\n"; int res = 0; if (choice.Contains("n")) res = MasterSetup(); else res = ClientSetup(); if (res != 0) return res; std::cout << "\n"; std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen) << "Done.\n\n" << ConsoleColorTag(Console_Normal); std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundRed) << "Now restart your Icinga 2 daemon to finish the installation!\n" << ConsoleColorTag(Console_Normal); return 0; } int NodeWizardCommand::ClientSetup(void) const { std::string answer; String choice; bool connectToParent = false; std::cout << "Starting the Client/Satellite setup routine...\n\n"; /* CN */ std::cout << ConsoleColorTag(Console_Bold) << "Please specify the common name (CN)" << ConsoleColorTag(Console_Normal) << " [" << Utility::GetFQDN() << "]: "; std::getline(std::cin, answer); if (answer.empty()) answer = Utility::GetFQDN(); String cn = answer; cn = cn.Trim(); std::vector endpoints; String endpointBuffer; std::cout << ConsoleColorTag(Console_Bold) << "\nPlease specify the parent endpoint(s) (master or satellite) where this node should connect to:" << ConsoleColorTag(Console_Normal) << "\n"; String parentEndpointName; wizard_endpoint_loop_start: std::cout << ConsoleColorTag(Console_Bold) << "Master/Satellite Common Name" << ConsoleColorTag(Console_Normal) << " (CN from your master/satellite node): "; std::getline(std::cin, answer); if (answer.empty()) { Log(LogWarning, "cli", "Master/Satellite CN is required! Please retry."); goto wizard_endpoint_loop_start; } endpointBuffer = answer; endpointBuffer = endpointBuffer.Trim(); std::cout << "\nDo you want to establish a connection to the parent node " << ConsoleColorTag(Console_Bold) << "from this node?" << ConsoleColorTag(Console_Normal) << " [Y/n]: "; std::getline (std::cin, answer); boost::algorithm::to_lower(answer); choice = answer; String parentEndpointPort = "5665"; if (choice.Contains("n")) { connectToParent = false; Log(LogWarning, "cli", "Node to master/satellite connection setup skipped"); std::cout << "Connection setup skipped. Please configure your parent node to\n" << "connect to this node by setting the 'host' attribute for the node Endpoint object.\n"; } else { connectToParent = true; std::cout << ConsoleColorTag(Console_Bold) << "Please specify the master/satellite connection information:" << ConsoleColorTag(Console_Normal) << "\n" << ConsoleColorTag(Console_Bold) << "Master/Satellite endpoint host" << ConsoleColorTag(Console_Normal) << " (IP address or FQDN): "; std::getline(std::cin, answer); if (answer.empty()) { Log(LogWarning, "cli", "Please enter the parent endpoint (master/satellite) connection information."); goto wizard_endpoint_loop_start; } String tmp = answer; tmp = tmp.Trim(); endpointBuffer += "," + tmp; parentEndpointName = tmp; std::cout << ConsoleColorTag(Console_Bold) << "Master/Satellite endpoint port" << ConsoleColorTag(Console_Normal) << " [" << parentEndpointPort << "]: "; std::getline(std::cin, answer); if (!answer.empty()) parentEndpointPort = answer; endpointBuffer += "," + parentEndpointPort.Trim(); } endpoints.push_back(endpointBuffer); std::cout << ConsoleColorTag(Console_Bold) << "\nAdd more master/satellite endpoints?" << ConsoleColorTag(Console_Normal) << " [y/N]: "; std::getline (std::cin, answer); boost::algorithm::to_lower(answer); choice = answer; if (choice.Contains("y")) goto wizard_endpoint_loop_start; String parentHost, parentPort; for (const String& endpoint : endpoints) { std::vector tokens = endpoint.Split(","); if (tokens.size() > 1) parentHost = tokens[1]; if (tokens.size() > 2) parentPort = tokens[2]; } /* workaround for fetching the master cert */ String certsDir = ApiListener::GetCertsDir(); Utility::MkDirP(certsDir, 0700); String user = ScriptGlobal::Get("RunAsUser"); String group = ScriptGlobal::Get("RunAsGroup"); if (!Utility::SetFileOwnership(certsDir, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << certsDir << "'. Verify it yourself!"; } String nodeCert = certsDir + "/" + cn + ".crt"; String nodeKey = certsDir + "/" + cn + ".key"; if (Utility::PathExists(nodeKey)) NodeUtility::CreateBackupFile(nodeKey, true); if (Utility::PathExists(nodeCert)) NodeUtility::CreateBackupFile(nodeCert); if (PkiUtility::NewCert(cn, nodeKey, Empty, nodeCert) > 0) { Log(LogCritical, "cli") << "Failed to create new self-signed certificate for CN '" << cn << "'. Please try again."; return 1; } /* fix permissions: root -> icinga daemon user */ if (!Utility::SetFileOwnership(nodeKey, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << nodeKey << "'. Verify it yourself!"; } boost::shared_ptr trustedParentCert; /* Check whether we should connect to the parent node and present its trusted certificate. */ if (connectToParent) { //save-cert and store the master certificate somewhere Log(LogInformation, "cli") << "Fetching public certificate from master (" << parentHost << ", " << parentPort << "):\n"; trustedParentCert = PkiUtility::FetchCert(parentHost, parentPort); if (!trustedParentCert) { Log(LogCritical, "cli", "Peer did not present a valid certificate."); return 1; } std::cout << ConsoleColorTag(Console_Bold) << "Parent certificate information:\n" << ConsoleColorTag(Console_Normal) << PkiUtility::GetCertificateInformation(trustedParentCert) << ConsoleColorTag(Console_Bold) << "\nIs this information correct?" << ConsoleColorTag(Console_Normal) << " [y/N]: "; std::getline (std::cin, answer); boost::algorithm::to_lower(answer); if (answer != "y") { Log(LogWarning, "cli", "Process aborted."); return 1; } Log(LogInformation, "cli", "Received trusted parent certificate.\n"); } wizard_ticket: String nodeCA = certsDir + "/ca.crt"; String ticket; /* Check whether we can connect to the parent node and fetch the client and CA certificate. */ if (connectToParent) { std::cout << ConsoleColorTag(Console_Bold) << "\nPlease specify the request ticket generated on your Icinga 2 master (optional)." << ConsoleColorTag(Console_Normal) << "\n" << " (Hint: # icinga2 pki ticket --cn '" << cn << "'): "; std::getline(std::cin, answer); if (answer.empty()) { std::cout << ConsoleColorTag(Console_Bold) << "\n" << "No ticket was specified. Please approve the certificate signing request manually\n" << "on the master (see 'icinga2 ca list' and 'icinga2 ca sign --help' for details)." << ConsoleColorTag(Console_Normal) << "\n"; } ticket = answer; ticket = ticket.Trim(); if (ticket.IsEmpty()) { Log(LogInformation, "cli") << "Requesting certificate without a ticket."; } else { Log(LogInformation, "cli") << "Requesting certificate with ticket '" << ticket << "'."; } if (Utility::PathExists(nodeCA)) NodeUtility::CreateBackupFile(nodeCA); if (Utility::PathExists(nodeCert)) NodeUtility::CreateBackupFile(nodeCert); if (PkiUtility::RequestCertificate(parentHost, parentPort, nodeKey, nodeCert, nodeCA, trustedParentCert, ticket) > 0) { Log(LogCritical, "cli") << "Failed to fetch signed certificate from master '" << parentHost << ", " << parentPort << "'. Please try again."; goto wizard_ticket; } /* fix permissions (again) when updating the signed certificate */ if (!Utility::SetFileOwnership(nodeCert, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << nodeCert << "'. Verify it yourself!"; } } else { /* We cannot retrieve the parent certificate. * Tell the user to manually copy the ca.crt file * into LocalStateDir + "/lib/icinga2/certs" */ std::cout << ConsoleColorTag(Console_Bold) << "\nNo connection to the parent node was specified.\n\n" << "Please copy the public CA certificate from your master/satellite\n" << "into '" << nodeCA << "' before starting Icinga 2.\n" << ConsoleColorTag(Console_Normal); if (Utility::PathExists(nodeCA)) { std::cout << ConsoleColorTag(Console_Bold) << "\nFound public CA certificate in '" << nodeCA << "'.\n" << "Please verify that it is the same as on your master/satellite.\n" << ConsoleColorTag(Console_Normal); } } /* apilistener config */ std::cout << ConsoleColorTag(Console_Bold) << "\nPlease specify the API bind host/port" << ConsoleColorTag(Console_Normal) << " (optional):\n" << ConsoleColorTag(Console_Bold) << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: "; std::getline(std::cin, answer); String bindHost = answer; bindHost = bindHost.Trim(); std::cout << "Bind Port []: "; std::getline(std::cin, answer); String bindPort = answer; bindPort = bindPort.Trim(); std::cout << ConsoleColorTag(Console_Bold) << "\n" << "Accept config from parent node?" << ConsoleColorTag(Console_Normal) << " [y/N]: "; std::getline(std::cin, answer); boost::algorithm::to_lower(answer); choice = answer; String acceptConfig = choice.Contains("y") ? "true" : "false"; std::cout << ConsoleColorTag(Console_Bold) << "Accept commands from parent node?" << ConsoleColorTag(Console_Normal) << " [y/N]: "; std::getline(std::cin, answer); boost::algorithm::to_lower(answer); choice = answer; String acceptCommands = choice.Contains("y") ? "true" : "false"; std::cout << "\n"; std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen) << "Reconfiguring Icinga...\n" << ConsoleColorTag(Console_Normal); /* disable the notifications feature on client nodes */ Log(LogInformation, "cli", "Disabling the Notification feature."); std::vector disable; disable.push_back("notification"); FeatureUtility::DisableFeatures(disable); Log(LogInformation, "cli", "Enabling the ApiListener feature."); std::vector enable; enable.push_back("api"); FeatureUtility::EnableFeatures(enable); String apiConfPath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apiConfPath); std::fstream fp; String tempApiConfPath = Utility::CreateTempFile(apiConfPath + ".XXXXXX", 0644, fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" << " */\n" << "object ApiListener \"api\" {\n" << " accept_config = " << acceptConfig << "\n" << " accept_commands = " << acceptCommands << "\n"; if (!bindHost.IsEmpty()) fp << " bind_host = \"" << bindHost << "\"\n"; if (!bindPort.IsEmpty()) fp << " bind_port = " << bindPort << "\n"; fp << "}\n"; fp.close(); #ifdef _WIN32 _unlink(apiConfPath.CStr()); #endif /* _WIN32 */ if (rename(tempApiConfPath.CStr(), apiConfPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempApiConfPath)); } /* apilistener config */ Log(LogInformation, "cli", "Generating local zones.conf."); std::vector globalZones; globalZones.push_back("global-templates"); globalZones.push_back("director-global"); NodeUtility::GenerateNodeIcingaConfig(endpoints, globalZones); if (cn != Utility::GetFQDN()) { Log(LogWarning, "cli") << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!"; } Log(LogInformation, "cli", "Updating constants.conf."); String constants_file = Application::GetSysconfDir() + "/icinga2/constants.conf"; NodeUtility::CreateBackupFile(constants_file); NodeUtility::UpdateConstant("NodeName", cn); NodeUtility::UpdateConstant("ZoneName", cn); if (!ticket.IsEmpty()) { String ticketPath = ApiListener::GetCertsDir() + "/ticket"; String tempTicketPath = Utility::CreateTempFile(ticketPath + ".XXXXXX", 0600, fp); if (!Utility::SetFileOwnership(tempTicketPath, user, group)) { Log(LogWarning, "cli") << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << tempTicketPath << "'. Verify it yourself!"; } fp << ticket; fp.close(); #ifdef _WIN32 _unlink(ticketPath.CStr()); #endif /* _WIN32 */ if (rename(tempTicketPath.CStr(), ticketPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempTicketPath)); } } return 0; } int NodeWizardCommand::MasterSetup(void) const { std::string answer; String choice; std::cout << ConsoleColorTag(Console_Bold) << "Starting the Master setup routine...\n\n"; /* CN */ std::cout << ConsoleColorTag(Console_Bold) << "Please specify the common name" << ConsoleColorTag(Console_Normal) << " (CN) [" << Utility::GetFQDN() << "]: "; std::getline(std::cin, answer); if (answer.empty()) answer = Utility::GetFQDN(); String cn = answer; cn = cn.Trim(); std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen) << "Reconfiguring Icinga...\n" << ConsoleColorTag(Console_Normal); /* check whether the user wants to generate a new certificate or not */ String existing_path = ApiListener::GetCertsDir() + "/" + cn + ".crt"; std::cout << ConsoleColorTag(Console_Normal) << "Checking for existing certificates for common name '" << cn << "'...\n"; if (Utility::PathExists(existing_path)) { std::cout << "Certificate '" << existing_path << "' for CN '" << cn << "' already existing. Skipping certificate generation.\n"; } else { std::cout << "Certificates not yet generated. Running 'api setup' now.\n"; ApiSetupUtility::SetupMasterCertificates(cn); } std::cout << ConsoleColorTag(Console_Bold) << "Generating master configuration for Icinga 2.\n" << ConsoleColorTag(Console_Normal); ApiSetupUtility::SetupMasterApiUser(); if (!FeatureUtility::CheckFeatureEnabled("api")) ApiSetupUtility::SetupMasterEnableApi(); else std::cout << "'api' feature already enabled.\n"; std::vector globalZones; globalZones.push_back("global-templates"); globalZones.push_back("director-global"); NodeUtility::GenerateNodeMasterIcingaConfig(globalZones); /* apilistener config */ std::cout << ConsoleColorTag(Console_Bold) << "Please specify the API bind host/port (optional):\n"; std::cout << ConsoleColorTag(Console_Bold) << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: "; std::getline(std::cin, answer); String bindHost = answer; bindHost = bindHost.Trim(); std::cout << ConsoleColorTag(Console_Bold) << "Bind Port" << ConsoleColorTag(Console_Normal) << " []: "; std::getline(std::cin, answer); String bindPort = answer; bindPort = bindPort.Trim(); /* api feature is always enabled, check above */ String apiConfPath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apiConfPath); std::fstream fp; String tempApiConfPath = Utility::CreateTempFile(apiConfPath + ".XXXXXX", 0644, fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" << " */\n" << "object ApiListener \"api\" {\n"; if (!bindHost.IsEmpty()) fp << " bind_host = \"" << bindHost << "\"\n"; if (!bindPort.IsEmpty()) fp << " bind_port = " << bindPort << "\n"; fp << "\n" << " ticket_salt = TicketSalt\n" << "}\n"; fp.close(); #ifdef _WIN32 _unlink(apiConfPath.CStr()); #endif /* _WIN32 */ if (rename(tempApiConfPath.CStr(), apiConfPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempApiConfPath)); } /* update constants.conf with NodeName = CN + TicketSalt = random value */ if (cn != Utility::GetFQDN()) { Log(LogWarning, "cli") << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires an update for the NodeName constant in constants.conf!"; } Log(LogInformation, "cli", "Updating constants.conf."); String constants_file = Application::GetSysconfDir() + "/icinga2/constants.conf"; NodeUtility::CreateBackupFile(constants_file); NodeUtility::UpdateConstant("NodeName", cn); NodeUtility::UpdateConstant("ZoneName", cn); String salt = RandomString(16); NodeUtility::UpdateConstant("TicketSalt", salt); return 0; } icinga2-2.8.1/lib/cli/nodewizardcommand.hpp000066400000000000000000000044331322762156600206070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NODEWIZARDCOMMAND_H #define NODEWIZARDCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "node wizard" command. * * @ingroup cli */ class NodeWizardCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(NodeWizardCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMaxArguments(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; virtual ImpersonationLevel GetImpersonationLevel(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; private: int ClientSetup(void) const; int MasterSetup(void) const; }; } #endif /* NODEWIZARDCOMMAND_H */ icinga2-2.8.1/lib/cli/objectlistcommand.cpp000066400000000000000000000106051322762156600205740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/objectlistcommand.hpp" #include "cli/objectlistutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/convert.hpp" #include "base/configobject.hpp" #include "base/configtype.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/stdiostream.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/console.hpp" #include #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("object/list", ObjectListCommand); String ObjectListCommand::GetDescription(void) const { return "Lists all Icinga 2 objects."; } String ObjectListCommand::GetShortDescription(void) const { return "lists all objects"; } void ObjectListCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("count,c", "display object counts by types") ("name,n", po::value(), "filter by name matches") ("type,t", po::value(), "filter by type matches"); } /** * The entry point for the "object list" CLI command. * * @returns An exit status. */ int ObjectListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { String objectfile = Application::GetObjectsPath(); if (!Utility::PathExists(objectfile)) { Log(LogCritical, "cli") << "Cannot open objects file '" << Application::GetObjectsPath() << "'."; Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file."); return 1; } std::fstream fp; fp.open(objectfile.CStr(), std::ios_base::in); StdioStream::Ptr sfp = new StdioStream(&fp, false); unsigned long objects_count = 0; std::map type_count; String name_filter, type_filter; if (vm.count("name")) name_filter = vm["name"].as(); if (vm.count("type")) type_filter = vm["type"].as(); bool first = true; String message; StreamReadContext src; for (;;) { StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; ObjectListUtility::PrintObject(std::cout, first, message, type_count, name_filter, type_filter); objects_count++; } sfp->Close(); fp.close(); if (vm.count("count")) { if (!first) std::cout << "\n"; PrintTypeCounts(std::cout, type_count); std::cout << "\n"; } Log(LogNotice, "cli") << "Parsed " << objects_count << " objects."; return 0; } void ObjectListCommand::PrintTypeCounts(std::ostream& fp, const std::map& type_count) { typedef std::map::value_type TypeCount; for (const TypeCount& kv : type_count) { fp << "Found " << kv.second << " " << kv.first << " object"; if (kv.second != 1) fp << "s"; fp << ".\n"; } } icinga2-2.8.1/lib/cli/objectlistcommand.hpp000066400000000000000000000044111322762156600205770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTLISTCOMMAND_H #define OBJECTLISTCOMMAND_H #include "base/dictionary.hpp" #include "base/array.hpp" #include "cli/clicommand.hpp" #include namespace icinga { /** * The "object list" command. * * @ingroup cli */ class ObjectListCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(ObjectListCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; private: static void PrintTypeCounts(std::ostream& fp, const std::map& type_count); }; } #endif /* OBJECTLISTCOMMAND_H */ icinga2-2.8.1/lib/cli/objectlistutility.cpp000066400000000000000000000124551322762156600206660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/objectlistutility.hpp" #include "base/json.hpp" #include "base/utility.hpp" #include "base/console.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include #include using namespace icinga; bool ObjectListUtility::PrintObject(std::ostream& fp, bool& first, const String& message, std::map& type_count, const String& name_filter, const String& type_filter) { Dictionary::Ptr object = JsonDecode(message); Dictionary::Ptr properties = object->Get("properties"); String internal_name = properties->Get("__name"); String name = object->Get("name"); String type = object->Get("type"); if (!name_filter.IsEmpty() && !Utility::Match(name_filter, name) && !Utility::Match(name_filter, internal_name)) return false; if (!type_filter.IsEmpty() && !Utility::Match(type_filter, type)) return false; if (first) first = false; else fp << "\n"; Dictionary::Ptr debug_hints = object->Get("debug_hints"); fp << "Object '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << internal_name << ConsoleColorTag(Console_Normal) << "'"; fp << " of type '" << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << type << ConsoleColorTag(Console_Normal) << "':\n"; Array::Ptr di = object->Get("debug_info"); if (di) { fp << ConsoleColorTag(Console_ForegroundCyan) << " % declared in '" << di->Get(0) << "', lines " << di->Get(1) << ":" << di->Get(2) << "-" << di->Get(3) << ":" << di->Get(4) << ConsoleColorTag(Console_Normal) << "\n"; } PrintProperties(fp, properties, debug_hints, 2); type_count[type]++; return true; } void ObjectListUtility::PrintProperties(std::ostream& fp, const Dictionary::Ptr& props, const Dictionary::Ptr& debug_hints, int indent) { /* get debug hint props */ Dictionary::Ptr debug_hint_props; if (debug_hints) debug_hint_props = debug_hints->Get("properties"); int offset = 2; ObjectLock olock(props); for (const Dictionary::Pair& kv : props) { String key = kv.first; Value val = kv.second; /* key & value */ fp << std::setw(indent) << " " << "* " << ConsoleColorTag(Console_ForegroundGreen) << key << ConsoleColorTag(Console_Normal); /* extract debug hints for key */ Dictionary::Ptr debug_hints_fwd; if (debug_hint_props) debug_hints_fwd = debug_hint_props->Get(key); /* print dicts recursively */ if (val.IsObjectType()) { fp << "\n"; PrintHints(fp, debug_hints_fwd, indent + offset); PrintProperties(fp, val, debug_hints_fwd, indent + offset); } else { fp << " = "; PrintValue(fp, val); fp << "\n"; PrintHints(fp, debug_hints_fwd, indent + offset); } } } void ObjectListUtility::PrintHints(std::ostream& fp, const Dictionary::Ptr& debug_hints, int indent) { if (!debug_hints) return; Array::Ptr messages = debug_hints->Get("messages"); if (messages) { ObjectLock olock(messages); for (const Value& msg : messages) { PrintHint(fp, msg, indent); } } } void ObjectListUtility::PrintHint(std::ostream& fp, const Array::Ptr& msg, int indent) { fp << std::setw(indent) << " " << ConsoleColorTag(Console_ForegroundCyan) << "% " << msg->Get(0) << " modified in '" << msg->Get(1) << "', lines " << msg->Get(2) << ":" << msg->Get(3) << "-" << msg->Get(4) << ":" << msg->Get(5) << ConsoleColorTag(Console_Normal) << "\n"; } void ObjectListUtility::PrintValue(std::ostream& fp, const Value& val) { if (val.IsObjectType()) { PrintArray(fp, val); return; } if (val.IsString()) { fp << "\"" << Convert::ToString(val) << "\""; return; } if (val.IsEmpty()) { fp << "null"; return; } fp << Convert::ToString(val); } void ObjectListUtility::PrintArray(std::ostream& fp, const Array::Ptr& arr) { bool first = true; fp << "[ "; if (arr) { ObjectLock olock(arr); for (const Value& value : arr) { if (first) first = false; else fp << ", "; PrintValue(fp, value); } } if (!first) fp << " "; fp << "]"; } icinga2-2.8.1/lib/cli/objectlistutility.hpp000066400000000000000000000045311322762156600206670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTLISTUTILITY_H #define OBJECTLISTUTILITY_H #include "base/i2-base.hpp" #include "cli/i2-cli.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include "base/value.hpp" #include "base/string.hpp" namespace icinga { /** * @ingroup cli */ class I2_CLI_API ObjectListUtility { public: static bool PrintObject(std::ostream& fp, bool& first, const String& message, std::map& type_count, const String& name_filter, const String& type_filter); private: static void PrintProperties(std::ostream& fp, const Dictionary::Ptr& props, const Dictionary::Ptr& debug_hints, int indent); static void PrintHints(std::ostream& fp, const Dictionary::Ptr& debug_hints, int indent); static void PrintHint(std::ostream& fp, const Array::Ptr& msg, int indent); static void PrintValue(std::ostream& fp, const Value& val); static void PrintArray(std::ostream& fp, const Array::Ptr& arr); }; } #endif /* OBJECTLISTUTILITY_H */ icinga2-2.8.1/lib/cli/pkinewcacommand.cpp000066400000000000000000000040021322762156600202250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkinewcacommand.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_CLICOMMAND("pki/new-ca", PKINewCACommand); String PKINewCACommand::GetDescription(void) const { return "Sets up a new Certificate Authority."; } String PKINewCACommand::GetShortDescription(void) const { return "sets up a new CA"; } /** * The entry point for the "pki new-ca" CLI command. * * @returns An exit status. */ int PKINewCACommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { return PkiUtility::NewCa(); } icinga2-2.8.1/lib/cli/pkinewcacommand.hpp000066400000000000000000000036531322762156600202450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKINEWCACOMMAND_H #define PKINEWCACOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki new-ca" command. * * @ingroup cli */ class PKINewCACommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKINewCACommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKINEWCACOMMAND_H */ icinga2-2.8.1/lib/cli/pkinewcertcommand.cpp000066400000000000000000000064231322762156600206100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkinewcertcommand.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("pki/new-cert", PKINewCertCommand); String PKINewCertCommand::GetDescription(void) const { return "Creates a new Certificate Signing Request, a self-signed X509 certificate or both."; } String PKINewCertCommand::GetShortDescription(void) const { return "creates a new CSR"; } void PKINewCertCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("cn", po::value(), "Common Name") ("key", po::value(), "Key file path (output)") ("csr", po::value(), "CSR file path (optional, output)") ("cert", po::value(), "Certificate file path (optional, output)"); } std::vector PKINewCertCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "key" || argument == "csr" || argument == "cert") return GetBashCompletionSuggestions("file", word); else return CLICommand::GetArgumentSuggestions(argument, word); } /** * The entry point for the "pki new-cert" CLI command. * * @returns An exit status. */ int PKINewCertCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("cn")) { Log(LogCritical, "cli", "Common name (--cn) must be specified."); return 1; } if (!vm.count("key")) { Log(LogCritical, "cli", "Key file path (--key) must be specified."); return 1; } String csr, cert; if (vm.count("csr")) csr = vm["csr"].as(); if (vm.count("cert")) cert = vm["cert"].as(); return PkiUtility::NewCert(vm["cn"].as(), vm["key"].as(), csr, cert); } icinga2-2.8.1/lib/cli/pkinewcertcommand.hpp000066400000000000000000000043141322762156600206120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKINEWCERTCOMMAND_H #define PKINEWCERTCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki new-cert" command. * * @ingroup cli */ class PKINewCertCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKINewCertCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKINEWCERTCOMMAND_H */ icinga2-2.8.1/lib/cli/pkirequestcommand.cpp000066400000000000000000000104001322762156600206170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkirequestcommand.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/tlsutility.hpp" #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("pki/request", PKIRequestCommand); String PKIRequestCommand::GetDescription(void) const { return "Sends a PKI request to Icinga 2."; } String PKIRequestCommand::GetShortDescription(void) const { return "requests a certificate"; } void PKIRequestCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("key", po::value(), "Key file path (input)") ("cert", po::value(), "Certificate file path (input + output)") ("ca", po::value(), "CA file path (output)") ("trustedcert", po::value(), "Trusted certificate file path (input)") ("host", po::value(), "Icinga 2 host") ("port", po::value(), "Icinga 2 port") ("ticket", po::value(), "Icinga 2 PKI ticket"); } std::vector PKIRequestCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "key" || argument == "cert" || argument == "ca" || argument == "trustedcert") return GetBashCompletionSuggestions("file", word); else if (argument == "host") return GetBashCompletionSuggestions("hostname", word); else if (argument == "port") return GetBashCompletionSuggestions("service", word); else return CLICommand::GetArgumentSuggestions(argument, word); } /** * The entry point for the "pki request" CLI command. * * @returns An exit status. */ int PKIRequestCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("host")) { Log(LogCritical, "cli", "Icinga 2 host (--host) must be specified."); return 1; } if (!vm.count("key")) { Log(LogCritical, "cli", "Key input file path (--key) must be specified."); return 1; } if (!vm.count("cert")) { Log(LogCritical, "cli", "Certificate output file path (--cert) must be specified."); return 1; } if (!vm.count("ca")) { Log(LogCritical, "cli", "CA certificate output file path (--ca) must be specified."); return 1; } if (!vm.count("trustedcert")) { Log(LogCritical, "cli", "Trusted certificate input file path (--trustedcert) must be specified."); return 1; } String port = "5665"; String ticket; if (vm.count("port")) port = vm["port"].as(); if (vm.count("ticket")) ticket = vm["ticket"].as(); return PkiUtility::RequestCertificate(vm["host"].as(), port, vm["key"].as(), vm["cert"].as(), vm["ca"].as(), GetX509Certificate(vm["trustedcert"].as()), ticket); } icinga2-2.8.1/lib/cli/pkirequestcommand.hpp000066400000000000000000000043131322762156600206320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKIREQUESTCOMMAND_H #define PKIREQUESTCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki request" command. * * @ingroup cli */ class PKIRequestCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKIRequestCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKIREQUESTCOMMAND_H */ icinga2-2.8.1/lib/cli/pkisavecertcommand.cpp000066400000000000000000000103561322762156600207550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkisavecertcommand.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" #include "base/tlsutility.hpp" #include "base/console.hpp" #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("pki/save-cert", PKISaveCertCommand); String PKISaveCertCommand::GetDescription(void) const { return "Saves another Icinga 2 instance's certificate."; } String PKISaveCertCommand::GetShortDescription(void) const { return "saves another Icinga 2 instance's certificate"; } void PKISaveCertCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("key", po::value(), "Key file path (input), obsolete") ("cert", po::value(), "Certificate file path (input), obsolete") ("trustedcert", po::value(), "Trusted certificate file path (output)") ("host", po::value(), "Icinga 2 host") ("port", po::value()->default_value("5665"), "Icinga 2 port"); } std::vector PKISaveCertCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "key" || argument == "cert" || argument == "trustedcert") return GetBashCompletionSuggestions("file", word); else if (argument == "host") return GetBashCompletionSuggestions("hostname", word); else if (argument == "port") return GetBashCompletionSuggestions("service", word); else return CLICommand::GetArgumentSuggestions(argument, word); } /** * The entry point for the "pki save-cert" CLI command. * * @returns An exit status. */ int PKISaveCertCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("host")) { Log(LogCritical, "cli", "Icinga 2 host (--host) must be specified."); return 1; } if (!vm.count("trustedcert")) { Log(LogCritical, "cli", "Trusted certificate output file path (--trustedcert) must be specified."); return 1; } String host = vm["host"].as(); String port = vm["port"].as(); Log(LogInformation, "cli") << "Retrieving X.509 certificate for '" << host << ":" << port << "'."; boost::shared_ptr cert = PkiUtility::FetchCert(host, port); if (!cert) { Log(LogCritical, "cli", "Failed to fetch certificate from host."); return 1; } std::cout << PkiUtility::GetCertificateInformation(cert) << "\n"; std::cout << ConsoleColorTag(Console_ForegroundRed) << "***\n" << "*** You have to ensure that this certificate actually matches the parent\n" << "*** instance's certificate in order to avoid man-in-the-middle attacks.\n" << "***\n\n" << ConsoleColorTag(Console_Normal); return PkiUtility::WriteCert(cert, vm["trustedcert"].as()); } icinga2-2.8.1/lib/cli/pkisavecertcommand.hpp000066400000000000000000000043221322762156600207560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKISAVECERTCOMMAND_H #define PKISAVECERTCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki save-cert" command. * * @ingroup cli */ class PKISaveCertCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKISaveCertCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKISAVECERTCOMMAND_H */ icinga2-2.8.1/lib/cli/pkisigncsrcommand.cpp000066400000000000000000000060161322762156600206070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkisigncsrcommand.hpp" #include "remote/pkiutility.hpp" #include "base/logger.hpp" using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("pki/sign-csr", PKISignCSRCommand); String PKISignCSRCommand::GetDescription(void) const { return "Reads a Certificate Signing Request from stdin and prints a signed certificate on stdout."; } String PKISignCSRCommand::GetShortDescription(void) const { return "signs a CSR"; } void PKISignCSRCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("csr", po::value(), "CSR file path (input)") ("cert", po::value(), "Certificate file path (output)"); } std::vector PKISignCSRCommand::GetArgumentSuggestions(const String& argument, const String& word) const { if (argument == "csr" || argument == "cert") return GetBashCompletionSuggestions("file", word); else return CLICommand::GetArgumentSuggestions(argument, word); } /** * The entry point for the "pki sign-csr" CLI command. * * @returns An exit status. */ int PKISignCSRCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("csr")) { Log(LogCritical, "cli", "Certificate signing request file path (--csr) must be specified."); return 1; } if (!vm.count("cert")) { Log(LogCritical, "cli", "Certificate file path (--cert) must be specified."); return 1; } return PkiUtility::SignCsr(vm["csr"].as(), vm["cert"].as()); } icinga2-2.8.1/lib/cli/pkisigncsrcommand.hpp000066400000000000000000000043141322762156600206130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKISIGNCSRCOMMAND_H #define PKISIGNCSRCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki sign-csr" command. * * @ingroup cli */ class PKISignCSRCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKISignCSRCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKISIGNCSRCOMMAND_H */ icinga2-2.8.1/lib/cli/pkiticketcommand.cpp000066400000000000000000000054361322762156600204270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/pkiticketcommand.hpp" #include "remote/pkiutility.hpp" #include "cli/variableutility.hpp" #include "base/logger.hpp" #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("pki/ticket", PKITicketCommand); String PKITicketCommand::GetDescription(void) const { return "Generates an Icinga 2 ticket"; } String PKITicketCommand::GetShortDescription(void) const { return "generates a ticket"; } void PKITicketCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("cn", po::value(), "Certificate common name") ("salt", po::value(), "Ticket salt"); } /** * The entry point for the "pki ticket" CLI command. * * @returns An exit status. */ int PKITicketCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (!vm.count("cn")) { Log(LogCritical, "cli", "Common name (--cn) must be specified."); return 1; } String salt = VariableUtility::GetVariable("TicketSalt"); if (vm.count("salt")) salt = vm["salt"].as(); if (salt.IsEmpty()) { Log(LogCritical, "cli", "Ticket salt (--salt) must be specified."); return 1; } return PkiUtility::GenTicket(vm["cn"].as(), salt, std::cout); } icinga2-2.8.1/lib/cli/pkiticketcommand.hpp000066400000000000000000000041251322762156600204260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKITICKETCOMMAND_H #define PKITICKETCOMMAND_H #include "cli/clicommand.hpp" namespace icinga { /** * The "pki ticket" command. * * @ingroup cli */ class PKITicketCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(PKITicketCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* PKITICKETCOMMAND_H */ icinga2-2.8.1/lib/cli/troubleshootcommand.cpp000066400000000000000000000514561322762156600211740ustar00rootroot00000000000000/***************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" #include "base/console.hpp" #include "base/convert.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/objectlock.hpp" #include "base/stdiostream.hpp" #include "cli/daemonutility.hpp" #include "cli/featureutility.hpp" #include "cli/objectlistutility.hpp" #include "cli/troubleshootcommand.hpp" #include "cli/variableutility.hpp" #include "config/configitembuilder.hpp" #include #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("troubleshoot", TroubleshootCommand); String TroubleshootCommand::GetDescription(void) const { return "Collect logs and other relevant information for troubleshooting purposes."; } String TroubleshootCommand::GetShortDescription(void) const { return "collect information for troubleshooting"; } class TroubleshootCommand::InfoLog { public: InfoLog(const String& path, const bool cons) { m_Console = cons; m_ConsoleType = Console_Dumb; if (m_Console) { m_Stream = new std::ostream(std::cout.rdbuf()); #ifndef _WIN32 m_ConsoleType = Console_VT100; #else /*_WIN32*/ m_ConsoleType = Console_Windows; #endif /*_WIN32*/ } else { std::ofstream *ofs = new std::ofstream(); ofs->open(path.CStr(), std::ios::out | std::ios::trunc); m_Stream = ofs; } } ~InfoLog(void) { delete m_Stream; } void WriteLine(const LogSeverity sev, const int color, const String& str) { if (!m_Console) Log(sev, "troubleshoot", str); if (sev == LogWarning) { *m_Stream << '\n' << ConsoleColorTag(Console_ForegroundYellow, m_ConsoleType) << std::string(24, '#') << '\n' << ConsoleColorTag(Console_Normal, m_ConsoleType) << str << ConsoleColorTag(Console_ForegroundYellow, m_ConsoleType) << std::string(24, '#') << "\n\n" << ConsoleColorTag(Console_Normal, m_ConsoleType); } else if (sev == LogCritical) { *m_Stream << '\n' << ConsoleColorTag(Console_ForegroundRed, m_ConsoleType) << std::string(24, '#') << '\n' << ConsoleColorTag(Console_Normal, m_ConsoleType) << str << ConsoleColorTag(Console_ForegroundRed, m_ConsoleType) << std::string(24, '#') << "\n\n" << ConsoleColorTag(Console_Normal, m_ConsoleType); } else *m_Stream << ConsoleColorTag(color, m_ConsoleType) << str << ConsoleColorTag(Console_Normal, m_ConsoleType); } bool GetStreamHealth(void) const { return m_Stream->good(); } private: bool m_Console; ConsoleType m_ConsoleType; std::ostream *m_Stream; }; class TroubleshootCommand::InfoLogLine { public: InfoLogLine(InfoLog& log, int col = Console_Normal, LogSeverity sev = LogInformation) : m_Log(log), m_Color(col), m_Sev(sev) {} ~InfoLogLine(void) { m_Log.WriteLine(m_Sev, m_Color, m_String.str()); } template InfoLogLine& operator<<(const T& info) { m_String << info; return *this; } private: std::ostringstream m_String; InfoLog& m_Log; int m_Color; LogSeverity m_Sev; }; bool TroubleshootCommand::GeneralInfo(InfoLog& log, const boost::program_options::variables_map& vm) { InfoLogLine(log, Console_ForegroundBlue) << std::string(14, '=') << " GENERAL INFORMATION " << std::string(14, '=') << "\n\n"; //Application::DisplayInfoMessage() but formatted InfoLogLine(log) << "\tApplication version: " << Application::GetAppVersion() << '\n' << "\tInstallation root: " << Application::GetPrefixDir() << '\n' << "\tSysconf directory: " << Application::GetSysconfDir() << '\n' << "\tRun directory: " << Application::GetRunDir() << '\n' << "\tLocal state directory: " << Application::GetLocalStateDir() << '\n' << "\tPackage data directory: " << Application::GetPkgDataDir() << '\n' << "\tState path: " << Application::GetStatePath() << '\n' << "\tObjects path: " << Application::GetObjectsPath() << '\n' << "\tVars path: " << Application::GetVarsPath() << '\n' << "\tPID path: " << Application::GetPidPath() << '\n'; InfoLogLine(log) << '\n'; return true; } bool TroubleshootCommand::FeatureInfo(InfoLog& log, const boost::program_options::variables_map& vm) { TroubleshootCommand::CheckFeatures(log); //TODO Check whether active features are operational. return true; } bool TroubleshootCommand::ObjectInfo(InfoLog& log, const boost::program_options::variables_map& vm, Dictionary::Ptr& logs, const String& path) { InfoLogLine(log, Console_ForegroundBlue) << std::string(14, '=') << " OBJECT INFORMATION " << std::string(14, '=') << "\n\n"; String objectfile = Application::GetObjectsPath(); std::set configs; if (!Utility::PathExists(objectfile)) { InfoLogLine(log, 0, LogCritical) << "Cannot open object file '" << objectfile << "'.\n" << "FAILED: This probably means you have a fault configuration.\n"; return false; } else { InfoLog *OFile = NULL; bool OConsole = false; if (vm.count("include-objects")) { if (vm.count("console")) OConsole = true; else { OFile = new InfoLog(path+"-objects", false); if (!OFile->GetStreamHealth()) { InfoLogLine(log, 0, LogWarning) << "Failed to open Object-write-stream, not printing objects\n\n"; delete OFile; OFile = NULL; } else InfoLogLine(log) << "Printing all objects to " << path+"-objects\n"; } } CheckObjectFile(objectfile, log, OFile, OConsole, logs, configs); delete OFile; } if (vm.count("include-vars")) { if (vm.count("console")) { InfoLogLine(log, Console_ForegroundBlue) << "\n[begin: varsfile]\n"; if (!PrintVarsFile(path, true)) InfoLogLine(log, 0, LogWarning) << "Failed to print vars file\n"; InfoLogLine(log, Console_ForegroundBlue) << "[end: varsfile]\n"; } else { if (PrintVarsFile(path, false)) InfoLogLine(log) << "Successfully printed all variables to " << path+"-vars\n"; else InfoLogLine(log, 0, LogWarning) << "Failed to print vars to " << path+"-vars\n"; } } InfoLogLine(log) << '\n'; return true; } bool TroubleshootCommand::ReportInfo(InfoLog& log, const boost::program_options::variables_map& vm, Dictionary::Ptr& logs) { InfoLogLine(log, Console_ForegroundBlue) << std::string(14, '=') << " LOGS AND CRASH REPORTS " << std::string(14, '=') << "\n\n"; PrintLoggers(log, logs); PrintCrashReports(log); InfoLogLine(log) << '\n'; return true; } bool TroubleshootCommand::ConfigInfo(InfoLog& log, const boost::program_options::variables_map& vm) { InfoLogLine(log, Console_ForegroundBlue) << std::string(14, '=') << " CONFIGURATION FILES " << std::string(14, '=') << "\n\n"; InfoLogLine(log) << "A collection of important configuration files follows, please make sure to remove any sensitive data such as credentials, internal company names, etc\n"; if (!PrintFile(log, Application::GetSysconfDir() + "/icinga2/icinga2.conf")) { InfoLogLine(log, 0, LogWarning) << "icinga2.conf not found, therefore skipping validation.\n" << "If you are using an icinga2.conf somewhere but the default path please validate it via 'icinga2 daemon -C -c \"path\to/icinga2.conf\"'\n" << "and provide it with your support request.\n"; } if (!PrintFile(log, Application::GetSysconfDir() + "/icinga2/zones.conf")) { InfoLogLine(log, 0, LogWarning) << "zones.conf not found.\n" << "If you are using a zones.conf somewhere but the default path please provide it with your support request\n"; } InfoLogLine(log) << '\n'; return true; } /*Print the last *numLines* of *file* to *os* */ int TroubleshootCommand::Tail(const String& file, int numLines, InfoLog& log) { boost::circular_buffer ringBuf(numLines); std::ifstream text; text.open(file.CStr(), std::ifstream::in); if (!text.good()) return 0; std::string line; int lines = 0; while (std::getline(text, line)) { ringBuf.push_back(line); lines++; } if (lines < numLines) numLines = lines; InfoLogLine(log, Console_ForegroundCyan) << "[begin: '" << file << "' line: " << lines-numLines << "]\n"; for (int k = 0; k < numLines; k++) { InfoLogLine(log, Console_ForegroundCyan) << "# "; InfoLogLine(log) << ringBuf[k] << '\n'; } text.close(); InfoLogLine(log, Console_ForegroundCyan) << "[end: '" << file << "' line: " << lines << "]\n\n"; return numLines; } bool TroubleshootCommand::CheckFeatures(InfoLog& log) { Dictionary::Ptr features = new Dictionary; std::vector disabled_features; std::vector enabled_features; if (!FeatureUtility::GetFeatures(disabled_features, true) || !FeatureUtility::GetFeatures(enabled_features, false)) { InfoLogLine(log, 0, LogCritical) << "Failed to collect enabled and/or disabled features. Check\n" << FeatureUtility::GetFeaturesAvailablePath() << '\n' << FeatureUtility::GetFeaturesEnabledPath() << '\n'; return false; } for (const String feature : disabled_features) features->Set(feature, false); for (const String feature : enabled_features) features->Set(feature, true); InfoLogLine(log) << "Enabled features:\n"; InfoLogLine(log, Console_ForegroundGreen) << '\t' << boost::algorithm::join(enabled_features, " ") << '\n'; InfoLogLine(log) << "Disabled features:\n"; InfoLogLine(log, Console_ForegroundRed) << '\t' << boost::algorithm::join(disabled_features, " ") << '\n'; if (!features->Get("checker").ToBool()) InfoLogLine(log, 0, LogWarning) << "checker is disabled, no checks can be run from this instance\n"; if (!features->Get("mainlog").ToBool()) InfoLogLine(log, 0, LogWarning) << "mainlog is disabled, please activate it and rerun icinga2\n"; if (!features->Get("debuglog").ToBool()) InfoLogLine(log, 0, LogWarning) << "debuglog is disabled, please activate it and rerun icinga2\n"; return true; } void TroubleshootCommand::GetLatestReport(const String& filename, time_t& bestTimestamp, String& bestFilename) { #ifdef _WIN32 struct _stat buf; if (_stat(filename.CStr(), &buf)) return; #else struct stat buf; if (stat(filename.CStr(), &buf)) return; #endif /*_WIN32*/ if (buf.st_mtime > bestTimestamp) { bestTimestamp = buf.st_mtime; bestFilename = filename; } } bool TroubleshootCommand::PrintCrashReports(InfoLog& log) { String spath = Application::GetLocalStateDir() + "/log/icinga2/crash/report.*"; time_t bestTimestamp = 0; String bestFilename; try { Utility::Glob(spath, boost::bind(&GetLatestReport, _1, boost::ref(bestTimestamp), boost::ref(bestFilename)), GlobFile); } #ifdef _WIN32 catch (win32_error &ex) { if (int const * err = boost::get_error_info(ex)) { if (*err != 3) {//Error code for path does not exist InfoLogLine(log, 0, LogWarning) << Application::GetLocalStateDir() << "/log/icinga2/crash/ does not exist\n"; return false; } } InfoLogLine(log, 0, LogWarning) << "Error printing crash reports\n"; return false; } #else catch (...) { InfoLogLine(log, 0, LogWarning) << "Error printing crash reports.\n" << "Does " << Application::GetLocalStateDir() << "/log/icinga2/crash/ exist?\n"; return false; } #endif /*_WIN32*/ if (!bestTimestamp) InfoLogLine(log, Console_ForegroundYellow) << "No crash logs found in " << Application::GetLocalStateDir().CStr() << "/log/icinga2/crash/\n\n"; else { InfoLogLine(log) << "Latest crash report is from " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", Utility::GetTime()) << '\n' << "File: " << bestFilename << "\n\n"; PrintFile(log, bestFilename); InfoLogLine(log) << '\n'; } return true; } bool TroubleshootCommand::PrintFile(InfoLog& log, const String& path) { std::ifstream text; text.open(path.CStr(), std::ifstream::in); if (!text.is_open()) return false; std::string line; InfoLogLine(log, Console_ForegroundCyan) << "[begin: '" << path << "']\n"; while (std::getline(text, line)) { InfoLogLine(log, Console_ForegroundCyan) << "# "; InfoLogLine(log) << line << '\n'; } InfoLogLine(log, Console_ForegroundCyan) << "[end: '" << path << "']\n"; return true; } bool TroubleshootCommand::CheckConfig(void) { std::vector configs; configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf"); return DaemonUtility::ValidateConfigFiles(configs, Application::GetObjectsPath()); } //print is supposed allow the user to print the object file void TroubleshootCommand::CheckObjectFile(const String& objectfile, InfoLog& log, InfoLog *OFile, const bool objectConsole, Dictionary::Ptr& logs, std::set& configs) { InfoLogLine(log) << "Checking object file from " << objectfile << '\n'; std::fstream fp; fp.open(objectfile.CStr(), std::ios_base::in); if (!fp.is_open()) { InfoLogLine(log, 0, LogWarning) << "Could not open object file.\n"; return; } StdioStream::Ptr sfp = new StdioStream(&fp, false); String::SizeType typeL = 0, countTotal = 0; String message; StreamReadContext src; StreamReadStatus srs; std::map type_count; bool first = true; std::stringstream sStream; if (objectConsole) InfoLogLine(log, Console_ForegroundBlue) << "\n[begin: objectfile]\n"; while ((srs = NetString::ReadStringFromStream(sfp, &message, src)) != StatusEof) { if (srs != StatusNewItem) continue; if (objectConsole) { ObjectListUtility::PrintObject(std::cout, first, message, type_count, "", ""); } else { ObjectListUtility::PrintObject(sStream, first, message, type_count, "", ""); if (OFile) { InfoLogLine(*OFile) << sStream.str(); sStream.flush(); } } Dictionary::Ptr object = JsonDecode(message); Dictionary::Ptr properties = object->Get("properties"); String name = object->Get("name"); String type = object->Get("type"); //Find longest typename for padding typeL = type.GetLength() > typeL ? type.GetLength() : typeL; countTotal++; Array::Ptr debug_info = object->Get("debug_info"); if (debug_info) configs.insert(debug_info->Get(0)); if (Utility::Match(type, "FileLogger")) { Dictionary::Ptr debug_hints = object->Get("debug_hints"); Dictionary::Ptr properties = object->Get("properties"); ObjectLock olock(properties); for (const Dictionary::Pair& kv : properties) { if (Utility::Match(kv.first, "path")) logs->Set(name, kv.second); } } } if (objectConsole) InfoLogLine(log, Console_ForegroundBlue) << "\n[end: objectfile]\n"; if (!countTotal) { InfoLogLine(log, 0, LogCritical) << "No objects found in objectfile.\n"; return; } //Print objects with count InfoLogLine(log) << "Found the " << countTotal << " objects:\n" << " Type" << std::string(typeL-4, ' ') << " : Count\n"; for (const Dictionary::Pair& kv : type_count) { InfoLogLine(log) << " " << kv.first << std::string(typeL - kv.first.GetLength(), ' ') << " : " << kv.second << '\n'; } InfoLogLine(log) << '\n'; TroubleshootCommand::PrintObjectOrigin(log, configs); } bool TroubleshootCommand::PrintVarsFile(const String& path, const bool console) { if (!console) { std::ofstream *ofs = new std::ofstream(); ofs->open((path+"-vars").CStr(), std::ios::out | std::ios::trunc); if (!ofs->is_open()) return false; else VariableUtility::PrintVariables(*ofs); ofs->close(); } else VariableUtility::PrintVariables(std::cout); return true; } void TroubleshootCommand::PrintLoggers(InfoLog& log, Dictionary::Ptr& logs) { if (!logs->GetLength()) { InfoLogLine(log, 0, LogWarning) << "No loggers found, check whether you enabled any logging features\n"; } else { InfoLogLine(log) << "Getting the last 20 lines of " << logs->GetLength() << " FileLogger objects.\n"; ObjectLock ulock(logs); for (const Dictionary::Pair& kv : logs) { InfoLogLine(log) << "Logger " << kv.first << " at path: " << kv.second << '\n'; if (!Tail(kv.second, 20, log)) { InfoLogLine(log, 0, LogWarning) << kv.second << " either does not exist or is empty\n"; } } } } void TroubleshootCommand::PrintObjectOrigin(InfoLog& log, const std::set& configSet) { InfoLogLine(log) << "The objects origins are:\n"; for (const String& config : configSet) { InfoLogLine(log) << " " << config << '\n'; } } void TroubleshootCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("console,c", "print to console instead of file") ("output,o", boost::program_options::value(), "path to output file") ("include-objects", "Print the whole objectfile (like `object list`)") ("include-vars", "Print all Variables (like `variable list`)") ; } int TroubleshootCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { #ifdef _WIN32 //Dislikes ':' in filenames String path = Application::GetLocalStateDir() + "/log/icinga2/troubleshooting-" + Utility::FormatDateTime("%Y-%m-%d_%H-%M-%S", Utility::GetTime()) + ".log"; #else String path = Application::GetLocalStateDir() + "/log/icinga2/troubleshooting-" + Utility::FormatDateTime("%Y-%m-%d_%H:%M:%S", Utility::GetTime()) + ".log"; #endif /*_WIN32*/ InfoLog *log; Logger::SetConsoleLogSeverity(LogWarning); if (vm.count("output")) path = vm["output"].as(); if (vm.count("console")) { log = new InfoLog("", true); } else { log = new InfoLog(path, false); if (!log->GetStreamHealth()) { Log(LogCritical, "troubleshoot", "Failed to open file to write: " + path); delete log; return 3; } } String appName = Utility::BaseName(Application::GetArgV()[0]); double goTime = Utility::GetTime(); InfoLogLine(*log) << appName << " -- Troubleshooting help:\n" << "Should you run into problems with Icinga please add this file to your help request\n" << "Started collection at " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", goTime) << "\n"; InfoLogLine(*log, Console_ForegroundMagenta) << std::string(52, '=') << "\n\n"; if (appName.GetLength() > 3 && appName.SubStr(0, 3) == "lt-") appName = appName.SubStr(3, appName.GetLength() - 3); Dictionary::Ptr logs = new Dictionary; if (!GeneralInfo(*log, vm) || !FeatureInfo(*log, vm) || !ObjectInfo(*log, vm, logs, path) || !ReportInfo(*log, vm, logs) || !ConfigInfo(*log, vm)) { InfoLogLine(*log, 0, LogCritical) << "Could not recover from critical failure, exiting.\n"; delete log; return 3; } double endTime = Utility::GetTime(); InfoLogLine(*log, Console_ForegroundMagenta) << std::string(52, '=') << '\n'; InfoLogLine(*log, Console_ForegroundGreen) << "Finished collection at " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "\nTook " << Convert::ToString(endTime - goTime) << " seconds\n"; if (!vm.count("console")) { std::cout << "Started collection at " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", goTime) << "\n" << "Finished collection at " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "\nTook " << Convert::ToString(endTime - goTime) << " seconds\n\n"; std::cout << "General log file: '" << path << "'\n"; if (vm.count("include-vars")) std::cout << "Vars log file: '" << path << "-vars'\n"; if (vm.count("include-objects")) std::cout << "Objects log file: '" << path << "-objects'\n"; std::cout << "\nPlease compress the files before uploading them,, for example:\n" << " # tar czf troubleshoot.tar.gz " << path << "*\n"; } delete log; return 0; } icinga2-2.8.1/lib/cli/troubleshootcommand.hpp000066400000000000000000000066341322762156600211770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TROUBLESHOOTCOMMAND_H #define TROUBLESHOOTCOMMAND_H #include "cli/clicommand.hpp" #include "base/i2-base.hpp" #include "base/dictionary.hpp" namespace icinga { /** * The "troubleshoot" command. * * @ingroup cli */ class TroubleshootCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(TroubleshootCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; private: class InfoLog; class InfoLogLine; static bool GeneralInfo(InfoLog& log, const boost::program_options::variables_map& vm); static bool FeatureInfo(InfoLog& log, const boost::program_options::variables_map& vm); static bool ObjectInfo(InfoLog& log, const boost::program_options::variables_map& vm, Dictionary::Ptr& logs, const String& path); static bool ReportInfo(InfoLog& log, const boost::program_options::variables_map& vm, Dictionary::Ptr& logs); static bool ConfigInfo(InfoLog& log, const boost::program_options::variables_map& vm); static int Tail(const String& file, const int numLines, InfoLog& log); static bool CheckFeatures(InfoLog& log); static void GetLatestReport(const String& filename, time_t& bestTimestamp, String& bestFilename); static bool PrintCrashReports(InfoLog& log); static bool PrintFile(InfoLog& log, const String& path); static bool CheckConfig(void); static void CheckObjectFile(const String& objectfile, InfoLog& log, InfoLog *OFile, const bool objectConsole, Dictionary::Ptr& logs, std::set& configs); static bool PrintVarsFile(const String& path, const bool console); static void PrintLoggers(InfoLog& log, Dictionary::Ptr& logs); static void PrintObjectOrigin(InfoLog& log, const std::set& configSet); }; } #endif /* TROUBLESHOOTCOMMAND_H */ icinga2-2.8.1/lib/cli/variablegetcommand.cpp000066400000000000000000000065011322762156600207170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/variablegetcommand.hpp" #include "cli/variableutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/convert.hpp" #include "base/configobject.hpp" #include "base/configtype.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/stdiostream.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/console.hpp" #include "base/scriptglobal.hpp" #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("variable/get", VariableGetCommand); String VariableGetCommand::GetDescription(void) const { return "Prints the value of an Icinga 2 variable."; } String VariableGetCommand::GetShortDescription(void) const { return "gets a variable"; } void VariableGetCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { visibleDesc.add_options() ("current", "Uses the current value (i.e. from the running process, rather than from the vars file)"); } int VariableGetCommand::GetMinArguments(void) const { return 1; } /** * The entry point for the "variable get" CLI command. * * @returns An exit status. */ int VariableGetCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { if (vm.count("current")) { std::cout << ScriptGlobal::Get(ap[0], &Empty) << "\n"; return 0; } String varsfile = Application::GetVarsPath(); if (!Utility::PathExists(varsfile)) { Log(LogCritical, "cli") << "Cannot open variables file '" << varsfile << "'."; Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file."); return 1; } Value value = VariableUtility::GetVariable(ap[0]); std::cout << value << "\n"; return 0; } icinga2-2.8.1/lib/cli/variablegetcommand.hpp000066400000000000000000000043271322762156600207300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VARIABLEGETCOMMAND_H #define VARIABLEGETCOMMAND_H #include "base/dictionary.hpp" #include "base/array.hpp" #include "cli/clicommand.hpp" #include namespace icinga { /** * The "variable get" command. * * @ingroup cli */ class VariableGetCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(VariableGetCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int GetMinArguments(void) const override; void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; }; } #endif /* VARIABLEGETCOMMAND_H */ icinga2-2.8.1/lib/cli/variablelistcommand.cpp000066400000000000000000000052641322762156600211200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/variablelistcommand.hpp" #include "cli/variableutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/convert.hpp" #include "base/configobject.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/console.hpp" #include #include #include #include using namespace icinga; namespace po = boost::program_options; REGISTER_CLICOMMAND("variable/list", VariableListCommand); String VariableListCommand::GetDescription(void) const { return "Lists all Icinga 2 variables."; } String VariableListCommand::GetShortDescription(void) const { return "lists all variables"; } /** * The entry point for the "variable list" CLI command. * * @returns An exit status. */ int VariableListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { String varsfile = Application::GetVarsPath(); if (!Utility::PathExists(varsfile)) { Log(LogCritical, "cli") << "Cannot open variables file '" << varsfile << "'."; Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file."); return 1; } VariableUtility::PrintVariables(std::cout); return 0; } icinga2-2.8.1/lib/cli/variablelistcommand.hpp000066400000000000000000000041341322762156600211200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VARIABLELISTCOMMAND_H #define VARIABLELISTCOMMAND_H #include "base/dictionary.hpp" #include "base/array.hpp" #include "cli/clicommand.hpp" #include namespace icinga { /** * The "variable list" command. * * @ingroup cli */ class VariableListCommand : public CLICommand { public: DECLARE_PTR_TYPEDEFS(VariableListCommand); virtual String GetDescription(void) const override; virtual String GetShortDescription(void) const override; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; private: static void PrintVariable(std::ostream& fp, const String& message); }; } #endif /* VARIABLELISTCOMMAND_H */ icinga2-2.8.1/lib/cli/variableutility.cpp000066400000000000000000000057421322762156600203120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "cli/variableutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/utility.hpp" #include "base/stdiostream.hpp" #include "base/netstring.hpp" #include "base/json.hpp" #include "remote/jsonrpc.hpp" #include using namespace icinga; Value VariableUtility::GetVariable(const String& name) { String varsfile = Application::GetVarsPath(); std::fstream fp; fp.open(varsfile.CStr(), std::ios_base::in); StdioStream::Ptr sfp = new StdioStream(&fp, false); String message; StreamReadContext src; for (;;) { StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; Dictionary::Ptr variable = JsonDecode(message); if (variable->Get("name") == name) { return variable->Get("value"); } } return Empty; } void VariableUtility::PrintVariables(std::ostream& outfp) { String varsfile = Application::GetVarsPath(); std::fstream fp; fp.open(varsfile.CStr(), std::ios_base::in); StdioStream::Ptr sfp = new StdioStream(&fp, false); unsigned long variables_count = 0; String message; StreamReadContext src; for (;;) { StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; Dictionary::Ptr variable = JsonDecode(message); outfp << variable->Get("name") << " = " << variable->Get("value") << "\n"; variables_count++; } sfp->Close(); fp.close(); Log(LogNotice, "cli") << "Parsed " << variables_count << " variables."; } icinga2-2.8.1/lib/cli/variableutility.hpp000066400000000000000000000035341322762156600203140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VARIABLEUTILITY_H #define VARIABLEUTILITY_H #include "base/i2-base.hpp" #include "cli/i2-cli.hpp" #include "base/dictionary.hpp" #include "base/string.hpp" #include namespace icinga { /** * @ingroup cli */ class I2_CLI_API VariableUtility { public: static Value GetVariable(const String& name); static void PrintVariables(std::ostream& outfp); private: VariableUtility(void); }; } #endif /* VARIABLEUTILITY_H */ icinga2-2.8.1/lib/compat/000077500000000000000000000000001322762156600151015ustar00rootroot00000000000000icinga2-2.8.1/lib/compat/CMakeLists.txt000066400000000000000000000051761322762156600176520ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(checkresultreader.ti checkresultreader.tcpp checkresultreader.thpp) mkclass_target(compatlogger.ti compatlogger.tcpp compatlogger.thpp) mkclass_target(externalcommandlistener.ti externalcommandlistener.tcpp externalcommandlistener.thpp) mkclass_target(statusdatawriter.ti statusdatawriter.tcpp statusdatawriter.thpp) set(compat_SOURCES checkresultreader.cpp checkresultreader.thpp compatlogger.cpp compatlogger.thpp externalcommandlistener.cpp externalcommandlistener.thpp statusdatawriter.cpp statusdatawriter.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(compat compat compat_SOURCES) endif() add_library(compat SHARED ${compat_SOURCES}) target_link_libraries(compat ${Boost_LIBRARIES} base config icinga) set_target_properties ( compat PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_COMPAT_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/command.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/compatlog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/statusdata.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install(TARGETS compat RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/icinga2/compat/archives\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/spool/icinga2\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ICINGA2_RUNDIR}/icinga2/cmd\")") set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/compat/checkresultreader.cpp000066400000000000000000000143341322762156600213110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/compatutility.hpp" #include "compat/checkresultreader.hpp" #include "compat/checkresultreader.tcpp" #include "icinga/service.hpp" #include "icinga/pluginutility.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/application.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/context.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(CheckResultReader); REGISTER_STATSFUNCTION(CheckResultReader, &CheckResultReader::StatsFunc); void CheckResultReader::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const CheckResultReader::Ptr& checkresultreader : ConfigType::GetObjectsByType()) { nodes->Set(checkresultreader->GetName(), 1); //add more stats } status->Set("checkresultreader", nodes); } /** * @threadsafety Always. */ void CheckResultReader::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "CheckResultReader") << "'" << GetName() << "' started."; #ifndef _WIN32 m_ReadTimer = new Timer(); m_ReadTimer->OnTimerExpired.connect(boost::bind(&CheckResultReader::ReadTimerHandler, this)); m_ReadTimer->SetInterval(5); m_ReadTimer->Start(); #endif /* _WIN32 */ } /** * @threadsafety Always. */ void CheckResultReader::Stop(bool runtimeRemoved) { Log(LogInformation, "CheckResultReader") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } /** * @threadsafety Always. */ void CheckResultReader::ReadTimerHandler(void) const { CONTEXT("Processing check result files in '" + GetSpoolDir() + "'"); Utility::Glob(GetSpoolDir() + "/c??????.ok", boost::bind(&CheckResultReader::ProcessCheckResultFile, this, _1), GlobFile); } void CheckResultReader::ProcessCheckResultFile(const String& path) const { CONTEXT("Processing check result file '" + path + "'"); String crfile = String(path.Begin(), path.End() - 3); /* Remove the ".ok" extension. */ std::ifstream fp; fp.exceptions(std::ifstream::badbit); fp.open(crfile.CStr()); std::map attrs; while (fp.good()) { std::string line; std::getline(fp, line); if (line.empty() || line[0] == '#') continue; /* Ignore comments and empty lines. */ size_t pos = line.find_first_of('='); if (pos == std::string::npos) continue; /* Ignore invalid lines. */ String key = line.substr(0, pos); String value = line.substr(pos + 1); attrs[key] = value; } /* Remove the checkresult files. */ if (unlink(path.CStr()) < 0) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); if (unlink(crfile.CStr()) < 0) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(crfile)); Checkable::Ptr checkable; Host::Ptr host = Host::GetByName(attrs["host_name"]); if (!host) { Log(LogWarning, "CheckResultReader") << "Ignoring checkresult file for host '" << attrs["host_name"] << "': Host does not exist."; return; } if (attrs.find("service_description") != attrs.end()) { Service::Ptr service = host->GetServiceByShortName(attrs["service_description"]); if (!service) { Log(LogWarning, "CheckResultReader") << "Ignoring checkresult file for host '" << attrs["host_name"] << "', service '" << attrs["service_description"] << "': Service does not exist."; return; } checkable = service; } else checkable = host; CheckResult::Ptr result = new CheckResult(); String output = CompatUtility::UnEscapeString(attrs["output"]); std::pair co = PluginUtility::ParseCheckOutput(output); result->SetOutput(co.first); result->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); result->SetState(PluginUtility::ExitStatusToState(Convert::ToLong(attrs["return_code"]))); if (attrs.find("start_time") != attrs.end()) result->SetExecutionStart(Convert::ToDouble(attrs["start_time"])); else result->SetExecutionStart(Utility::GetTime()); if (attrs.find("finish_time") != attrs.end()) result->SetExecutionEnd(Convert::ToDouble(attrs["finish_time"])); else result->SetExecutionEnd(result->GetExecutionStart()); checkable->ProcessCheckResult(result); Log(LogDebug, "CheckResultReader") << "Processed checkresult file for object '" << checkable->GetName() << "'"; /* Reschedule the next check. The side effect of this is that for as long * as we receive check result files for a host/service we won't execute any * active checks. */ checkable->SetNextCheck(Utility::GetTime() + checkable->GetCheckInterval()); } icinga2-2.8.1/lib/compat/checkresultreader.hpp000066400000000000000000000042061322762156600213130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECKRESULTREADER_H #define CHECKRESULTREADER_H #include "compat/checkresultreader.thpp" #include "base/timer.hpp" #include namespace icinga { /** * An Icinga checkresult reader. * * @ingroup compat */ class CheckResultReader : public ObjectImpl { public: DECLARE_OBJECT(CheckResultReader); DECLARE_OBJECTNAME(CheckResultReader); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Timer::Ptr m_ReadTimer; void ReadTimerHandler(void) const; void ProcessCheckResultFile(const String& path) const; }; } #endif /* CHECKRESULTREADER_H */ icinga2-2.8.1/lib/compat/checkresultreader.ti000066400000000000000000000032701322762156600211400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library compat; namespace icinga { class CheckResultReader : ConfigObject { [config] String spool_dir { default {{{ return Application::GetLocalStateDir() + "/lib/icinga2/spool/checkresults/"; }}} }; }; } icinga2-2.8.1/lib/compat/compatlogger.cpp000066400000000000000000000405211322762156600202720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "compat/compatlogger.hpp" #include "compat/compatlogger.tcpp" #include "icinga/service.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notification.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/externalcommandprocessor.hpp" #include "icinga/compatutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/application.hpp" #include "base/utility.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(CompatLogger); REGISTER_STATSFUNCTION(CompatLogger, &CompatLogger::StatsFunc); void CompatLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const CompatLogger::Ptr& compat_logger : ConfigType::GetObjectsByType()) { nodes->Set(compat_logger->GetName(), 1); //add more stats } status->Set("compatlogger", nodes); } /** * @threadsafety Always. */ void CompatLogger::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "CompatLogger") << "'" << GetName() << "' started."; Checkable::OnNewCheckResult.connect(bind(&CompatLogger::CheckResultHandler, this, _1, _2)); Checkable::OnNotificationSentToUser.connect(bind(&CompatLogger::NotificationSentHandler, this, _1, _2, _3, _4, _5, _6, _7, _8)); Downtime::OnDowntimeTriggered.connect(boost::bind(&CompatLogger::TriggerDowntimeHandler, this, _1)); Downtime::OnDowntimeRemoved.connect(boost::bind(&CompatLogger::RemoveDowntimeHandler, this, _1)); Checkable::OnEventCommandExecuted.connect(bind(&CompatLogger::EventCommandHandler, this, _1)); Checkable::OnFlappingChanged.connect(boost::bind(&CompatLogger::FlappingChangedHandler, this, _1)); Checkable::OnEnableFlappingChanged.connect(boost::bind(&CompatLogger::EnableFlappingChangedHandler, this, _1)); ExternalCommandProcessor::OnNewExternalCommand.connect(boost::bind(&CompatLogger::ExternalCommandHandler, this, _2, _3)); m_RotationTimer = new Timer(); m_RotationTimer->OnTimerExpired.connect(boost::bind(&CompatLogger::RotationTimerHandler, this)); m_RotationTimer->Start(); ReopenFile(false); ScheduleNextRotation(); } /** * @threadsafety Always. */ void CompatLogger::Stop(bool runtimeRemoved) { Log(LogInformation, "CompatLogger") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } /** * @threadsafety Always. */ void CompatLogger::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr vars_after = cr->GetVarsAfter(); long state_after = vars_after->Get("state"); long stateType_after = vars_after->Get("state_type"); long attempt_after = vars_after->Get("attempt"); bool reachable_after = vars_after->Get("reachable"); Dictionary::Ptr vars_before = cr->GetVarsBefore(); if (vars_before) { long state_before = vars_before->Get("state"); long stateType_before = vars_before->Get("state_type"); long attempt_before = vars_before->Get("attempt"); bool reachable_before = vars_before->Get("reachable"); if (state_before == state_after && stateType_before == stateType_after && attempt_before == attempt_after && reachable_before == reachable_after) return; /* Nothing changed, ignore this checkresult. */ } String output; if (cr) output = CompatUtility::GetCheckResultOutput(cr); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << Service::StateToString(service->GetState()) << ";" << Service::StateTypeToString(service->GetStateType()) << ";" << attempt_after << ";" << output << "" << ""; } else { String state = Host::StateToString(Host::CalculateState(static_cast(state_after))); msgbuf << "HOST ALERT: " << host->GetName() << ";" << CompatUtility::GetHostStateString(host) << ";" << Host::StateTypeToString(host->GetStateType()) << ";" << attempt_after << ";" << output << "" << ""; } { ObjectLock olock(this); WriteLine(msgbuf.str()); Flush(); } } /** * @threadsafety Always. */ void CompatLogger::TriggerDowntimeHandler(const Downtime::Ptr& downtime) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(downtime->GetCheckable()); if (!downtime) return; std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << "STARTED" << "; " << "Checkable has entered a period of scheduled downtime." << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << "STARTED" << "; " << "Checkable has entered a period of scheduled downtime." << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } /** * @threadsafety Always. */ void CompatLogger::RemoveDowntimeHandler(const Downtime::Ptr& downtime) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(downtime->GetCheckable()); if (!downtime) return; String downtime_output; String downtime_state_str; if (downtime->GetWasCancelled()) { downtime_output = "Scheduled downtime for service has been cancelled."; downtime_state_str = "CANCELLED"; } else { downtime_output = "Checkable has exited from a period of scheduled downtime."; downtime_state_str = "STOPPED"; } std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << downtime_state_str << "; " << downtime_output << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << downtime_state_str << "; " << downtime_output << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } /** * @threadsafety Always. */ void CompatLogger::NotificationSentHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notification_type, CheckResult::Ptr const& cr, const String& author, const String& comment_text, const String& command_name) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); String notification_type_str = Notification::NotificationTypeToString(notification_type); /* override problem notifications with their current state string */ if (notification_type == NotificationProblem) { if (service) notification_type_str = Service::StateToString(service->GetState()); else notification_type_str = CompatUtility::GetHostStateString(host); } String author_comment = ""; if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) { author_comment = author + ";" + comment_text; } if (!cr) return; String output; if (cr) output = CompatUtility::GetCheckResultOutput(cr); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE NOTIFICATION: " << user->GetName() << ";" << host->GetName() << ";" << service->GetShortName() << ";" << notification_type_str << ";" << command_name << ";" << output << ";" << author_comment << ""; } else { msgbuf << "HOST NOTIFICATION: " << user->GetName() << ";" << host->GetName() << ";" << notification_type_str << " " << "(" << CompatUtility::GetHostStateString(host) << ");" << command_name << ";" << output << ";" << author_comment << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } /** * @threadsafety Always. */ void CompatLogger::FlappingChangedHandler(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); String flapping_state_str; String flapping_output; if (checkable->IsFlapping()) { flapping_output = "Checkable appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThresholdHigh()) + "% threshold)"; flapping_state_str = "STARTED"; } else { flapping_output = "Checkable appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThresholdLow()) + "% threshold)"; flapping_state_str = "STOPPED"; } std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE FLAPPING ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << flapping_state_str << "; " << flapping_output << ""; } else { msgbuf << "HOST FLAPPING ALERT: " << host->GetName() << ";" << flapping_state_str << "; " << flapping_output << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } void CompatLogger::EnableFlappingChangedHandler(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); if (checkable->GetEnableFlapping()) return; String flapping_output = "Flap detection has been disabled"; String flapping_state_str = "DISABLED"; std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE FLAPPING ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << flapping_state_str << "; " << flapping_output << ""; } else { msgbuf << "HOST FLAPPING ALERT: " << host->GetName() << ";" << flapping_state_str << "; " << flapping_output << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } void CompatLogger::ExternalCommandHandler(const String& command, const std::vector& arguments) { std::ostringstream msgbuf; msgbuf << "EXTERNAL COMMAND: " << command << ";" << boost::algorithm::join(arguments, ";") << ""; { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } void CompatLogger::EventCommandHandler(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); EventCommand::Ptr event_command = checkable->GetEventCommand(); String event_command_name = event_command->GetName(); long current_attempt = checkable->GetCheckAttempt(); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE EVENT HANDLER: " << host->GetName() << ";" << service->GetShortName() << ";" << Service::StateToString(service->GetState()) << ";" << Service::StateTypeToString(service->GetStateType()) << ";" << current_attempt << ";" << event_command_name; } else { msgbuf << "HOST EVENT HANDLER: " << host->GetName() << ";" << CompatUtility::GetHostStateString(host) << ";" << Host::StateTypeToString(host->GetStateType()) << ";" << current_attempt << ";" << event_command_name; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } } void CompatLogger::WriteLine(const String& line) { ASSERT(OwnsLock()); if (!m_OutputFile.good()) return; m_OutputFile << "[" << (long)Utility::GetTime() << "] " << line << "\n"; } void CompatLogger::Flush(void) { ASSERT(OwnsLock()); if (!m_OutputFile.good()) return; m_OutputFile << std::flush; } /** * @threadsafety Always. */ void CompatLogger::ReopenFile(bool rotate) { ObjectLock olock(this); String tempFile = GetLogDir() + "/icinga.log"; if (m_OutputFile) { m_OutputFile.close(); if (rotate) { String archiveFile = GetLogDir() + "/archives/icinga-" + Utility::FormatDateTime("%m-%d-%Y-%H", Utility::GetTime()) + ".log"; Log(LogNotice, "CompatLogger") << "Rotating compat log file '" << tempFile << "' -> '" << archiveFile << "'"; (void) rename(tempFile.CStr(), archiveFile.CStr()); } } m_OutputFile.open(tempFile.CStr(), std::ofstream::app); if (!m_OutputFile) { Log(LogWarning, "CompatLogger") << "Could not open compat log file '" << tempFile << "' for writing. Log output will be lost."; return; } WriteLine("LOG ROTATION: " + GetRotationMethod()); WriteLine("LOG VERSION: 2.0"); for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { String output; CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) output = CompatUtility::GetCheckResultOutput(cr); std::ostringstream msgbuf; msgbuf << "CURRENT HOST STATE: " << host->GetName() << ";" << CompatUtility::GetHostStateString(host) << ";" << Host::StateTypeToString(host->GetStateType()) << ";" << host->GetCheckAttempt() << ";" << output << ""; WriteLine(msgbuf.str()); } for (const Service::Ptr& service : ConfigType::GetObjectsByType()) { Host::Ptr host = service->GetHost(); String output; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) output = CompatUtility::GetCheckResultOutput(cr); std::ostringstream msgbuf; msgbuf << "CURRENT SERVICE STATE: " << host->GetName() << ";" << service->GetShortName() << ";" << Service::StateToString(service->GetState()) << ";" << Service::StateTypeToString(service->GetStateType()) << ";" << service->GetCheckAttempt() << ";" << output << ""; WriteLine(msgbuf.str()); } Flush(); } void CompatLogger::ScheduleNextRotation(void) { time_t now = (time_t)Utility::GetTime(); String method = GetRotationMethod(); tm tmthen; #ifdef _MSC_VER tm *temp = localtime(&now); if (temp == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime") << boost::errinfo_errno(errno)); } tmthen = *temp; #else /* _MSC_VER */ if (localtime_r(&now, &tmthen) == NULL) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("localtime_r") << boost::errinfo_errno(errno)); } #endif /* _MSC_VER */ tmthen.tm_min = 0; tmthen.tm_sec = 0; if (method == "HOURLY") { tmthen.tm_hour++; } else if (method == "DAILY") { tmthen.tm_mday++; tmthen.tm_hour = 0; } else if (method == "WEEKLY") { tmthen.tm_mday += 7 - tmthen.tm_wday; tmthen.tm_hour = 0; } else if (method == "MONTHLY") { tmthen.tm_mon++; tmthen.tm_mday = 1; tmthen.tm_hour = 0; } time_t ts = mktime(&tmthen); Log(LogNotice, "CompatLogger") << "Rescheduling rotation timer for compat log '" << GetName() << "' to '" << Utility::FormatDateTime("%Y/%m/%d %H:%M:%S %z", ts) << "'"; m_RotationTimer->Reschedule(ts); } /** * @threadsafety Always. */ void CompatLogger::RotationTimerHandler(void) { try { ReopenFile(true); } catch (...) { ScheduleNextRotation(); throw; } ScheduleNextRotation(); } void CompatLogger::ValidateRotationMethod(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateRotationMethod(value, utils); if (value != "HOURLY" && value != "DAILY" && value != "WEEKLY" && value != "MONTHLY" && value != "NONE") { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("rotation_method"), "Rotation method '" + value + "' is invalid.")); } } icinga2-2.8.1/lib/compat/compatlogger.hpp000066400000000000000000000060741322762156600203040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMPATLOGGER_H #define COMPATLOGGER_H #include "compat/compatlogger.thpp" #include "icinga/service.hpp" #include "base/timer.hpp" #include namespace icinga { /** * An Icinga compat log writer. * * @ingroup compat */ class CompatLogger : public ObjectImpl { public: DECLARE_OBJECT(CompatLogger); DECLARE_OBJECTNAME(CompatLogger); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void ValidateRotationMethod(const String& value, const ValidationUtils& utils) override; protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: void WriteLine(const String& line); void Flush(void); void CheckResultHandler(const Checkable::Ptr& service, const CheckResult::Ptr& cr); void NotificationSentHandler(const Notification::Ptr& notification, const Checkable::Ptr& service, const User::Ptr& user, NotificationType notification_type, CheckResult::Ptr const& cr, const String& author, const String& comment_text, const String& command_name); void FlappingChangedHandler(const Checkable::Ptr& checkable); void EnableFlappingChangedHandler(const Checkable::Ptr& checkable); void TriggerDowntimeHandler(const Downtime::Ptr& downtime); void RemoveDowntimeHandler(const Downtime::Ptr& downtime); void ExternalCommandHandler(const String& command, const std::vector& arguments); void EventCommandHandler(const Checkable::Ptr& service); Timer::Ptr m_RotationTimer; void RotationTimerHandler(void); void ScheduleNextRotation(void); std::ofstream m_OutputFile; void ReopenFile(bool rotate); }; } #endif /* COMPATLOGGER_H */ icinga2-2.8.1/lib/compat/compatlogger.ti000066400000000000000000000033561322762156600201310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library compat; namespace icinga { class CompatLogger : ConfigObject { [config] String log_dir { default {{{ return Application::GetLocalStateDir() + "/log/icinga2/compat"; }}} }; [config] String rotation_method { default {{{ return "HOURLY"; }}} }; }; } icinga2-2.8.1/lib/compat/externalcommandlistener.cpp000066400000000000000000000131321322762156600225340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "compat/externalcommandlistener.hpp" #include "compat/externalcommandlistener.tcpp" #include "icinga/externalcommandprocessor.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/application.hpp" #include "base/statsfunction.hpp" using namespace icinga; REGISTER_TYPE(ExternalCommandListener); REGISTER_STATSFUNCTION(ExternalCommandListener, &ExternalCommandListener::StatsFunc); void ExternalCommandListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const ExternalCommandListener::Ptr& externalcommandlistener : ConfigType::GetObjectsByType()) { nodes->Set(externalcommandlistener->GetName(), 1); //add more stats } status->Set("externalcommandlistener", nodes); } /** * Starts the component. */ void ExternalCommandListener::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "ExternalCommandListener") << "'" << GetName() << "' started."; #ifndef _WIN32 m_CommandThread = boost::thread(boost::bind(&ExternalCommandListener::CommandPipeThread, this, GetCommandPath())); m_CommandThread.detach(); #endif /* _WIN32 */ } /** * Stops the component. */ void ExternalCommandListener::Stop(bool runtimeRemoved) { Log(LogInformation, "ExternalCommandListener") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } #ifndef _WIN32 void ExternalCommandListener::CommandPipeThread(const String& commandPath) { Utility::SetThreadName("Command Pipe"); struct stat statbuf; bool fifo_ok = false; if (lstat(commandPath.CStr(), &statbuf) >= 0) { if (S_ISFIFO(statbuf.st_mode) && access(commandPath.CStr(), R_OK) >= 0) { fifo_ok = true; } else { if (unlink(commandPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(commandPath)); } } } mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if (!fifo_ok && mkfifo(commandPath.CStr(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) { Log(LogCritical, "ExternalCommandListener") << "mkfifo() for fifo path '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return; } /* mkfifo() uses umask to mask off some bits, which means we need to chmod() the * fifo to get the right mask. */ if (chmod(commandPath.CStr(), mode) < 0) { Log(LogCritical, "ExternalCommandListener") << "chmod() on fifo '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return; } for (;;) { int fd = open(commandPath.CStr(), O_RDWR | O_NONBLOCK); if (fd < 0) { Log(LogCritical, "ExternalCommandListener") << "open() for fifo path '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return; } FIFO::Ptr fifo = new FIFO(); Socket::Ptr sock = new Socket(fd); StreamReadContext src; for (;;) { sock->Poll(true, false); char buffer[8192]; size_t rc; try { rc = sock->Read(buffer, sizeof(buffer)); } catch (const std::exception& ex) { /* We have read all data. */ if (errno == EAGAIN) continue; Log(LogWarning, "ExternalCommandListener") << "Cannot read from command pipe." << DiagnosticInformation(ex); break; } /* Empty pipe (EOF) */ if (rc == 0) continue; fifo->Write(buffer, rc); for (;;) { String command; StreamReadStatus srs = fifo->ReadLine(&command, src); if (srs != StatusNewItem) break; try { Log(LogInformation, "ExternalCommandListener") << "Executing external command: " << command; ExternalCommandProcessor::Execute(command); } catch (const std::exception& ex) { Log(LogWarning, "ExternalCommandListener") << "External command failed: " << DiagnosticInformation(ex, false); Log(LogNotice, "ExternalCommandListener") << "External command failed: " << DiagnosticInformation(ex, true); } } } } } #endif /* _WIN32 */ icinga2-2.8.1/lib/compat/externalcommandlistener.hpp000066400000000000000000000043641322762156600225500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXTERNALCOMMANDLISTENER_H #define EXTERNALCOMMANDLISTENER_H #include "compat/externalcommandlistener.thpp" #include "base/objectlock.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include #include namespace icinga { /** * @ingroup compat */ class ExternalCommandListener : public ObjectImpl { public: DECLARE_OBJECT(ExternalCommandListener); DECLARE_OBJECTNAME(ExternalCommandListener); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: #ifndef _WIN32 boost::thread m_CommandThread; void CommandPipeThread(const String& commandPath); #endif /* _WIN32 */ }; } #endif /* EXTERNALCOMMANDLISTENER_H */ icinga2-2.8.1/lib/compat/externalcommandlistener.ti000066400000000000000000000032621322762156600223710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library compat; namespace icinga { class ExternalCommandListener : ConfigObject { [config] String command_path { default {{{ return Application::GetRunDir() + "/icinga2/cmd/icinga2.cmd"; }}} }; }; } icinga2-2.8.1/lib/compat/statusdatawriter.cpp000066400000000000000000000776371322762156600212430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "compat/statusdatawriter.hpp" #include "compat/statusdatawriter.tcpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "icinga/hostgroup.hpp" #include "icinga/servicegroup.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/timeperiod.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/compatutility.hpp" #include "icinga/dependency.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/application.hpp" #include "base/context.hpp" #include "base/statsfunction.hpp" #include #include #include #include using namespace icinga; REGISTER_TYPE(StatusDataWriter); REGISTER_STATSFUNCTION(StatusDataWriter, &StatusDataWriter::StatsFunc); void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const StatusDataWriter::Ptr& statusdatawriter : ConfigType::GetObjectsByType()) { nodes->Set(statusdatawriter->GetName(), 1); //add more stats } status->Set("statusdatawriter", nodes); } /** * Hint: The reason why we're using "\n" rather than std::endl is because * std::endl also _flushes_ the output stream which severely degrades * performance (see https://stackoverflow.com/questions/213907/c-stdendl-vs-n). */ /** * Starts the component. */ void StatusDataWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "StatusDataWriter") << "'" << GetName() << "' started."; m_ObjectsCacheOutdated = true; m_StatusTimer = new Timer(); m_StatusTimer->SetInterval(GetUpdateInterval()); m_StatusTimer->OnTimerExpired.connect(boost::bind(&StatusDataWriter::StatusTimerHandler, this)); m_StatusTimer->Start(); m_StatusTimer->Reschedule(0); ConfigObject::OnVersionChanged.connect(boost::bind(&StatusDataWriter::ObjectHandler, this)); ConfigObject::OnActiveChanged.connect(boost::bind(&StatusDataWriter::ObjectHandler, this)); } /** * Stops the component. */ void StatusDataWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "StatusDataWriter") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } void StatusDataWriter::DumpComments(std::ostream& fp, const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); for (const Comment::Ptr& comment : checkable->GetComments()) { if (comment->IsExpired()) continue; if (service) fp << "servicecomment {" << "\n" << "\t" << "service_description=" << service->GetShortName() << "\n"; else fp << "hostcomment {" << "\n"; fp << "\t" "host_name=" << host->GetName() << "\n" "\t" "comment_id=" << comment->GetLegacyId() << "\n" "\t" "entry_time=" << comment->GetEntryTime() << "\n" "\t" "entry_type=" << comment->GetEntryType() << "\n" "\t" "persistent=" "1" "\n" "\t" "author=" << comment->GetAuthor() << "\n" "\t" "comment_data=" << comment->GetText() << "\n" "\t" "expires=" << (comment->GetExpireTime() != 0 ? 1 : 0) << "\n" "\t" "expire_time=" << comment->GetExpireTime() << "\n" "\t" "}" "\n" "\n"; } } void StatusDataWriter::DumpTimePeriod(std::ostream& fp, const TimePeriod::Ptr& tp) { fp << "define timeperiod {" "\n" "\t" "timeperiod_name" "\t" << tp->GetName() << "\n" "\t" "alias" "\t" << tp->GetName() << "\n"; Dictionary::Ptr ranges = tp->GetRanges(); if (ranges) { ObjectLock olock(ranges); for (const Dictionary::Pair& kv : ranges) { fp << "\t" << kv.first << "\t" << kv.second << "\n"; } } fp << "\t" "}" "\n" "\n"; } void StatusDataWriter::DumpCommand(std::ostream& fp, const Command::Ptr& command) { fp << "define command {" "\n" "\t" "command_name\t"; fp << CompatUtility::GetCommandName(command) << "\n"; fp << "\t" "command_line" "\t" << CompatUtility::GetCommandLine(command); fp << "\n"; DumpCustomAttributes(fp, command); fp << "\n" "\t" "}" "\n" "\n"; } void StatusDataWriter::DumpDowntimes(std::ostream& fp, const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); for (const Downtime::Ptr& downtime : checkable->GetDowntimes()) { if (downtime->IsExpired()) continue; if (service) fp << "servicedowntime {" << "\n" "\t" "service_description=" << service->GetShortName() << "\n"; else fp << "hostdowntime {" "\n"; Downtime::Ptr triggeredByObj = Downtime::GetByName(downtime->GetTriggeredBy()); int triggeredByLegacy = 0; if (triggeredByObj) triggeredByLegacy = triggeredByObj->GetLegacyId(); fp << "\t" << "host_name=" << host->GetName() << "\n" "\t" "downtime_id=" << downtime->GetLegacyId() << "\n" "\t" "entry_time=" << downtime->GetEntryTime() << "\n" "\t" "start_time=" << downtime->GetStartTime() << "\n" "\t" "end_time=" << downtime->GetEndTime() << "\n" "\t" "triggered_by=" << triggeredByLegacy << "\n" "\t" "fixed=" << static_cast(downtime->GetFixed()) << "\n" "\t" "duration=" << static_cast(downtime->GetDuration()) << "\n" "\t" "is_in_effect=" << (downtime->IsInEffect() ? 1 : 0) << "\n" "\t" "author=" << downtime->GetAuthor() << "\n" "\t" "comment=" << downtime->GetComment() << "\n" "\t" "trigger_time=" << downtime->GetTriggerTime() << "\n" "\t" "}" "\n" "\n"; } } void StatusDataWriter::DumpHostStatus(std::ostream& fp, const Host::Ptr& host) { fp << "hoststatus {" << "\n" << "\t" << "host_name=" << host->GetName() << "\n"; { ObjectLock olock(host); DumpCheckableStatusAttrs(fp, host); } /* ugly but cgis parse only that */ fp << "\t" "last_time_up=" << host->GetLastStateUp() << "\n" "\t" "last_time_down=" << host->GetLastStateDown() << "\n" "\t" "last_time_unreachable=" << host->GetLastStateUnreachable() << "\n"; fp << "\t" "}" "\n" "\n"; DumpDowntimes(fp, host); DumpComments(fp, host); } void StatusDataWriter::DumpHostObject(std::ostream& fp, const Host::Ptr& host) { String notes = host->GetNotes(); String notes_url = host->GetNotesUrl(); String action_url = host->GetActionUrl(); String icon_image = host->GetIconImage(); String icon_image_alt = host->GetIconImageAlt(); String display_name = host->GetDisplayName(); String address = host->GetAddress(); String address6 = host->GetAddress6(); fp << "define host {" "\n" "\t" "host_name" "\t" << host->GetName() << "\n"; if (!display_name.IsEmpty()) { fp << "\t" "display_name" "\t" << host->GetDisplayName() << "\n" "\t" "alias" "\t" << host->GetDisplayName() << "\n"; } if (!address.IsEmpty()) fp << "\t" "address" "\t" << address << "\n"; if (!address6.IsEmpty()) fp << "\t" "address6" "\t" << address6 << "\n"; if (!notes.IsEmpty()) fp << "\t" "notes" "\t" << notes << "\n"; if (!notes_url.IsEmpty()) fp << "\t" "notes_url" "\t" << notes_url << "\n"; if (!action_url.IsEmpty()) fp << "\t" "action_url" "\t" << action_url << "\n"; if (!icon_image.IsEmpty()) fp << "\t" "icon_image" "\t" << icon_image << "\n"; if (!icon_image_alt.IsEmpty()) fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n"; std::set parents = host->GetParents(); if (!parents.empty()) { fp << "\t" "parents" "\t"; DumpNameList(fp, parents); fp << "\n"; } ObjectLock olock(host); fp << "\t" "check_interval" "\t" << CompatUtility::GetCheckableCheckInterval(host) << "\n" "\t" "retry_interval" "\t" << CompatUtility::GetCheckableRetryInterval(host) << "\n" "\t" "max_check_attempts" "\t" << host->GetMaxCheckAttempts() << "\n" "\t" "active_checks_enabled" "\t" << CompatUtility::GetCheckableActiveChecksEnabled(host) << "\n" "\t" "passive_checks_enabled" "\t" << CompatUtility::GetCheckablePassiveChecksEnabled(host) << "\n" "\t" "notifications_enabled" "\t" << CompatUtility::GetCheckableNotificationsEnabled(host) << "\n" "\t" "notification_options" "\t" << CompatUtility::GetCheckableNotificationNotificationOptions(host) << "\n" "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(host) << "\n" "\t" "event_handler_enabled" "\t" << CompatUtility::GetCheckableEventHandlerEnabled(host) << "\n"; CheckCommand::Ptr checkcommand = host->GetCheckCommand(); if (checkcommand) fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(host) << "\n"; EventCommand::Ptr eventcommand = host->GetEventCommand(); if (eventcommand && host->GetEnableEventHandler()) fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n"; fp << "\t" "check_period" "\t" << CompatUtility::GetCheckableCheckPeriod(host) << "\n"; fp << "\t" "contacts" "\t"; DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(host)); fp << "\n"; fp << "\t" "contact_groups" "\t"; DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(host)); fp << "\n"; fp << "\t" << "initial_state" "\t" "o" "\n" "\t" "low_flap_threshold" "\t" << host->GetFlappingThresholdLow() << "\n" "\t" "high_flap_threshold" "\t" << host->GetFlappingThresholdHigh() << "\n" "\t" "process_perf_data" "\t" << CompatUtility::GetCheckableProcessPerformanceData(host) << "\n" "\t" "check_freshness" "\t" "1" "\n"; fp << "\t" "host_groups" "\t"; bool first = true; Array::Ptr groups = host->GetGroups(); if (groups) { ObjectLock olock(groups); for (const String& name : groups) { HostGroup::Ptr hg = HostGroup::GetByName(name); if (hg) { if (!first) fp << ","; else first = false; fp << hg->GetName(); } } } fp << "\n"; DumpCustomAttributes(fp, host); fp << "\t" "}" "\n" "\n"; } void StatusDataWriter::DumpCheckableStatusAttrs(std::ostream& fp, const Checkable::Ptr& checkable) { CheckResult::Ptr cr = checkable->GetLastCheckResult(); EventCommand::Ptr eventcommand = checkable->GetEventCommand(); CheckCommand::Ptr checkcommand = checkable->GetCheckCommand(); fp << "\t" << "check_command=" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(checkable) << "\n" "\t" "event_handler=" << CompatUtility::GetCommandName(eventcommand) << "\n" "\t" "check_period=" << CompatUtility::GetCheckableCheckPeriod(checkable) << "\n" "\t" "check_interval=" << CompatUtility::GetCheckableCheckInterval(checkable) << "\n" "\t" "retry_interval=" << CompatUtility::GetCheckableRetryInterval(checkable) << "\n" "\t" "has_been_checked=" << CompatUtility::GetCheckableHasBeenChecked(checkable) << "\n" "\t" "should_be_scheduled=" << checkable->GetEnableActiveChecks() << "\n" "\t" "event_handler_enabled=" << CompatUtility::GetCheckableEventHandlerEnabled(checkable) << "\n"; if (cr) { fp << "\t" << "check_execution_time=" << Convert::ToString(cr->CalculateExecutionTime()) << "\n" "\t" "check_latency=" << Convert::ToString(cr->CalculateLatency()) << "\n"; } Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); if (service) { fp << "\t" "current_state=" << service->GetState() << "\n" "\t" "last_hard_state=" << service->GetLastHardState() << "\n" "\t" "last_time_ok=" << static_cast(service->GetLastStateOK()) << "\n" "\t" "last_time_warn=" << static_cast(service->GetLastStateWarning()) << "\n" "\t" "last_time_critical=" << static_cast(service->GetLastStateCritical()) << "\n" "\t" "last_time_unknown=" << static_cast(service->GetLastStateUnknown()) << "\n"; } else { fp << "\t" "current_state=" << CompatUtility::GetHostCurrentState(host) << "\n" "\t" "last_hard_state=" << host->GetLastHardState() << "\n" "\t" "last_time_up=" << static_cast(host->GetLastStateUp()) << "\n" "\t" "last_time_down=" << static_cast(host->GetLastStateDown()) << "\n"; } fp << "\t" "state_type=" << checkable->GetStateType() << "\n" "\t" "plugin_output=" << CompatUtility::GetCheckResultOutput(cr) << "\n" "\t" "long_plugin_output=" << CompatUtility::GetCheckResultLongOutput(cr) << "\n" "\t" "performance_data=" << CompatUtility::GetCheckResultPerfdata(cr) << "\n"; if (cr) { fp << "\t" << "check_source=" << cr->GetCheckSource() << "\n" "\t" "last_check=" << static_cast(cr->GetScheduleEnd()) << "\n"; } fp << "\t" << "next_check=" << static_cast(checkable->GetNextCheck()) << "\n" "\t" "current_attempt=" << checkable->GetCheckAttempt() << "\n" "\t" "max_attempts=" << checkable->GetMaxCheckAttempts() << "\n" "\t" "last_state_change=" << static_cast(checkable->GetLastStateChange()) << "\n" "\t" "last_hard_state_change=" << static_cast(checkable->GetLastHardStateChange()) << "\n" "\t" "last_update=" << static_cast(time(NULL)) << "\n" "\t" "notifications_enabled=" << CompatUtility::GetCheckableNotificationsEnabled(checkable) << "\n" "\t" "active_checks_enabled=" << CompatUtility::GetCheckableActiveChecksEnabled(checkable) << "\n" "\t" "passive_checks_enabled=" << CompatUtility::GetCheckablePassiveChecksEnabled(checkable) << "\n" "\t" "flap_detection_enabled=" << CompatUtility::GetCheckableFlapDetectionEnabled(checkable) << "\n" "\t" "is_flapping=" << CompatUtility::GetCheckableIsFlapping(checkable) << "\n" "\t" "percent_state_change=" << CompatUtility::GetCheckablePercentStateChange(checkable) << "\n" "\t" "problem_has_been_acknowledged=" << CompatUtility::GetCheckableProblemHasBeenAcknowledged(checkable) << "\n" "\t" "acknowledgement_type=" << CompatUtility::GetCheckableAcknowledgementType(checkable) << "\n" "\t" "acknowledgement_end_time=" << checkable->GetAcknowledgementExpiry() << "\n" "\t" "scheduled_downtime_depth=" << checkable->GetDowntimeDepth() << "\n" "\t" "last_notification=" << CompatUtility::GetCheckableNotificationLastNotification(checkable) << "\n" "\t" "next_notification=" << CompatUtility::GetCheckableNotificationNextNotification(checkable) << "\n" "\t" "current_notification_number=" << CompatUtility::GetCheckableNotificationNotificationNumber(checkable) << "\n" "\t" "is_reachable=" << CompatUtility::GetCheckableIsReachable(checkable) << "\n"; } void StatusDataWriter::DumpServiceStatus(std::ostream& fp, const Service::Ptr& service) { Host::Ptr host = service->GetHost(); fp << "servicestatus {" "\n" "\t" "host_name=" << host->GetName() << "\n" "\t" "service_description=" << service->GetShortName() << "\n"; { ObjectLock olock(service); DumpCheckableStatusAttrs(fp, service); } fp << "\t" "}" "\n" "\n"; DumpDowntimes(fp, service); DumpComments(fp, service); } void StatusDataWriter::DumpServiceObject(std::ostream& fp, const Service::Ptr& service) { Host::Ptr host = service->GetHost(); { ObjectLock olock(service); fp << "define service {" "\n" "\t" "host_name" "\t" << host->GetName() << "\n" "\t" "service_description" "\t" << service->GetShortName() << "\n" "\t" "display_name" "\t" << service->GetDisplayName() << "\n" "\t" "check_period" "\t" << CompatUtility::GetCheckableCheckPeriod(service) << "\n" "\t" "check_interval" "\t" << CompatUtility::GetCheckableCheckInterval(service) << "\n" "\t" "retry_interval" "\t" << CompatUtility::GetCheckableRetryInterval(service) << "\n" "\t" "max_check_attempts" "\t" << service->GetMaxCheckAttempts() << "\n" "\t" "active_checks_enabled" "\t" << CompatUtility::GetCheckableActiveChecksEnabled(service) << "\n" "\t" "passive_checks_enabled" "\t" << CompatUtility::GetCheckablePassiveChecksEnabled(service) << "\n" "\t" "flap_detection_enabled" "\t" << CompatUtility::GetCheckableFlapDetectionEnabled(service) << "\n" "\t" "is_volatile" "\t" << CompatUtility::GetCheckableIsVolatile(service) << "\n" "\t" "notifications_enabled" "\t" << CompatUtility::GetCheckableNotificationsEnabled(service) << "\n" "\t" "notification_options" "\t" << CompatUtility::GetCheckableNotificationNotificationOptions(service) << "\n" "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(service) << "\n" "\t" "notification_period" "\t" << "" << "\n" "\t" "event_handler_enabled" "\t" << CompatUtility::GetCheckableEventHandlerEnabled(service) << "\n"; CheckCommand::Ptr checkcommand = service->GetCheckCommand(); if (checkcommand) fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(service)<< "\n"; EventCommand::Ptr eventcommand = service->GetEventCommand(); if (eventcommand && service->GetEnableEventHandler()) fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n"; fp << "\t" "contacts" "\t"; DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(service)); fp << "\n"; fp << "\t" "contact_groups" "\t"; DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(service)); fp << "\n"; String notes = service->GetNotes(); String notes_url = service->GetNotesUrl(); String action_url = service->GetActionUrl(); String icon_image = service->GetIconImage(); String icon_image_alt = service->GetIconImageAlt(); fp << "\t" "initial_state" "\t" "o" "\n" "\t" "low_flap_threshold" "\t" << service->GetFlappingThresholdLow() << "\n" "\t" "high_flap_threshold" "\t" << service->GetFlappingThresholdHigh() << "\n" "\t" "process_perf_data" "\t" << CompatUtility::GetCheckableProcessPerformanceData(service) << "\n" "\t" "check_freshness" << "\t" "1" "\n"; if (!notes.IsEmpty()) fp << "\t" "notes" "\t" << notes << "\n"; if (!notes_url.IsEmpty()) fp << "\t" "notes_url" "\t" << notes_url << "\n"; if (!action_url.IsEmpty()) fp << "\t" "action_url" "\t" << action_url << "\n"; if (!icon_image.IsEmpty()) fp << "\t" "icon_image" "\t" << icon_image << "\n"; if (!icon_image_alt.IsEmpty()) fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n"; } fp << "\t" "service_groups" "\t"; bool first = true; Array::Ptr groups = service->GetGroups(); if (groups) { ObjectLock olock(groups); for (const String& name : groups) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(name); if (sg) { if (!first) fp << ","; else first = false; fp << sg->GetName(); } } } fp << "\n"; DumpCustomAttributes(fp, service); fp << "\t" "}" "\n" "\n"; } void StatusDataWriter::DumpCustomAttributes(std::ostream& fp, const CustomVarObject::Ptr& object) { Dictionary::Ptr vars = object->GetVars(); if (!vars) return; bool is_json = false; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.first.IsEmpty()) continue; Value value; if (kv.second.IsObjectType() || kv.second.IsObjectType()) { value = JsonEncode(kv.second); is_json = true; } else value = CompatUtility::EscapeString(kv.second); fp << "\t" "_" << kv.first << "\t" << value << "\n"; } if (is_json) fp << "\t" "_is_json" "\t" "1" "\n"; } void StatusDataWriter::UpdateObjectsCache(void) { CONTEXT("Writing objects.cache file"); String objectsPath = GetObjectsPath(); std::fstream objectfp; String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", 0644, objectfp); objectfp << std::fixed; objectfp << "# Icinga objects cache file" "\n" "# This file is auto-generated. Do not modify this file." "\n" "\n"; for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; DumpHostObject(tempobjectfp, host); objectfp << tempobjectfp.str(); for (const Service::Ptr& service : host->GetServices()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; DumpServiceObject(tempobjectfp, service); objectfp << tempobjectfp.str(); } } for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; String display_name = hg->GetDisplayName(); String notes = hg->GetNotes(); String notes_url = hg->GetNotesUrl(); String action_url = hg->GetActionUrl(); tempobjectfp << "define hostgroup {" "\n" "\t" "hostgroup_name" "\t" << hg->GetName() << "\n"; if (!display_name.IsEmpty()) tempobjectfp << "\t" "alias" "\t" << display_name << "\n"; if (!notes.IsEmpty()) tempobjectfp << "\t" "notes" "\t" << notes << "\n"; if (!notes_url.IsEmpty()) tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n"; if (!action_url.IsEmpty()) tempobjectfp << "\t" "action_url" "\t" << action_url << "\n"; DumpCustomAttributes(tempobjectfp, hg); tempobjectfp << "\t" "members" "\t"; DumpNameList(tempobjectfp, hg->GetMembers()); tempobjectfp << "\n" "\t" "}" "\n"; objectfp << tempobjectfp.str(); } for (const ServiceGroup::Ptr& sg : ConfigType::GetObjectsByType()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; String display_name = sg->GetDisplayName(); String notes = sg->GetNotes(); String notes_url = sg->GetNotesUrl(); String action_url = sg->GetActionUrl(); tempobjectfp << "define servicegroup {" "\n" "\t" "servicegroup_name" "\t" << sg->GetName() << "\n"; if (!display_name.IsEmpty()) tempobjectfp << "\t" "alias" "\t" << display_name << "\n"; if (!notes.IsEmpty()) tempobjectfp << "\t" "notes" "\t" << notes << "\n"; if (!notes_url.IsEmpty()) tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n"; if (!action_url.IsEmpty()) tempobjectfp << "\t" "action_url" "\t" << action_url << "\n"; DumpCustomAttributes(tempobjectfp, sg); tempobjectfp << "\t" "members" "\t"; std::vector sglist; for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); sglist.push_back(host->GetName()); sglist.push_back(service->GetShortName()); } DumpStringList(tempobjectfp, sglist); tempobjectfp << "\n" "}" "\n"; objectfp << tempobjectfp.str(); } for (const User::Ptr& user : ConfigType::GetObjectsByType()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; String email = user->GetEmail(); String pager = user->GetPager(); String alias = user->GetDisplayName(); tempobjectfp << "define contact {" "\n" "\t" "contact_name" "\t" << user->GetName() << "\n"; if (!alias.IsEmpty()) tempobjectfp << "\t" "alias" "\t" << alias << "\n"; if (!email.IsEmpty()) tempobjectfp << "\t" "email" "\t" << email << "\n"; if (!pager.IsEmpty()) tempobjectfp << "\t" "pager" "\t" << pager << "\n"; tempobjectfp << "\t" "service_notification_options" "\t" "w,u,c,r,f,s" "\n" "\t" "host_notification_options""\t" "d,u,r,f,s" "\n" "\t" "host_notifications_enabled" "\t" "1" "\n" "\t" "service_notifications_enabled" "\t" "1" "\n" "\t" "}" "\n" "\n"; objectfp << tempobjectfp.str(); } for (const UserGroup::Ptr& ug : ConfigType::GetObjectsByType()) { std::ostringstream tempobjectfp; tempobjectfp << std::fixed; tempobjectfp << "define contactgroup {" "\n" "\t" "contactgroup_name" "\t" << ug->GetName() << "\n" "\t" "alias" "\t" << ug->GetDisplayName() << "\n"; tempobjectfp << "\t" "members" "\t"; DumpNameList(tempobjectfp, ug->GetMembers()); tempobjectfp << "\n" "\t" "}" "\n"; objectfp << tempobjectfp.str(); } for (const Command::Ptr& command : ConfigType::GetObjectsByType()) { DumpCommand(objectfp, command); } for (const Command::Ptr& command : ConfigType::GetObjectsByType()) { DumpCommand(objectfp, command); } for (const Command::Ptr& command : ConfigType::GetObjectsByType()) { DumpCommand(objectfp, command); } for (const TimePeriod::Ptr& tp : ConfigType::GetObjectsByType()) { DumpTimePeriod(objectfp, tp); } for (const Dependency::Ptr& dep : ConfigType::GetObjectsByType()) { Checkable::Ptr parent = dep->GetParent(); if (!parent) { Log(LogDebug, "StatusDataWriter") << "Missing parent for dependency '" << dep->GetName() << "'."; continue; } Host::Ptr parent_host; Service::Ptr parent_service; tie(parent_host, parent_service) = GetHostService(parent); Checkable::Ptr child = dep->GetChild(); if (!child) { Log(LogDebug, "StatusDataWriter") << "Missing child for dependency '" << dep->GetName() << "'."; continue; } Host::Ptr child_host; Service::Ptr child_service; tie(child_host, child_service) = GetHostService(child); int state_filter = dep->GetStateFilter(); std::vector failure_criteria; if (state_filter & StateFilterOK || state_filter & StateFilterUp) failure_criteria.push_back("o"); if (state_filter & StateFilterWarning) failure_criteria.push_back("w"); if (state_filter & StateFilterCritical) failure_criteria.push_back("c"); if (state_filter & StateFilterUnknown) failure_criteria.push_back("u"); if (state_filter & StateFilterDown) failure_criteria.push_back("d"); String criteria = boost::algorithm::join(failure_criteria, ","); /* Icinga 1.x only allows host->host, service->service dependencies */ if (!child_service && !parent_service) { objectfp << "define hostdependency {" "\n" "\t" "dependent_host_name" "\t" << child_host->GetName() << "\n" "\t" "host_name" "\t" << parent_host->GetName() << "\n" "\t" "execution_failure_criteria" "\t" << criteria << "\n" "\t" "notification_failure_criteria" "\t" << criteria << "\n" "\t" "}" "\n" "\n"; } else if (child_service && parent_service){ objectfp << "define servicedependency {" "\n" "\t" "dependent_host_name" "\t" << child_service->GetHost()->GetName() << "\n" "\t" "dependent_service_description" "\t" << child_service->GetShortName() << "\n" "\t" "host_name" "\t" << parent_service->GetHost()->GetName() << "\n" "\t" "service_description" "\t" << parent_service->GetShortName() << "\n" "\t" "execution_failure_criteria" "\t" << criteria << "\n" "\t" "notification_failure_criteria" "\t" << criteria << "\n" "\t" "}" "\n" "\n"; } } objectfp.close(); #ifdef _WIN32 _unlink(objectsPath.CStr()); #endif /* _WIN32 */ if (rename(tempObjectsPath.CStr(), objectsPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempObjectsPath)); } } /** * Periodically writes the status.dat and objects.cache files. */ void StatusDataWriter::StatusTimerHandler(void) { if (m_ObjectsCacheOutdated) { UpdateObjectsCache(); m_ObjectsCacheOutdated = false; } double start = Utility::GetTime(); String statusPath = GetStatusPath(); std::fstream statusfp; String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", 0644, statusfp); statusfp << std::fixed; statusfp << "# Icinga status file" "\n" "# This file is auto-generated. Do not modify this file." "\n" "\n"; statusfp << "info {" "\n" "\t" "created=" << Utility::GetTime() << "\n" "\t" "version=" << Application::GetAppVersion() << "\n" "\t" "}" "\n" "\n"; statusfp << "programstatus {" "\n" "\t" "icinga_pid=" << Utility::GetPid() << "\n" "\t" "daemon_mode=1" "\n" "\t" "program_start=" << static_cast(Application::GetStartTime()) << "\n" "\t" "active_host_checks_enabled=" << (IcingaApplication::GetInstance()->GetEnableHostChecks() ? 1 : 0) << "\n" "\t" "passive_host_checks_enabled=1" "\n" "\t" "active_service_checks_enabled=" << (IcingaApplication::GetInstance()->GetEnableServiceChecks() ? 1 : 0) << "\n" "\t" "passive_service_checks_enabled=1" "\n" "\t" "check_service_freshness=1" "\n" "\t" "check_host_freshness=1" "\n" "\t" "enable_notifications=" << (IcingaApplication::GetInstance()->GetEnableNotifications() ? 1 : 0) << "\n" "\t" "enable_event_handlers=" << (IcingaApplication::GetInstance()->GetEnableEventHandlers() ? 1 : 0) << "\n" "\t" "enable_flap_detection=" << (IcingaApplication::GetInstance()->GetEnableFlapping() ? 1 : 0) << "\n" "\t" "enable_failure_prediction=0" "\n" "\t" "process_performance_data=" << (IcingaApplication::GetInstance()->GetEnablePerfdata() ? 1 : 0) << "\n" "\t" "active_scheduled_host_check_stats=" << CIB::GetActiveHostChecksStatistics(60) << "," << CIB::GetActiveHostChecksStatistics(5 * 60) << "," << CIB::GetActiveHostChecksStatistics(15 * 60) << "\n" "\t" "passive_host_check_stats=" << CIB::GetPassiveHostChecksStatistics(60) << "," << CIB::GetPassiveHostChecksStatistics(5 * 60) << "," << CIB::GetPassiveHostChecksStatistics(15 * 60) << "\n" "\t" "active_scheduled_service_check_stats=" << CIB::GetActiveServiceChecksStatistics(60) << "," << CIB::GetActiveServiceChecksStatistics(5 * 60) << "," << CIB::GetActiveServiceChecksStatistics(15 * 60) << "\n" "\t" "passive_service_check_stats=" << CIB::GetPassiveServiceChecksStatistics(60) << "," << CIB::GetPassiveServiceChecksStatistics(5 * 60) << "," << CIB::GetPassiveServiceChecksStatistics(15 * 60) << "\n" "\t" "next_downtime_id=" << Downtime::GetNextDowntimeID() << "\n" "\t" "next_comment_id=" << Comment::GetNextCommentID() << "\n"; statusfp << "\t" "}" "\n" "\n"; for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { std::ostringstream tempstatusfp; tempstatusfp << std::fixed; DumpHostStatus(tempstatusfp, host); statusfp << tempstatusfp.str(); for (const Service::Ptr& service : host->GetServices()) { std::ostringstream tempstatusfp; tempstatusfp << std::fixed; DumpServiceStatus(tempstatusfp, service); statusfp << tempstatusfp.str(); } } statusfp.close(); #ifdef _WIN32 _unlink(statusPath.CStr()); #endif /* _WIN32 */ if (rename(tempStatusPath.CStr(), statusPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempStatusPath)); } Log(LogNotice, "StatusDataWriter") << "Writing status.dat file took " << Utility::FormatDuration(Utility::GetTime() - start); } void StatusDataWriter::ObjectHandler(void) { m_ObjectsCacheOutdated = true; } icinga2-2.8.1/lib/compat/statusdatawriter.hpp000066400000000000000000000067211322762156600212320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STATUSDATAWRITER_H #define STATUSDATAWRITER_H #include "compat/statusdatawriter.thpp" #include "icinga/customvarobject.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/command.hpp" #include "icinga/compatutility.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include #include namespace icinga { /** * @ingroup compat */ class StatusDataWriter : public ObjectImpl { public: DECLARE_OBJECT(StatusDataWriter); DECLARE_OBJECTNAME(StatusDataWriter); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Timer::Ptr m_StatusTimer; bool m_ObjectsCacheOutdated; void DumpCommand(std::ostream& fp, const Command::Ptr& command); void DumpTimePeriod(std::ostream& fp, const TimePeriod::Ptr& tp); void DumpDowntimes(std::ostream& fp, const Checkable::Ptr& owner); void DumpComments(std::ostream& fp, const Checkable::Ptr& owner); void DumpHostStatus(std::ostream& fp, const Host::Ptr& host); void DumpHostObject(std::ostream& fp, const Host::Ptr& host); void DumpCheckableStatusAttrs(std::ostream& fp, const Checkable::Ptr& checkable); template void DumpNameList(std::ostream& fp, const T& list) { bool first = true; for (const auto& obj : list) { if (!first) fp << ","; else first = false; fp << obj->GetName(); } } template void DumpStringList(std::ostream& fp, const T& list) { bool first = true; for (const auto& str : list) { if (!first) fp << ","; else first = false; fp << str; } } void DumpServiceStatus(std::ostream& fp, const Service::Ptr& service); void DumpServiceObject(std::ostream& fp, const Service::Ptr& service); void DumpCustomAttributes(std::ostream& fp, const CustomVarObject::Ptr& object); void UpdateObjectsCache(void); void StatusTimerHandler(void); void ObjectHandler(void); }; } #endif /* STATUSDATAWRITER_H */ icinga2-2.8.1/lib/compat/statusdatawriter.ti000066400000000000000000000035651322762156600210620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library compat; namespace icinga { class StatusDataWriter : ConfigObject { [config] String status_path { default {{{ return Application::GetLocalStateDir() + "/cache/icinga2/status.dat"; }}} }; [config] String objects_path { default {{{ return Application::GetLocalStateDir() + "/cache/icinga2/objects.cache"; }}} }; [config] double update_interval { default {{{ return 15; }}} }; }; } icinga2-2.8.1/lib/config/000077500000000000000000000000001322762156600150635ustar00rootroot00000000000000icinga2-2.8.1/lib/config/CMakeLists.txt000066400000000000000000000050161322762156600176250ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. find_package(BISON 2.3.0 REQUIRED) find_package(FLEX 2.5.31 REQUIRED) bison_target(config_parser config_parser.yy ${CMAKE_CURRENT_BINARY_DIR}/config_parser.cc) set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/config_parser.cc PROPERTY EXCLUDE_UNITY_BUILD TRUE) flex_target(config_lexer config_lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/config_lexer.cc) set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/config_lexer.cc PROPERTY EXCLUDE_UNITY_BUILD TRUE) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/config_parser.cc PROPERTY COMPILE_FLAGS "-Wno-deprecated-register -Wno-parentheses-equality -Wno-unused-function") set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/config_lexer.cc PROPERTY COMPILE_FLAGS "-Wno-deprecated-register -Wno-null-conversion") endif() add_flex_bison_dependency(config_lexer config_parser) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) set(config_SOURCES activationcontext.cpp applyrule.cpp configcompilercontext.cpp configcompiler.cpp configitembuilder.cpp configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS} expression.cpp objectrule.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(config config config_SOURCES) endif() add_library(config SHARED ${config_SOURCES}) target_link_libraries(config ${Boost_LIBRARIES} base) set_target_properties ( config PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_CONFIG_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS config RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS config LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() icinga2-2.8.1/lib/config/activationcontext.cpp000066400000000000000000000053671322762156600213500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/activationcontext.hpp" #include "base/exception.hpp" using namespace icinga; boost::thread_specific_ptr > ActivationContext::m_ActivationStack; std::stack& ActivationContext::GetActivationStack(void) { std::stack *actx = m_ActivationStack.get(); if (!actx) { actx = new std::stack(); m_ActivationStack.reset(actx); } return *actx; } void ActivationContext::PushContext(const ActivationContext::Ptr& context) { GetActivationStack().push(context); } void ActivationContext::PopContext(void) { ASSERT(!GetActivationStack().empty()); GetActivationStack().pop(); } ActivationContext::Ptr ActivationContext::GetCurrentContext(void) { std::stack& astack = GetActivationStack(); if (astack.empty()) BOOST_THROW_EXCEPTION(std::runtime_error("Objects may not be created outside of an activation context.")); return astack.top(); } ActivationScope::ActivationScope(const ActivationContext::Ptr& context) : m_Context(context) { if (!m_Context) m_Context = new ActivationContext(); ActivationContext::PushContext(m_Context); } ActivationScope::~ActivationScope(void) { ActivationContext::PopContext(); } ActivationContext::Ptr ActivationScope::GetContext(void) const { return m_Context; } icinga2-2.8.1/lib/config/activationcontext.hpp000066400000000000000000000045211322762156600213440ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ACTIVATIONCONTEXT_H #define ACTIVATIONCONTEXT_H #include "config/i2-config.hpp" #include "base/object.hpp" #include #include namespace icinga { class I2_CONFIG_API ActivationContext : public Object { public: DECLARE_PTR_TYPEDEFS(ActivationContext); static ActivationContext::Ptr GetCurrentContext(void); private: static void PushContext(const ActivationContext::Ptr& context); static void PopContext(void); static std::stack& GetActivationStack(void); static boost::thread_specific_ptr > m_ActivationStack; friend class ActivationScope; }; class I2_CONFIG_API ActivationScope { public: ActivationScope(const ActivationContext::Ptr& context = ActivationContext::Ptr()); ~ActivationScope(void); ActivationContext::Ptr GetContext(void) const; private: ActivationContext::Ptr m_Context; }; } #endif /* ACTIVATIONCONTEXT_H */ icinga2-2.8.1/lib/config/applyrule.cpp000066400000000000000000000117671322762156600176200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/applyrule.hpp" #include "base/logger.hpp" #include using namespace icinga; ApplyRule::RuleMap ApplyRule::m_Rules; ApplyRule::TypeMap ApplyRule::m_Types; ApplyRule::ApplyRule(const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope) : m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_Package(package), m_FKVar(fkvar), m_FVVar(fvvar), m_FTerm(fterm), m_IgnoreOnError(ignoreOnError), m_DebugInfo(di), m_Scope(scope), m_HasMatches(false) { } String ApplyRule::GetTargetType(void) const { return m_TargetType; } String ApplyRule::GetName(void) const { return m_Name; } boost::shared_ptr ApplyRule::GetExpression(void) const { return m_Expression; } boost::shared_ptr ApplyRule::GetFilter(void) const { return m_Filter; } String ApplyRule::GetPackage(void) const { return m_Package; } String ApplyRule::GetFKVar(void) const { return m_FKVar; } String ApplyRule::GetFVVar(void) const { return m_FVVar; } boost::shared_ptr ApplyRule::GetFTerm(void) const { return m_FTerm; } bool ApplyRule::GetIgnoreOnError(void) const { return m_IgnoreOnError; } DebugInfo ApplyRule::GetDebugInfo(void) const { return m_DebugInfo; } Dictionary::Ptr ApplyRule::GetScope(void) const { return m_Scope; } void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope) { m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, package, fkvar, fvvar, fterm, ignoreOnError, di, scope)); } bool ApplyRule::EvaluateFilter(ScriptFrame& frame) const { return Convert::ToBool(m_Filter->Evaluate(frame)); } void ApplyRule::RegisterType(const String& sourceType, const std::vector& targetTypes) { m_Types[sourceType] = targetTypes; } bool ApplyRule::IsValidSourceType(const String& sourceType) { return m_Types.find(sourceType) != m_Types.end(); } bool ApplyRule::IsValidTargetType(const String& sourceType, const String& targetType) { auto it = m_Types.find(sourceType); if (it == m_Types.end()) return false; if (it->second.size() == 1 && targetType == "") return true; for (const String& type : it->second) { if (type == targetType) return true; } return false; } std::vector ApplyRule::GetTargetTypes(const String& sourceType) { auto it = m_Types.find(sourceType); if (it == m_Types.end()) return std::vector(); return it->second; } void ApplyRule::AddMatch(void) { m_HasMatches = true; } bool ApplyRule::HasMatches(void) const { return m_HasMatches; } std::vector& ApplyRule::GetRules(const String& type) { auto it = m_Rules.find(type); if (it == m_Rules.end()) { static std::vector emptyList; return emptyList; } return it->second; } void ApplyRule::CheckMatches(void) { for (const RuleMap::value_type& kv : m_Rules) { for (const ApplyRule& rule : kv.second) { if (!rule.HasMatches()) Log(LogWarning, "ApplyRule") << "Apply rule '" << rule.GetName() << "' (" << rule.GetDebugInfo() << ") for type '" << kv.first << "' does not match anywhere!"; } } } icinga2-2.8.1/lib/config/applyrule.hpp000066400000000000000000000074431322762156600176210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APPLYRULE_H #define APPLYRULE_H #include "config/i2-config.hpp" #include "config/expression.hpp" #include "base/debuginfo.hpp" #include namespace icinga { /** * @ingroup config */ class I2_CONFIG_API ApplyRule { public: typedef std::map > TypeMap; typedef std::map > RuleMap; String GetTargetType(void) const; String GetName(void) const; boost::shared_ptr GetExpression(void) const; boost::shared_ptr GetFilter(void) const; String GetPackage(void) const; String GetFKVar(void) const; String GetFVVar(void) const; boost::shared_ptr GetFTerm(void) const; bool GetIgnoreOnError(void) const; DebugInfo GetDebugInfo(void) const; Dictionary::Ptr GetScope(void) const; void AddMatch(void); bool HasMatches(void) const; bool EvaluateFilter(ScriptFrame& frame) const; static void AddRule(const String& sourceType, const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope); static std::vector& GetRules(const String& type); static void RegisterType(const String& sourceType, const std::vector& targetTypes); static bool IsValidSourceType(const String& sourceType); static bool IsValidTargetType(const String& sourceType, const String& targetType); static std::vector GetTargetTypes(const String& sourceType); static void CheckMatches(void); private: String m_TargetType; String m_Name; boost::shared_ptr m_Expression; boost::shared_ptr m_Filter; String m_Package; String m_FKVar; String m_FVVar; boost::shared_ptr m_FTerm; bool m_IgnoreOnError; DebugInfo m_DebugInfo; Dictionary::Ptr m_Scope; bool m_HasMatches; static TypeMap m_Types; static RuleMap m_Rules; ApplyRule(const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope); }; } #endif /* APPLYRULE_H */ icinga2-2.8.1/lib/config/config_lexer.ll000066400000000000000000000205001322762156600200550ustar00rootroot00000000000000%{ /****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configcompiler.hpp" #include "config/expression.hpp" #include "base/exception.hpp" using namespace icinga; #include "config/config_parser.hh" #include #define YYLTYPE icinga::CompilerDebugInfo #define YY_EXTRA_TYPE ConfigCompiler * #define YY_USER_ACTION \ do { \ yylloc->Path = yyextra->GetPath(); \ yylloc->FirstLine = yylineno; \ yylloc->FirstColumn = yycolumn; \ yylloc->LastLine = yylineno; \ yylloc->LastColumn = yycolumn + yyleng - 1; \ yycolumn += yyleng; \ } while (0); #define YY_INPUT(buf, result, max_size) \ do { \ result = yyextra->ReadInput(buf, max_size); \ } while (0) %} %option reentrant noyywrap yylineno %option bison-bridge bison-locations %option never-interactive nounistd %option noinput nounput %x C_COMMENT %x STRING %x HEREDOC %% \" { yyextra->m_LexBuffer.str(""); yyextra->m_LexBuffer.clear(); yyextra->m_LocationBegin = *yylloc; BEGIN(STRING); } \" { BEGIN(INITIAL); yylloc->FirstLine = yyextra->m_LocationBegin.FirstLine; yylloc->FirstColumn = yyextra->m_LocationBegin.FirstColumn; yylval->text = new String(yyextra->m_LexBuffer.str()); return T_STRING; } \n { BOOST_THROW_EXCEPTION(ScriptError("Unterminated string literal", DebugInfoRange(yyextra->m_LocationBegin, *yylloc))); } \\[0-7]{1,3} { /* octal escape sequence */ int result; (void) sscanf(yytext + 1, "%o", &result); if (result > 0xff) { /* error, constant is out-of-bounds */ BOOST_THROW_EXCEPTION(ScriptError("Constant is out of bounds: " + String(yytext), *yylloc)); } yyextra->m_LexBuffer << static_cast(result); } \\[0-9]+ { /* generate error - bad escape sequence; something * like '\48' or '\0777777' */ BOOST_THROW_EXCEPTION(ScriptError("Bad escape sequence found: " + String(yytext), *yylloc)); } \\n { yyextra->m_LexBuffer << "\n"; } \\\\ { yyextra->m_LexBuffer << "\\"; } \\\" { yyextra->m_LexBuffer << "\""; } \\t { yyextra->m_LexBuffer << "\t"; } \\r { yyextra->m_LexBuffer << "\r"; } \\b { yyextra->m_LexBuffer << "\b"; } \\f { yyextra->m_LexBuffer << "\f"; } \\\n { yyextra->m_LexBuffer << yytext[1]; } \\. { BOOST_THROW_EXCEPTION(ScriptError("Bad escape sequence found: " + String(yytext), *yylloc)); } [^\\\n\"]+ { char *yptr = yytext; while (*yptr) yyextra->m_LexBuffer << *yptr++; } <> { BOOST_THROW_EXCEPTION(ScriptError("End-of-file while in string literal", DebugInfoRange(yyextra->m_LocationBegin, *yylloc))); } \{\{\{ { yyextra->m_LexBuffer.str(""); yyextra->m_LexBuffer.clear(); yyextra->m_LocationBegin = *yylloc; BEGIN(HEREDOC); } \}\}\} { BEGIN(INITIAL); yylloc->FirstLine = yyextra->m_LocationBegin.FirstLine; yylloc->FirstColumn = yyextra->m_LocationBegin.FirstColumn; yylval->text = new String(yyextra->m_LexBuffer.str()); return T_STRING; } (.|\n) { yyextra->m_LexBuffer << yytext[0]; } { "/*" BEGIN(C_COMMENT); } { "*/" BEGIN(INITIAL); [^*] /* ignore comment */ "*" /* ignore star */ } <> { BOOST_THROW_EXCEPTION(ScriptError("End-of-file while in comment", *yylloc)); } \/\/[^\n]* /* ignore C++-style comments */ #[^\n]* /* ignore shell-style comments */ [ \t] /* ignore whitespace */ { object return T_OBJECT; template return T_TEMPLATE; include return T_INCLUDE; include_recursive return T_INCLUDE_RECURSIVE; include_zones return T_INCLUDE_ZONES; library return T_LIBRARY; null return T_NULL; true { yylval->boolean = 1; return T_BOOLEAN; } false { yylval->boolean = 0; return T_BOOLEAN; } const return T_CONST; var return T_VAR; this return T_THIS; globals return T_GLOBALS; locals return T_LOCALS; use return T_USE; __using return T_USING; apply return T_APPLY; default return T_DEFAULT; to return T_TO; where return T_WHERE; import return T_IMPORT; assign return T_ASSIGN; ignore return T_IGNORE; function return T_FUNCTION; return return T_RETURN; break return T_BREAK; continue return T_CONTINUE; for return T_FOR; if return T_IF; else return T_ELSE; while return T_WHILE; throw return T_THROW; try return T_TRY; except return T_EXCEPT; ignore_on_error return T_IGNORE_ON_ERROR; current_filename return T_CURRENT_FILENAME; current_line return T_CURRENT_LINE; debugger return T_DEBUGGER; =\> return T_FOLLOWS; \<\< return T_SHIFT_LEFT; \>\> return T_SHIFT_RIGHT; \<= return T_LESS_THAN_OR_EQUAL; \>= return T_GREATER_THAN_OR_EQUAL; == return T_EQUAL; != return T_NOT_EQUAL; !in return T_NOT_IN; in return T_IN; && return T_LOGICAL_AND; \|\| return T_LOGICAL_OR; \{\{ return T_NULLARY_LAMBDA_BEGIN; \}\} return T_NULLARY_LAMBDA_END; [a-zA-Z_][a-zA-Z0-9\_]* { yylval->text = new String(yytext); return T_IDENTIFIER; } @[a-zA-Z_][a-zA-Z0-9\_]* { yylval->text = new String(yytext + 1); return T_IDENTIFIER; } \<[^ \>]*\> { yytext[yyleng-1] = '\0'; yylval->text = new String(yytext + 1); return T_STRING_ANGLE; } [0-9]+(\.[0-9]+)?ms { yylval->num = strtod(yytext, NULL) / 1000; return T_NUMBER; } [0-9]+(\.[0-9]+)?d { yylval->num = strtod(yytext, NULL) * 60 * 60 * 24; return T_NUMBER; } [0-9]+(\.[0-9]+)?h { yylval->num = strtod(yytext, NULL) * 60 * 60; return T_NUMBER; } [0-9]+(\.[0-9]+)?m { yylval->num = strtod(yytext, NULL) * 60; return T_NUMBER; } [0-9]+(\.[0-9]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; } [0-9]+(\.[0-9]+)? { yylval->num = strtod(yytext, NULL); return T_NUMBER; } = { yylval->csop = OpSetLiteral; return T_SET; } \+= { yylval->csop = OpSetAdd; return T_SET_ADD; } -= { yylval->csop = OpSetSubtract; return T_SET_SUBTRACT; } \*= { yylval->csop = OpSetMultiply; return T_SET_MULTIPLY; } \/= { yylval->csop = OpSetDivide; return T_SET_DIVIDE; } \%= { yylval->csop = OpSetModulo; return T_SET_MODULO; } \^= { yylval->csop = OpSetXor; return T_SET_XOR; } \&= { yylval->csop = OpSetBinaryAnd; return T_SET_BINARY_AND; } \|= { yylval->csop = OpSetBinaryOr; return T_SET_BINARY_OR; } \+ return T_PLUS; \- return T_MINUS; \* return T_MULTIPLY; \/ return T_DIVIDE_OP; \% return T_MODULO; \^ return T_XOR; \& return T_BINARY_AND; \| return T_BINARY_OR; \< return T_LESS_THAN; \> return T_GREATER_THAN; } \( { yyextra->m_IgnoreNewlines.push(true); return '('; } \) { yyextra->m_IgnoreNewlines.pop(); return ')'; } [\r\n]+ { yycolumn -= strlen(yytext) - 1; if (!yyextra->m_IgnoreNewlines.top()) { return T_NEWLINE; } } <> { if (!yyextra->m_Eof) { yyextra->m_Eof = true; return T_NEWLINE; } else { yyterminate(); } } . return yytext[0]; %% void ConfigCompiler::InitializeScanner(void) { yylex_init(&m_Scanner); yyset_extra(this, m_Scanner); } void ConfigCompiler::DestroyScanner(void) { yylex_destroy(m_Scanner); } icinga2-2.8.1/lib/config/config_parser.yy000066400000000000000000000764471322762156600203110ustar00rootroot00000000000000%{ #define YYDEBUG 1 /****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/i2-config.hpp" #include "config/configcompiler.hpp" #include "config/expression.hpp" #include "config/applyrule.hpp" #include "config/objectrule.hpp" #include "base/value.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/configtype.hpp" #include "base/exception.hpp" #include #include #define YYLTYPE icinga::CompilerDebugInfo #define YYERROR_VERBOSE #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) { \ (Current).Path = YYRHSLOC(Rhs, 1).Path; \ (Current).FirstLine = YYRHSLOC(Rhs, 1).FirstLine; \ (Current).FirstColumn = YYRHSLOC(Rhs, 1).FirstColumn; \ (Current).LastLine = YYRHSLOC(Rhs, N).LastLine; \ (Current).LastColumn = YYRHSLOC(Rhs, N).LastColumn; \ } else { \ (Current).Path = YYRHSLOC(Rhs, 0).Path; \ (Current).FirstLine = (Current).LastLine = \ YYRHSLOC(Rhs, 0).LastLine; \ (Current).FirstColumn = (Current).LastColumn = \ YYRHSLOC(Rhs, 0).LastColumn; \ } \ } while (0) #define YY_LOCATION_PRINT(file, loc) \ do { \ std::ostringstream msgbuf; \ msgbuf << loc; \ std::string str = msgbuf.str(); \ fputs(str.c_str(), file); \ } while (0) #define YYINITDEPTH 10000 using namespace icinga; template static void MakeRBinaryOp(Expression** result, Expression *left, Expression *right, const DebugInfo& diLeft, const DebugInfo& diRight) { *result = new T(left, right, DebugInfoRange(diLeft, diRight)); } %} %pure-parser %locations %defines %error-verbose %glr-parser %parse-param { std::vector > *llist } %parse-param { ConfigCompiler *context } %lex-param { void *scanner } %union { String *text; double num; bool boolean; icinga::Expression *expr; icinga::DictExpression *dexpr; CombinedSetOp csop; std::vector *slist; std::vector > *llist; std::vector *elist; std::vector > *ebranchlist; std::pair *ebranch; std::pair *cvitem; std::map *cvlist; icinga::ScopeSpecifier scope; } %token T_NEWLINE "new-line" %token T_STRING %token T_STRING_ANGLE %token T_NUMBER %token T_BOOLEAN %token T_NULL %token T_IDENTIFIER %token T_SET "= (T_SET)" %token T_SET_ADD "+= (T_SET_ADD)" %token T_SET_SUBTRACT "-= (T_SET_SUBTRACT)" %token T_SET_MULTIPLY "*= (T_SET_MULTIPLY)" %token T_SET_DIVIDE "/= (T_SET_DIVIDE)" %token T_SET_MODULO "%= (T_SET_MODULO)" %token T_SET_XOR "^= (T_SET_XOR)" %token T_SET_BINARY_AND "&= (T_SET_BINARY_AND)" %token T_SET_BINARY_OR "|= (T_SET_BINARY_OR)" %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)" %token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)" %token T_EQUAL "== (T_EQUAL)" %token T_NOT_EQUAL "!= (T_NOT_EQUAL)" %token T_IN "in (T_IN)" %token T_NOT_IN "!in (T_NOT_IN)" %token T_LOGICAL_AND "&& (T_LOGICAL_AND)" %token T_LOGICAL_OR "|| (T_LOGICAL_OR)" %token T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)" %token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)" %token T_PLUS "+ (T_PLUS)" %token T_MINUS "- (T_MINUS)" %token T_MULTIPLY "* (T_MULTIPLY)" %token T_DIVIDE_OP "/ (T_DIVIDE_OP)" %token T_MODULO "% (T_MODULO)" %token T_XOR "^ (T_XOR)" %token T_BINARY_AND "& (T_BINARY_AND)" %token T_BINARY_OR "| (T_BINARY_OR)" %token T_LESS_THAN "< (T_LESS_THAN)" %token T_GREATER_THAN "> (T_GREATER_THAN)" %token T_VAR "var (T_VAR)" %token T_GLOBALS "globals (T_GLOBALS)" %token T_LOCALS "locals (T_LOCALS)" %token T_CONST "const (T_CONST)" %token T_DEFAULT "default (T_DEFAULT)" %token T_IGNORE_ON_ERROR "ignore_on_error (T_IGNORE_ON_ERROR)" %token T_CURRENT_FILENAME "current_filename (T_CURRENT_FILENAME)" %token T_CURRENT_LINE "current_line (T_CURRENT_LINE)" %token T_DEBUGGER "debugger (T_DEBUGGER)" %token T_USE "use (T_USE)" %token T_USING "__using (T_USING)" %token T_OBJECT "object (T_OBJECT)" %token T_TEMPLATE "template (T_TEMPLATE)" %token T_INCLUDE "include (T_INCLUDE)" %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)" %token T_INCLUDE_ZONES "include_zones (T_INCLUDE_ZONES)" %token T_LIBRARY "library (T_LIBRARY)" %token T_APPLY "apply (T_APPLY)" %token T_TO "to (T_TO)" %token T_WHERE "where (T_WHERE)" %token T_IMPORT "import (T_IMPORT)" %token T_ASSIGN "assign (T_ASSIGN)" %token T_IGNORE "ignore (T_IGNORE)" %token T_FUNCTION "function (T_FUNCTION)" %token T_RETURN "return (T_RETURN)" %token T_BREAK "break (T_BREAK)" %token T_CONTINUE "continue (T_CONTINUE)" %token T_FOR "for (T_FOR)" %token T_IF "if (T_IF)" %token T_ELSE "else (T_ELSE)" %token T_WHILE "while (T_WHILE)" %token T_THROW "throw (T_THROW)" %token T_TRY "try (T_TRY)" %token T_EXCEPT "except (T_EXCEPT)" %token T_FOLLOWS "=> (T_FOLLOWS)" %token T_NULLARY_LAMBDA_BEGIN "{{ (T_NULLARY_LAMBDA_BEGIN)" %token T_NULLARY_LAMBDA_END "}} (T_NULLARY_LAMBDA_END)" %type identifier %type rterm_items %type rterm_items_inner %type identifier_items %type identifier_items_inner %type combined_set_op %type statements %type lterm_items %type lterm_items_inner %type rterm %type rterm_array %type rterm_dict %type rterm_scope_require_side_effect %type rterm_scope %type else_if_branches %type else_if_branch %type rterm_side_effect %type rterm_no_side_effect %type rterm_no_side_effect_no_dict %type lterm %type object %type apply %type optional_rterm %type target_type_specifier %type default_specifier %type ignore_specifier %type use_specifier %type use_specifier_items %type use_specifier_item %type object_declaration %right T_FOLLOWS %right T_INCLUDE T_INCLUDE_RECURSIVE T_INCLUDE_ZONES T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE %right T_FUNCTION T_FOR %left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR %left T_LOGICAL_OR %left T_LOGICAL_AND %left T_RETURN T_BREAK T_CONTINUE %left T_IDENTIFIER %left T_BINARY_OR %left T_XOR %left T_BINARY_AND %nonassoc T_EQUAL T_NOT_EQUAL %left T_IN T_NOT_IN %nonassoc T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL %left T_SHIFT_LEFT T_SHIFT_RIGHT %left T_PLUS T_MINUS %left T_MULTIPLY T_DIVIDE_OP T_MODULO %left UNARY_MINUS UNARY_PLUS %right '!' '~' %left '.' '(' '[' %left T_VAR T_THIS T_GLOBALS T_LOCALS %right ';' ',' %right T_NEWLINE %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); extern int yydebug; void yyerror(const YYLTYPE *locp, std::vector > *, ConfigCompiler *context, const char *err) { bool incomplete = context && context->m_Eof && (context->m_OpenBraces > 0); BOOST_THROW_EXCEPTION(ScriptError(err, *locp, incomplete)); } int yyparse(std::vector > *llist, ConfigCompiler *context); static void BeginFlowControlBlock(ConfigCompiler *compiler, int allowedTypes, bool inherit) { if (inherit) allowedTypes |= compiler->m_FlowControlInfo.top(); compiler->m_FlowControlInfo.push(allowedTypes); } static void EndFlowControlBlock(ConfigCompiler *compiler) { compiler->m_FlowControlInfo.pop(); } static void UseFlowControl(ConfigCompiler *compiler, FlowControlType type, const CompilerDebugInfo& location) { int fci = compiler->m_FlowControlInfo.top(); if ((type & fci) != type) BOOST_THROW_EXCEPTION(ScriptError("Invalid flow control statement.", location)); } Expression *ConfigCompiler::Compile(void) { std::vector > llist; //yydebug = 1; m_IgnoreNewlines.push(false); BeginFlowControlBlock(this, 0, false); if (yyparse(&llist, this) != 0) return NULL; EndFlowControlBlock(this); m_IgnoreNewlines.pop(); std::vector dlist; std::vector >::size_type num = 0; for (const auto& litem : llist) { if (!litem.second.SideEffect && num != llist.size() - 1) { yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); } dlist.push_back(litem.first); num++; } DictExpression *expr = new DictExpression(dlist); expr->MakeInline(); return expr; } #define scanner (context->GetScanner()) %} %% script: statements { llist->swap(*$1); delete $1; } ; statements: newlines lterm_items { $$ = $2; } | lterm_items ; lterm_items: /* empty */ { $$ = new std::vector >(); } | lterm_items_inner | lterm_items_inner sep ; lterm_items_inner: lterm %dprec 2 { $$ = new std::vector >(); EItemInfo info = { true, @1 }; $$->push_back(std::make_pair($1, info)); } | rterm_no_side_effect { $$ = new std::vector >(); EItemInfo info = { false, @1 }; $$->push_back(std::make_pair($1, info)); } | lterm_items_inner sep lterm %dprec 1 { if ($1) $$ = $1; else $$ = new std::vector >(); if ($3) { EItemInfo info = { true, @3 }; $$->push_back(std::make_pair($3, info)); } } | lterm_items_inner sep rterm_no_side_effect %dprec 1 { if ($1) $$ = $1; else $$ = new std::vector >(); if ($3) { EItemInfo info = { false, @3 }; $$->push_back(std::make_pair($3, info)); } } ; identifier: T_IDENTIFIER | T_STRING ; object: { context->m_ObjectAssign.push(true); context->m_SeenAssign.push(false); context->m_SeenIgnore.push(false); context->m_Assign.push(0); context->m_Ignore.push(0); } object_declaration rterm optional_rterm use_specifier default_specifier ignore_specifier { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope_require_side_effect { EndFlowControlBlock(context); context->m_ObjectAssign.pop(); bool abstract = $2; bool defaultTmpl = $6; if (!abstract && defaultTmpl) BOOST_THROW_EXCEPTION(ScriptError("'default' keyword is invalid for object definitions", DebugInfoRange(@2, @4))); bool seen_assign = context->m_SeenAssign.top(); context->m_SeenAssign.pop(); bool seen_ignore = context->m_SeenIgnore.top(); context->m_SeenIgnore.pop(); Expression *ignore = context->m_Ignore.top(); context->m_Ignore.pop(); Expression *assign = context->m_Assign.top(); context->m_Assign.pop(); Expression *filter = NULL; if (seen_assign) { if (ignore) { Expression *rex = new LogicalNegateExpression(ignore, DebugInfoRange(@2, @5)); filter = new LogicalAndExpression(assign, rex, DebugInfoRange(@2, @5)); } else filter = assign; } else if (seen_ignore) { BOOST_THROW_EXCEPTION(ScriptError("object rule 'ignore where' cannot be used without 'assign where'", DebugInfoRange(@2, @4))); } $$ = new ObjectExpression(abstract, $3, $4, filter, context->GetZone(), context->GetPackage(), $5, $6, $7, $9, DebugInfoRange(@2, @7)); } ; object_declaration: T_OBJECT { $$ = false; } | T_TEMPLATE { $$ = true; } ; identifier_items: /* empty */ { $$ = new std::vector(); } | identifier_items_inner | identifier_items_inner ',' ; identifier_items_inner: identifier { $$ = new std::vector(); $$->push_back(*$1); delete $1; } | identifier_items_inner ',' identifier { if ($1) $$ = $1; else $$ = new std::vector(); $$->push_back(*$3); delete $3; } ; combined_set_op: T_SET | T_SET_ADD | T_SET_SUBTRACT | T_SET_MULTIPLY | T_SET_DIVIDE | T_SET_MODULO | T_SET_XOR | T_SET_BINARY_AND | T_SET_BINARY_OR ; lterm: T_LIBRARY rterm { $$ = new LibraryExpression($2, @$); } | rterm combined_set_op rterm { $$ = new SetExpression($1, $2, $3, @$); } | T_INCLUDE rterm { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, NULL, NULL, IncludeRegular, false, context->GetZone(), context->GetPackage(), @$); } | T_INCLUDE T_STRING_ANGLE { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), MakeLiteral(*$2), NULL, NULL, IncludeRegular, true, context->GetZone(), context->GetPackage(), @$); delete $2; } | T_INCLUDE_RECURSIVE rterm { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, MakeLiteral("*.conf"), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); } | T_INCLUDE_RECURSIVE rterm ',' rterm { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, $4, NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); } | T_INCLUDE_ZONES rterm ',' rterm { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, MakeLiteral("*.conf"), $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$); } | T_INCLUDE_ZONES rterm ',' rterm ',' rterm { $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, $6, $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$); } | T_IMPORT rterm { $$ = new ImportExpression($2, @$); } | T_ASSIGN T_WHERE { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope %dprec 2 { EndFlowControlBlock(context); if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$)); context->m_SeenAssign.top() = true; if (context->m_Assign.top()) context->m_Assign.top() = new LogicalOrExpression(context->m_Assign.top(), $4, @$); else context->m_Assign.top() = $4; $$ = MakeLiteral(); } | T_ASSIGN T_WHERE rterm %dprec 1 { ASSERT(!dynamic_cast($3)); if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$)); context->m_SeenAssign.top() = true; if (context->m_Assign.top()) context->m_Assign.top() = new LogicalOrExpression(context->m_Assign.top(), $3, @$); else context->m_Assign.top() = $3; $$ = MakeLiteral(); } | T_IGNORE T_WHERE { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope %dprec 2 { EndFlowControlBlock(context); if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$)); context->m_SeenIgnore.top() = true; if (context->m_Ignore.top()) context->m_Ignore.top() = new LogicalOrExpression(context->m_Ignore.top(), $4, @$); else context->m_Ignore.top() = $4; $$ = MakeLiteral(); } | T_IGNORE T_WHERE rterm %dprec 1 { ASSERT(!dynamic_cast($3)); if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$)); context->m_SeenIgnore.top() = true; if (context->m_Ignore.top()) context->m_Ignore.top() = new LogicalOrExpression(context->m_Ignore.top(), $3, @$); else context->m_Ignore.top() = $3; $$ = MakeLiteral(); } | T_RETURN optional_rterm { UseFlowControl(context, FlowControlReturn, @$); $$ = new ReturnExpression($2, @$); } | T_BREAK { UseFlowControl(context, FlowControlBreak, @$); $$ = new BreakExpression(@$); } | T_CONTINUE { UseFlowControl(context, FlowControlContinue, @$); $$ = new ContinueExpression(@$); } | T_DEBUGGER { $$ = new BreakpointExpression(@$); } | T_USING rterm { $$ = new UsingExpression($2, @$); } | apply | object | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' { BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); } rterm_scope_require_side_effect { EndFlowControlBlock(context); $$ = new ForExpression(*$3, *$5, $7, $10, @$); delete $3; delete $5; } | T_FOR '(' identifier T_IN rterm ')' { BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); } rterm_scope_require_side_effect { EndFlowControlBlock(context); $$ = new ForExpression(*$3, "", $5, $8, @$); delete $3; } | T_FUNCTION identifier '(' identifier_items ')' use_specifier { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope { EndFlowControlBlock(context); FunctionExpression *fexpr = new FunctionExpression(*$2, *$4, $6, $8, @$); delete $4; $$ = new SetExpression(MakeIndexer(ScopeThis, *$2), OpSetLiteral, fexpr, @$); delete $2; } | T_CONST T_IDENTIFIER T_SET rterm { $$ = new SetExpression(MakeIndexer(ScopeGlobal, *$2), OpSetLiteral, $4); delete $2; } | T_VAR rterm { Expression *expr = $2; BindToScope(expr, ScopeLocal); $$ = new SetExpression(expr, OpSetLiteral, MakeLiteral(), @$); } | T_VAR rterm combined_set_op rterm { Expression *expr = $2; BindToScope(expr, ScopeLocal); $$ = new SetExpression(expr, $3, $4, @$); } | T_WHILE '(' rterm ')' { BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); } rterm_scope { EndFlowControlBlock(context); $$ = new WhileExpression($3, $6, @$); } | T_THROW rterm { $$ = new ThrowExpression($2, false, @$); } | T_TRY rterm_scope T_EXCEPT rterm_scope { $$ = new TryExceptExpression($2, $4, @$); } | rterm_side_effect ; rterm_items: /* empty */ { $$ = new std::vector(); } | rterm_items_inner | rterm_items_inner ',' | rterm_items_inner ',' newlines | rterm_items_inner newlines ; rterm_items_inner: rterm { $$ = new std::vector(); $$->push_back($1); } | rterm_items_inner arraysep rterm { $$ = $1; $$->push_back($3); } ; rterm_array: '[' { context->m_OpenBraces++; } newlines rterm_items ']' { context->m_OpenBraces--; $$ = new ArrayExpression(*$4, @$); delete $4; } | '[' { context->m_OpenBraces++; } rterm_items ']' { context->m_OpenBraces--; $$ = new ArrayExpression(*$3, @$); delete $3; } ; rterm_dict: '{' { BeginFlowControlBlock(context, 0, false); context->m_IgnoreNewlines.push(false); context->m_OpenBraces++; } statements '}' { EndFlowControlBlock(context); context->m_OpenBraces--; context->m_IgnoreNewlines.pop(); std::vector dlist; typedef std::pair EListItem; int num = 0; for (const EListItem& litem : *$3) { if (!litem.second.SideEffect) yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); dlist.push_back(litem.first); num++; } delete $3; $$ = new DictExpression(dlist, @$); } ; rterm_scope_require_side_effect: '{' { context->m_IgnoreNewlines.push(false); context->m_OpenBraces++; } statements '}' { context->m_OpenBraces--; context->m_IgnoreNewlines.pop(); std::vector dlist; typedef std::pair EListItem; int num = 0; for (const EListItem& litem : *$3) { if (!litem.second.SideEffect) yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); dlist.push_back(litem.first); num++; } delete $3; $$ = new DictExpression(dlist, @$); $$->MakeInline(); } ; rterm_scope: '{' { context->m_IgnoreNewlines.push(false); context->m_OpenBraces++; } statements '}' { context->m_OpenBraces--; context->m_IgnoreNewlines.pop(); std::vector dlist; typedef std::pair EListItem; std::vector >::size_type num = 0; for (const EListItem& litem : *$3) { if (!litem.second.SideEffect && num != $3->size() - 1) yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); dlist.push_back(litem.first); num++; } delete $3; $$ = new DictExpression(dlist, @$); $$->MakeInline(); } ; else_if_branch: T_ELSE T_IF '(' rterm ')' rterm_scope { $$ = new std::pair($4, $6); } ; else_if_branches: /* empty */ { $$ = new std::vector >(); } | else_if_branches else_if_branch { $$ = $1; $$->push_back(*$2); delete $2; } ; rterm_side_effect: rterm '(' rterm_items ')' { $$ = new FunctionCallExpression($1, *$3, @$); delete $3; } | T_IF '(' rterm ')' rterm_scope else_if_branches { std::vector > ebranches = *$6; delete $6; Expression *afalse = NULL; for (int i = ebranches.size() - 1; i >= 0; i--) { const std::pair& ebranch = ebranches[i]; afalse = new ConditionalExpression(ebranch.first, ebranch.second, afalse, @6); } $$ = new ConditionalExpression($3, $5, afalse, @$); } | T_IF '(' rterm ')' rterm_scope else_if_branches T_ELSE rterm_scope { std::vector > ebranches = *$6; delete $6; $8->MakeInline(); Expression *afalse = $8; for (int i = ebranches.size() - 1; i >= 0; i--) { const std::pair& ebranch = ebranches[i]; afalse = new ConditionalExpression(ebranch.first, ebranch.second, afalse, @6); } $$ = new ConditionalExpression($3, $5, afalse, @$); } ; rterm_no_side_effect_no_dict: T_STRING { $$ = MakeLiteral(*$1); delete $1; } | T_NUMBER { $$ = MakeLiteral($1); } | T_BOOLEAN { $$ = MakeLiteral($1); } | T_NULL { $$ = MakeLiteral(); } | rterm '.' T_IDENTIFIER %dprec 2 { $$ = new IndexerExpression($1, MakeLiteral(*$3), @$); delete $3; } | rterm '[' rterm ']' { $$ = new IndexerExpression($1, $3, @$); } | T_IDENTIFIER { $$ = new VariableExpression(*$1, @1); delete $1; } | '!' rterm { $$ = new LogicalNegateExpression($2, @$); } | '~' rterm { $$ = new NegateExpression($2, @$); } | T_PLUS rterm %prec UNARY_PLUS { $$ = $2; } | T_MINUS rterm %prec UNARY_MINUS { $$ = new SubtractExpression(MakeLiteral(0), $2, @$); } | T_THIS { $$ = new GetScopeExpression(ScopeThis); } | T_GLOBALS { $$ = new GetScopeExpression(ScopeGlobal); } | T_LOCALS { $$ = new GetScopeExpression(ScopeLocal); } | T_CURRENT_FILENAME { $$ = MakeLiteral(@$.Path); } | T_CURRENT_LINE { $$ = MakeLiteral(@$.FirstLine); } | identifier T_FOLLOWS { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope %dprec 2 { EndFlowControlBlock(context); std::vector args; args.push_back(*$1); delete $1; $$ = new FunctionExpression("", args, new std::map(), $4, @$); } | identifier T_FOLLOWS rterm %dprec 1 { ASSERT(!dynamic_cast($3)); std::vector args; args.push_back(*$1); delete $1; $$ = new FunctionExpression("", args, new std::map(), $3, @$); } | '(' identifier_items ')' T_FOLLOWS { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope %dprec 2 { EndFlowControlBlock(context); $$ = new FunctionExpression("", *$2, new std::map(), $6, @$); delete $2; } | '(' identifier_items ')' T_FOLLOWS rterm %dprec 1 { ASSERT(!dynamic_cast($5)); $$ = new FunctionExpression("", *$2, new std::map(), $5, @$); delete $2; } | rterm_array | '(' { context->m_OpenBraces++; } rterm ')' { context->m_OpenBraces--; $$ = $3; } | rterm T_LOGICAL_OR rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_LOGICAL_AND rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_BINARY_OR rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_BINARY_AND rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_IN rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_NOT_IN rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_EQUAL rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_NOT_EQUAL rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_LESS_THAN rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_GREATER_THAN rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_SHIFT_LEFT rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_PLUS rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_MINUS rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_MULTIPLY rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_DIVIDE_OP rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_MODULO rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_XOR rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | T_FUNCTION '(' identifier_items ')' use_specifier { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope { EndFlowControlBlock(context); $$ = new FunctionExpression("", *$3, $5, $7, @$); delete $3; } | T_NULLARY_LAMBDA_BEGIN { BeginFlowControlBlock(context, FlowControlReturn, false); } statements T_NULLARY_LAMBDA_END { EndFlowControlBlock(context); std::vector dlist; typedef std::pair EListItem; std::vector >::size_type num = 0; for (const EListItem& litem : *$3) { if (!litem.second.SideEffect && num != $3->size() - 1) yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); dlist.push_back(litem.first); num++; } delete $3; DictExpression *aexpr = new DictExpression(dlist, @$); aexpr->MakeInline(); $$ = new FunctionExpression("", std::vector(), NULL, aexpr, @$); } ; rterm_no_side_effect: rterm_no_side_effect_no_dict %dprec 1 | rterm_dict %dprec 2 { Expression *expr = $1; BindToScope(expr, ScopeThis); $$ = expr; } ; rterm: rterm_side_effect %dprec 2 | rterm_no_side_effect %dprec 1 ; target_type_specifier: /* empty */ { $$ = new String(); } | T_TO identifier { $$ = $2; } ; default_specifier: /* empty */ { $$ = false; } | T_DEFAULT { $$ = true; } ; ignore_specifier: /* empty */ { $$ = false; } | T_IGNORE_ON_ERROR { $$ = true; } ; use_specifier: /* empty */ { $$ = NULL; } | T_USE '(' use_specifier_items ')' { $$ = $3; } ; use_specifier_items: use_specifier_item { $$ = new std::map(); $$->insert(*$1); delete $1; } | use_specifier_items ',' use_specifier_item { $$ = $1; $$->insert(*$3); delete $3; } ; use_specifier_item: identifier { $$ = new std::pair(*$1, new VariableExpression(*$1, @1)); delete $1; } | identifier T_SET rterm { $$ = new std::pair(*$1, $3); delete $1; } ; apply_for_specifier: /* empty */ | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' { context->m_FKVar.top() = *$3; delete $3; context->m_FVVar.top() = *$5; delete $5; context->m_FTerm.top() = $7; } | T_FOR '(' identifier T_IN rterm ')' { context->m_FKVar.top() = *$3; delete $3; context->m_FVVar.top() = ""; context->m_FTerm.top() = $5; } ; optional_rterm: /* empty */ { $$ = MakeLiteral(); } | rterm ; apply: { context->m_Apply.push(true); context->m_SeenAssign.push(false); context->m_SeenIgnore.push(false); context->m_Assign.push(NULL); context->m_Ignore.push(NULL); context->m_FKVar.push(""); context->m_FVVar.push(""); context->m_FTerm.push(NULL); } T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier ignore_specifier { BeginFlowControlBlock(context, FlowControlReturn, false); } rterm_scope_require_side_effect { EndFlowControlBlock(context); context->m_Apply.pop(); String type = *$3; delete $3; String target = *$6; delete $6; if (!ApplyRule::IsValidSourceType(type)) BOOST_THROW_EXCEPTION(ScriptError("'apply' cannot be used with type '" + type + "'", DebugInfoRange(@2, @3))); if (!ApplyRule::IsValidTargetType(type, target)) { if (target == "") { std::vector types = ApplyRule::GetTargetTypes(type); String typeNames; for (std::vector::size_type i = 0; i < types.size(); i++) { if (typeNames != "") { if (i == types.size() - 1) typeNames += " or "; else typeNames += ", "; } typeNames += "'" + types[i] + "'"; } BOOST_THROW_EXCEPTION(ScriptError("'apply' target type is ambiguous (can be one of " + typeNames + "): use 'to' to specify a type", DebugInfoRange(@2, @3))); } else BOOST_THROW_EXCEPTION(ScriptError("'apply' target type '" + target + "' is invalid", DebugInfoRange(@2, @5))); } bool seen_assign = context->m_SeenAssign.top(); context->m_SeenAssign.pop(); // assign && !ignore if (!seen_assign && !context->m_FTerm.top()) BOOST_THROW_EXCEPTION(ScriptError("'apply' is missing 'assign'/'for'", DebugInfoRange(@2, @3))); Expression *ignore = context->m_Ignore.top(); context->m_Ignore.pop(); Expression *assign; if (!seen_assign) assign = MakeLiteral(true); else assign = context->m_Assign.top(); context->m_Assign.pop(); Expression *filter; if (ignore) { Expression *rex = new LogicalNegateExpression(ignore, DebugInfoRange(@2, @5)); filter = new LogicalAndExpression(assign, rex, DebugInfoRange(@2, @5)); } else filter = assign; String fkvar = context->m_FKVar.top(); context->m_FKVar.pop(); String fvvar = context->m_FVVar.top(); context->m_FVVar.pop(); Expression *fterm = context->m_FTerm.top(); context->m_FTerm.pop(); $$ = new ApplyExpression(type, target, $4, filter, context->GetPackage(), fkvar, fvvar, fterm, $7, $8, $10, DebugInfoRange(@2, @8)); } ; newlines: T_NEWLINE | T_NEWLINE newlines ; /* required separator */ sep: ',' newlines | ',' | ';' newlines | ';' | newlines ; arraysep: ',' newlines | ',' ; %% icinga2-2.8.1/lib/config/configcompiler.cpp000066400000000000000000000243171322762156600205760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configcompiler.hpp" #include "config/configitem.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/loader.hpp" #include "base/context.hpp" #include "base/exception.hpp" #include using namespace icinga; std::vector ConfigCompiler::m_IncludeSearchDirs; boost::mutex ConfigCompiler::m_ZoneDirsMutex; std::map > ConfigCompiler::m_ZoneDirs; /** * Constructor for the ConfigCompiler class. * * @param path The path of the configuration file (or another name that * identifies the source of the configuration text). * @param input Input stream for the configuration file. * @param zone The zone. */ ConfigCompiler::ConfigCompiler(const String& path, std::istream *input, const String& zone, const String& package) : m_Path(path), m_Input(input), m_Zone(zone), m_Package(package), m_Eof(false), m_OpenBraces(0) { InitializeScanner(); } /** * Destructor for the ConfigCompiler class. */ ConfigCompiler::~ConfigCompiler(void) { DestroyScanner(); } /** * Reads data from the input stream. Used internally by the lexer. * * @param buffer Where to store data. * @param max_size The maximum number of bytes to read from the stream. * @returns The actual number of bytes read. */ size_t ConfigCompiler::ReadInput(char *buffer, size_t max_size) { m_Input->read(buffer, max_size); return static_cast(m_Input->gcount()); } /** * Retrieves the scanner object. * * @returns The scanner object. */ void *ConfigCompiler::GetScanner(void) const { return m_Scanner; } /** * Retrieves the path for the input file. * * @returns The path. */ const char *ConfigCompiler::GetPath(void) const { return m_Path.CStr(); } void ConfigCompiler::SetZone(const String& zone) { m_Zone = zone; } String ConfigCompiler::GetZone(void) const { return m_Zone; } void ConfigCompiler::SetPackage(const String& package) { m_Package = package; } String ConfigCompiler::GetPackage(void) const { return m_Package; } void ConfigCompiler::CollectIncludes(std::vector& expressions, const String& file, const String& zone, const String& package) { try { Expression *expr = CompileFile(file, zone, package); expressions.push_back(expr); } catch (const std::exception& ex) { Log(LogWarning, "ConfigCompiler") << "Cannot compile file '" << file << "': " << DiagnosticInformation(ex); } } /** * Handles an include directive. * * @param relativeBath The path this include is relative to. * @param path The path from the include directive. * @param search Whether to search global include dirs. * @param debuginfo Debug information. */ Expression *ConfigCompiler::HandleInclude(const String& relativeBase, const String& path, bool search, const String& zone, const String& package, const DebugInfo& debuginfo) { String upath; if (search || (IsAbsolutePath(path))) upath = path; else upath = relativeBase + "/" + path; String includePath = upath; if (search) { for (const String& dir : m_IncludeSearchDirs) { String spath = dir + "/" + path; if (Utility::PathExists(spath)) { includePath = spath; break; } } } std::vector expressions; if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zone, package), GlobFile) && includePath.FindFirstOf("*?") == String::NPos) { std::ostringstream msgbuf; msgbuf << "Include file '" + path + "' does not exist"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debuginfo)); } DictExpression *expr = new DictExpression(expressions); expr->MakeInline(); return expr; } /** * Handles recursive includes. * * @param relativeBase The path this include is relative to. * @param path The directory path. * @param pattern The file pattern. * @param debuginfo Debug information. */ Expression *ConfigCompiler::HandleIncludeRecursive(const String& relativeBase, const String& path, const String& pattern, const String& zone, const String& package, const DebugInfo&) { String ppath; if (IsAbsolutePath(path)) ppath = path; else ppath = relativeBase + "/" + path; std::vector expressions; Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zone, package), GlobFile); DictExpression *dict = new DictExpression(expressions); dict->MakeInline(); return dict; } void ConfigCompiler::HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector& expressions) { String zoneName = Utility::BaseName(path); String ppath; if (IsAbsolutePath(path)) ppath = path; else ppath = relativeBase + "/" + path; RegisterZoneDir(tag, ppath, zoneName); Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName, package), GlobFile); } /** * Handles zone includes. * * @param relativeBase The path this include is relative to. * @param tag The tag name. * @param path The directory path. * @param pattern The file pattern. * @param debuginfo Debug information. */ Expression *ConfigCompiler::HandleIncludeZones(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, const DebugInfo&) { String ppath; String newRelativeBase = relativeBase; if (IsAbsolutePath(path)) ppath = path; else { ppath = relativeBase + "/" + path; newRelativeBase = "."; } std::vector expressions; Utility::Glob(ppath + "/*", boost::bind(&ConfigCompiler::HandleIncludeZone, newRelativeBase, tag, _1, pattern, package, boost::ref(expressions)), GlobDirectory); return new DictExpression(expressions); } /** * Compiles a stream. * * @param path A name identifying the stream. * @param stream The input stream. * @returns Configuration items. */ Expression *ConfigCompiler::CompileStream(const String& path, std::istream *stream, const String& zone, const String& package) { CONTEXT("Compiling configuration stream with name '" + path + "'"); stream->exceptions(std::istream::badbit); ConfigCompiler ctx(path, stream, zone, package); try { return ctx.Compile(); } catch (const ScriptError& ex) { return new ThrowExpression(MakeLiteral(ex.what()), ex.IsIncompleteExpression(), ex.GetDebugInfo()); } catch (const std::exception& ex) { return new ThrowExpression(MakeLiteral(DiagnosticInformation(ex)), false); } } /** * Compiles a file. * * @param path The path. * @returns Configuration items. */ Expression *ConfigCompiler::CompileFile(const String& path, const String& zone, const String& package) { CONTEXT("Compiling configuration file '" + path + "'"); std::ifstream stream(path.CStr(), std::ifstream::in); if (!stream) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("std::ifstream::open") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); Log(LogNotice, "ConfigCompiler") << "Compiling config file: " << path; return CompileStream(path, &stream, zone, package); } /** * Compiles a snippet of text. * * @param path A name identifying the text. * @param text The text. * @returns Configuration items. */ Expression *ConfigCompiler::CompileText(const String& path, const String& text, const String& zone, const String& package) { std::stringstream stream(text); return CompileStream(path, &stream, zone, package); } /** * Adds a directory to the list of include search dirs. * * @param dir The new dir. */ void ConfigCompiler::AddIncludeSearchDir(const String& dir) { Log(LogInformation, "ConfigCompiler") << "Adding include search dir: " << dir; m_IncludeSearchDirs.push_back(dir); } std::vector ConfigCompiler::GetZoneDirs(const String& zone) { boost::mutex::scoped_lock lock(m_ZoneDirsMutex); auto it = m_ZoneDirs.find(zone); if (it == m_ZoneDirs.end()) return std::vector(); else return it->second; } void ConfigCompiler::RegisterZoneDir(const String& tag, const String& ppath, const String& zoneName) { ZoneFragment zf; zf.Tag = tag; zf.Path = ppath; boost::mutex::scoped_lock lock(m_ZoneDirsMutex); m_ZoneDirs[zoneName].push_back(zf); } bool ConfigCompiler::HasZoneConfigAuthority(const String& zoneName) { std::vector zoneDirs = m_ZoneDirs[zoneName]; bool empty = zoneDirs.empty(); if (!empty) { std::vector paths; for (const ZoneFragment& zf : zoneDirs) { paths.push_back(zf.Path); } Log(LogNotice, "ConfigCompiler") << "Registered authoritative config directories for zone '" << zoneName << "': " << Utility::NaturalJoin(paths); } return !empty; } bool ConfigCompiler::IsAbsolutePath(const String& path) { #ifndef _WIN32 return (path.GetLength() > 0 && path[0] == '/'); #else /* _WIN32 */ return !PathIsRelative(path.CStr()); #endif /* _WIN32 */ } icinga2-2.8.1/lib/config/configcompiler.hpp000066400000000000000000000126661322762156600206070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGCOMPILER_H #define CONFIGCOMPILER_H #include "config/i2-config.hpp" #include "config/expression.hpp" #include "base/debuginfo.hpp" #include "base/registry.hpp" #include "base/initialize.hpp" #include "base/singleton.hpp" #include #include #include typedef union YYSTYPE YYSTYPE; typedef void *yyscan_t; namespace icinga { struct CompilerDebugInfo { const char *Path; int FirstLine; int FirstColumn; int LastLine; int LastColumn; operator DebugInfo(void) const { DebugInfo di; di.Path = Path; di.FirstLine = FirstLine; di.FirstColumn = FirstColumn; di.LastLine = LastLine; di.LastColumn = LastColumn; return di; } }; struct EItemInfo { bool SideEffect; CompilerDebugInfo DebugInfo; }; enum FlowControlType { FlowControlReturn = 1, FlowControlContinue = 2, FlowControlBreak = 4 }; struct ZoneFragment { String Tag; String Path; }; /** * The configuration compiler can be used to compile a configuration file * into a number of configuration items. * * @ingroup config */ class I2_CONFIG_API ConfigCompiler { public: explicit ConfigCompiler(const String& path, std::istream *input, const String& zone = String(), const String& package = String()); virtual ~ConfigCompiler(void); Expression *Compile(void); static Expression *CompileStream(const String& path, std::istream *stream, const String& zone = String(), const String& package = String()); static Expression *CompileFile(const String& path, const String& zone = String(), const String& package = String()); static Expression *CompileText(const String& path, const String& text, const String& zone = String(), const String& package = String()); static void AddIncludeSearchDir(const String& dir); const char *GetPath(void) const; void SetZone(const String& zone); String GetZone(void) const; void SetPackage(const String& package); String GetPackage(void) const; static void CollectIncludes(std::vector& expressions, const String& file, const String& zone, const String& package); static Expression *HandleInclude(const String& relativeBase, const String& path, bool search, const String& zone, const String& package, const DebugInfo& debuginfo = DebugInfo()); static Expression *HandleIncludeRecursive(const String& relativeBase, const String& path, const String& pattern, const String& zone, const String& package, const DebugInfo& debuginfo = DebugInfo()); static Expression *HandleIncludeZones(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, const DebugInfo& debuginfo = DebugInfo()); size_t ReadInput(char *buffer, size_t max_bytes); void *GetScanner(void) const; static std::vector GetZoneDirs(const String& zone); static void RegisterZoneDir(const String& tag, const String& ppath, const String& zoneName); static bool HasZoneConfigAuthority(const String& zoneName); private: boost::promise > m_Promise; String m_Path; std::istream *m_Input; String m_Zone; String m_Package; void *m_Scanner; static std::vector m_IncludeSearchDirs; static boost::mutex m_ZoneDirsMutex; static std::map > m_ZoneDirs; void InitializeScanner(void); void DestroyScanner(void); static void HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector& expressions); static bool IsAbsolutePath(const String& path); public: bool m_Eof; int m_OpenBraces; std::ostringstream m_LexBuffer; CompilerDebugInfo m_LocationBegin; std::stack m_IgnoreNewlines; std::stack m_Apply; std::stack m_ObjectAssign; std::stack m_SeenAssign; std::stack m_SeenIgnore; std::stack m_Assign; std::stack m_Ignore; std::stack m_FKVar; std::stack m_FVVar; std::stack m_FTerm; std::stack m_FlowControlInfo; }; } #endif /* CONFIGCOMPILER_H */ icinga2-2.8.1/lib/config/configcompilercontext.cpp000066400000000000000000000063141322762156600222000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configcompilercontext.hpp" #include "base/singleton.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/exception.hpp" #include "base/application.hpp" using namespace icinga; ConfigCompilerContext *ConfigCompilerContext::GetInstance(void) { return Singleton::GetInstance(); } ConfigCompilerContext::ConfigCompilerContext(void) : m_ObjectsFP(NULL) { } void ConfigCompilerContext::OpenObjectsFile(const String& filename) { m_ObjectsPath = filename; std::fstream *fp = new std::fstream(); try { m_ObjectsTempFile = Utility::CreateTempFile(filename + ".XXXXXX", 0600, *fp); } catch (const std::exception& ex) { Log(LogCritical, "cli", "Could not create temporary objects file: " + DiagnosticInformation(ex, false)); Application::Exit(1); } if (!*fp) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + m_ObjectsTempFile + "' file")); m_ObjectsFP = fp; } void ConfigCompilerContext::WriteObject(const Dictionary::Ptr& object) { if (!m_ObjectsFP) return; String json = JsonEncode(object); { boost::mutex::scoped_lock lock(m_Mutex); NetString::WriteStringToStream(*m_ObjectsFP, json); } } void ConfigCompilerContext::CancelObjectsFile(void) { delete m_ObjectsFP; m_ObjectsFP = NULL; #ifdef _WIN32 _unlink(m_ObjectsTempFile.CStr()); #else /* _WIN32 */ unlink(m_ObjectsTempFile.CStr()); #endif /* _WIN32 */ } void ConfigCompilerContext::FinishObjectsFile(void) { delete m_ObjectsFP; m_ObjectsFP = NULL; #ifdef _WIN32 _unlink(m_ObjectsPath.CStr()); #endif /* _WIN32 */ if (rename(m_ObjectsTempFile.CStr(), m_ObjectsPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(m_ObjectsTempFile)); } } icinga2-2.8.1/lib/config/configcompilercontext.hpp000066400000000000000000000041171322762156600222040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGCOMPILERCONTEXT_H #define CONFIGCOMPILERCONTEXT_H #include "config/i2-config.hpp" #include "base/dictionary.hpp" #include #include namespace icinga { /* * @ingroup config */ class I2_CONFIG_API ConfigCompilerContext { public: ConfigCompilerContext(void); void OpenObjectsFile(const String& filename); void WriteObject(const Dictionary::Ptr& object); void CancelObjectsFile(void); void FinishObjectsFile(void); static ConfigCompilerContext *GetInstance(void); private: String m_ObjectsPath; String m_ObjectsTempFile; std::fstream *m_ObjectsFP; mutable boost::mutex m_Mutex; }; } #endif /* CONFIGCOMPILERCONTEXT_H */ icinga2-2.8.1/lib/config/configfragment.hpp000066400000000000000000000041341322762156600205670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGFRAGMENT_H #define CONFIGFRAGMENT_H #include "config/configcompiler.hpp" #include "base/initialize.hpp" #include "base/debug.hpp" #include "base/exception.hpp" #include "base/application.hpp" #define REGISTER_CONFIG_FRAGMENT(name, fragment) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ icinga::Expression *expression = icinga::ConfigCompiler::CompileText(name, fragment); \ VERIFY(expression); \ try { \ icinga::ScriptFrame frame; \ expression->Evaluate(frame); \ } catch (const std::exception& ex) { \ std::cerr << icinga::DiagnosticInformation(ex) << std::endl; \ icinga::Application::Exit(1); \ } \ delete expression; \ }, 5) #endif /* CONFIGFRAGMENT_H */ icinga2-2.8.1/lib/config/configitem.cpp000066400000000000000000000441321322762156600177170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configitem.hpp" #include "config/configcompilercontext.hpp" #include "config/applyrule.hpp" #include "config/objectrule.hpp" #include "config/configcompiler.hpp" #include "base/application.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/debug.hpp" #include "base/workqueue.hpp" #include "base/exception.hpp" #include "base/stdiostream.hpp" #include "base/netstring.hpp" #include "base/serializer.hpp" #include "base/json.hpp" #include "base/exception.hpp" #include "base/function.hpp" #include #include using namespace icinga; boost::mutex ConfigItem::m_Mutex; ConfigItem::TypeMap ConfigItem::m_Items; ConfigItem::TypeMap ConfigItem::m_DefaultTemplates; ConfigItem::ItemList ConfigItem::m_UnnamedItems; ConfigItem::IgnoredItemList ConfigItem::m_IgnoredItems; REGISTER_SCRIPTFUNCTION_NS(Internal, run_with_activation_context, &ConfigItem::RunWithActivationContext, "func"); /** * Constructor for the ConfigItem class. * * @param type The object type. * @param name The name of the item. * @param unit The unit of the item. * @param abstract Whether the item is a template. * @param exprl Expression list for the item. * @param debuginfo Debug information. */ ConfigItem::ConfigItem(const Type::Ptr& type, const String& name, bool abstract, const boost::shared_ptr& exprl, const boost::shared_ptr& filter, bool defaultTmpl, bool ignoreOnError, const DebugInfo& debuginfo, const Dictionary::Ptr& scope, const String& zone, const String& package) : m_Type(type), m_Name(name), m_Abstract(abstract), m_Expression(exprl), m_Filter(filter), m_DefaultTmpl(defaultTmpl), m_IgnoreOnError(ignoreOnError), m_DebugInfo(debuginfo), m_Scope(scope), m_Zone(zone), m_Package(package) { } /** * Retrieves the type of the configuration item. * * @returns The type. */ Type::Ptr ConfigItem::GetType(void) const { return m_Type; } /** * Retrieves the name of the configuration item. * * @returns The name. */ String ConfigItem::GetName(void) const { return m_Name; } /** * Checks whether the item is abstract. * * @returns true if the item is abstract, false otherwise. */ bool ConfigItem::IsAbstract(void) const { return m_Abstract; } bool ConfigItem::IsDefaultTemplate(void) const { return m_DefaultTmpl; } bool ConfigItem::IsIgnoreOnError(void) const { return m_IgnoreOnError; } /** * Retrieves the debug information for the configuration item. * * @returns The debug information. */ DebugInfo ConfigItem::GetDebugInfo(void) const { return m_DebugInfo; } Dictionary::Ptr ConfigItem::GetScope(void) const { return m_Scope; } ConfigObject::Ptr ConfigItem::GetObject(void) const { return m_Object; } /** * Retrieves the expression list for the configuration item. * * @returns The expression list. */ boost::shared_ptr ConfigItem::GetExpression(void) const { return m_Expression; } /** * Retrieves the object filter for the configuration item. * * @returns The filter expression. */ boost::shared_ptr ConfigItem::GetFilter(void) const { return m_Filter; } class DefaultValidationUtils : public ValidationUtils { public: virtual bool ValidateName(const String& type, const String& name) const override { ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name); if (!item || (item && item->IsAbstract())) return false; return true; } }; /** * Commits the configuration item by creating a ConfigObject * object. * * @returns The ConfigObject that was created/updated. */ ConfigObject::Ptr ConfigItem::Commit(bool discard) { #ifdef I2_DEBUG Log(LogDebug, "ConfigItem") << "Commit called for ConfigItem Type=" << GetType() << ", Name=" << GetName(); #endif /* I2_DEBUG */ /* Make sure the type is valid. */ Type::Ptr type = GetType(); if (!type || !ConfigObject::TypeInstance->IsAssignableFrom(type)) BOOST_THROW_EXCEPTION(ScriptError("Type '" + GetType() + "' does not exist.", m_DebugInfo)); if (IsAbstract()) return ConfigObject::Ptr(); ConfigObject::Ptr dobj = static_pointer_cast(type->Instantiate(std::vector())); dobj->SetDebugInfo(m_DebugInfo); dobj->SetZoneName(m_Zone); dobj->SetPackage(m_Package); dobj->SetName(m_Name); DebugHint debugHints; ScriptFrame frame(dobj); if (m_Scope) m_Scope->CopyTo(frame.Locals); try { m_Expression->Evaluate(frame, &debugHints); } catch (const std::exception& ex) { if (m_IgnoreOnError) { Log(LogNotice, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex); { boost::mutex::scoped_lock lock(m_Mutex); m_IgnoredItems.push_back(m_DebugInfo.Path); } return ConfigObject::Ptr(); } throw; } if (discard) m_Expression.reset(); String item_name; String short_name = dobj->GetShortName(); if (!short_name.IsEmpty()) { item_name = short_name; dobj->SetName(short_name); } else item_name = m_Name; String name = item_name; NameComposer *nc = dynamic_cast(type.get()); if (nc) { if (name.IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Object name must not be empty.", m_DebugInfo)); name = nc->MakeName(name, dobj); if (name.IsEmpty()) BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object")); } if (name != item_name) dobj->SetShortName(item_name); dobj->SetName(name); Dictionary::Ptr dhint = debugHints.ToDictionary(); try { DefaultValidationUtils utils; dobj->Validate(FAConfig, utils); } catch (ValidationError& ex) { if (m_IgnoreOnError) { Log(LogNotice, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex); { boost::mutex::scoped_lock lock(m_Mutex); m_IgnoredItems.push_back(m_DebugInfo.Path); } return ConfigObject::Ptr(); } ex.SetDebugHint(dhint); throw; } try { dobj->OnConfigLoaded(); } catch (const std::exception& ex) { if (m_IgnoreOnError) { Log(LogNotice, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex); { boost::mutex::scoped_lock lock(m_Mutex); m_IgnoredItems.push_back(m_DebugInfo.Path); } return ConfigObject::Ptr(); } throw; } Dictionary::Ptr persistentItem = new Dictionary(); persistentItem->Set("type", GetType()->GetName()); persistentItem->Set("name", GetName()); persistentItem->Set("properties", Serialize(dobj, FAConfig)); persistentItem->Set("debug_hints", dhint); Array::Ptr di = new Array(); di->Add(m_DebugInfo.Path); di->Add(m_DebugInfo.FirstLine); di->Add(m_DebugInfo.FirstColumn); di->Add(m_DebugInfo.LastLine); di->Add(m_DebugInfo.LastColumn); persistentItem->Set("debug_info", di); ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); persistentItem.reset(); dhint.reset(); dobj->Register(); m_Object = dobj; return dobj; } /** * Registers the configuration item. */ void ConfigItem::Register(void) { m_ActivationContext = ActivationContext::GetCurrentContext(); boost::mutex::scoped_lock lock(m_Mutex); /* If this is a non-abstract object with a composite name * we register it in m_UnnamedItems instead of m_Items. */ if (!m_Abstract && dynamic_cast(m_Type.get())) m_UnnamedItems.push_back(this); else { auto& items = m_Items[m_Type]; auto it = items.find(m_Name); if (it != items.end()) { std::ostringstream msgbuf; msgbuf << "A configuration item of type '" << m_Type->GetName() << "' and name '" << GetName() << "' already exists (" << it->second->GetDebugInfo() << "), new declaration: " << GetDebugInfo(); BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str())); } m_Items[m_Type][m_Name] = this; if (m_DefaultTmpl) m_DefaultTemplates[m_Type][m_Name] = this; } } /** * Unregisters the configuration item. */ void ConfigItem::Unregister(void) { if (m_Object) { m_Object->Unregister(); m_Object.reset(); } boost::mutex::scoped_lock lock(m_Mutex); m_UnnamedItems.erase(std::remove(m_UnnamedItems.begin(), m_UnnamedItems.end(), this), m_UnnamedItems.end()); m_Items[m_Type].erase(m_Name); m_DefaultTemplates[m_Type].erase(m_Name); } /** * Retrieves a configuration item by type and name. * * @param type The type of the ConfigItem that is to be looked up. * @param name The name of the ConfigItem that is to be looked up. * @returns The configuration item. */ ConfigItem::Ptr ConfigItem::GetByTypeAndName(const Type::Ptr& type, const String& name) { boost::mutex::scoped_lock lock(m_Mutex); auto it = m_Items.find(type); if (it == m_Items.end()) return ConfigItem::Ptr(); auto it2 = it->second.find(name); if (it2 == it->second.end()) return ConfigItem::Ptr(); return it2->second; } bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems) { typedef std::pair ItemPair; std::vector items; { boost::mutex::scoped_lock lock(m_Mutex); for (const TypeMap::value_type& kv : m_Items) { for (const ItemMap::value_type& kv2 : kv.second) { if (kv2.second->m_Abstract || kv2.second->m_Object) continue; if (kv2.second->m_ActivationContext != context) continue; items.push_back(std::make_pair(kv2.second, false)); } } ItemList newUnnamedItems; for (const ConfigItem::Ptr& item : m_UnnamedItems) { if (item->m_ActivationContext != context) { newUnnamedItems.push_back(item); continue; } if (item->m_Abstract || item->m_Object) continue; items.push_back(std::make_pair(item, true)); } m_UnnamedItems.swap(newUnnamedItems); } if (items.empty()) return true; for (const ItemPair& ip : items) { newItems.push_back(ip.first); upq.Enqueue([&]() { ip.first->Commit(ip.second); }); } upq.Join(); if (upq.HasExceptions()) return false; std::set types; for (const Type::Ptr& type : Type::GetAllTypes()) { if (ConfigObject::TypeInstance->IsAssignableFrom(type)) types.insert(type); } std::set completed_types; while (types.size() != completed_types.size()) { for (const Type::Ptr& type : types) { if (completed_types.find(type) != completed_types.end()) continue; bool unresolved_dep = false; /* skip this type (for now) if there are unresolved load dependencies */ for (const String& loadDep : type->GetLoadDependencies()) { Type::Ptr pLoadDep = Type::GetByName(loadDep); if (types.find(pLoadDep) != types.end() && completed_types.find(pLoadDep) == completed_types.end()) { unresolved_dep = true; break; } } if (unresolved_dep) continue; for (const ItemPair& ip : items) { const ConfigItem::Ptr& item = ip.first; if (!item->m_Object) continue; if (item->m_Type == type) { upq.Enqueue([&]() { try { item->m_Object->OnAllConfigLoaded(); } catch (const std::exception& ex) { if (item->m_IgnoreOnError) { Log(LogNotice, "ConfigObject") << "Ignoring config object '" << item->m_Name << "' of type '" << item->m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex); item->Unregister(); { boost::mutex::scoped_lock lock(item->m_Mutex); item->m_IgnoredItems.push_back(item->m_DebugInfo.Path); } return; } throw; } }); } } completed_types.insert(type); upq.Join(); if (upq.HasExceptions()) return false; for (const String& loadDep : type->GetLoadDependencies()) { for (const ItemPair& ip : items) { const ConfigItem::Ptr& item = ip.first; if (!item->m_Object) continue; if (item->m_Type->GetName() == loadDep) { upq.Enqueue([&]() { ActivationScope ascope(item->m_ActivationContext); item->m_Object->CreateChildObjects(type); }); } } } upq.Join(); if (upq.HasExceptions()) return false; if (!CommitNewItems(context, upq, newItems)) return false; } } return true; } bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems, bool silent) { if (!silent) Log(LogInformation, "ConfigItem", "Committing config item(s)."); if (!CommitNewItems(context, upq, newItems)) { upq.ReportExceptions("config"); for (const ConfigItem::Ptr& item : newItems) { item->Unregister(); } return false; } ApplyRule::CheckMatches(); if (!silent) { /* log stats for external parsers */ typedef std::map ItemCountMap; ItemCountMap itemCounts; for (const ConfigItem::Ptr& item : newItems) { if (!item->m_Object) continue; itemCounts[item->m_Object->GetReflectionType()]++; } for (const ItemCountMap::value_type& kv : itemCounts) { Log(LogInformation, "ConfigItem") << "Instantiated " << kv.second << " " << (kv.second != 1 ? kv.first->GetPluralName() : kv.first->GetName()) << "."; } } return true; } bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector& newItems, bool runtimeCreated, bool silent, bool withModAttrs) { static boost::mutex mtx; boost::mutex::scoped_lock lock(mtx); if (withModAttrs) { /* restore modified attributes */ if (Utility::PathExists(Application::GetModAttrPath())) { Expression *expression = ConfigCompiler::CompileFile(Application::GetModAttrPath()); if (expression) { try { ScriptFrame frame; expression->Evaluate(frame); } catch (const std::exception& ex) { Log(LogCritical, "config", DiagnosticInformation(ex)); } } delete expression; } } for (const ConfigItem::Ptr& item : newItems) { if (!item->m_Object) continue; ConfigObject::Ptr object = item->m_Object; if (object->IsActive()) continue; #ifdef I2_DEBUG Log(LogDebug, "ConfigItem") << "Setting 'active' to true for object '" << object->GetName() << "' of type '" << object->GetReflectionType()->GetName() << "'"; #endif /* I2_DEBUG */ upq.Enqueue(boost::bind(&ConfigObject::PreActivate, object)); } upq.Join(); if (upq.HasExceptions()) { upq.ReportExceptions("ConfigItem"); return false; } if (!silent) Log(LogInformation, "ConfigItem", "Triggering Start signal for config items"); for (const ConfigItem::Ptr& item : newItems) { if (!item->m_Object) continue; ConfigObject::Ptr object = item->m_Object; #ifdef I2_DEBUG Log(LogDebug, "ConfigItem") << "Activating object '" << object->GetName() << "' of type '" << object->GetReflectionType()->GetName() << "'"; #endif /* I2_DEBUG */ upq.Enqueue(boost::bind(&ConfigObject::Activate, object, runtimeCreated)); } upq.Join(); if (upq.HasExceptions()) { upq.ReportExceptions("ConfigItem"); return false; } #ifdef I2_DEBUG for (const ConfigItem::Ptr& item : newItems) { ConfigObject::Ptr object = item->m_Object; if (!object) continue; ASSERT(object && object->IsActive()); } #endif /* I2_DEBUG */ if (!silent) Log(LogInformation, "ConfigItem", "Activated all objects."); return true; } bool ConfigItem::RunWithActivationContext(const Function::Ptr& function) { ActivationScope scope; if (!function) BOOST_THROW_EXCEPTION(ScriptError("'function' argument must not be null.")); function->Invoke(); WorkQueue upq(25000, Application::GetConcurrency()); upq.SetName("ConfigItem::RunWithActivationContext"); std::vector newItems; if (!CommitItems(scope.GetContext(), upq, newItems, true)) return false; if (!ActivateItems(upq, newItems, false, true)) return false; return true; } std::vector ConfigItem::GetItems(const Type::Ptr& type) { std::vector items; boost::mutex::scoped_lock lock(m_Mutex); auto it = m_Items.find(type); if (it == m_Items.end()) return items; items.reserve(it->second.size()); for (const ItemMap::value_type& kv : it->second) { items.push_back(kv.second); } return items; } std::vector ConfigItem::GetDefaultTemplates(const Type::Ptr& type) { std::vector items; boost::mutex::scoped_lock lock(m_Mutex); auto it = m_DefaultTemplates.find(type); if (it == m_DefaultTemplates.end()) return items; items.reserve(it->second.size()); for (const ItemMap::value_type& kv : it->second) { items.push_back(kv.second); } return items; } void ConfigItem::RemoveIgnoredItems(const String& allowedConfigPath) { boost::mutex::scoped_lock lock(m_Mutex); for (const String& path : m_IgnoredItems) { if (path.Find(allowedConfigPath) == String::NPos) continue; Log(LogNotice, "ConfigItem") << "Removing ignored item path '" << path << "'."; (void) unlink(path.CStr()); } m_IgnoredItems.clear(); } icinga2-2.8.1/lib/config/configitem.hpp000066400000000000000000000110311322762156600177140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGITEM_H #define CONFIGITEM_H #include "config/i2-config.hpp" #include "config/expression.hpp" #include "config/activationcontext.hpp" #include "base/configobject.hpp" #include "base/workqueue.hpp" namespace icinga { /** * A configuration item. Non-abstract configuration items can be used to * create configuration objects at runtime. * * @ingroup config */ class I2_CONFIG_API ConfigItem : public Object { public: DECLARE_PTR_TYPEDEFS(ConfigItem); ConfigItem(const Type::Ptr& type, const String& name, bool abstract, const boost::shared_ptr& exprl, const boost::shared_ptr& filter, bool defaultTmpl, bool ignoreOnError, const DebugInfo& debuginfo, const Dictionary::Ptr& scope, const String& zone, const String& package); Type::Ptr GetType(void) const; String GetName(void) const; bool IsAbstract(void) const; bool IsDefaultTemplate(void) const; bool IsIgnoreOnError(void) const; std::vector GetParents(void) const; boost::shared_ptr GetExpression(void) const; boost::shared_ptr GetFilter(void) const; void Register(void); void Unregister(void); DebugInfo GetDebugInfo(void) const; Dictionary::Ptr GetScope(void) const; ConfigObject::Ptr GetObject(void) const; static ConfigItem::Ptr GetByTypeAndName(const Type::Ptr& type, const String& name); static bool CommitItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems, bool silent = false); static bool ActivateItems(WorkQueue& upq, const std::vector& newItems, bool runtimeCreated = false, bool silent = false, bool withModAttrs = false); static bool RunWithActivationContext(const Function::Ptr& function); static std::vector GetItems(const Type::Ptr& type); static std::vector GetDefaultTemplates(const Type::Ptr& type); static void RemoveIgnoredItems(const String& allowedConfigPath); private: Type::Ptr m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether this is a template. */ boost::shared_ptr m_Expression; boost::shared_ptr m_Filter; bool m_DefaultTmpl; bool m_IgnoreOnError; DebugInfo m_DebugInfo; /**< Debug information. */ Dictionary::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ String m_Package; ActivationContext::Ptr m_ActivationContext; ConfigObject::Ptr m_Object; static boost::mutex m_Mutex; typedef std::map ItemMap; typedef std::map TypeMap; static TypeMap m_Items; /**< All registered configuration items. */ static TypeMap m_DefaultTemplates; typedef std::vector ItemList; static ItemList m_UnnamedItems; typedef std::vector IgnoredItemList; static IgnoredItemList m_IgnoredItems; static ConfigItem::Ptr GetObjectUnlocked(const String& type, const String& name); ConfigObject::Ptr Commit(bool discard = true); static bool CommitNewItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems); }; } #endif /* CONFIGITEM_H */ icinga2-2.8.1/lib/config/configitembuilder.cpp000066400000000000000000000107051322762156600212650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configitembuilder.hpp" #include "base/configtype.hpp" #include #include using namespace icinga; ConfigItemBuilder::ConfigItemBuilder(void) : m_Abstract(false), m_DefaultTmpl(false), m_IgnoreOnError(false) { m_DebugInfo.FirstLine = 0; m_DebugInfo.FirstColumn = 0; m_DebugInfo.LastLine = 0; m_DebugInfo.LastColumn = 0; } ConfigItemBuilder::ConfigItemBuilder(const DebugInfo& debugInfo) : m_Abstract(false), m_DefaultTmpl(false), m_IgnoreOnError(false) { m_DebugInfo = debugInfo; } void ConfigItemBuilder::SetType(const Type::Ptr& type) { m_Type = type; } void ConfigItemBuilder::SetName(const String& name) { m_Name = name; } void ConfigItemBuilder::SetAbstract(bool abstract) { m_Abstract = abstract; } void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope) { m_Scope = scope; } void ConfigItemBuilder::SetZone(const String& zone) { m_Zone = zone; } void ConfigItemBuilder::SetPackage(const String& package) { m_Package = package; } void ConfigItemBuilder::AddExpression(Expression *expr) { m_Expressions.push_back(expr); } void ConfigItemBuilder::SetFilter(const boost::shared_ptr& filter) { m_Filter = filter; } void ConfigItemBuilder::SetDefaultTemplate(bool defaultTmpl) { m_DefaultTmpl = defaultTmpl; } void ConfigItemBuilder::SetIgnoreOnError(bool ignoreOnError) { m_IgnoreOnError = ignoreOnError; } ConfigItem::Ptr ConfigItemBuilder::Compile(void) { if (!m_Type) { std::ostringstream msgbuf; msgbuf << "The type of an object must be specified"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), m_DebugInfo)); } ConfigType *ctype = dynamic_cast(m_Type.get()); if (!ctype) { std::ostringstream msgbuf; msgbuf << "The type '" + m_Type->GetName() + "' cannot be used for config objects"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), m_DebugInfo)); } if (m_Name.FindFirstOf("!") != String::NPos) { std::ostringstream msgbuf; msgbuf << "Name for object '" << m_Name << "' of type '" << m_Type->GetName() << "' is invalid: Object names may not contain '!'"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), m_DebugInfo)); } std::vector exprs; Array::Ptr templateArray = new Array(); templateArray->Add(m_Name); exprs.push_back(new SetExpression(MakeIndexer(ScopeThis, "templates"), OpSetAdd, new LiteralExpression(templateArray), m_DebugInfo)); DictExpression *dexpr = new DictExpression(m_Expressions, m_DebugInfo); dexpr->MakeInline(); exprs.push_back(dexpr); #ifdef I2_DEBUG if (!m_Abstract) { bool foundDefaultImport = false; for (Expression *expr : m_Expressions) { if (dynamic_cast(expr)) { foundDefaultImport = true; break; } } ASSERT(foundDefaultImport); } #endif /* I2_DEBUG */ boost::shared_ptr exprl = boost::make_shared(exprs, m_DebugInfo); exprl->MakeInline(); return new ConfigItem(m_Type, m_Name, m_Abstract, exprl, m_Filter, m_DefaultTmpl, m_IgnoreOnError, m_DebugInfo, m_Scope, m_Zone, m_Package); } icinga2-2.8.1/lib/config/configitembuilder.hpp000066400000000000000000000057471322762156600213040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGITEMBUILDER_H #define CONFIGITEMBUILDER_H #include "config/expression.hpp" #include "config/configitem.hpp" #include "base/debuginfo.hpp" #include "base/object.hpp" namespace icinga { /** * Config item builder. Used to dynamically build configuration objects * at runtime. * * @ingroup config */ class I2_CONFIG_API ConfigItemBuilder : public Object { public: DECLARE_PTR_TYPEDEFS(ConfigItemBuilder); ConfigItemBuilder(void); explicit ConfigItemBuilder(const DebugInfo& debugInfo); void SetType(const Type::Ptr& type); void SetName(const String& name); void SetAbstract(bool abstract); void SetScope(const Dictionary::Ptr& scope); void SetZone(const String& zone); void SetPackage(const String& package); void SetDefaultTemplate(bool defaultTmpl); void SetIgnoreOnError(bool ignoreOnError); void AddExpression(Expression *expr); void SetFilter(const boost::shared_ptr& filter); ConfigItem::Ptr Compile(void); private: Type::Ptr m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether the item is abstract. */ std::vector m_Expressions; /**< Expressions for this item. */ boost::shared_ptr m_Filter; /**< Filter expression. */ DebugInfo m_DebugInfo; /**< Debug information. */ Dictionary::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ String m_Package; /**< The package name. */ bool m_DefaultTmpl; bool m_IgnoreOnError; /**< Whether the object should be ignored when an error occurs in one of the expressions. */ }; } #endif /* CONFIGITEMBUILDER */ icinga2-2.8.1/lib/config/expression.cpp000066400000000000000000000650741322762156600200020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/expression.hpp" #include "config/configitem.hpp" #include "config/configcompiler.hpp" #include "config/vmops.hpp" #include "base/array.hpp" #include "base/json.hpp" #include "base/object.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/scriptglobal.hpp" #include "base/loader.hpp" #include #include using namespace icinga; boost::signals2::signal Expression::OnBreakpoint; boost::thread_specific_ptr l_InBreakpointHandler; Expression::~Expression(void) { } void Expression::ScriptBreakpoint(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di) { bool *inHandler = l_InBreakpointHandler.get(); if (!inHandler || !*inHandler) { inHandler = new bool(true); l_InBreakpointHandler.reset(inHandler); OnBreakpoint(frame, ex, di); *inHandler = false; } } ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) const { try { #ifdef I2_DEBUG /* std::ostringstream msgbuf; ShowCodeLocation(msgbuf, GetDebugInfo(), false); Log(LogDebug, "Expression") << "Executing:\n" << msgbuf.str();*/ #endif /* I2_DEBUG */ frame.IncreaseStackDepth(); ExpressionResult result = DoEvaluate(frame, dhint); frame.DecreaseStackDepth(); return result; } catch (ScriptError& ex) { frame.DecreaseStackDepth(); ScriptBreakpoint(frame, &ex, GetDebugInfo()); throw; } catch (const std::exception& ex) { frame.DecreaseStackDepth(); BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo()) << boost::errinfo_nested_exception(boost::current_exception())); } frame.DecreaseStackDepth(); } bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { return false; } const DebugInfo& Expression::GetDebugInfo(void) const { static DebugInfo debugInfo; return debugInfo; } Expression *icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index) { Expression *scope = new GetScopeExpression(scopeSpec); return new IndexerExpression(scope, MakeLiteral(index)); } void DictExpression::MakeInline(void) { m_Inline = true; } LiteralExpression::LiteralExpression(const Value& value) : m_Value(value) { } ExpressionResult LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return m_Value; } const DebugInfo& DebuggableExpression::GetDebugInfo(void) const { return m_DebugInfo; } ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value value; if (frame.Locals && frame.Locals->Get(m_Variable, &value)) return value; else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get() && frame.Self.Get()->GetOwnField(m_Variable, &value)) return value; else if (VMOps::FindVarImport(frame, m_Variable, &value, m_DebugInfo)) return value; else return ScriptGlobal::Get(m_Variable); } bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { *index = m_Variable; if (frame.Locals && frame.Locals->Contains(m_Variable)) { *parent = frame.Locals; if (dhint) *dhint = NULL; } else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get() && frame.Self.Get()->HasOwnField(m_Variable)) { *parent = frame.Self; if (dhint && *dhint) *dhint = new DebugHint((*dhint)->GetChild(m_Variable)); } else if (VMOps::FindVarImportRef(frame, m_Variable, parent, m_DebugInfo)) { return true; } else if (ScriptGlobal::Exists(m_Variable)) { *parent = ScriptGlobal::GetGlobals(); if (dhint) *dhint = NULL; } else *parent = frame.Self; return true; } ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return ~(long)operand.GetValue(); } ExpressionResult LogicalNegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return !operand.GetValue().ToBool(); } ExpressionResult AddExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() + operand2.GetValue(); } ExpressionResult SubtractExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() - operand2.GetValue(); } ExpressionResult MultiplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() * operand2.GetValue(); } ExpressionResult DivideExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() / operand2.GetValue(); } ExpressionResult ModuloExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() % operand2.GetValue(); } ExpressionResult XorExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() ^ operand2.GetValue(); } ExpressionResult BinaryAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() & operand2.GetValue(); } ExpressionResult BinaryOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() | operand2.GetValue(); } ExpressionResult ShiftLeftExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() << operand2.GetValue(); } ExpressionResult ShiftRightExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() >> operand2.GetValue(); } ExpressionResult EqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() == operand2.GetValue(); } ExpressionResult NotEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() != operand2.GetValue(); } ExpressionResult LessThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() < operand2.GetValue(); } ExpressionResult GreaterThanExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() > operand2.GetValue(); } ExpressionResult LessThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() <= operand2.GetValue(); } ExpressionResult GreaterThanOrEqualExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand1.GetValue() >= operand2.GetValue(); } ExpressionResult InExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); if (operand2.GetValue().IsEmpty()) return false; else if (!operand2.GetValue().IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1) Array::Ptr arr = operand2.GetValue(); return arr->Contains(operand1.GetValue()); } ExpressionResult NotInExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); if (operand2.GetValue().IsEmpty()) return true; else if (!operand2.GetValue().IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Invalid right side argument for 'in' operator: " + JsonEncode(operand2.GetValue()), m_DebugInfo)); ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); Array::Ptr arr = operand2.GetValue(); return !arr->Contains(operand1.GetValue()); } ExpressionResult LogicalAndExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); if (!operand1.GetValue().ToBool()) return operand1; else { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand2.GetValue(); } } ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame); CHECK_RESULT(operand1); if (operand1.GetValue().ToBool()) return operand1; else { ExpressionResult operand2 = m_Operand2->Evaluate(frame); CHECK_RESULT(operand2); return operand2.GetValue(); } } ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value self, vfunc; String index; if (m_FName->GetReference(frame, false, &self, &index)) vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo); else { ExpressionResult vfuncres = m_FName->Evaluate(frame); CHECK_RESULT(vfuncres); vfunc = vfuncres.GetValue(); } if (vfunc.IsObjectType()) { std::vector arguments; for (Expression *arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo); } if (!vfunc.IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo)); Function::Ptr func = vfunc; if (!func->IsSideEffectFree() && frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo)); std::vector arguments; for (Expression *arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::FunctionCall(frame, self, func, arguments); } ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Array::Ptr result = new Array(); result->Reserve(m_Expressions.size()); for (Expression *aexpr : m_Expressions) { ExpressionResult element = aexpr->Evaluate(frame); CHECK_RESULT(element); result->Add(element.GetValue()); } return result; } ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value self; if (!m_Inline) { self = frame.Self; frame.Self = new Dictionary(); } Value result; try { for (Expression *aexpr : m_Expressions) { ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : NULL); CHECK_RESULT(element); result = element.GetValue(); } } catch (...) { if (!m_Inline) std::swap(self, frame.Self); throw; } if (m_Inline) return result; else { std::swap(self, frame.Self); return self; } } ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (m_ScopeSpec == ScopeLocal) return frame.Locals; else if (m_ScopeSpec == ScopeThis) return frame.Self; else if (m_ScopeSpec == ScopeGlobal) return ScriptGlobal::GetGlobals(); else VERIFY(!"Invalid scope."); } ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Assignments are not allowed in sandbox mode.", m_DebugInfo)); DebugHint *psdhint = dhint; Value parent; String index; if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint)) BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo)); ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint); CHECK_RESULT(operand2); if (m_Op != OpSetLiteral) { Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo); switch (m_Op) { case OpSetAdd: operand2 = object + operand2; break; case OpSetSubtract: operand2 = object - operand2; break; case OpSetMultiply: operand2 = object * operand2; break; case OpSetDivide: operand2 = object / operand2; break; case OpSetModulo: operand2 = object % operand2; break; case OpSetXor: operand2 = object ^ operand2; break; case OpSetBinaryAnd: operand2 = object & operand2; break; case OpSetBinaryOr: operand2 = object | operand2; break; default: VERIFY(!"Invalid opcode."); } } VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo); if (psdhint) { psdhint->AddMessage("=", m_DebugInfo); if (psdhint != dhint) delete psdhint; } return Empty; } ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult condition = m_Condition->Evaluate(frame, dhint); CHECK_RESULT(condition); if (condition.GetValue().ToBool()) return m_TrueBranch->Evaluate(frame, dhint); else if (m_FalseBranch) return m_FalseBranch->Evaluate(frame, dhint); return Empty; } ExpressionResult WhileExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("While loops are not allowed in sandbox mode.", m_DebugInfo)); for (;;) { ExpressionResult condition = m_Condition->Evaluate(frame, dhint); CHECK_RESULT(condition); if (!condition.GetValue().ToBool()) break; ExpressionResult loop_body = m_LoopBody->Evaluate(frame, dhint); CHECK_RESULT_LOOP(loop_body); } return Empty; } ExpressionResult ReturnExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand = m_Operand->Evaluate(frame); CHECK_RESULT(operand); return ExpressionResult(operand.GetValue(), ResultReturn); } ExpressionResult BreakExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return ExpressionResult(Empty, ResultBreak); } ExpressionResult ContinueExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return ExpressionResult(Empty, ResultContinue); } ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult operand1 = m_Operand1->Evaluate(frame, dhint); CHECK_RESULT(operand1); ExpressionResult operand2 = m_Operand2->Evaluate(frame, dhint); CHECK_RESULT(operand2); return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo); } bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const { Value vparent; String vindex; DebugHint *psdhint = NULL; bool free_psd = false; if (dhint) psdhint = *dhint; if (frame.Sandboxed) init_dict = false; if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) { if (init_dict) { Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo()); if (old_value.IsEmpty() && !old_value.IsString()) VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo()); } *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo); free_psd = true; } else { ExpressionResult operand1 = m_Operand1->Evaluate(frame); *parent = operand1.GetValue(); } ExpressionResult operand2 = m_Operand2->Evaluate(frame); *index = operand2.GetValue(); if (dhint) { if (psdhint) *dhint = new DebugHint(psdhint->GetChild(*index)); else *dhint = NULL; } if (free_psd) delete psdhint; return true; } void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec) { DictExpression *dexpr = dynamic_cast(expr); if (dexpr) { for (Expression *& expr : dexpr->m_Expressions) BindToScope(expr, scopeSpec); return; } SetExpression *aexpr = dynamic_cast(expr); if (aexpr) { BindToScope(aexpr->m_Operand1, scopeSpec); return; } IndexerExpression *iexpr = dynamic_cast(expr); if (iexpr) { BindToScope(iexpr->m_Operand1, scopeSpec); return; } LiteralExpression *lexpr = dynamic_cast(expr); if (lexpr && lexpr->GetValue().IsString()) { Expression *scope = new GetScopeExpression(scopeSpec); expr = new IndexerExpression(scope, lexpr, lexpr->GetDebugInfo()); } VariableExpression *vexpr = dynamic_cast(expr); if (vexpr) { Expression *scope = new GetScopeExpression(scopeSpec); Expression *new_expr = new IndexerExpression(scope, MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo()); delete expr; expr = new_expr; } } ExpressionResult ThrowExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult messageres = m_Message->Evaluate(frame); CHECK_RESULT(messageres); Value message = messageres.GetValue(); BOOST_THROW_EXCEPTION(ScriptError(message, m_DebugInfo, m_IncompleteExpr)); } ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo)); String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo); ExpressionResult nameres = m_Name->Evaluate(frame); CHECK_RESULT(nameres); Value name = nameres.GetValue(); if (!name.IsString()) BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo)); ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name); if (!item) BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo)); Dictionary::Ptr scope = item->GetScope(); if (scope) scope->CopyTo(frame.Locals); ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint); CHECK_RESULT(result); return Empty; } ExpressionResult ImportDefaultTemplatesExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo)); String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo); Type::Ptr ptype = Type::GetByName(type); for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(ptype)) { Dictionary::Ptr scope = item->GetScope(); if (scope) scope->CopyTo(frame.Locals); ExpressionResult result = item->GetExpression()->Evaluate(frame, dhint); CHECK_RESULT(result); } return Empty; } ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression); } ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Apply rules are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult nameres = m_Name->Evaluate(frame); CHECK_RESULT(nameres); return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter, m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo); } ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult typeres = m_Type->Evaluate(frame, dhint); CHECK_RESULT(typeres); Type::Ptr type = typeres.GetValue(); String name; if (m_Name) { ExpressionResult nameres = m_Name->Evaluate(frame, dhint); CHECK_RESULT(nameres); name = nameres.GetValue(); } return VMOps::NewObject(frame, m_Abstract, type, name, m_Filter, m_Zone, m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo); } ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("For loops are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult valueres = m_Value->Evaluate(frame, dhint); CHECK_RESULT(valueres); return VMOps::For(frame, m_FKVar, m_FVVar, valueres.GetValue(), m_Expression, m_DebugInfo); } ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Loading libraries is not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult libres = m_Operand->Evaluate(frame, dhint); CHECK_RESULT(libres); Loader::LoadExtensionLibrary(libres.GetValue()); return Empty; } ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo)); Expression *expr; String name, path, pattern; switch (m_Type) { case IncludeRegular: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo); break; case IncludeRecursive: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo); break; case IncludeZones: { ExpressionResult nameres = m_Name->Evaluate(frame, dhint); CHECK_RESULT(nameres); name = nameres.GetValue(); } { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo); break; } ExpressionResult res(Empty); try { res = expr->Evaluate(frame, dhint); } catch (const std::exception&) { delete expr; throw; } delete expr; return res; } ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ScriptBreakpoint(frame, NULL, GetDebugInfo()); return Empty; } ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Using directives are not allowed in sandbox mode.", m_DebugInfo)); ExpressionResult importres = m_Name->Evaluate(frame); CHECK_RESULT(importres); Value import = importres.GetValue(); if (!import.IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("The parameter must resolve to an object of type 'Dictionary'", m_DebugInfo)); ScriptFrame::AddImport(import); return Empty; } ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { try { ExpressionResult tryResult = m_TryBody->Evaluate(frame, dhint); CHECK_RESULT(tryResult); } catch (const std::exception& ex) { ExpressionResult exceptResult = m_ExceptBody->Evaluate(frame, dhint); CHECK_RESULT(exceptResult); } return Empty; } icinga2-2.8.1/lib/config/expression.hpp000066400000000000000000000670061322762156600200040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXPRESSION_H #define EXPRESSION_H #include "config/i2-config.hpp" #include "base/debuginfo.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/exception.hpp" #include "base/scriptframe.hpp" #include "base/convert.hpp" #include #include namespace icinga { struct DebugHint { public: DebugHint(const Dictionary::Ptr& hints = Dictionary::Ptr()) : m_Hints(hints) { } DebugHint(Dictionary::Ptr&& hints) : m_Hints(std::move(hints)) { } inline void AddMessage(const String& message, const DebugInfo& di) { GetMessages()->Add(new Array({ message, di.Path, di.FirstLine, di.FirstColumn, di.LastLine, di.LastColumn })); } inline DebugHint GetChild(const String& name) { const Dictionary::Ptr& children = GetChildren(); Value vchild; Dictionary::Ptr child; if (!children->Get(name, &vchild)) { child = new Dictionary(); children->Set(name, child); } else child = vchild; return DebugHint(child); } Dictionary::Ptr ToDictionary(void) const { return m_Hints; } private: Dictionary::Ptr m_Hints; Array::Ptr m_Messages; Dictionary::Ptr m_Children; const Array::Ptr& GetMessages(void) { if (m_Messages) return m_Messages; if (!m_Hints) m_Hints = new Dictionary(); Value vmessages; if (!m_Hints->Get("messages", &vmessages)) { m_Messages = new Array(); m_Hints->Set("messages", m_Messages); } else m_Messages = vmessages; return m_Messages; } const Dictionary::Ptr& GetChildren(void) { if (m_Children) return m_Children; if (!m_Hints) m_Hints = new Dictionary(); Value vchildren; if (!m_Hints->Get("properties", &vchildren)) { m_Children = new Dictionary(); m_Hints->Set("properties", m_Children); } else m_Children = vchildren; return m_Children; } }; enum CombinedSetOp { OpSetLiteral, OpSetAdd, OpSetSubtract, OpSetMultiply, OpSetDivide, OpSetModulo, OpSetXor, OpSetBinaryAnd, OpSetBinaryOr }; enum ScopeSpecifier { ScopeLocal, ScopeThis, ScopeGlobal }; typedef std::map DefinitionMap; /** * @ingroup config */ enum ExpressionResultCode { ResultOK, ResultReturn, ResultContinue, ResultBreak }; /** * @ingroup config */ struct ExpressionResult { public: template ExpressionResult(const T& value, ExpressionResultCode code = ResultOK) : m_Value(value), m_Code(code) { } operator const Value&(void) const { return m_Value; } const Value& GetValue(void) const { return m_Value; } ExpressionResultCode GetCode(void) const { return m_Code; } private: Value m_Value; ExpressionResultCode m_Code; }; #define CHECK_RESULT(res) \ do { \ if (res.GetCode() != ResultOK) \ return res; \ } while (0); #define CHECK_RESULT_LOOP(res) \ if (res.GetCode() == ResultReturn) \ return res; \ if (res.GetCode() == ResultContinue) \ continue; \ if (res.GetCode() == ResultBreak) \ break; \ /** * @ingroup config */ class I2_CONFIG_API Expression { public: virtual ~Expression(void); ExpressionResult Evaluate(ScriptFrame& frame, DebugHint *dhint = NULL) const; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint = NULL) const; virtual const DebugInfo& GetDebugInfo(void) const; virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const = 0; static boost::signals2::signal OnBreakpoint; static void ScriptBreakpoint(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di); }; I2_CONFIG_API Expression *MakeIndexer(ScopeSpecifier scopeSpec, const String& index); class I2_CONFIG_API OwnedExpression : public Expression { public: OwnedExpression(const boost::shared_ptr& expression) : m_Expression(expression) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override { return m_Expression->DoEvaluate(frame, dhint); } virtual const DebugInfo& GetDebugInfo(void) const override { return m_Expression->GetDebugInfo(); } private: boost::shared_ptr m_Expression; }; class I2_CONFIG_API LiteralExpression : public Expression { public: LiteralExpression(const Value& value = Value()); const Value& GetValue(void) const { return m_Value; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Value m_Value; }; inline LiteralExpression *MakeLiteral(const Value& literal = Value()) { return new LiteralExpression(literal); } class I2_CONFIG_API DebuggableExpression : public Expression { public: DebuggableExpression(const DebugInfo& debugInfo = DebugInfo()) : m_DebugInfo(debugInfo) { } protected: virtual const DebugInfo& GetDebugInfo(void) const override; DebugInfo m_DebugInfo; }; class I2_CONFIG_API UnaryExpression : public DebuggableExpression { public: UnaryExpression(Expression *operand, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Operand(operand) { } ~UnaryExpression(void) { delete m_Operand; } protected: Expression *m_Operand; }; class I2_CONFIG_API BinaryExpression : public DebuggableExpression { public: BinaryExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Operand1(operand1), m_Operand2(operand2) { } ~BinaryExpression(void) { delete m_Operand1; delete m_Operand2; } protected: Expression *m_Operand1; Expression *m_Operand2; }; class I2_CONFIG_API VariableExpression : public DebuggableExpression { public: VariableExpression(const String& variable, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Variable(variable) { } String GetVariable(void) const { return m_Variable; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override; private: String m_Variable; friend I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); }; class I2_CONFIG_API NegateExpression : public UnaryExpression { public: NegateExpression(Expression *operand, const DebugInfo& debugInfo = DebugInfo()) : UnaryExpression(operand, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API LogicalNegateExpression : public UnaryExpression { public: LogicalNegateExpression(Expression *operand, const DebugInfo& debugInfo = DebugInfo()) : UnaryExpression(operand, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API AddExpression : public BinaryExpression { public: AddExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API SubtractExpression : public BinaryExpression { public: SubtractExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API MultiplyExpression : public BinaryExpression { public: MultiplyExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API DivideExpression : public BinaryExpression { public: DivideExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API ModuloExpression : public BinaryExpression { public: ModuloExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API XorExpression : public BinaryExpression { public: XorExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API BinaryAndExpression : public BinaryExpression { public: BinaryAndExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API BinaryOrExpression : public BinaryExpression { public: BinaryOrExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API ShiftLeftExpression : public BinaryExpression { public: ShiftLeftExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API ShiftRightExpression : public BinaryExpression { public: ShiftRightExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API EqualExpression : public BinaryExpression { public: EqualExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API NotEqualExpression : public BinaryExpression { public: NotEqualExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API LessThanExpression : public BinaryExpression { public: LessThanExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API GreaterThanExpression : public BinaryExpression { public: GreaterThanExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API LessThanOrEqualExpression : public BinaryExpression { public: LessThanOrEqualExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API GreaterThanOrEqualExpression : public BinaryExpression { public: GreaterThanOrEqualExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API InExpression : public BinaryExpression { public: InExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API NotInExpression : public BinaryExpression { public: NotInExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API LogicalAndExpression : public BinaryExpression { public: LogicalAndExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API LogicalOrExpression : public BinaryExpression { public: LogicalOrExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API FunctionCallExpression : public DebuggableExpression { public: FunctionCallExpression(Expression *fname, const std::vector& args, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_FName(fname), m_Args(args) { } ~FunctionCallExpression(void) { delete m_FName; for (Expression *expr : m_Args) delete expr; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; public: Expression *m_FName; std::vector m_Args; }; class I2_CONFIG_API ArrayExpression : public DebuggableExpression { public: ArrayExpression(const std::vector& expressions, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Expressions(expressions) { } ~ArrayExpression(void) { for (Expression *expr : m_Expressions) delete expr; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: std::vector m_Expressions; }; class I2_CONFIG_API DictExpression : public DebuggableExpression { public: DictExpression(const std::vector& expressions = std::vector(), const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Expressions(expressions), m_Inline(false) { } ~DictExpression(void) { for (Expression *expr : m_Expressions) delete expr; } void MakeInline(void); protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: std::vector m_Expressions; bool m_Inline; friend I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); }; class I2_CONFIG_API SetExpression : public BinaryExpression { public: SetExpression(Expression *operand1, CombinedSetOp op, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo), m_Op(op) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: CombinedSetOp m_Op; friend I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); }; class I2_CONFIG_API ConditionalExpression : public DebuggableExpression { public: ConditionalExpression(Expression *condition, Expression *true_branch, Expression *false_branch, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Condition(condition), m_TrueBranch(true_branch), m_FalseBranch(false_branch) { } ~ConditionalExpression(void) { delete m_Condition; delete m_TrueBranch; delete m_FalseBranch; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_Condition; Expression *m_TrueBranch; Expression *m_FalseBranch; }; class I2_CONFIG_API WhileExpression : public DebuggableExpression { public: WhileExpression(Expression *condition, Expression *loop_body, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Condition(condition), m_LoopBody(loop_body) { } ~WhileExpression(void) { delete m_Condition; delete m_LoopBody; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_Condition; Expression *m_LoopBody; }; class I2_CONFIG_API ReturnExpression : public UnaryExpression { public: ReturnExpression(Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : UnaryExpression(expression, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API BreakExpression : public DebuggableExpression { public: BreakExpression(const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API ContinueExpression : public DebuggableExpression { public: ContinueExpression(const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API GetScopeExpression : public Expression { public: GetScopeExpression(ScopeSpecifier scopeSpec) : m_ScopeSpec(scopeSpec) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: ScopeSpecifier m_ScopeSpec; }; class I2_CONFIG_API IndexerExpression : public BinaryExpression { public: IndexerExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) : BinaryExpression(operand1, operand2, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override; friend I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); }; I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec); class I2_CONFIG_API ThrowExpression : public DebuggableExpression { public: ThrowExpression(Expression *message, bool incompleteExpr, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Message(message), m_IncompleteExpr(incompleteExpr) { } ~ThrowExpression(void) { delete m_Message; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_Message; bool m_IncompleteExpr; }; class I2_CONFIG_API ImportExpression : public DebuggableExpression { public: ImportExpression(Expression *name, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Name(name) { } ~ImportExpression(void) { delete m_Name; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_Name; }; class I2_CONFIG_API ImportDefaultTemplatesExpression : public DebuggableExpression { public: ImportDefaultTemplatesExpression(const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API FunctionExpression : public DebuggableExpression { public: FunctionExpression(const String& name, const std::vector& args, std::map *closedVars, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Name(name), m_Args(args), m_ClosedVars(closedVars), m_Expression(expression) { } ~FunctionExpression(void) { if (m_ClosedVars) { typedef std::pair kv_pair; for (const kv_pair& kv : *m_ClosedVars) { delete kv.second; } } delete m_ClosedVars; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: String m_Name; std::vector m_Args; std::map *m_ClosedVars; boost::shared_ptr m_Expression; }; class I2_CONFIG_API ApplyExpression : public DebuggableExpression { public: ApplyExpression(const String& type, const String& target, Expression *name, Expression *filter, const String& package, const String& fkvar, const String& fvvar, Expression *fterm, std::map *closedVars, bool ignoreOnError, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Type(type), m_Target(target), m_Name(name), m_Filter(filter), m_Package(package), m_FKVar(fkvar), m_FVVar(fvvar), m_FTerm(fterm), m_IgnoreOnError(ignoreOnError), m_ClosedVars(closedVars), m_Expression(expression) { } ~ApplyExpression(void) { delete m_Name; if (m_ClosedVars) { typedef std::pair kv_pair; for (const kv_pair& kv : *m_ClosedVars) { delete kv.second; } } delete m_ClosedVars; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: String m_Type; String m_Target; Expression *m_Name; boost::shared_ptr m_Filter; String m_Package; String m_FKVar; String m_FVVar; boost::shared_ptr m_FTerm; bool m_IgnoreOnError; std::map *m_ClosedVars; boost::shared_ptr m_Expression; }; class I2_CONFIG_API ObjectExpression : public DebuggableExpression { public: ObjectExpression(bool abstract, Expression *type, Expression *name, Expression *filter, const String& zone, const String& package, std::map *closedVars, bool defaultTmpl, bool ignoreOnError, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Abstract(abstract), m_Type(type), m_Name(name), m_Filter(filter), m_Zone(zone), m_Package(package), m_DefaultTmpl(defaultTmpl), m_IgnoreOnError(ignoreOnError), m_ClosedVars(closedVars), m_Expression(expression) { } ~ObjectExpression(void) { delete m_Name; if (m_ClosedVars) { typedef std::pair kv_pair; for (const kv_pair& kv : *m_ClosedVars) { delete kv.second; } } delete m_ClosedVars; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: bool m_Abstract; Expression *m_Type; Expression *m_Name; boost::shared_ptr m_Filter; String m_Zone; String m_Package; bool m_DefaultTmpl; bool m_IgnoreOnError; std::map *m_ClosedVars; boost::shared_ptr m_Expression; }; class I2_CONFIG_API ForExpression : public DebuggableExpression { public: ForExpression(const String& fkvar, const String& fvvar, Expression *value, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_FKVar(fkvar), m_FVVar(fvvar), m_Value(value), m_Expression(expression) { } ~ForExpression(void) { delete m_Value; delete m_Expression; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: String m_FKVar; String m_FVVar; Expression *m_Value; Expression *m_Expression; }; class I2_CONFIG_API LibraryExpression : public UnaryExpression { public: LibraryExpression(Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : UnaryExpression(expression, debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; enum IncludeType { IncludeRegular, IncludeRecursive, IncludeZones }; class I2_CONFIG_API IncludeExpression : public DebuggableExpression { public: IncludeExpression(const String& relativeBase, Expression *path, Expression *pattern, Expression *name, IncludeType type, bool searchIncludes, const String& zone, const String& package, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_RelativeBase(relativeBase), m_Path(path), m_Pattern(pattern), m_Name(name), m_Type(type), m_SearchIncludes(searchIncludes), m_Zone(zone), m_Package(package) { } ~IncludeExpression(void) { delete m_Path; delete m_Pattern; delete m_Name; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: String m_RelativeBase; Expression *m_Path; Expression *m_Pattern; Expression *m_Name; IncludeType m_Type; bool m_SearchIncludes; String m_Zone; String m_Package; }; class I2_CONFIG_API BreakpointExpression : public DebuggableExpression { public: BreakpointExpression(const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo) { } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; class I2_CONFIG_API UsingExpression : public DebuggableExpression { public: UsingExpression(Expression *name, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Name(name) { } ~UsingExpression(void) { delete m_Name; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_Name; }; class I2_CONFIG_API TryExceptExpression : public DebuggableExpression { public: TryExceptExpression(Expression *tryBody, Expression *exceptBody, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_TryBody(tryBody), m_ExceptBody(exceptBody) { } ~TryExceptExpression(void) { delete m_TryBody; delete m_ExceptBody; } protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: Expression *m_TryBody; Expression *m_ExceptBody; }; } #endif /* EXPRESSION_H */ icinga2-2.8.1/lib/config/i2-config.hpp000066400000000000000000000035631322762156600173600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2CONFIG_H #define I2CONFIG_H /** * @defgroup config Configuration library * * The configuration library implements a compiler for Icinga 2's configuration * format. It also provides functionality for creating configuration objects * at runtime. */ #include "base/i2-base.hpp" #ifdef I2_CONFIG_BUILD # define I2_CONFIG_API I2_EXPORT #else /* I2_CONFIG_BUILD */ # define I2_CONFIG_API I2_IMPORT #endif /* I2_CONFIG_BUILD */ #endif /* I2CONFIG_H */ icinga2-2.8.1/lib/config/objectrule.cpp000066400000000000000000000033441322762156600177310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/objectrule.hpp" #include using namespace icinga; ObjectRule::TypeSet ObjectRule::m_Types; void ObjectRule::RegisterType(const String& sourceType) { m_Types.insert(sourceType); } bool ObjectRule::IsValidSourceType(const String& sourceType) { return m_Types.find(sourceType) != m_Types.end(); } icinga2-2.8.1/lib/config/objectrule.hpp000066400000000000000000000035771322762156600177460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTRULE_H #define OBJECTRULE_H #include "config/i2-config.hpp" #include "config/expression.hpp" #include "base/debuginfo.hpp" #include namespace icinga { /** * @ingroup config */ class I2_CONFIG_API ObjectRule { public: typedef std::set TypeSet; static void RegisterType(const String& sourceType); static bool IsValidSourceType(const String& sourceType); private: ObjectRule(void); static TypeSet m_Types; }; } #endif /* OBJECTRULE_H */ icinga2-2.8.1/lib/config/vmops.hpp000066400000000000000000000231071322762156600167430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VMOPS_H #define VMOPS_H #include "config/i2-config.hpp" #include "config/expression.hpp" #include "config/configitembuilder.hpp" #include "config/applyrule.hpp" #include "config/objectrule.hpp" #include "base/debuginfo.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/scriptglobal.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include #include #include namespace icinga { class VMOps { public: static inline bool FindVarImportRef(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo()) { Array::Ptr imports = ScriptFrame::GetImports(); ObjectLock olock(imports); for (const Value& import : imports) { Object::Ptr obj = import; if (obj->HasOwnField(name)) { *result = import; return true; } } return false; } static inline bool FindVarImport(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo()) { Value parent; if (FindVarImportRef(frame, name, &parent, debugInfo)) { *result = GetField(parent, name, frame.Sandboxed, debugInfo); return true; } return false; } static inline Value ConstructorCall(const Type::Ptr& type, const std::vector& args, const DebugInfo& debugInfo = DebugInfo()) { if (type->GetName() == "String") { if (args.empty()) return ""; else if (args.size() == 1) return Convert::ToString(args[0]); else BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); } else if (type->GetName() == "Number") { if (args.empty()) return 0; else if (args.size() == 1) return Convert::ToDouble(args[0]); else BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); } else if (type->GetName() == "Boolean") { if (args.empty()) return 0; else if (args.size() == 1) return Convert::ToBool(args[0]); else BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); } else if (args.size() == 1 && type->IsAssignableFrom(args[0].GetReflectionType())) return args[0]; else return type->Instantiate(args); } static inline Value FunctionCall(ScriptFrame& frame, const Value& self, const Function::Ptr& func, const std::vector& arguments) { if (!self.IsEmpty() || self.IsString()) return func->Invoke(self, arguments); else return func->Invoke(arguments); } static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector& args, std::map *closedVars, const boost::shared_ptr& expression) { return new Function(name, boost::bind(&FunctionWrapper, _1, args, EvaluateClosedVars(frame, closedVars), expression), args); } static inline Value NewApply(ScriptFrame& frame, const String& type, const String& target, const String& name, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, std::map *closedVars, bool ignoreOnError, const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) { ApplyRule::AddRule(type, target, name, expression, filter, package, fkvar, fvvar, fterm, ignoreOnError, debugInfo, EvaluateClosedVars(frame, closedVars)); return Empty; } static inline Value NewObject(ScriptFrame& frame, bool abstract, const Type::Ptr& type, const String& name, const boost::shared_ptr& filter, const String& zone, const String& package, bool defaultTmpl, bool ignoreOnError, std::map *closedVars, const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) { ConfigItemBuilder::Ptr item = new ConfigItemBuilder(debugInfo); String checkName = name; if (!abstract) { NameComposer *nc = dynamic_cast(type.get()); if (nc) checkName = nc->MakeName(name, Dictionary::Ptr()); } if (!checkName.IsEmpty()) { ConfigItem::Ptr oldItem = ConfigItem::GetByTypeAndName(type, checkName); if (oldItem) { std::ostringstream msgbuf; msgbuf << "Object '" << name << "' of type '" << type->GetName() << "' re-defined: " << debugInfo << "; previous definition: " << oldItem->GetDebugInfo(); BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debugInfo)); } } if (filter && !ObjectRule::IsValidSourceType(type->GetName())) { std::ostringstream msgbuf; msgbuf << "Object '" << name << "' of type '" << type->GetName() << "' must not have 'assign where' and 'ignore where' rules: " << debugInfo; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debugInfo)); } item->SetType(type); item->SetName(name); if (!abstract) item->AddExpression(new ImportDefaultTemplatesExpression()); item->AddExpression(new OwnedExpression(expression)); item->SetAbstract(abstract); item->SetScope(EvaluateClosedVars(frame, closedVars)); item->SetZone(zone); item->SetPackage(package); item->SetFilter(filter); item->SetDefaultTemplate(defaultTmpl); item->SetIgnoreOnError(ignoreOnError); item->Compile()->Register(); return Empty; } static inline ExpressionResult For(ScriptFrame& frame, const String& fkvar, const String& fvvar, const Value& value, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) { if (value.IsObjectType()) { if (!fvvar.IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Cannot use dictionary iterator for array.", debugInfo)); Array::Ptr arr = value; for (Array::SizeType i = 0; i < arr->GetLength(); i++) { frame.Locals->Set(fkvar, arr->Get(i)); ExpressionResult res = expression->Evaluate(frame); CHECK_RESULT_LOOP(res); } } else if (value.IsObjectType()) { if (fvvar.IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Cannot use array iterator for dictionary.", debugInfo)); Dictionary::Ptr dict = value; std::vector keys; { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { keys.push_back(kv.first); } } for (const String& key : keys) { frame.Locals->Set(fkvar, key); frame.Locals->Set(fvvar, dict->Get(key)); ExpressionResult res = expression->Evaluate(frame); CHECK_RESULT_LOOP(res); } } else BOOST_THROW_EXCEPTION(ScriptError("Invalid type in for expression: " + value.GetTypeName(), debugInfo)); return Empty; } static inline Value GetField(const Value& context, const String& field, bool sandboxed = false, const DebugInfo& debugInfo = DebugInfo()) { if (unlikely(context.IsEmpty() && !context.IsString())) return Empty; if (unlikely(!context.IsObject())) return GetPrototypeField(context, field, true, debugInfo); Object::Ptr object = context; return object->GetFieldByName(field, sandboxed, debugInfo); } static inline void SetField(const Object::Ptr& context, const String& field, const Value& value, const DebugInfo& debugInfo = DebugInfo()) { if (!context) BOOST_THROW_EXCEPTION(ScriptError("Cannot set field '" + field + "' on a value that is not an object.", debugInfo)); return context->SetFieldByName(field, value, debugInfo); } private: static inline Value FunctionWrapper(const std::vector& arguments, const std::vector& funcargs, const Dictionary::Ptr& closedVars, const boost::shared_ptr& expr) { if (arguments.size() < funcargs.size()) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); ScriptFrame *frame = ScriptFrame::GetCurrentFrame(); if (closedVars) closedVars->CopyTo(frame->Locals); for (std::vector::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++) frame->Locals->Set(funcargs[i], arguments[i]); return expr->Evaluate(*frame); } static inline Dictionary::Ptr EvaluateClosedVars(ScriptFrame& frame, std::map *closedVars) { Dictionary::Ptr locals; if (closedVars) { locals = new Dictionary(); typedef std::pair ClosedVar; for (const ClosedVar& cvar : *closedVars) { locals->Set(cvar.first, cvar.second->Evaluate(frame)); } } return locals; } }; } #endif /* VMOPS_H */ icinga2-2.8.1/lib/db_ido/000077500000000000000000000000001322762156600150365ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido/CMakeLists.txt000066400000000000000000000034611322762156600176020ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(dbconnection.ti dbconnection.tcpp dbconnection.thpp) mkembedconfig_target(db_ido-itl.conf db_ido-itl.cpp) set(db_ido_SOURCES commanddbobject.cpp dbconnection.cpp dbconnection.thpp db_ido-itl.cpp dbevents.cpp dbobject.cpp dbquery.cpp dbreference.cpp dbtype.cpp dbvalue.cpp endpointdbobject.cpp hostdbobject.cpp hostgroupdbobject.cpp idochecktask.cpp servicedbobject.cpp servicegroupdbobject.cpp timeperioddbobject.cpp userdbobject.cpp usergroupdbobject.cpp zonedbobject.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(db_ido db_ido db_ido_SOURCES) endif() add_library(db_ido SHARED ${db_ido_SOURCES}) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(db_ido ${Boost_LIBRARIES} base config icinga remote) set_target_properties ( db_ido PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_DB_IDO_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS db_ido RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/db_ido/commanddbobject.cpp000066400000000000000000000043411322762156600206570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/commanddbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/command.hpp" #include "icinga/compatutility.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_DBTYPE(Command, "command", DbObjectTypeCommand, "object_id", CommandDbObject); CommandDbObject::CommandDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr CommandDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); Command::Ptr command = static_pointer_cast(GetObject()); fields->Set("command_line", CompatUtility::GetCommandLine(command)); return fields; } Dictionary::Ptr CommandDbObject::GetStatusFields(void) const { return Dictionary::Ptr(); } icinga2-2.8.1/lib/db_ido/commanddbobject.hpp000066400000000000000000000036721322762156600206720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMMANDDBOBJECT_H #define COMMANDDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" namespace icinga { /** * A Command database object. * * @ingroup ido */ class CommandDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(CommandDbObject); CommandDbObject(const DbType::Ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; }; } #endif /* COMMANDDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/db_ido-itl.conf000066400000000000000000000033731322762156600177210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ System.assert(Internal.run_with_activation_context(function() { var _Internal = Internal.clone() template CheckCommand "ido-check-command" use (_Internal) { execute = _Internal.IdoCheck } object CheckCommand "ido" { import "ido-check-command" } })) var methods = [ "IdoCheck" ] for (method in methods) { Internal.remove(method) } icinga2-2.8.1/lib/db_ido/dbconnection.cpp000066400000000000000000000355041322762156600202160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbconnection.hpp" #include "db_ido/dbconnection.tcpp" #include "db_ido/dbvalue.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "base/configtype.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_TYPE(DbConnection); Timer::Ptr DbConnection::m_ProgramStatusTimer; boost::once_flag DbConnection::m_OnceFlag = BOOST_ONCE_INIT; DbConnection::DbConnection(void) : m_IDCacheValid(false), m_QueryStats(15 * 60), m_ActiveChangedHandler(false) { } void DbConnection::OnConfigLoaded(void) { ConfigObject::OnConfigLoaded(); Value categories = GetCategories(); SetCategoryFilter(FilterArrayToInt(categories, DbQuery::GetCategoryFilterMap(), DbCatEverything)); if (!GetEnableHa()) { Log(LogDebug, "DbConnection") << "HA functionality disabled. Won't pause IDO connection: " << GetName(); SetHAMode(HARunEverywhere); } boost::call_once(m_OnceFlag, InitializeDbTimer); } void DbConnection::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "DbConnection") << "'" << GetName() << "' started."; DbObject::OnQuery.connect(boost::bind(&DbConnection::ExecuteQuery, this, _1)); DbObject::OnMultipleQueries.connect(boost::bind(&DbConnection::ExecuteMultipleQueries, this, _1)); } void DbConnection::Stop(bool runtimeRemoved) { Log(LogInformation, "DbConnection") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } void DbConnection::EnableActiveChangedHandler(void) { if (!m_ActiveChangedHandler) { ConfigObject::OnActiveChanged.connect(boost::bind(&DbConnection::UpdateObject, this, _1)); m_ActiveChangedHandler = true; } } void DbConnection::Resume(void) { ConfigObject::Resume(); Log(LogInformation, "DbConnection") << "Resuming IDO connection: " << GetName(); m_CleanUpTimer = new Timer(); m_CleanUpTimer->SetInterval(60); m_CleanUpTimer->OnTimerExpired.connect(boost::bind(&DbConnection::CleanUpHandler, this)); m_CleanUpTimer->Start(); } void DbConnection::Pause(void) { ConfigObject::Pause(); Log(LogInformation, "DbConnection") << "Pausing IDO connection: " << GetName(); m_CleanUpTimer.reset(); DbQuery query1; query1.Table = "programstatus"; query1.IdColumn = "programstatus_id"; query1.Type = DbQueryUpdate; query1.Category = DbCatProgramStatus; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.Fields = new Dictionary(); query1.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.Fields->Set("program_end_time", DbValue::FromTimestamp(Utility::GetTime())); query1.Priority = PriorityHigh; ExecuteQuery(query1); NewTransaction(); } void DbConnection::InitializeDbTimer(void) { m_ProgramStatusTimer = new Timer(); m_ProgramStatusTimer->SetInterval(10); m_ProgramStatusTimer->OnTimerExpired.connect(boost::bind(&DbConnection::UpdateProgramStatus)); m_ProgramStatusTimer->Start(); } void DbConnection::InsertRuntimeVariable(const String& key, const Value& value) { DbQuery query; query.Table = "runtimevariables"; query.Type = DbQueryInsert; query.Category = DbCatProgramStatus; query.Fields = new Dictionary(); query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query.Fields->Set("varname", key); query.Fields->Set("varvalue", value); DbObject::OnQuery(query); } void DbConnection::UpdateProgramStatus(void) { Log(LogNotice, "DbConnection") << "Updating programstatus table."; std::vector queries; DbQuery query1; query1.Table = "programstatus"; query1.IdColumn = "programstatus_id"; query1.Type = DbQueryInsert | DbQueryUpdate; query1.Category = DbCatProgramStatus; query1.Fields = new Dictionary(); query1.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.Fields->Set("program_version", Application::GetAppVersion()); query1.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime())); query1.Fields->Set("program_start_time", DbValue::FromTimestamp(Application::GetStartTime())); query1.Fields->Set("is_currently_running", 1); query1.Fields->Set("endpoint_name", IcingaApplication::GetInstance()->GetNodeName()); query1.Fields->Set("process_id", Utility::GetPid()); query1.Fields->Set("daemon_mode", 1); query1.Fields->Set("last_command_check", DbValue::FromTimestamp(Utility::GetTime())); query1.Fields->Set("notifications_enabled", (IcingaApplication::GetInstance()->GetEnableNotifications() ? 1 : 0)); query1.Fields->Set("active_host_checks_enabled", (IcingaApplication::GetInstance()->GetEnableHostChecks() ? 1 : 0)); query1.Fields->Set("passive_host_checks_enabled", 1); query1.Fields->Set("active_service_checks_enabled", (IcingaApplication::GetInstance()->GetEnableServiceChecks() ? 1 : 0)); query1.Fields->Set("passive_service_checks_enabled", 1); query1.Fields->Set("event_handlers_enabled", (IcingaApplication::GetInstance()->GetEnableEventHandlers() ? 1 : 0)); query1.Fields->Set("flap_detection_enabled", (IcingaApplication::GetInstance()->GetEnableFlapping() ? 1 : 0)); query1.Fields->Set("process_performance_data", (IcingaApplication::GetInstance()->GetEnablePerfdata() ? 1 : 0)); query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.Priority = PriorityHigh; queries.push_back(query1); DbQuery query2; query2.Type = DbQueryNewTransaction; queries.push_back(query2); DbObject::OnMultipleQueries(queries); DbQuery query3; query3.Table = "runtimevariables"; query3.Type = DbQueryDelete; query3.Category = DbCatProgramStatus; query3.WhereCriteria = new Dictionary(); query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query3); InsertRuntimeVariable("total_services", ConfigType::Get()->GetObjectCount()); InsertRuntimeVariable("total_scheduled_services", ConfigType::Get()->GetObjectCount()); InsertRuntimeVariable("total_hosts", ConfigType::Get()->GetObjectCount()); InsertRuntimeVariable("total_scheduled_hosts", ConfigType::Get()->GetObjectCount()); } void DbConnection::CleanUpHandler(void) { long now = static_cast(Utility::GetTime()); struct { String name; String time_column; } tables[] = { { "acknowledgements", "entry_time" }, { "commenthistory", "entry_time" }, { "contactnotifications", "start_time" }, { "contactnotificationmethods", "start_time" }, { "downtimehistory", "entry_time" }, { "eventhandlers", "start_time" }, { "externalcommands", "entry_time" }, { "flappinghistory", "event_time" }, { "hostchecks", "start_time" }, { "logentries", "logentry_time" }, { "notifications", "start_time" }, { "processevents", "event_time" }, { "statehistory", "state_time" }, { "servicechecks", "start_time" }, { "systemcommands", "start_time" } }; for (size_t i = 0; i < sizeof(tables) / sizeof(tables[0]); i++) { double max_age = GetCleanup()->Get(tables[i].name + "_age"); if (max_age == 0) continue; CleanUpExecuteQuery(tables[i].name, tables[i].time_column, now - max_age); Log(LogNotice, "DbConnection") << "Cleanup (" << tables[i].name << "): " << max_age << " now: " << now << " old: " << now - max_age; } } void DbConnection::CleanUpExecuteQuery(const String&, const String&, double) { /* Default handler does nothing. */ } void DbConnection::SetConfigHash(const DbObject::Ptr& dbobj, const String& hash) { SetConfigHash(dbobj->GetType(), GetObjectID(dbobj), hash); } void DbConnection::SetConfigHash(const DbType::Ptr& type, const DbReference& objid, const String& hash) { if (!objid.IsValid()) return; if (!hash.IsEmpty()) m_ConfigHashes[std::make_pair(type, objid)] = hash; else m_ConfigHashes.erase(std::make_pair(type, objid)); } String DbConnection::GetConfigHash(const DbObject::Ptr& dbobj) const { return GetConfigHash(dbobj->GetType(), GetObjectID(dbobj)); } String DbConnection::GetConfigHash(const DbType::Ptr& type, const DbReference& objid) const { if (!objid.IsValid()) return String(); auto it = m_ConfigHashes.find(std::make_pair(type, objid)); if (it == m_ConfigHashes.end()) return String(); return it->second; } void DbConnection::SetObjectID(const DbObject::Ptr& dbobj, const DbReference& dbref) { if (dbref.IsValid()) m_ObjectIDs[dbobj] = dbref; else m_ObjectIDs.erase(dbobj); } DbReference DbConnection::GetObjectID(const DbObject::Ptr& dbobj) const { auto it = m_ObjectIDs.find(dbobj); if (it == m_ObjectIDs.end()) return DbReference(); return it->second; } void DbConnection::SetInsertID(const DbObject::Ptr& dbobj, const DbReference& dbref) { SetInsertID(dbobj->GetType(), GetObjectID(dbobj), dbref); } void DbConnection::SetInsertID(const DbType::Ptr& type, const DbReference& objid, const DbReference& dbref) { if (!objid.IsValid()) return; if (dbref.IsValid()) m_InsertIDs[std::make_pair(type, objid)] = dbref; else m_InsertIDs.erase(std::make_pair(type, objid)); } DbReference DbConnection::GetInsertID(const DbObject::Ptr& dbobj) const { return GetInsertID(dbobj->GetType(), GetObjectID(dbobj)); } DbReference DbConnection::GetInsertID(const DbType::Ptr& type, const DbReference& objid) const { if (!objid.IsValid()) return DbReference(); auto it = m_InsertIDs.find(std::make_pair(type, objid)); if (it == m_InsertIDs.end()) return DbReference(); return it->second; } void DbConnection::SetObjectActive(const DbObject::Ptr& dbobj, bool active) { if (active) m_ActiveObjects.insert(dbobj); else m_ActiveObjects.erase(dbobj); } bool DbConnection::GetObjectActive(const DbObject::Ptr& dbobj) const { return (m_ActiveObjects.find(dbobj) != m_ActiveObjects.end()); } void DbConnection::ClearIDCache(void) { SetIDCacheValid(false); m_ObjectIDs.clear(); m_InsertIDs.clear(); m_ActiveObjects.clear(); m_ConfigUpdates.clear(); m_StatusUpdates.clear(); m_ConfigHashes.clear(); } void DbConnection::SetConfigUpdate(const DbObject::Ptr& dbobj, bool hasupdate) { if (hasupdate) m_ConfigUpdates.insert(dbobj); else m_ConfigUpdates.erase(dbobj); } bool DbConnection::GetConfigUpdate(const DbObject::Ptr& dbobj) const { return (m_ConfigUpdates.find(dbobj) != m_ConfigUpdates.end()); } void DbConnection::SetStatusUpdate(const DbObject::Ptr& dbobj, bool hasupdate) { if (hasupdate) m_StatusUpdates.insert(dbobj); else m_StatusUpdates.erase(dbobj); } bool DbConnection::GetStatusUpdate(const DbObject::Ptr& dbobj) const { return (m_StatusUpdates.find(dbobj) != m_StatusUpdates.end()); } void DbConnection::UpdateObject(const ConfigObject::Ptr& object) { if (!GetConnected() || Application::IsShuttingDown()) return; DbObject::Ptr dbobj = DbObject::GetOrCreateByObject(object); if (dbobj) { bool dbActive = GetObjectActive(dbobj); bool active = object->IsActive(); if (active) { if (!dbActive) ActivateObject(dbobj); Dictionary::Ptr configFields = dbobj->GetConfigFields(); String configHash = dbobj->CalculateConfigHash(configFields); ASSERT(configHash.GetLength() <= 64); configFields->Set("config_hash", configHash); String cachedHash = GetConfigHash(dbobj); if (cachedHash != configHash) { dbobj->SendConfigUpdateHeavy(configFields); dbobj->SendStatusUpdate(); } else { dbobj->SendConfigUpdateLight(); } } else if (!active) { /* Deactivate the deleted object no matter * which state it had in the database. */ DeactivateObject(dbobj); } } } void DbConnection::UpdateAllObjects(void) { for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { UpdateObject(object); } } } void DbConnection::PrepareDatabase(void) { for (const DbType::Ptr& type : DbType::GetAllTypes()) { FillIDCache(type); } } void DbConnection::ValidateFailoverTimeout(double value, const ValidationUtils& utils) { ObjectImpl::ValidateFailoverTimeout(value, utils); if (value < 60) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("failover_timeout"), "Failover timeout minimum is 60s.")); } void DbConnection::ValidateCategories(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateCategories(value, utils); int filter = FilterArrayToInt(value, DbQuery::GetCategoryFilterMap(), 0); if (filter != DbCatEverything && (filter & ~(DbCatInvalid | DbCatEverything | DbCatConfig | DbCatState | DbCatAcknowledgement | DbCatComment | DbCatDowntime | DbCatEventHandler | DbCatExternalCommand | DbCatFlapping | DbCatLog | DbCatNotification | DbCatProgramStatus | DbCatRetention | DbCatStateHistory)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("categories"), "categories filter is invalid.")); } void DbConnection::IncreaseQueryCount(void) { double now = Utility::GetTime(); boost::mutex::scoped_lock lock(m_StatsMutex); m_QueryStats.InsertValue(now, 1); } int DbConnection::GetQueryCount(RingBuffer::SizeType span) const { boost::mutex::scoped_lock lock(m_StatsMutex); return m_QueryStats.GetValues(span); } bool DbConnection::IsIDCacheValid(void) const { return m_IDCacheValid; } void DbConnection::SetIDCacheValid(bool valid) { m_IDCacheValid = valid; } int DbConnection::GetSessionToken(void) { return Application::GetStartTime(); } icinga2-2.8.1/lib/db_ido/dbconnection.hpp000066400000000000000000000124671322762156600202260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBCONNECTION_H #define DBCONNECTION_H #include "db_ido/i2-db_ido.hpp" #include "db_ido/dbconnection.thpp" #include "db_ido/dbobject.hpp" #include "db_ido/dbquery.hpp" #include "base/timer.hpp" #include "base/ringbuffer.hpp" #include #include #define IDO_CURRENT_SCHEMA_VERSION "1.14.3" #define IDO_COMPAT_SCHEMA_VERSION "1.14.3" namespace icinga { /** * A database connection. * * @ingroup db_ido */ class I2_DB_IDO_API DbConnection : public ObjectImpl { public: DECLARE_OBJECT(DbConnection); DbConnection(void); static void InitializeDbTimer(void); void SetConfigHash(const DbObject::Ptr& dbobj, const String& hash); void SetConfigHash(const DbType::Ptr& type, const DbReference& objid, const String& hash); String GetConfigHash(const DbObject::Ptr& dbobj) const; String GetConfigHash(const DbType::Ptr& type, const DbReference& objid) const; void SetObjectID(const DbObject::Ptr& dbobj, const DbReference& dbref); DbReference GetObjectID(const DbObject::Ptr& dbobj) const; void SetInsertID(const DbObject::Ptr& dbobj, const DbReference& dbref); void SetInsertID(const DbType::Ptr& type, const DbReference& objid, const DbReference& dbref); DbReference GetInsertID(const DbObject::Ptr& dbobj) const; DbReference GetInsertID(const DbType::Ptr& type, const DbReference& objid) const; void SetObjectActive(const DbObject::Ptr& dbobj, bool active); bool GetObjectActive(const DbObject::Ptr& dbobj) const; void ClearIDCache(void); void SetConfigUpdate(const DbObject::Ptr& dbobj, bool hasupdate); bool GetConfigUpdate(const DbObject::Ptr& dbobj) const; void SetStatusUpdate(const DbObject::Ptr& dbobj, bool hasupdate); bool GetStatusUpdate(const DbObject::Ptr& dbobj) const; int GetQueryCount(RingBuffer::SizeType span) const; virtual int GetPendingQueryCount(void) const = 0; virtual void ValidateFailoverTimeout(double value, const ValidationUtils& utils) override; virtual void ValidateCategories(const Array::Ptr& value, const ValidationUtils& utils) override; protected: virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; virtual void Resume(void) override; virtual void Pause(void) override; virtual void ExecuteQuery(const DbQuery& query) = 0; virtual void ExecuteMultipleQueries(const std::vector&) = 0; virtual void ActivateObject(const DbObject::Ptr& dbobj) = 0; virtual void DeactivateObject(const DbObject::Ptr& dbobj) = 0; virtual void CleanUpExecuteQuery(const String& table, const String& time_column, double max_age); virtual void FillIDCache(const DbType::Ptr& type) = 0; virtual void NewTransaction(void) = 0; void UpdateObject(const ConfigObject::Ptr& object); void UpdateAllObjects(void); void PrepareDatabase(void); void IncreaseQueryCount(void); bool IsIDCacheValid(void) const; void SetIDCacheValid(bool valid); void EnableActiveChangedHandler(void); static void UpdateProgramStatus(void); static int GetSessionToken(void); private: bool m_IDCacheValid; std::map, String> m_ConfigHashes; std::map m_ObjectIDs; std::map, DbReference> m_InsertIDs; std::set m_ActiveObjects; std::set m_ConfigUpdates; std::set m_StatusUpdates; Timer::Ptr m_CleanUpTimer; void CleanUpHandler(void); static Timer::Ptr m_ProgramStatusTimer; static boost::once_flag m_OnceFlag; static void InsertRuntimeVariable(const String& key, const Value& value); mutable boost::mutex m_StatsMutex; RingBuffer m_QueryStats; bool m_ActiveChangedHandler; }; struct database_error : virtual std::exception, virtual boost::exception { }; struct errinfo_database_query_; typedef boost::error_info errinfo_database_query; } #endif /* DBCONNECTION_H */ icinga2-2.8.1/lib/db_ido/dbconnection.ti000066400000000000000000000060561322762156600200500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbquery.hpp" #include "base/configobject.hpp" library db_ido; namespace icinga { abstract class DbConnection : ConfigObject { [config] String table_prefix { default {{{ return "icinga_"; }}} }; [config, required] Dictionary::Ptr cleanup { default {{{ return new Dictionary(); }}} }; [config] Array::Ptr categories { default {{{ Array::Ptr cat = new Array(); cat->Add("DbCatConfig"); cat->Add("DbCatState"); cat->Add("DbCatAcknowledgement"); cat->Add("DbCatComment"); cat->Add("DbCatDowntime"); cat->Add("DbCatEventHandler"); cat->Add("DbCatFlapping"); cat->Add("DbCatNotification"); cat->Add("DbCatProgramStatus"); cat->Add("DbCatRetention"); cat->Add("DbCatStateHistory"); return cat; }}} }; [no_user_view, no_user_modify] int categories_filter_real (CategoryFilter); [config] bool enable_ha { default {{{ return true; }}} }; [config] double failover_timeout { default {{{ return 60; }}} }; [no_user_modify] String schema_version; [no_user_modify] bool connected; [no_user_modify] bool should_connect { default {{{ return true; }}} }; }; validator DbConnection { Dictionary cleanup { Number acknowledgements_age; Number commenthistory_age; Number contactnotifications_age; Number contactnotificationmethods_age; Number downtimehistory_age; Number eventhandlers_age; Number externalcommands_age; Number flappinghistory_age; Number hostchecks_age; Number logentries_age; Number notifications_age; Number processevents_age; Number statehistory_age; Number servicechecks_age; Number systemcommands_age; }; Array categories { String "*"; }; }; } icinga2-2.8.1/lib/db_ido/dbevents.cpp000066400000000000000000001444121322762156600173620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbevents.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "remote/endpoint.hpp" #include "icinga/notification.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/externalcommandprocessor.hpp" #include "icinga/compatutility.hpp" #include "icinga/icingaapplication.hpp" #include using namespace icinga; INITIALIZE_ONCE(&DbEvents::StaticInitialize); void DbEvents::StaticInitialize(void) { /* Status */ Comment::OnCommentAdded.connect(boost::bind(&DbEvents::AddComment, _1)); Comment::OnCommentRemoved.connect(boost::bind(&DbEvents::RemoveComment, _1)); Downtime::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntime, _1)); Downtime::OnDowntimeRemoved.connect(boost::bind(&DbEvents::RemoveDowntime, _1)); Downtime::OnDowntimeTriggered.connect(boost::bind(&DbEvents::TriggerDowntime, _1)); Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgement, _1, _4)); Checkable::OnAcknowledgementCleared.connect(boost::bind(&DbEvents::RemoveAcknowledgement, _1)); Checkable::OnNextCheckUpdated.connect(boost::bind(&DbEvents::NextCheckUpdatedHandler, _1)); Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::FlappingChangedHandler, _1)); Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::LastNotificationChangedHandler, _1, _2)); Checkable::OnEnableActiveChecksChanged.connect(boost::bind(&DbEvents::EnableActiveChecksChangedHandler, _1)); Checkable::OnEnablePassiveChecksChanged.connect(boost::bind(&DbEvents::EnablePassiveChecksChangedHandler, _1)); Checkable::OnEnableNotificationsChanged.connect(boost::bind(&DbEvents::EnableNotificationsChangedHandler, _1)); Checkable::OnEnablePerfdataChanged.connect(boost::bind(&DbEvents::EnablePerfdataChangedHandler, _1)); Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::EnableFlappingChangedHandler, _1)); Checkable::OnReachabilityChanged.connect(boost::bind(&DbEvents::ReachabilityChangedHandler, _1, _2, _3)); /* History */ Comment::OnCommentAdded.connect(boost::bind(&DbEvents::AddCommentHistory, _1)); Downtime::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntimeHistory, _1)); Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgementHistory, _1, _2, _3, _4, _5, _6)); Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::AddNotificationHistory, _1, _2, _3, _4, _5, _6, _7)); Checkable::OnStateChange.connect(boost::bind(&DbEvents::AddStateChangeHistory, _1, _2, _3)); Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddCheckResultLogHistory, _1, _2)); Checkable::OnNotificationSentToUser.connect(boost::bind(&DbEvents::AddNotificationSentLogHistory, _1, _2, _3, _4, _5, _6, _7)); Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingChangedLogHistory, _1)); Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::AddEnableFlappingChangedLogHistory, _1)); Downtime::OnDowntimeTriggered.connect(boost::bind(&DbEvents::AddTriggerDowntimeLogHistory, _1)); Downtime::OnDowntimeRemoved.connect(boost::bind(&DbEvents::AddRemoveDowntimeLogHistory, _1)); Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingChangedHistory, _1)); Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::AddEnableFlappingChangedHistory, _1)); Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddCheckableCheckHistory, _1, _2)); Checkable::OnEventCommandExecuted.connect(boost::bind(&DbEvents::AddEventHandlerHistory, _1)); ExternalCommandProcessor::OnNewExternalCommand.connect(boost::bind(&DbEvents::AddExternalCommandHistory, _1, _2, _3)); } /* check events */ void DbEvents::NextCheckUpdatedHandler(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("next_check", DbValue::FromTimestamp(checkable->GetNextCheck())); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); DbObject::OnQuery(query1); } void DbEvents::FlappingChangedHandler(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("is_flapping", CompatUtility::GetCheckableIsFlapping(checkable)); fields1->Set("percent_state_change", CompatUtility::GetCheckablePercentStateChange(checkable)); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query1); } void DbEvents::LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable) { double now = Utility::GetTime(); std::pair now_bag = CompatUtility::ConvertTimestamp(now); std::pair time_bag = CompatUtility::ConvertTimestamp(notification->GetNextNotification()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("last_notification", DbValue::FromTimestamp(now_bag.first)); fields1->Set("next_notification", DbValue::FromTimestamp(time_bag.first)); fields1->Set("current_notification_number", notification->GetNotificationNumber()); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query1); } void DbEvents::ReachabilityChangedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, std::set children) { int is_reachable = 0; if (cr->GetState() == ServiceOK) is_reachable = 1; Log(LogDebug, "DbEvents") << "Updating reachability for checkable '" << checkable->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable for " << children.size() << " children."; for (const Checkable::Ptr& child : children) { Log(LogDebug, "DbEvents") << "Updating reachability for checkable '" << child->GetName() << "': " << (is_reachable ? "" : "not" ) << " reachable."; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(child); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(child); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("is_reachable", is_reachable); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query1); } } /* enable changed events */ void DbEvents::EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable) { EnableChangedHandlerInternal(checkable, "active_checks_enabled", checkable->GetEnableActiveChecks()); } void DbEvents::EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable) { EnableChangedHandlerInternal(checkable, "passive_checks_enabled", checkable->GetEnablePassiveChecks()); } void DbEvents::EnableNotificationsChangedHandler(const Checkable::Ptr& checkable) { EnableChangedHandlerInternal(checkable, "notifications_enabled", checkable->GetEnableNotifications()); } void DbEvents::EnablePerfdataChangedHandler(const Checkable::Ptr& checkable) { EnableChangedHandlerInternal(checkable, "process_performance_data", checkable->GetEnablePerfdata()); } void DbEvents::EnableFlappingChangedHandler(const Checkable::Ptr& checkable) { EnableChangedHandlerInternal(checkable, "flap_detection_enabled", checkable->GetEnableFlapping()); } void DbEvents::EnableChangedHandlerInternal(const Checkable::Ptr& checkable, const String& fieldName, bool enabled) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set(fieldName, enabled); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query1); } /* comments */ void DbEvents::AddComments(const Checkable::Ptr& checkable) { std::set comments = checkable->GetComments(); std::vector queries; for (const Comment::Ptr& comment : comments) { AddCommentInternal(queries, comment, false); } DbObject::OnMultipleQueries(queries); } void DbEvents::AddComment(const Comment::Ptr& comment) { std::vector queries; AddCommentInternal(queries, comment, false); DbObject::OnMultipleQueries(queries); } void DbEvents::AddCommentHistory(const Comment::Ptr& comment) { std::vector queries; AddCommentInternal(queries, comment, true); DbObject::OnMultipleQueries(queries); } void DbEvents::AddCommentInternal(std::vector& queries, const Comment::Ptr& comment, bool historical) { Checkable::Ptr checkable = comment->GetCheckable(); unsigned long entry_time = static_cast(comment->GetEntryTime()); unsigned long entry_time_usec = (comment->GetEntryTime() - entry_time) * 1000 * 1000; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("entry_time", DbValue::FromTimestamp(entry_time)); fields1->Set("entry_time_usec", entry_time_usec); fields1->Set("entry_type", comment->GetEntryType()); fields1->Set("object_id", checkable); if (checkable->GetReflectionType() == Host::TypeInstance) { fields1->Set("comment_type", 2); /* requires idoutils 1.10 schema fix */ fields1->Set("internal_comment_id", comment->GetLegacyId()); } else if (checkable->GetReflectionType() == Service::TypeInstance) { fields1->Set("comment_type", 1); fields1->Set("internal_comment_id", comment->GetLegacyId()); } else { Log(LogDebug, "DbEvents", "unknown object type for adding comment."); return; } fields1->Set("name", comment->GetName()); fields1->Set("comment_time", DbValue::FromTimestamp(entry_time)); /* same as entry_time */ fields1->Set("author_name", comment->GetAuthor()); fields1->Set("comment_data", comment->GetText()); fields1->Set("is_persistent", comment->GetPersistent() ? 1 : 0); fields1->Set("comment_source", 1); /* external */ fields1->Set("expires", (comment->GetExpireTime() > 0) ? 1 : 0); fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime())); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); DbQuery query1; if (!historical) { query1.Table = "comments"; query1.Type = DbQueryInsert | DbQueryUpdate; fields1->Set("session_token", 0); /* DbConnection class fills in real ID */ query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", checkable); query1.WhereCriteria->Set("name", comment->GetName()); query1.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(entry_time)); } else { query1.Table = "commenthistory"; query1.Type = DbQueryInsert; } query1.Category = DbCatComment; query1.Fields = fields1; queries.push_back(query1); } void DbEvents::RemoveComment(const Comment::Ptr& comment) { std::vector queries; RemoveCommentInternal(queries, comment); DbObject::OnMultipleQueries(queries); } void DbEvents::RemoveCommentInternal(std::vector& queries, const Comment::Ptr& comment) { Checkable::Ptr checkable = comment->GetCheckable(); unsigned long entry_time = static_cast(comment->GetEntryTime()); /* Status */ DbQuery query1; query1.Table = "comments"; query1.Type = DbQueryDelete; query1.Category = DbCatComment; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", checkable); query1.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(entry_time)); query1.WhereCriteria->Set("name", comment->GetName()); queries.push_back(query1); /* History - update deletion time for service/host */ double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query2; query2.Table = "commenthistory"; query2.Type = DbQueryUpdate; query2.Category = DbCatComment; Dictionary::Ptr fields2 = new Dictionary(); fields2->Set("deletion_time", DbValue::FromTimestamp(time_bag.first)); fields2->Set("deletion_time_usec", time_bag.second); query2.Fields = fields2; query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("object_id", checkable); query2.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(entry_time)); query2.WhereCriteria->Set("name", comment->GetName()); queries.push_back(query2); } /* downtimes */ void DbEvents::AddDowntimes(const Checkable::Ptr& checkable) { std::set downtimes = checkable->GetDowntimes(); std::vector queries; for (const Downtime::Ptr& downtime : downtimes) { AddDowntimeInternal(queries, downtime, false); } DbObject::OnMultipleQueries(queries); } void DbEvents::AddDowntime(const Downtime::Ptr& downtime) { std::vector queries; AddDowntimeInternal(queries, downtime, false); DbObject::OnMultipleQueries(queries); } void DbEvents::AddDowntimeHistory(const Downtime::Ptr& downtime) { std::vector queries; AddDowntimeInternal(queries, downtime, true); DbObject::OnMultipleQueries(queries); } void DbEvents::AddDowntimeInternal(std::vector& queries, const Downtime::Ptr& downtime, bool historical) { Checkable::Ptr checkable = downtime->GetCheckable(); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime())); fields1->Set("object_id", checkable); if (checkable->GetReflectionType() == Host::TypeInstance) { fields1->Set("downtime_type", 2); /* requires idoutils 1.10 schema fix */ fields1->Set("internal_downtime_id", downtime->GetLegacyId()); } else if (checkable->GetReflectionType() == Service::TypeInstance) { fields1->Set("downtime_type", 1); fields1->Set("internal_downtime_id", downtime->GetLegacyId()); } else { Log(LogDebug, "DbEvents", "unknown object type for adding downtime."); return; } fields1->Set("author_name", downtime->GetAuthor()); fields1->Set("comment_data", downtime->GetComment()); fields1->Set("triggered_by_id", Downtime::GetByName(downtime->GetTriggeredBy())); fields1->Set("is_fixed", downtime->GetFixed() ? 1 : 0); fields1->Set("duration", downtime->GetDuration()); fields1->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime())); fields1->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime())); fields1->Set("name", downtime->GetName()); /* flexible downtimes are started at trigger time */ if (downtime->GetFixed()) { std::pair time_bag = CompatUtility::ConvertTimestamp(downtime->GetStartTime()); fields1->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("actual_start_time_usec", time_bag.second); fields1->Set("was_started", ((downtime->GetStartTime() <= Utility::GetTime()) ? 1 : 0)); } fields1->Set("is_in_effect", (downtime->IsInEffect() ? 1 : 0)); fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime())); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); DbQuery query1; if (!historical) { query1.Table = "scheduleddowntime"; query1.Type = DbQueryInsert | DbQueryUpdate; fields1->Set("session_token", 0); /* DbConnection class fills in real ID */ query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", checkable); query1.WhereCriteria->Set("name", downtime->GetName()); query1.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime())); } else { query1.Table = "downtimehistory"; query1.Type = DbQueryInsert; } query1.Category = DbCatDowntime; query1.Fields = fields1; queries.push_back(query1); /* host/service status */ if (!historical) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query2; if (service) query2.Table = "servicestatus"; else query2.Table = "hoststatus"; query2.Type = DbQueryUpdate; query2.Category = DbCatState; query2.StatusUpdate = true; query2.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields2 = new Dictionary(); fields2->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth()); query2.Fields = fields2; query2.WhereCriteria = new Dictionary(); if (service) query2.WhereCriteria->Set("service_object_id", service); else query2.WhereCriteria->Set("host_object_id", host); query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ queries.push_back(query2); } } void DbEvents::RemoveDowntime(const Downtime::Ptr& downtime) { std::vector queries; RemoveDowntimeInternal(queries, downtime); DbObject::OnMultipleQueries(queries); } void DbEvents::RemoveDowntimeInternal(std::vector& queries, const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); /* Status */ DbQuery query1; query1.Table = "scheduleddowntime"; query1.Type = DbQueryDelete; query1.Category = DbCatDowntime; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", checkable); query1.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime())); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime())); query1.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime())); query1.WhereCriteria->Set("name", downtime->GetName()); queries.push_back(query1); /* History - update actual_end_time, was_cancelled for service (and host in case) */ double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query3; query3.Table = "downtimehistory"; query3.Type = DbQueryUpdate; query3.Category = DbCatDowntime; Dictionary::Ptr fields3 = new Dictionary(); fields3->Set("was_cancelled", downtime->GetWasCancelled() ? 1 : 0); if (downtime->GetFixed() || (!downtime->GetFixed() && downtime->GetTriggerTime() > 0)) { fields3->Set("actual_end_time", DbValue::FromTimestamp(time_bag.first)); fields3->Set("actual_end_time_usec", time_bag.second); } fields3->Set("is_in_effect", 0); query3.Fields = fields3; query3.WhereCriteria = new Dictionary(); query3.WhereCriteria->Set("object_id", checkable); query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime())); query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime())); query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime())); query3.WhereCriteria->Set("name", downtime->GetName()); queries.push_back(query3); /* host/service status */ Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query4; if (service) query4.Table = "servicestatus"; else query4.Table = "hoststatus"; query4.Type = DbQueryUpdate; query4.Category = DbCatState; query4.StatusUpdate = true; query4.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields4 = new Dictionary(); fields4->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth()); query4.Fields = fields4; query4.WhereCriteria = new Dictionary(); if (service) query4.WhereCriteria->Set("service_object_id", service); else query4.WhereCriteria->Set("host_object_id", host); query4.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ queries.push_back(query4); } void DbEvents::TriggerDowntime(const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); /* Status */ DbQuery query1; query1.Table = "scheduleddowntime"; query1.Type = DbQueryUpdate; query1.Category = DbCatDowntime; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("was_started", 1); fields1->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("actual_start_time_usec", time_bag.second); fields1->Set("is_in_effect", (downtime->IsInEffect() ? 1 : 0)); fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime())); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", checkable); query1.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime())); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query1.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime())); query1.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime())); query1.WhereCriteria->Set("name", downtime->GetName()); query1.Fields = fields1; DbObject::OnQuery(query1); /* History - downtime was started for service (and host in case) */ DbQuery query3; query3.Table = "downtimehistory"; query3.Type = DbQueryUpdate; query3.Category = DbCatDowntime; Dictionary::Ptr fields3 = new Dictionary(); fields3->Set("was_started", 1); fields3->Set("is_in_effect", 1); fields3->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first)); fields3->Set("actual_start_time_usec", time_bag.second); fields3->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime())); query3.Fields = fields3; query3.WhereCriteria = query1.WhereCriteria; DbObject::OnQuery(query3); /* host/service status */ Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query4; if (service) query4.Table = "servicestatus"; else query4.Table = "hoststatus"; query4.Type = DbQueryUpdate; query4.Category = DbCatState; query4.StatusUpdate = true; query4.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields4 = new Dictionary(); fields4->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth()); query4.Fields = fields4; query4.WhereCriteria = new Dictionary(); if (service) query4.WhereCriteria->Set("service_object_id", service); else query4.WhereCriteria->Set("host_object_id", host); query4.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query4); } /* acknowledgements */ void DbEvents::AddAcknowledgementHistory(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, double expiry) { Log(LogDebug, "DbEvents") << "add acknowledgement history for '" << checkable->GetName() << "'"; double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); unsigned long end_time = static_cast(expiry); DbQuery query1; query1.Table = "acknowledgements"; query1.Type = DbQueryInsert; query1.Category = DbCatAcknowledgement; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("entry_time_usec", time_bag.second); fields1->Set("acknowledgement_type", type); fields1->Set("object_id", checkable); fields1->Set("author_name", author); fields1->Set("comment_data", comment); fields1->Set("persistent_comment", 1); //always persistent fields1->Set("notify_contacts", notify ? 1 : 0); fields1->Set("is_sticky", type == AcknowledgementSticky ? 1 : 0); fields1->Set("end_time", DbValue::FromTimestamp(end_time)); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ if (service) { fields1->Set("state", service->GetState()); } else { fields1->Set("state", CompatUtility::GetHostCurrentState(host)); } String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } void DbEvents::AddAcknowledgement(const Checkable::Ptr& checkable, AcknowledgementType type) { Log(LogDebug, "DbEvents") << "add acknowledgement for '" << checkable->GetName() << "'"; AddAcknowledgementInternal(checkable, type, true); } void DbEvents::RemoveAcknowledgement(const Checkable::Ptr& checkable) { Log(LogDebug, "DbEvents") << "remove acknowledgement for '" << checkable->GetName() << "'"; AddAcknowledgementInternal(checkable, AcknowledgementNone, false); } void DbEvents::AddAcknowledgementInternal(const Checkable::Ptr& checkable, AcknowledgementType type, bool add) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); DbQuery query1; if (service) query1.Table = "servicestatus"; else query1.Table = "hoststatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; query1.StatusUpdate = true; query1.Object = DbObject::GetOrCreateByObject(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("acknowledgement_type", type); fields1->Set("problem_has_been_acknowledged", add ? 1 : 0); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); if (service) query1.WhereCriteria->Set("service_object_id", service); else query1.WhereCriteria->Set("host_object_id", host); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbObject::OnQuery(query1); } /* notifications */ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { Log(LogDebug, "DbEvents") << "add notification history for '" << checkable->GetName() << "'"; /* start and end happen at the same time */ double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query1; query1.Table = "notifications"; query1.Type = DbQueryInsert; query1.Category = DbCatNotification; query1.NotificationInsertID = new DbValue(DbValueObjectInsertID, -1); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("notification_type", 1); /* service */ fields1->Set("notification_reason", CompatUtility::MapNotificationReasonType(type)); fields1->Set("object_id", checkable); fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("start_time_usec", time_bag.second); fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("end_time_usec", time_bag.second); if (service) { fields1->Set("state", service->GetState()); } else { fields1->Set("state", CompatUtility::GetHostCurrentState(host)); } if (cr) { fields1->Set("output", CompatUtility::GetCheckResultOutput(cr)); fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr)); } fields1->Set("escalated", 0); fields1->Set("contacts_notified", static_cast(users.size())); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); std::vector queries; for (const User::Ptr& user : users) { Log(LogDebug, "DbEvents") << "add contact notification history for service '" << checkable->GetName() << "' and user '" << user->GetName() << "'."; DbQuery query2; query2.Table = "contactnotifications"; query2.Type = DbQueryInsert; query2.Category = DbCatNotification; Dictionary::Ptr fields2 = new Dictionary(); fields2->Set("contact_object_id", user); fields2->Set("start_time", DbValue::FromTimestamp(time_bag.first)); fields2->Set("start_time_usec", time_bag.second); fields2->Set("end_time", DbValue::FromTimestamp(time_bag.first)); fields2->Set("end_time_usec", time_bag.second); fields2->Set("notification_id", query1.NotificationInsertID); fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.Fields = fields2; queries.push_back(query2); } DbObject::OnMultipleQueries(queries); } /* statehistory */ void DbEvents::AddStateChangeHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type) { Log(LogDebug, "DbEvents") << "add state change history for '" << checkable->GetName() << "'"; double ts = cr->GetExecutionEnd(); std::pair state_time_bag = CompatUtility::ConvertTimestamp(ts); DbQuery query1; query1.Table = "statehistory"; query1.Type = DbQueryInsert; query1.Category = DbCatStateHistory; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("state_time", DbValue::FromTimestamp(state_time_bag.first)); fields1->Set("state_time_usec", state_time_bag.second); fields1->Set("object_id", checkable); fields1->Set("state_change", 1); /* service */ fields1->Set("state_type", checkable->GetStateType()); fields1->Set("current_check_attempt", checkable->GetCheckAttempt()); fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts()); if (service) { fields1->Set("state", service->GetState()); fields1->Set("last_state", service->GetLastState()); fields1->Set("last_hard_state", service->GetLastHardState()); } else { fields1->Set("state", CompatUtility::GetHostCurrentState(host)); fields1->Set("last_state", host->GetLastState()); fields1->Set("last_hard_state", host->GetLastHardState()); } if (cr) { fields1->Set("output", CompatUtility::GetCheckResultOutput(cr)); fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr)); fields1->Set("check_source", cr->GetCheckSource()); } fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } /* logentries */ void DbEvents::AddCheckResultLogHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr) { Dictionary::Ptr vars_after = cr->GetVarsAfter(); long state_after = vars_after->Get("state"); long stateType_after = vars_after->Get("state_type"); long attempt_after = vars_after->Get("attempt"); bool reachable_after = vars_after->Get("reachable"); Dictionary::Ptr vars_before = cr->GetVarsBefore(); if (vars_before) { long state_before = vars_before->Get("state"); long stateType_before = vars_before->Get("state_type"); long attempt_before = vars_before->Get("attempt"); bool reachable_before = vars_before->Get("reachable"); if (state_before == state_after && stateType_before == stateType_after && attempt_before == attempt_after && reachable_before == reachable_after) return; /* Nothing changed, ignore this checkresult. */ } LogEntryType type; String output; if (cr) output = CompatUtility::GetCheckResultOutput(cr); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << Service::StateToString(service->GetState()) << ";" << Service::StateTypeToString(service->GetStateType()) << ";" << attempt_after << ";" << output << "" << ""; switch (service->GetState()) { case ServiceOK: type = LogEntryTypeServiceOk; break; case ServiceUnknown: type = LogEntryTypeServiceUnknown; break; case ServiceWarning: type = LogEntryTypeServiceWarning; break; case ServiceCritical: type = LogEntryTypeServiceCritical; break; default: Log(LogCritical, "DbEvents") << "Unknown service state: " << state_after; return; } } else { msgbuf << "HOST ALERT: " << host->GetName() << ";" << CompatUtility::GetHostStateString(host) << ";" << Host::StateTypeToString(host->GetStateType()) << ";" << attempt_after << ";" << output << "" << ""; switch (host->GetState()) { case HostUp: type = LogEntryTypeHostUp; break; case HostDown: type = LogEntryTypeHostDown; break; default: Log(LogCritical, "DbEvents") << "Unknown host state: " << state_after; return; } if (!reachable_after) type = LogEntryTypeHostUnreachable; } AddLogHistory(checkable, msgbuf.str(), type); } void DbEvents::AddTriggerDowntimeLogHistory(const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << "STARTED" << "; " << "Service has entered a period of scheduled downtime." << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << "STARTED" << "; " << "Service has entered a period of scheduled downtime." << ""; } AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage); } void DbEvents::AddRemoveDowntimeLogHistory(const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); String downtime_output; String downtime_state_str; if (downtime->GetWasCancelled()) { downtime_output = "Scheduled downtime for service has been cancelled."; downtime_state_str = "CANCELLED"; } else { downtime_output = "Service has exited from a period of scheduled downtime."; downtime_state_str = "STOPPED"; } Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << downtime_state_str << "; " << downtime_output << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << downtime_state_str << "; " << downtime_output << ""; } AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage); } void DbEvents::AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notification_type, const CheckResult::Ptr& cr, const String& author, const String& comment_text) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); String check_command = ""; if (commandObj) check_command = commandObj->GetName(); String notification_type_str = Notification::NotificationTypeToString(notification_type); String author_comment = ""; if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) { author_comment = ";" + author + ";" + comment_text; } if (!cr) return; String output; if (cr) output = CompatUtility::GetCheckResultOutput(cr); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE NOTIFICATION: " << user->GetName() << ";" << host->GetName() << ";" << service->GetShortName() << ";" << notification_type_str << " " << "(" << Service::StateToString(service->GetState()) << ");" << check_command << ";" << output << author_comment << ""; } else { msgbuf << "HOST NOTIFICATION: " << user->GetName() << ";" << host->GetName() << ";" << notification_type_str << " " << "(" << Host::StateToString(host->GetState()) << ");" << check_command << ";" << output << author_comment << ""; } AddLogHistory(checkable, msgbuf.str(), LogEntryTypeHostNotification); } void DbEvents::AddFlappingChangedLogHistory(const Checkable::Ptr& checkable) { String flapping_state_str; String flapping_output; if (checkable->IsFlapping()) { flapping_output = "Service appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThresholdHigh()) + "% threshold)"; flapping_state_str = "STARTED"; } else { flapping_output = "Service appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThresholdLow()) + "% threshold)"; flapping_state_str = "STOPPED"; } Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE FLAPPING ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << flapping_state_str << "; " << flapping_output << ""; } else { msgbuf << "HOST FLAPPING ALERT: " << host->GetName() << ";" << flapping_state_str << "; " << flapping_output << ""; } AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage); } void DbEvents::AddEnableFlappingChangedLogHistory(const Checkable::Ptr& checkable) { if (!checkable->GetEnableFlapping()) return; String flapping_output = "Flap detection has been disabled"; String flapping_state_str = "DISABLED"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE FLAPPING ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << flapping_state_str << "; " << flapping_output << ""; } else { msgbuf << "HOST FLAPPING ALERT: " << host->GetName() << ";" << flapping_state_str << "; " << flapping_output << ""; } AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage); } void DbEvents::AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type) { Log(LogDebug, "DbEvents") << "add log entry history for '" << checkable->GetName() << "'"; double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query1; query1.Table = "logentries"; query1.Type = DbQueryInsert; query1.Category = DbCatLog; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("logentry_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("entry_time_usec", time_bag.second); fields1->Set("object_id", checkable); // added in 1.10 see #4754 fields1->Set("logentry_type", type); fields1->Set("logentry_data", buffer); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } /* flappinghistory */ void DbEvents::AddFlappingChangedHistory(const Checkable::Ptr& checkable) { Log(LogDebug, "DbEvents") << "add flapping history for '" << checkable->GetName() << "'"; double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query1; query1.Table = "flappinghistory"; query1.Type = DbQueryInsert; query1.Category = DbCatFlapping; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("event_time_usec", time_bag.second); if (checkable->IsFlapping()) fields1->Set("event_type", 1000); else { fields1->Set("event_type", 1001); fields1->Set("reason_type", 1); } Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); fields1->Set("flapping_type", service ? 1 : 0); fields1->Set("object_id", checkable); fields1->Set("percent_state_change", checkable->GetFlappingCurrent()); fields1->Set("low_threshold", checkable->GetFlappingThresholdLow()); fields1->Set("high_threshold", checkable->GetFlappingThresholdHigh()); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } void DbEvents::AddEnableFlappingChangedHistory(const Checkable::Ptr& checkable) { Log(LogDebug, "DbEvents") << "add flapping history for '" << checkable->GetName() << "'"; double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query1; query1.Table = "flappinghistory"; query1.Type = DbQueryInsert; query1.Category = DbCatFlapping; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("event_time_usec", time_bag.second); if (!checkable->GetEnableFlapping()) return; fields1->Set("event_type", 1001); fields1->Set("reason_type", 2); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); fields1->Set("flapping_type", service ? 1 : 0); fields1->Set("object_id", checkable); fields1->Set("percent_state_change", checkable->GetFlappingCurrent()); fields1->Set("low_threshold", checkable->GetFlappingThresholdLow()); fields1->Set("high_threshold", checkable->GetFlappingThresholdHigh()); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } /* servicechecks */ void DbEvents::AddCheckableCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { if (!cr) return; Log(LogDebug, "DbEvents") << "add checkable check history for '" << checkable->GetName() << "'"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); std::ostringstream msgbuf; DbQuery query1; query1.Table = service ? "servicechecks" : "hostchecks"; query1.Type = DbQueryInsert; query1.Category = DbCatCheck; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("check_type", CompatUtility::GetCheckableCheckType(checkable)); fields1->Set("current_check_attempt", checkable->GetCheckAttempt()); fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts()); fields1->Set("state_type", checkable->GetStateType()); double start = cr->GetExecutionStart(); std::pair time_bag_start = CompatUtility::ConvertTimestamp(start); double end = cr->GetExecutionEnd(); std::pair time_bag_end = CompatUtility::ConvertTimestamp(end); double execution_time = cr->CalculateExecutionTime(); fields1->Set("start_time", DbValue::FromTimestamp(time_bag_start.first)); fields1->Set("start_time_usec", time_bag_start.second); fields1->Set("end_time", DbValue::FromTimestamp(time_bag_end.first)); fields1->Set("end_time_usec", time_bag_end.second); fields1->Set("command_object_id", checkable->GetCheckCommand()); fields1->Set("command_args", Empty); fields1->Set("command_line", CompatUtility::GetCommandLine(checkable->GetCheckCommand())); fields1->Set("execution_time", Convert::ToString(execution_time)); fields1->Set("latency", Convert::ToString(cr->CalculateLatency())); fields1->Set("return_code", cr->GetExitStatus()); fields1->Set("output", CompatUtility::GetCheckResultOutput(cr)); fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr)); fields1->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr)); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ if (service) { fields1->Set("service_object_id", service); fields1->Set("state", service->GetState()); } else { fields1->Set("host_object_id", host); fields1->Set("state", CompatUtility::GetHostCurrentState(host)); } String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } /* eventhandlers */ void DbEvents::AddEventHandlerHistory(const Checkable::Ptr& checkable) { Log(LogDebug, "DbEvents") << "add eventhandler history for '" << checkable->GetName() << "'"; double now = Utility::GetTime(); std::pair time_bag = CompatUtility::ConvertTimestamp(now); DbQuery query1; query1.Table = "eventhandlers"; query1.Type = DbQueryInsert; query1.Category = DbCatEventHandler; Dictionary::Ptr fields1 = new Dictionary(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); fields1->Set("object_id", checkable); if (service) { fields1->Set("state", service->GetState()); fields1->Set("eventhandler_type", 1); } else { fields1->Set("state", CompatUtility::GetHostCurrentState(host)); fields1->Set("eventhandler_type", 0); } fields1->Set("state_type", checkable->GetStateType()); fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("start_time_usec", time_bag.second); fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first)); fields1->Set("end_time_usec", time_bag.second); fields1->Set("command_object_id", checkable->GetEventCommand()); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } /* externalcommands */ void DbEvents::AddExternalCommandHistory(double time, const String& command, const std::vector& arguments) { Log(LogDebug, "DbEvents", "add external command history"); DbQuery query1; query1.Table = "externalcommands"; query1.Type = DbQueryInsert; query1.Category = DbCatExternalCommand; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("entry_time", DbValue::FromTimestamp(static_cast(time))); fields1->Set("command_type", CompatUtility::MapExternalCommandType(command)); fields1->Set("command_name", command); fields1->Set("command_args", boost::algorithm::join(arguments, ";")); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) fields1->Set("endpoint_object_id", endpoint); query1.Fields = fields1; DbObject::OnQuery(query1); } icinga2-2.8.1/lib/db_ido/dbevents.hpp000066400000000000000000000147711322762156600173730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBEVENTS_H #define DBEVENTS_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" #include "icinga/service.hpp" namespace icinga { enum LogEntryType { LogEntryTypeRuntimeError = 1, LogEntryTypeRuntimeWarning = 2, LogEntryTypeVerificationError = 4, LogEntryTypeVerificationWarning = 8, LogEntryTypeConfigError = 16, LogEntryTypeConfigWarning = 32, LogEntryTypeProcessInfo = 64, LogEntryTypeEventHandler = 128, LogEntryTypeExternalCommand = 512, LogEntryTypeHostUp = 1024, LogEntryTypeHostDown = 2048, LogEntryTypeHostUnreachable = 4096, LogEntryTypeServiceOk = 8192, LogEntryTypeServiceUnknown = 16384, LogEntryTypeServiceWarning = 32768, LogEntryTypeServiceCritical = 65536, LogEntryTypePassiveCheck = 1231072, LogEntryTypeInfoMessage = 262144, LogEntryTypeHostNotification = 524288, LogEntryTypeServiceNotification = 1048576 }; /** * IDO events * * @ingroup ido */ class DbEvents { public: static void StaticInitialize(void); static void AddComments(const Checkable::Ptr& checkable); static void AddDowntimes(const Checkable::Ptr& checkable); static void RemoveDowntimes(const Checkable::Ptr& checkable); static void AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type); /* Status */ static void NextCheckUpdatedHandler(const Checkable::Ptr& checkable); static void FlappingChangedHandler(const Checkable::Ptr& checkable); static void LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable); static void EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable); static void EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable); static void EnableNotificationsChangedHandler(const Checkable::Ptr& checkable); static void EnablePerfdataChangedHandler(const Checkable::Ptr& checkable); static void EnableFlappingChangedHandler(const Checkable::Ptr& checkable); static void AddComment(const Comment::Ptr& comment); static void RemoveComment(const Comment::Ptr& comment); static void AddDowntime(const Downtime::Ptr& downtime); static void RemoveDowntime(const Downtime::Ptr& downtime); static void TriggerDowntime(const Downtime::Ptr& downtime); static void AddAcknowledgement(const Checkable::Ptr& checkable, AcknowledgementType type); static void RemoveAcknowledgement(const Checkable::Ptr& checkable); static void AddAcknowledgementInternal(const Checkable::Ptr& checkable, AcknowledgementType type, bool add); static void ReachabilityChangedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, std::set children); /* comment, downtime, acknowledgement history */ static void AddCommentHistory(const Comment::Ptr& comment); static void AddDowntimeHistory(const Downtime::Ptr& downtime); static void AddAcknowledgementHistory(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, double expiry); /* notification & contactnotification history */ static void AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text); /* statehistory */ static void AddStateChangeHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type); /* logentries */ static void AddCheckResultLogHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr); static void AddTriggerDowntimeLogHistory(const Downtime::Ptr& downtime); static void AddRemoveDowntimeLogHistory(const Downtime::Ptr& downtime); static void AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notification_type, const CheckResult::Ptr& cr, const String& author, const String& comment_text); static void AddFlappingChangedLogHistory(const Checkable::Ptr& checkable); static void AddEnableFlappingChangedLogHistory(const Checkable::Ptr& checkable); /* other history */ static void AddFlappingChangedHistory(const Checkable::Ptr& checkable); static void AddEnableFlappingChangedHistory(const Checkable::Ptr& checkable); static void AddCheckableCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr); static void AddEventHandlerHistory(const Checkable::Ptr& checkable); static void AddExternalCommandHistory(double time, const String& command, const std::vector& arguments); private: DbEvents(void); static void AddCommentInternal(std::vector& queries, const Comment::Ptr& comment, bool historical); static void RemoveCommentInternal(std::vector& queries, const Comment::Ptr& comment); static void AddDowntimeInternal(std::vector& queries, const Downtime::Ptr& downtime, bool historical); static void RemoveDowntimeInternal(std::vector& queries, const Downtime::Ptr& downtime); static void EnableChangedHandlerInternal(const Checkable::Ptr& checkable, const String& fieldName, bool enabled); }; } #endif /* DBEVENTS_H */ icinga2-2.8.1/lib/db_ido/dbobject.cpp000066400000000000000000000266071322762156600173310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/customvarobject.hpp" #include "icinga/service.hpp" #include "icinga/compatutility.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "remote/endpoint.hpp" #include "base/configobject.hpp" #include "base/configtype.hpp" #include "base/json.hpp" #include "base/serializer.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/initialize.hpp" #include "base/logger.hpp" using namespace icinga; boost::signals2::signal DbObject::OnQuery; boost::signals2::signal&)> DbObject::OnMultipleQueries; INITIALIZE_ONCE(&DbObject::StaticInitialize); DbObject::DbObject(const intrusive_ptr& type, const String& name1, const String& name2) : m_Name1(name1), m_Name2(name2), m_Type(type), m_LastConfigUpdate(0), m_LastStatusUpdate(0) { } void DbObject::StaticInitialize(void) { /* triggered in ProcessCheckResult(), requires UpdateNextCheck() to be called before */ ConfigObject::OnStateChanged.connect(boost::bind(&DbObject::StateChangedHandler, _1)); CustomVarObject::OnVarsChanged.connect(boost::bind(&DbObject::VarsChangedHandler, _1)); /* triggered on create, update and delete objects */ ConfigObject::OnVersionChanged.connect(boost::bind(&DbObject::VersionChangedHandler, _1)); } void DbObject::SetObject(const ConfigObject::Ptr& object) { m_Object = object; } ConfigObject::Ptr DbObject::GetObject(void) const { return m_Object; } String DbObject::GetName1(void) const { return m_Name1; } String DbObject::GetName2(void) const { return m_Name2; } DbType::Ptr DbObject::GetType(void) const { return m_Type; } String DbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const { Dictionary::Ptr configFieldsDup = configFields->ShallowClone(); { ObjectLock olock(configFieldsDup); for (const Dictionary::Pair& kv : configFieldsDup) { if (kv.second.IsObjectType()) { ConfigObject::Ptr obj = kv.second; configFieldsDup->Set(kv.first, obj->GetName()); } } } Array::Ptr data = new Array(); data->Add(configFieldsDup); CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast(GetObject()); if (custom_var_object) data->Add(custom_var_object->GetVars()); return HashValue(data); } String DbObject::HashValue(const Value& value) { Value temp; Type::Ptr type = value.GetReflectionType(); if (ConfigObject::TypeInstance->IsAssignableFrom(type)) temp = Serialize(value, FAConfig); else temp = value; return SHA256(JsonEncode(temp)); } void DbObject::SendConfigUpdateHeavy(const Dictionary::Ptr& configFields) { /* update custom var config and status */ SendVarsConfigUpdateHeavy(); SendVarsStatusUpdate(); /* config attributes */ if (!configFields) return; ASSERT(configFields->Contains("config_hash")); ConfigObject::Ptr object = GetObject(); DbQuery query; query.Table = GetType()->GetTable() + "s"; query.Type = DbQueryInsert | DbQueryUpdate; query.Category = DbCatConfig; query.Fields = configFields; query.Fields->Set(GetType()->GetIDColumn(), object); query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query.Fields->Set("config_type", 1); query.WhereCriteria = new Dictionary(); query.WhereCriteria->Set(GetType()->GetIDColumn(), object); query.Object = this; query.ConfigUpdate = true; OnQuery(query); m_LastConfigUpdate = Utility::GetTime(); OnConfigUpdateHeavy(); } void DbObject::SendConfigUpdateLight(void) { OnConfigUpdateLight(); } void DbObject::SendStatusUpdate(void) { /* status attributes */ Dictionary::Ptr fields = GetStatusFields(); if (!fields) return; DbQuery query; query.Table = GetType()->GetTable() + "status"; query.Type = DbQueryInsert | DbQueryUpdate; query.Category = DbCatState; query.Fields = fields; query.Fields->Set(GetType()->GetIDColumn(), GetObject()); /* do not override endpoint_object_id for endpoints & zones */ if (query.Table != "endpointstatus" && query.Table != "zonestatus") { String node = IcingaApplication::GetInstance()->GetNodeName(); Endpoint::Ptr endpoint = Endpoint::GetByName(node); if (endpoint) query.Fields->Set("endpoint_object_id", endpoint); } query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime())); query.WhereCriteria = new Dictionary(); query.WhereCriteria->Set(GetType()->GetIDColumn(), GetObject()); query.Object = this; query.StatusUpdate = true; OnQuery(query); m_LastStatusUpdate = Utility::GetTime(); OnStatusUpdate(); } void DbObject::SendVarsConfigUpdateHeavy(void) { ConfigObject::Ptr obj = GetObject(); CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast(obj); if (!custom_var_object) return; std::vector queries; DbQuery query1; query1.Table = "customvariables"; query1.Type = DbQueryDelete; query1.Category = DbCatConfig; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("object_id", obj); queries.push_back(query1); DbQuery query2; query2.Table = "customvariablestatus"; query2.Type = DbQueryDelete; query2.Category = DbCatConfig; query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("object_id", obj); queries.push_back(query2); Dictionary::Ptr vars = CompatUtility::GetCustomAttributeConfig(custom_var_object); if (vars) { ObjectLock olock (vars); for (const Dictionary::Pair& kv : vars) { if (kv.first.IsEmpty()) continue; String value; int is_json = 0; if (kv.second.IsObjectType() || kv.second.IsObjectType()) { value = JsonEncode(kv.second); is_json = 1; } else value = kv.second; Dictionary::Ptr fields = new Dictionary(); fields->Set("varname", kv.first); fields->Set("varvalue", value); fields->Set("is_json", is_json); fields->Set("config_type", 1); fields->Set("object_id", obj); fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query3; query3.Table = "customvariables"; query3.Type = DbQueryInsert; query3.Category = DbCatConfig; query3.Fields = fields; queries.push_back(query3); } } OnMultipleQueries(queries); } void DbObject::SendVarsStatusUpdate(void) { ConfigObject::Ptr obj = GetObject(); CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast(obj); if (!custom_var_object) return; Dictionary::Ptr vars = CompatUtility::GetCustomAttributeConfig(custom_var_object); if (vars) { std::vector queries; ObjectLock olock (vars); for (const Dictionary::Pair& kv : vars) { if (kv.first.IsEmpty()) continue; String value; int is_json = 0; if (kv.second.IsObjectType() || kv.second.IsObjectType()) { value = JsonEncode(kv.second); is_json = 1; } else value = kv.second; Dictionary::Ptr fields = new Dictionary(); fields->Set("varname", kv.first); fields->Set("varvalue", value); fields->Set("is_json", is_json); fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime())); fields->Set("object_id", obj); fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query; query.Table = "customvariablestatus"; query.Type = DbQueryInsert | DbQueryUpdate; query.Category = DbCatState; query.Fields = fields; query.WhereCriteria = new Dictionary(); query.WhereCriteria->Set("object_id", obj); query.WhereCriteria->Set("varname", kv.first); queries.push_back(query); } OnMultipleQueries(queries); } } double DbObject::GetLastConfigUpdate(void) const { return m_LastConfigUpdate; } double DbObject::GetLastStatusUpdate(void) const { return m_LastStatusUpdate; } void DbObject::OnConfigUpdateHeavy(void) { /* Default handler does nothing. */ } void DbObject::OnConfigUpdateLight(void) { /* Default handler does nothing. */ } void DbObject::OnStatusUpdate(void) { /* Default handler does nothing. */ } DbObject::Ptr DbObject::GetOrCreateByObject(const ConfigObject::Ptr& object) { boost::mutex::scoped_lock lock(GetStaticMutex()); DbObject::Ptr dbobj = object->GetExtension("DbObject"); if (dbobj) return dbobj; DbType::Ptr dbtype = DbType::GetByName(object->GetReflectionType()->GetName()); if (!dbtype) return DbObject::Ptr(); Service::Ptr service; String name1, name2; service = dynamic_pointer_cast(object); if (service) { Host::Ptr host = service->GetHost(); name1 = service->GetHost()->GetName(); name2 = service->GetShortName(); } else { if (object->GetReflectionType() == CheckCommand::TypeInstance || object->GetReflectionType() == EventCommand::TypeInstance || object->GetReflectionType() == NotificationCommand::TypeInstance) { Command::Ptr command = dynamic_pointer_cast(object); name1 = CompatUtility::GetCommandName(command); } else name1 = object->GetName(); } dbobj = dbtype->GetOrCreateObjectByName(name1, name2); dbobj->SetObject(object); object->SetExtension("DbObject", dbobj); return dbobj; } void DbObject::StateChangedHandler(const ConfigObject::Ptr& object) { DbObject::Ptr dbobj = GetOrCreateByObject(object); if (!dbobj) return; dbobj->SendStatusUpdate(); } void DbObject::VarsChangedHandler(const CustomVarObject::Ptr& object) { DbObject::Ptr dbobj = GetOrCreateByObject(object); if (!dbobj) return; dbobj->SendVarsStatusUpdate(); } void DbObject::VersionChangedHandler(const ConfigObject::Ptr& object) { DbObject::Ptr dbobj = DbObject::GetOrCreateByObject(object); if (dbobj) { Dictionary::Ptr configFields = dbobj->GetConfigFields(); String configHash = dbobj->CalculateConfigHash(configFields); configFields->Set("config_hash", configHash); dbobj->SendConfigUpdateHeavy(configFields); dbobj->SendStatusUpdate(); } } boost::mutex& DbObject::GetStaticMutex(void) { static boost::mutex mutex; return mutex; } icinga2-2.8.1/lib/db_ido/dbobject.hpp000066400000000000000000000076631322762156600173370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBOBJECT_H #define DBOBJECT_H #include "db_ido/i2-db_ido.hpp" #include "db_ido/dbreference.hpp" #include "db_ido/dbquery.hpp" #include "db_ido/dbtype.hpp" #include "icinga/customvarobject.hpp" #include "base/configobject.hpp" namespace icinga { enum DbObjectUpdateType { DbObjectCreated, DbObjectRemoved }; enum DbObjectType { DbObjectTypeHost = 1, DbObjectTypeService = 2, DbObjectTypeHostGroup = 3, DbObjectTypeServiceGroup = 4, DbObjectTypeHostEscalation = 5, DbObjectTypeServiceEscalation = 6, DbObjectTypeHostDependency = 7, DbObjectTypeServiceDependency = 8, DbObjectTypeTimePeriod = 9, DbObjectTypeContact = 10, DbObjectTypeContactGroup = 11, DbObjectTypeCommand = 12, DbObjectTypeEndpoint = 13, DbObjectTypeZone = 14, }; /** * A database object. * * @ingroup ido */ class I2_DB_IDO_API DbObject : public Object { public: DECLARE_PTR_TYPEDEFS(DbObject); static void StaticInitialize(void); void SetObject(const ConfigObject::Ptr& object); ConfigObject::Ptr GetObject(void) const; String GetName1(void) const; String GetName2(void) const; intrusive_ptr GetType(void) const; virtual Dictionary::Ptr GetConfigFields(void) const = 0; virtual Dictionary::Ptr GetStatusFields(void) const = 0; static DbObject::Ptr GetOrCreateByObject(const ConfigObject::Ptr& object); static boost::signals2::signal OnQuery; static boost::signals2::signal&)> OnMultipleQueries; void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields); void SendConfigUpdateLight(void); void SendStatusUpdate(void); void SendVarsConfigUpdateHeavy(void); void SendVarsStatusUpdate(void); double GetLastConfigUpdate(void) const; double GetLastStatusUpdate(void) const; virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const; protected: DbObject(const intrusive_ptr& type, const String& name1, const String& name2); virtual void OnConfigUpdateHeavy(void); virtual void OnConfigUpdateLight(void); virtual void OnStatusUpdate(void); static String HashValue(const Value& value); private: String m_Name1; String m_Name2; intrusive_ptr m_Type; ConfigObject::Ptr m_Object; double m_LastConfigUpdate; double m_LastStatusUpdate; static void StateChangedHandler(const ConfigObject::Ptr& object); static void VarsChangedHandler(const CustomVarObject::Ptr& object); static void VersionChangedHandler(const ConfigObject::Ptr& object); static boost::mutex& GetStaticMutex(void); friend class DbType; }; } #endif /* DBOBJECT_H */ icinga2-2.8.1/lib/db_ido/dbquery.cpp000066400000000000000000000066401322762156600172230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbquery.hpp" #include "base/initialize.hpp" #include "base/scriptglobal.hpp" using namespace icinga; INITIALIZE_ONCE(&DbQuery::StaticInitialize); std::map DbQuery::m_CategoryFilterMap; void DbQuery::StaticInitialize(void) { ScriptGlobal::Set("DbCatConfig", DbCatConfig); ScriptGlobal::Set("DbCatState", DbCatState); ScriptGlobal::Set("DbCatAcknowledgement", DbCatAcknowledgement); ScriptGlobal::Set("DbCatComment", DbCatComment); ScriptGlobal::Set("DbCatDowntime", DbCatDowntime); ScriptGlobal::Set("DbCatEventHandler", DbCatEventHandler); ScriptGlobal::Set("DbCatExternalCommand", DbCatExternalCommand); ScriptGlobal::Set("DbCatFlapping", DbCatFlapping); ScriptGlobal::Set("DbCatCheck", DbCatCheck); ScriptGlobal::Set("DbCatLog", DbCatLog); ScriptGlobal::Set("DbCatNotification", DbCatNotification); ScriptGlobal::Set("DbCatProgramStatus", DbCatProgramStatus); ScriptGlobal::Set("DbCatRetention", DbCatRetention); ScriptGlobal::Set("DbCatStateHistory", DbCatStateHistory); ScriptGlobal::Set("DbCatEverything", DbCatEverything); m_CategoryFilterMap["DbCatConfig"] = DbCatConfig; m_CategoryFilterMap["DbCatState"] = DbCatState; m_CategoryFilterMap["DbCatAcknowledgement"] = DbCatAcknowledgement; m_CategoryFilterMap["DbCatComment"] = DbCatComment; m_CategoryFilterMap["DbCatDowntime"] = DbCatDowntime; m_CategoryFilterMap["DbCatEventHandler"] = DbCatEventHandler; m_CategoryFilterMap["DbCatExternalCommand"] = DbCatExternalCommand; m_CategoryFilterMap["DbCatFlapping"] = DbCatFlapping; m_CategoryFilterMap["DbCatCheck"] = DbCatCheck; m_CategoryFilterMap["DbCatLog"] = DbCatLog; m_CategoryFilterMap["DbCatNotification"] = DbCatNotification; m_CategoryFilterMap["DbCatProgramStatus"] = DbCatProgramStatus; m_CategoryFilterMap["DbCatRetention"] = DbCatRetention; m_CategoryFilterMap["DbCatStateHistory"] = DbCatStateHistory; m_CategoryFilterMap["DbCatEverything"] = DbCatEverything; } const std::map& DbQuery::GetCategoryFilterMap(void) { return m_CategoryFilterMap; } icinga2-2.8.1/lib/db_ido/dbquery.hpp000066400000000000000000000054611322762156600172300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBQUERY_H #define DBQUERY_H #include "db_ido/i2-db_ido.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/customvarobject.hpp" #include "base/dictionary.hpp" #include "base/configobject.hpp" namespace icinga { enum DbQueryType { DbQueryInsert = 1, DbQueryUpdate = 2, DbQueryDelete = 4, DbQueryNewTransaction = 8 }; enum DbQueryCategory { DbCatInvalid = 0, //-1 is required for DbCatEverything DbCatEverything = ~0, DbCatConfig = 1, DbCatState = 2, DbCatAcknowledgement = 4, DbCatComment = 8, DbCatDowntime = 16, DbCatEventHandler = 32, DbCatExternalCommand = 64, DbCatFlapping = 128, DbCatCheck = 256, DbCatLog = 512, DbCatNotification = 1024, DbCatProgramStatus = 2048, DbCatRetention = 4096, DbCatStateHistory = 8192 }; class DbObject; struct I2_DB_IDO_API DbQuery { int Type; DbQueryCategory Category; String Table; String IdColumn; Dictionary::Ptr Fields; Dictionary::Ptr WhereCriteria; intrusive_ptr Object; DbValue::Ptr NotificationInsertID; bool ConfigUpdate; bool StatusUpdate; WorkQueuePriority Priority; static void StaticInitialize(void); DbQuery(void) : Type(0), Category(DbCatInvalid), ConfigUpdate(false), StatusUpdate(false), Priority(PriorityNormal) { } static const std::map& GetCategoryFilterMap(void); private: static std::map m_CategoryFilterMap; }; } #endif /* DBQUERY_H */ #include "db_ido/dbobject.hpp" icinga2-2.8.1/lib/db_ido/dbreference.cpp000066400000000000000000000032641322762156600200130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "dbreference.hpp" using namespace icinga; DbReference::DbReference(void) : m_Id(-1) { } DbReference::DbReference(long id) : m_Id(id) { } bool DbReference::IsValid(void) const { return (m_Id != -1); } DbReference::operator long(void) const { return m_Id; } icinga2-2.8.1/lib/db_ido/dbreference.hpp000066400000000000000000000033751322762156600200230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBREFERENCE_H #define DBREFERENCE_H #include "db_ido/i2-db_ido.hpp" namespace icinga { /** * A database reference. * * @ingroup ido */ struct I2_DB_IDO_API DbReference { public: DbReference(void); DbReference(long id); bool IsValid(void) const; operator long(void) const; private: long m_Id; }; } #endif /* DBREFERENCE_H */ icinga2-2.8.1/lib/db_ido/dbtype.cpp000066400000000000000000000103121322762156600170260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbtype.hpp" #include "db_ido/dbconnection.hpp" #include "base/objectlock.hpp" #include "base/debug.hpp" #include using namespace icinga; DbType::DbType(const String& name, const String& table, long tid, const String& idcolumn, const DbType::ObjectFactory& factory) : m_Name(name), m_Table(table), m_TypeID(tid), m_IDColumn(idcolumn), m_ObjectFactory(factory) { } String DbType::GetName(void) const { return m_Name; } String DbType::GetTable(void) const { return m_Table; } long DbType::GetTypeID(void) const { return m_TypeID; } String DbType::GetIDColumn(void) const { return m_IDColumn; } void DbType::RegisterType(const DbType::Ptr& type) { boost::mutex::scoped_lock lock(GetStaticMutex()); GetTypes()[type->GetName()] = type; } DbType::Ptr DbType::GetByName(const String& name) { String typeName; if (name == "CheckCommand" || name == "NotificationCommand" || name == "EventCommand") typeName = "Command"; else typeName = name; boost::mutex::scoped_lock lock(GetStaticMutex()); auto it = GetTypes().find(typeName); if (it == GetTypes().end()) return DbType::Ptr(); return it->second; } DbType::Ptr DbType::GetByID(long tid) { boost::mutex::scoped_lock lock(GetStaticMutex()); for (const TypeMap::value_type& kv : GetTypes()) { if (kv.second->GetTypeID() == tid) return kv.second; } return DbType::Ptr(); } DbObject::Ptr DbType::GetOrCreateObjectByName(const String& name1, const String& name2) { ObjectLock olock(this); auto it = m_Objects.find(std::make_pair(name1, name2)); if (it != m_Objects.end()) return it->second; DbObject::Ptr dbobj = m_ObjectFactory(this, name1, name2); m_Objects[std::make_pair(name1, name2)] = dbobj; String objName = name1; if (!name2.IsEmpty()) objName += "!" + name2; String objType = m_Name; if (m_TypeID == DbObjectTypeCommand) { if (objName.SubStr(0, 6) == "check_") { objType = "CheckCommand"; objName = objName.SubStr(6); } else if (objName.SubStr(0, 13) == "notification_") { objType = "NotificationCommand"; objName = objName.SubStr(13); } else if (objName.SubStr(0, 6) == "event_") { objType = "EventCommand"; objName = objName.SubStr(6); } } dbobj->SetObject(ConfigObject::GetObject(objType, objName)); return dbobj; } boost::mutex& DbType::GetStaticMutex(void) { static boost::mutex mutex; return mutex; } /** * Caller must hold static mutex. */ DbType::TypeMap& DbType::GetTypes(void) { static DbType::TypeMap tm; return tm; } std::set DbType::GetAllTypes(void) { std::set result; { boost::mutex::scoped_lock lock(GetStaticMutex()); for (const auto& kv : GetTypes()) { result.insert(kv.second); } } return result; } DbTypeRegistry *DbTypeRegistry::GetInstance(void) { return Singleton::GetInstance(); } icinga2-2.8.1/lib/db_ido/dbtype.hpp000066400000000000000000000066021322762156600170420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBTYPE_H #define DBTYPE_H #include "db_ido/i2-db_ido.hpp" #include "base/object.hpp" #include "base/registry.hpp" #include "base/singleton.hpp" #include namespace icinga { class DbObject; /** * A database object type. * * @ingroup ido */ class I2_DB_IDO_API DbType : public Object { public: DECLARE_PTR_TYPEDEFS(DbType); typedef boost::function (const intrusive_ptr&, const String&, const String&)> ObjectFactory; typedef std::map TypeMap; typedef std::map, intrusive_ptr > ObjectMap; DbType(const String& name, const String& table, long tid, const String& idcolumn, const ObjectFactory& factory); String GetName(void) const; String GetTable(void) const; long GetTypeID(void) const; String GetIDColumn(void) const; static void RegisterType(const DbType::Ptr& type); static DbType::Ptr GetByName(const String& name); static DbType::Ptr GetByID(long tid); intrusive_ptr GetOrCreateObjectByName(const String& name1, const String& name2); static std::set GetAllTypes(void); private: String m_Name; String m_Table; long m_TypeID; String m_IDColumn; ObjectFactory m_ObjectFactory; static boost::mutex& GetStaticMutex(void); static TypeMap& GetTypes(void); ObjectMap m_Objects; }; /** * A registry for DbType objects. * * @ingroup ido */ class I2_DB_IDO_API DbTypeRegistry : public Registry { public: static DbTypeRegistry *GetInstance(void); }; /** * Factory function for DbObject-based classes. * * @ingroup ido */ template intrusive_ptr DbObjectFactory(const DbType::Ptr& type, const String& name1, const String& name2) { return new T(type, name1, name2); } #define REGISTER_DBTYPE(name, table, tid, idcolumn, type) \ INITIALIZE_ONCE([]() { \ DbType::Ptr dbtype = new DbType(#name, table, tid, idcolumn, DbObjectFactory); \ DbType::RegisterType(dbtype); \ }) } #endif /* DBTYPE_H */ icinga2-2.8.1/lib/db_ido/dbvalue.cpp000066400000000000000000000055061322762156600171720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbvalue.hpp" using namespace icinga; DbValue::DbValue(DbValueType type, const Value& value) : m_Type(type), m_Value(value) { } Value DbValue::FromTimestamp(const Value& ts) { if (ts.IsEmpty() || ts == 0) return Empty; return new DbValue(DbValueTimestamp, ts); } Value DbValue::FromTimestampNow(void) { return new DbValue(DbValueTimestampNow, Empty); } Value DbValue::FromValue(const Value& value) { return value; } Value DbValue::FromObjectInsertID(const Value& value) { return new DbValue(DbValueObjectInsertID, value); } bool DbValue::IsTimestamp(const Value& value) { if (!value.IsObjectType()) return false; DbValue::Ptr dbv = value; return dbv->GetType() == DbValueTimestamp; } bool DbValue::IsTimestampNow(const Value& value) { if (!value.IsObjectType()) return false; DbValue::Ptr dbv = value; return dbv->GetType() == DbValueTimestampNow; } bool DbValue::IsObjectInsertID(const Value& value) { if (!value.IsObjectType()) return false; DbValue::Ptr dbv = value; return dbv->GetType() == DbValueObjectInsertID; } Value DbValue::ExtractValue(const Value& value) { if (!value.IsObjectType()) return value; DbValue::Ptr dbv = value; return dbv->GetValue(); } DbValueType DbValue::GetType(void) const { return m_Type; } Value DbValue::GetValue(void) const { return m_Value; } void DbValue::SetValue(const Value& value) { m_Value = value; } icinga2-2.8.1/lib/db_ido/dbvalue.hpp000066400000000000000000000045561322762156600172030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DBVALUE_H #define DBVALUE_H #include "db_ido/i2-db_ido.hpp" #include "base/object.hpp" #include "base/value.hpp" namespace icinga { enum DbValueType { DbValueTimestamp, DbValueTimestampNow, DbValueObjectInsertID }; /** * A database value. * * @ingroup ido */ struct I2_DB_IDO_API DbValue : public Object { public: DECLARE_PTR_TYPEDEFS(DbValue); DbValue(DbValueType type, const Value& value); static Value FromTimestamp(const Value& ts); static Value FromTimestampNow(void); static Value FromValue(const Value& value); static Value FromObjectInsertID(const Value& value); static bool IsTimestamp(const Value& value); static bool IsTimestampNow(const Value& value); static bool IsObjectInsertID(const Value& value); static Value ExtractValue(const Value& value); DbValueType GetType(void) const; Value GetValue(void) const; void SetValue(const Value& value); private: DbValueType m_Type; Value m_Value; }; } #endif /* DBVALUE_H */ icinga2-2.8.1/lib/db_ido/endpointdbobject.cpp000066400000000000000000000103471322762156600210640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/endpointdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/icingaapplication.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_DBTYPE(Endpoint, "endpoint", DbObjectTypeEndpoint, "endpoint_object_id", EndpointDbObject); INITIALIZE_ONCE(&EndpointDbObject::StaticInitialize); void EndpointDbObject::StaticInitialize(void) { Endpoint::OnConnected.connect(boost::bind(&EndpointDbObject::UpdateConnectedStatus, _1)); Endpoint::OnDisconnected.connect(boost::bind(&EndpointDbObject::UpdateConnectedStatus, _1)); } EndpointDbObject::EndpointDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr EndpointDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); Endpoint::Ptr endpoint = static_pointer_cast(GetObject()); fields->Set("identity", endpoint->GetName()); fields->Set("node", IcingaApplication::GetInstance()->GetNodeName()); fields->Set("zone_object_id", endpoint->GetZone()); return fields; } Dictionary::Ptr EndpointDbObject::GetStatusFields(void) const { Dictionary::Ptr fields = new Dictionary(); Endpoint::Ptr endpoint = static_pointer_cast(GetObject()); Log(LogDebug, "EndpointDbObject") << "update status for endpoint '" << endpoint->GetName() << "'"; fields->Set("identity", endpoint->GetName()); fields->Set("node", IcingaApplication::GetInstance()->GetNodeName()); fields->Set("zone_object_id", endpoint->GetZone()); fields->Set("is_connected", EndpointIsConnected(endpoint)); return fields; } void EndpointDbObject::UpdateConnectedStatus(const Endpoint::Ptr& endpoint) { bool connected = EndpointIsConnected(endpoint); Log(LogDebug, "EndpointDbObject") << "update is_connected=" << connected << " for endpoint '" << endpoint->GetName() << "'"; DbQuery query1; query1.Table = "endpointstatus"; query1.Type = DbQueryUpdate; query1.Category = DbCatState; Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("is_connected", (connected ? 1 : 0)); fields1->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime())); query1.Fields = fields1; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("endpoint_object_id", endpoint); query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ OnQuery(query1); } int EndpointDbObject::EndpointIsConnected(const Endpoint::Ptr& endpoint) { unsigned int is_connected = endpoint->GetConnected() ? 1 : 0; /* if identity is equal to node, fake is_connected */ if (endpoint->GetName() == IcingaApplication::GetInstance()->GetNodeName()) is_connected = 1; return is_connected; } icinga2-2.8.1/lib/db_ido/endpointdbobject.hpp000066400000000000000000000042341322762156600210670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ENDPOINTDBOBJECT_H #define ENDPOINTDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" #include "remote/endpoint.hpp" namespace icinga { /** * A Command database object. * * @ingroup ido */ class EndpointDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(EndpointDbObject); EndpointDbObject(const intrusive_ptr& type, const String& name1, const String& name2); static void StaticInitialize(void); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; private: static void UpdateConnectedStatus(const Endpoint::Ptr& endpoint); static int EndpointIsConnected(const Endpoint::Ptr& endpoint); }; } #endif /* ENDPOINTDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/hostdbobject.cpp000066400000000000000000000420261322762156600202200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/hostdbobject.hpp" #include "db_ido/hostgroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "db_ido/dbevents.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/notification.hpp" #include "icinga/dependency.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/compatutility.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/json.hpp" using namespace icinga; REGISTER_DBTYPE(Host, "host", DbObjectTypeHost, "host_object_id", HostDbObject); HostDbObject::HostDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr HostDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); Host::Ptr host = static_pointer_cast(GetObject()); fields->Set("alias", CompatUtility::GetHostAlias(host)); fields->Set("display_name", host->GetDisplayName()); fields->Set("address", host->GetAddress()); fields->Set("address6", host->GetAddress6()); fields->Set("check_command_object_id", host->GetCheckCommand()); fields->Set("check_command_args", CompatUtility::GetCheckableCommandArgs(host)); fields->Set("eventhandler_command_object_id", host->GetEventCommand()); fields->Set("eventhandler_command_args", Empty); fields->Set("notification_timeperiod_object_id", Empty); fields->Set("check_timeperiod_object_id", host->GetCheckPeriod()); fields->Set("failure_prediction_options", Empty); fields->Set("check_interval", CompatUtility::GetCheckableCheckInterval(host)); fields->Set("retry_interval", CompatUtility::GetCheckableRetryInterval(host)); fields->Set("max_check_attempts", host->GetMaxCheckAttempts()); fields->Set("first_notification_delay", Empty); fields->Set("notification_interval", CompatUtility::GetCheckableNotificationNotificationInterval(host)); fields->Set("notify_on_down", CompatUtility::GetHostNotifyOnDown(host)); fields->Set("notify_on_unreachable", CompatUtility::GetHostNotifyOnDown(host)); fields->Set("notify_on_recovery", CompatUtility::GetCheckableNotifyOnRecovery(host)); fields->Set("notify_on_flapping", CompatUtility::GetCheckableNotifyOnFlapping(host)); fields->Set("notify_on_downtime", CompatUtility::GetCheckableNotifyOnDowntime(host)); fields->Set("stalk_on_up", Empty); fields->Set("stalk_on_down", Empty); fields->Set("stalk_on_unreachable", Empty); fields->Set("flap_detection_enabled", CompatUtility::GetCheckableFlapDetectionEnabled(host)); fields->Set("flap_detection_on_up", Empty); fields->Set("flap_detection_on_down", Empty); fields->Set("flap_detection_on_unreachable", Empty); fields->Set("low_flap_threshold", CompatUtility::GetCheckableLowFlapThreshold(host)); fields->Set("high_flap_threshold", CompatUtility::GetCheckableHighFlapThreshold(host)); fields->Set("process_performance_data", CompatUtility::GetCheckableProcessPerformanceData(host)); fields->Set("freshness_checks_enabled", CompatUtility::GetCheckableFreshnessChecksEnabled(host)); fields->Set("freshness_threshold", CompatUtility::GetCheckableFreshnessThreshold(host)); fields->Set("passive_checks_enabled", CompatUtility::GetCheckablePassiveChecksEnabled(host)); fields->Set("event_handler_enabled", CompatUtility::GetCheckableEventHandlerEnabled(host)); fields->Set("active_checks_enabled", CompatUtility::GetCheckableActiveChecksEnabled(host)); fields->Set("retain_status_information", 1); fields->Set("retain_nonstatus_information", 1); fields->Set("notifications_enabled", CompatUtility::GetCheckableNotificationsEnabled(host)); fields->Set("obsess_over_host", 0); fields->Set("failure_prediction_enabled", 0); fields->Set("notes", host->GetNotes()); fields->Set("notes_url", host->GetNotesUrl()); fields->Set("action_url", host->GetActionUrl()); fields->Set("icon_image", host->GetIconImage()); fields->Set("icon_image_alt", host->GetIconImageAlt()); return fields; } Dictionary::Ptr HostDbObject::GetStatusFields(void) const { Dictionary::Ptr fields = new Dictionary(); Host::Ptr host = static_pointer_cast(GetObject()); CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) { fields->Set("output", CompatUtility::GetCheckResultOutput(cr)); fields->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr)); fields->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr)); fields->Set("check_source", cr->GetCheckSource()); } fields->Set("current_state", CompatUtility::GetHostCurrentState(host)); fields->Set("has_been_checked", CompatUtility::GetCheckableHasBeenChecked(host)); fields->Set("should_be_scheduled", host->GetEnableActiveChecks()); fields->Set("current_check_attempt", host->GetCheckAttempt()); fields->Set("max_check_attempts", host->GetMaxCheckAttempts()); if (cr) fields->Set("last_check", DbValue::FromTimestamp(cr->GetScheduleEnd())); fields->Set("next_check", DbValue::FromTimestamp(host->GetNextCheck())); fields->Set("check_type", CompatUtility::GetCheckableCheckType(host)); fields->Set("last_state_change", DbValue::FromTimestamp(host->GetLastStateChange())); fields->Set("last_hard_state_change", DbValue::FromTimestamp(host->GetLastHardStateChange())); fields->Set("last_hard_state", host->GetLastHardState()); fields->Set("last_time_up", DbValue::FromTimestamp(static_cast(host->GetLastStateUp()))); fields->Set("last_time_down", DbValue::FromTimestamp(static_cast(host->GetLastStateDown()))); fields->Set("last_time_unreachable", DbValue::FromTimestamp(static_cast(host->GetLastStateUnreachable()))); fields->Set("state_type", host->GetStateType()); fields->Set("last_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationLastNotification(host))); fields->Set("next_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationNextNotification(host))); fields->Set("no_more_notifications", Empty); fields->Set("notifications_enabled", CompatUtility::GetCheckableNotificationsEnabled(host)); fields->Set("problem_has_been_acknowledged", CompatUtility::GetCheckableProblemHasBeenAcknowledged(host)); fields->Set("acknowledgement_type", CompatUtility::GetCheckableAcknowledgementType(host)); fields->Set("current_notification_number", CompatUtility::GetCheckableNotificationNotificationNumber(host)); fields->Set("passive_checks_enabled", CompatUtility::GetCheckablePassiveChecksEnabled(host)); fields->Set("active_checks_enabled", CompatUtility::GetCheckableActiveChecksEnabled(host)); fields->Set("event_handler_enabled", CompatUtility::GetCheckableEventHandlerEnabled(host)); fields->Set("flap_detection_enabled", CompatUtility::GetCheckableFlapDetectionEnabled(host)); fields->Set("is_flapping", CompatUtility::GetCheckableIsFlapping(host)); fields->Set("percent_state_change", CompatUtility::GetCheckablePercentStateChange(host)); if (cr) { fields->Set("latency", Convert::ToString(cr->CalculateLatency())); fields->Set("execution_time", Convert::ToString(cr->CalculateExecutionTime())); } fields->Set("scheduled_downtime_depth", host->GetDowntimeDepth()); fields->Set("failure_prediction_enabled", Empty); fields->Set("process_performance_data", CompatUtility::GetCheckableProcessPerformanceData(host)); fields->Set("obsess_over_host", Empty); fields->Set("event_handler", CompatUtility::GetCheckableEventHandler(host)); fields->Set("check_command", CompatUtility::GetCheckableCheckCommand(host)); fields->Set("normal_check_interval", CompatUtility::GetCheckableCheckInterval(host)); fields->Set("retry_check_interval", CompatUtility::GetCheckableRetryInterval(host)); fields->Set("check_timeperiod_object_id", host->GetCheckPeriod()); fields->Set("is_reachable", CompatUtility::GetCheckableIsReachable(host)); fields->Set("original_attributes", JsonEncode(host->GetOriginalAttributes())); return fields; } void HostDbObject::OnConfigUpdateHeavy(void) { Host::Ptr host = static_pointer_cast(GetObject()); /* groups */ Array::Ptr groups = host->GetGroups(); std::vector queries; DbQuery query1; query1.Table = DbType::GetByName("HostGroup")->GetTable() + "_members"; query1.Type = DbQueryDelete; query1.Category = DbCatConfig; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("host_object_id", host); queries.push_back(query1); if (groups) { ObjectLock olock(groups); for (const String& groupName : groups) { HostGroup::Ptr group = HostGroup::GetByName(groupName); DbQuery query2; query2.Table = DbType::GetByName("HostGroup")->GetTable() + "_members"; query2.Type = DbQueryInsert; query2.Category = DbCatConfig; query2.Fields = new Dictionary(); query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.Fields->Set("hostgroup_id", DbValue::FromObjectInsertID(group)); query2.Fields->Set("host_object_id", host); query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.WhereCriteria->Set("hostgroup_id", DbValue::FromObjectInsertID(group)); query2.WhereCriteria->Set("host_object_id", host); queries.push_back(query2); } } DbObject::OnMultipleQueries(queries); queries.clear(); DbQuery query2; query2.Table = GetType()->GetTable() + "_parenthosts"; query2.Type = DbQueryDelete; query2.Category = DbCatConfig; query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set(GetType()->GetTable() + "_id", DbValue::FromObjectInsertID(GetObject())); queries.push_back(query2); /* parents */ for (const Checkable::Ptr& checkable : host->GetParents()) { Host::Ptr parent = dynamic_pointer_cast(checkable); if (!parent) continue; Log(LogDebug, "HostDbObject") << "host parents: " << parent->GetName(); /* parents: host_id, parent_host_object_id */ Dictionary::Ptr fields1 = new Dictionary(); fields1->Set(GetType()->GetTable() + "_id", DbValue::FromObjectInsertID(GetObject())); fields1->Set("parent_host_object_id", parent); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query1; query1.Table = GetType()->GetTable() + "_parenthosts"; query1.Type = DbQueryInsert; query1.Category = DbCatConfig; query1.Fields = fields1; queries.push_back(query1); } DbObject::OnMultipleQueries(queries); /* host dependencies */ Log(LogDebug, "HostDbObject") << "host dependencies for '" << host->GetName() << "'"; queries.clear(); DbQuery query3; query3.Table = GetType()->GetTable() + "dependencies"; query3.Type = DbQueryDelete; query3.Category = DbCatConfig; query3.WhereCriteria = new Dictionary(); query3.WhereCriteria->Set("dependent_host_object_id", host); queries.push_back(query3); for (const Dependency::Ptr& dep : host->GetDependencies()) { Checkable::Ptr parent = dep->GetParent(); if (!parent) { Log(LogDebug, "HostDbObject") << "Missing parent for dependency '" << dep->GetName() << "'."; continue; } int state_filter = dep->GetStateFilter(); Log(LogDebug, "HostDbObject") << "parent host: " << parent->GetName(); Dictionary::Ptr fields2 = new Dictionary(); fields2->Set("host_object_id", parent); fields2->Set("dependent_host_object_id", host); fields2->Set("inherits_parent", 1); fields2->Set("timeperiod_object_id", dep->GetPeriod()); fields2->Set("fail_on_up", (state_filter & StateFilterUp) ? 1 : 0); fields2->Set("fail_on_down", (state_filter & StateFilterDown) ? 1 : 0); fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query2; query2.Table = GetType()->GetTable() + "dependencies"; query2.Type = DbQueryInsert; query2.Category = DbCatConfig; query2.Fields = fields2; queries.push_back(query2); } DbObject::OnMultipleQueries(queries); Log(LogDebug, "HostDbObject") << "host contacts: " << host->GetName(); queries.clear(); DbQuery query4; query4.Table = GetType()->GetTable() + "_contacts"; query4.Type = DbQueryDelete; query4.Category = DbCatConfig; query4.WhereCriteria = new Dictionary(); query4.WhereCriteria->Set("host_id", DbValue::FromObjectInsertID(host)); queries.push_back(query4); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(host)) { Log(LogDebug, "HostDbObject") << "host contacts: " << user->GetName(); Dictionary::Ptr fields_contact = new Dictionary(); fields_contact->Set("host_id", DbValue::FromObjectInsertID(host)); fields_contact->Set("contact_object_id", user); fields_contact->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query_contact; query_contact.Table = GetType()->GetTable() + "_contacts"; query_contact.Type = DbQueryInsert; query_contact.Category = DbCatConfig; query_contact.Fields = fields_contact; queries.push_back(query_contact); } DbObject::OnMultipleQueries(queries); Log(LogDebug, "HostDbObject") << "host contactgroups: " << host->GetName(); queries.clear(); DbQuery query5; query5.Table = GetType()->GetTable() + "_contactgroups"; query5.Type = DbQueryDelete; query5.Category = DbCatConfig; query5.WhereCriteria = new Dictionary(); query5.WhereCriteria->Set("host_id", DbValue::FromObjectInsertID(host)); queries.push_back(query5); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(host)) { Log(LogDebug, "HostDbObject") << "host contactgroups: " << usergroup->GetName(); Dictionary::Ptr fields_contact = new Dictionary(); fields_contact->Set("host_id", DbValue::FromObjectInsertID(host)); fields_contact->Set("contactgroup_object_id", usergroup); fields_contact->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query_contact; query_contact.Table = GetType()->GetTable() + "_contactgroups"; query_contact.Type = DbQueryInsert; query_contact.Category = DbCatConfig; query_contact.Fields = fields_contact; queries.push_back(query_contact); } DbObject::OnMultipleQueries(queries); DoCommonConfigUpdate(); } void HostDbObject::OnConfigUpdateLight(void) { DoCommonConfigUpdate(); } void HostDbObject::DoCommonConfigUpdate(void) { Host::Ptr host = static_pointer_cast(GetObject()); /* update comments and downtimes on config change */ DbEvents::AddComments(host); DbEvents::AddDowntimes(host); } String HostDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const { String hashData = DbObject::CalculateConfigHash(configFields); Host::Ptr host = static_pointer_cast(GetObject()); Array::Ptr groups = host->GetGroups(); if (groups) hashData += DbObject::HashValue(groups); Array::Ptr parents = new Array(); /* parents */ for (const Checkable::Ptr& checkable : host->GetParents()) { Host::Ptr parent = dynamic_pointer_cast(checkable); if (!parent) continue; parents->Add(parent->GetName()); } parents->Sort(); hashData += DbObject::HashValue(parents); Array::Ptr dependencies = new Array(); /* dependencies */ for (const Dependency::Ptr& dep : host->GetDependencies()) { Checkable::Ptr parent = dep->GetParent(); if (!parent) continue; Array::Ptr depInfo = new Array(); depInfo->Add(parent->GetName()); depInfo->Add(dep->GetStateFilter()); depInfo->Add(dep->GetPeriodRaw()); dependencies->Add(depInfo); } dependencies->Sort(); hashData += DbObject::HashValue(dependencies); Array::Ptr users = new Array(); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(host)) { users->Add(user->GetName()); } users->Sort(); hashData += DbObject::HashValue(users); Array::Ptr userGroups = new Array(); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(host)) { userGroups->Add(usergroup->GetName()); } userGroups->Sort(); hashData += DbObject::HashValue(userGroups); return SHA256(hashData); } icinga2-2.8.1/lib/db_ido/hostdbobject.hpp000066400000000000000000000042201322762156600202170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOSTDBOBJECT_H #define HOSTDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" namespace icinga { /** * A Host database object. * * @ingroup ido */ class HostDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(HostDbObject); HostDbObject(const DbType::Ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; virtual void OnConfigUpdateHeavy(void) override; virtual void OnConfigUpdateLight(void) override; virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const override; private: void DoCommonConfigUpdate(void); }; } #endif /* HOSTDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/hostgroupdbobject.cpp000066400000000000000000000045271322762156600213010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/hostgroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" using namespace icinga; REGISTER_DBTYPE(HostGroup, "hostgroup", DbObjectTypeHostGroup, "hostgroup_object_id", HostGroupDbObject); HostGroupDbObject::HostGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr HostGroupDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); HostGroup::Ptr group = static_pointer_cast(GetObject()); fields->Set("alias", group->GetDisplayName()); fields->Set("notes", group->GetNotes()); fields->Set("notes_url", group->GetNotesUrl()); fields->Set("action_url", group->GetActionUrl()); return fields; } Dictionary::Ptr HostGroupDbObject::GetStatusFields(void) const { return Dictionary::Ptr(); } icinga2-2.8.1/lib/db_ido/hostgroupdbobject.hpp000066400000000000000000000040661322762156600213040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOSTGROUPDBOBJECT_H #define HOSTGROUPDBOBJECT_H #include "db_ido/dbobject.hpp" #include "icinga/hostgroup.hpp" #include "base/configobject.hpp" namespace icinga { /** * A HostGroup database object. * * @ingroup ido */ class HostGroupDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(HostGroupDbObject); HostGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; private: static void MembersChangedHandler(const HostGroup::Ptr& hgfilter); }; } #endif /* HOSTGROUPDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/i2-db_ido.hpp000066400000000000000000000034031322762156600172770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2DB_IDO_H #define I2DB_IDO_H /** * @defgroup db_ido IDO library * * The Icinga library implements database-agnostic IDO functionality. */ #include "base/i2-base.hpp" #ifdef I2_DB_IDO_BUILD # define I2_DB_IDO_API I2_EXPORT #else /* I2_DB_IDO_BUILD */ # define I2_DB_IDO_API I2_IMPORT #endif /* I2_DB_IDO_BUILD */ #endif /* I2DB_IDO_H */ icinga2-2.8.1/lib/db_ido/idochecktask.cpp000066400000000000000000000127361322762156600202070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/idochecktask.hpp" #include "icinga/host.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include "remote/apilistener.hpp" #include "remote/endpoint.hpp" #include "remote/zone.hpp" #include "base/function.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/configtype.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); Value raw_command = commandObj->GetCommandLine(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); String idoType = MacroProcessor::ResolveMacros("$ido_type$", resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); String idoName = MacroProcessor::ResolveMacros("$ido_name$", resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); if (resolvedMacros && !useResolvedMacros) return; if (idoType.IsEmpty()) { cr->SetOutput("Macro 'ido_type' must be set."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } if (idoName.IsEmpty()) { cr->SetOutput("Macro 'ido_name' must be set."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } Type::Ptr type = Type::GetByName(idoType); if (!type || !DbConnection::TypeInstance->IsAssignableFrom(type)) { cr->SetOutput("IDO type '" + idoType + "' is invalid."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } ConfigType *dtype = dynamic_cast(type.get()); VERIFY(dtype); DbConnection::Ptr conn = static_pointer_cast(dtype->GetObject(idoName)); if (!conn) { cr->SetOutput("IDO connection '" + idoName + "' does not exist."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } double qps = conn->GetQueryCount(60) / 60.0; if (conn->IsPaused()) { cr->SetOutput("IDO connection is temporarily disabled on this cluster instance."); cr->SetState(ServiceOK); checkable->ProcessCheckResult(cr); return; } if (!conn->GetConnected()) { if (conn->GetShouldConnect()) { cr->SetOutput("Could not connect to the database server."); cr->SetState(ServiceCritical); } else { cr->SetOutput("Not currently enabled: Another cluster instance is responsible for the IDO database."); cr->SetState(ServiceOK); } } else { String schema_version = conn->GetSchemaVersion(); std::ostringstream msgbuf; if (Utility::CompareVersion(IDO_CURRENT_SCHEMA_VERSION, schema_version) < 0) { msgbuf << "Outdated schema version: '" << schema_version << "'. Latest version: '" << IDO_CURRENT_SCHEMA_VERSION << "'."; cr->SetState(ServiceWarning); } else { msgbuf << "Connected to the database server (Schema version: '" << schema_version << "')."; cr->SetState(ServiceOK); } msgbuf << " Queries per second: " << std::fixed << std::setprecision(3) << qps; cr->SetOutput(msgbuf.str()); } Array::Ptr perfdata = new Array(); perfdata->Add(new PerfdataValue("queries", qps)); perfdata->Add(new PerfdataValue("queries_1min", conn->GetQueryCount(60))); perfdata->Add(new PerfdataValue("queries_5mins", conn->GetQueryCount(5 * 60))); perfdata->Add(new PerfdataValue("queries_15mins", conn->GetQueryCount(15 * 60))); perfdata->Add(new PerfdataValue("pending_queries", conn->GetPendingQueryCount())); cr->SetPerformanceData(perfdata); checkable->ProcessCheckResult(cr); } icinga2-2.8.1/lib/db_ido/idochecktask.hpp000066400000000000000000000035211322762156600202040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef IDOCHECKTASK_H #define IDOCHECKTASK_H #include "db_ido/dbconnection.hpp" #include "icinga/checkable.hpp" namespace icinga { /** * IDO check type. * * @ingroup db_ido */ class IdoCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IdoCheckTask(void); }; } #endif /* IDOCHECKTASK_H */ icinga2-2.8.1/lib/db_ido/servicedbobject.cpp000066400000000000000000000412371322762156600207060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/servicedbobject.hpp" #include "db_ido/servicegroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "db_ido/dbevents.hpp" #include "icinga/notification.hpp" #include "icinga/dependency.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/externalcommandprocessor.hpp" #include "icinga/compatutility.hpp" #include "icinga/icingaapplication.hpp" #include "remote/endpoint.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/json.hpp" #include using namespace icinga; REGISTER_DBTYPE(Service, "service", DbObjectTypeService, "service_object_id", ServiceDbObject); ServiceDbObject::ServiceDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr ServiceDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); Service::Ptr service = static_pointer_cast(GetObject()); Host::Ptr host = service->GetHost(); fields->Set("host_object_id", host); fields->Set("display_name", service->GetDisplayName()); fields->Set("check_command_object_id", service->GetCheckCommand()); fields->Set("check_command_args", CompatUtility::GetCheckableCommandArgs(service)); fields->Set("eventhandler_command_object_id", service->GetEventCommand()); fields->Set("eventhandler_command_args", Empty); fields->Set("notification_timeperiod_object_id", Empty); fields->Set("check_timeperiod_object_id", service->GetCheckPeriod()); fields->Set("failure_prediction_options", Empty); fields->Set("check_interval", CompatUtility::GetCheckableCheckInterval(service)); fields->Set("retry_interval", CompatUtility::GetCheckableRetryInterval(service)); fields->Set("max_check_attempts", service->GetMaxCheckAttempts()); fields->Set("first_notification_delay", Empty); fields->Set("notification_interval", CompatUtility::GetCheckableNotificationNotificationInterval(service)); fields->Set("notify_on_warning", CompatUtility::GetCheckableNotifyOnWarning(service)); fields->Set("notify_on_unknown", CompatUtility::GetCheckableNotifyOnUnknown(service)); fields->Set("notify_on_critical", CompatUtility::GetCheckableNotifyOnCritical(service)); fields->Set("notify_on_recovery", CompatUtility::GetCheckableNotifyOnRecovery(service)); fields->Set("notify_on_flapping", CompatUtility::GetCheckableNotifyOnFlapping(service)); fields->Set("notify_on_downtime", CompatUtility::GetCheckableNotifyOnDowntime(service)); fields->Set("stalk_on_ok", 0); fields->Set("stalk_on_warning", 0); fields->Set("stalk_on_unknown", 0); fields->Set("stalk_on_critical", 0); fields->Set("is_volatile", CompatUtility::GetCheckableIsVolatile(service)); fields->Set("flap_detection_enabled", CompatUtility::GetCheckableFlapDetectionEnabled(service)); fields->Set("flap_detection_on_ok", Empty); fields->Set("flap_detection_on_warning", Empty); fields->Set("flap_detection_on_unknown", Empty); fields->Set("flap_detection_on_critical", Empty); fields->Set("low_flap_threshold", CompatUtility::GetCheckableLowFlapThreshold(service)); fields->Set("high_flap_threshold", CompatUtility::GetCheckableHighFlapThreshold(service)); fields->Set("process_performance_data", CompatUtility::GetCheckableProcessPerformanceData(service)); fields->Set("freshness_checks_enabled", CompatUtility::GetCheckableFreshnessChecksEnabled(service)); fields->Set("freshness_threshold", CompatUtility::GetCheckableFreshnessThreshold(service)); fields->Set("passive_checks_enabled", CompatUtility::GetCheckablePassiveChecksEnabled(service)); fields->Set("event_handler_enabled", CompatUtility::GetCheckableEventHandlerEnabled(service)); fields->Set("active_checks_enabled", CompatUtility::GetCheckableActiveChecksEnabled(service)); fields->Set("retain_status_information", Empty); fields->Set("retain_nonstatus_information", Empty); fields->Set("notifications_enabled", CompatUtility::GetCheckableNotificationsEnabled(service)); fields->Set("obsess_over_service", Empty); fields->Set("failure_prediction_enabled", Empty); fields->Set("notes", service->GetNotes()); fields->Set("notes_url", service->GetNotesUrl()); fields->Set("action_url", service->GetActionUrl()); fields->Set("icon_image", service->GetIconImage()); fields->Set("icon_image_alt", service->GetIconImageAlt()); return fields; } Dictionary::Ptr ServiceDbObject::GetStatusFields(void) const { Dictionary::Ptr fields = new Dictionary(); Service::Ptr service = static_pointer_cast(GetObject()); CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) { fields->Set("output", CompatUtility::GetCheckResultOutput(cr)); fields->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr)); fields->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr)); fields->Set("check_source", cr->GetCheckSource()); } fields->Set("current_state", service->GetState()); fields->Set("has_been_checked", CompatUtility::GetCheckableHasBeenChecked(service)); fields->Set("should_be_scheduled", service->GetEnableActiveChecks()); fields->Set("current_check_attempt", service->GetCheckAttempt()); fields->Set("max_check_attempts", service->GetMaxCheckAttempts()); if (cr) fields->Set("last_check", DbValue::FromTimestamp(cr->GetScheduleEnd())); fields->Set("next_check", DbValue::FromTimestamp(service->GetNextCheck())); fields->Set("check_type", CompatUtility::GetCheckableCheckType(service)); fields->Set("last_state_change", DbValue::FromTimestamp(service->GetLastStateChange())); fields->Set("last_hard_state_change", DbValue::FromTimestamp(service->GetLastHardStateChange())); fields->Set("last_hard_state", service->GetLastHardState()); fields->Set("last_time_ok", DbValue::FromTimestamp(static_cast(service->GetLastStateOK()))); fields->Set("last_time_warning", DbValue::FromTimestamp(static_cast(service->GetLastStateWarning()))); fields->Set("last_time_critical", DbValue::FromTimestamp(static_cast(service->GetLastStateCritical()))); fields->Set("last_time_unknown", DbValue::FromTimestamp(static_cast(service->GetLastStateUnknown()))); fields->Set("state_type", service->GetStateType()); fields->Set("last_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationLastNotification(service))); fields->Set("next_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationNextNotification(service))); fields->Set("no_more_notifications", Empty); fields->Set("notifications_enabled", CompatUtility::GetCheckableNotificationsEnabled(service)); fields->Set("problem_has_been_acknowledged", CompatUtility::GetCheckableProblemHasBeenAcknowledged(service)); fields->Set("acknowledgement_type", CompatUtility::GetCheckableAcknowledgementType(service)); fields->Set("current_notification_number", CompatUtility::GetCheckableNotificationNotificationNumber(service)); fields->Set("passive_checks_enabled", CompatUtility::GetCheckablePassiveChecksEnabled(service)); fields->Set("active_checks_enabled", CompatUtility::GetCheckableActiveChecksEnabled(service)); fields->Set("event_handler_enabled", CompatUtility::GetCheckableEventHandlerEnabled(service)); fields->Set("flap_detection_enabled", CompatUtility::GetCheckableFlapDetectionEnabled(service)); fields->Set("is_flapping", CompatUtility::GetCheckableIsFlapping(service)); fields->Set("percent_state_change", CompatUtility::GetCheckablePercentStateChange(service)); if (cr) { fields->Set("latency", Convert::ToString(cr->CalculateLatency())); fields->Set("execution_time", Convert::ToString(cr->CalculateExecutionTime())); } fields->Set("scheduled_downtime_depth", service->GetDowntimeDepth()); fields->Set("process_performance_data", CompatUtility::GetCheckableProcessPerformanceData(service)); fields->Set("event_handler", CompatUtility::GetCheckableEventHandler(service)); fields->Set("check_command", CompatUtility::GetCheckableCheckCommand(service)); fields->Set("normal_check_interval", CompatUtility::GetCheckableCheckInterval(service)); fields->Set("retry_check_interval", CompatUtility::GetCheckableRetryInterval(service)); fields->Set("check_timeperiod_object_id", service->GetCheckPeriod()); fields->Set("is_reachable", CompatUtility::GetCheckableIsReachable(service)); fields->Set("original_attributes", JsonEncode(service->GetOriginalAttributes())); return fields; } void ServiceDbObject::OnConfigUpdateHeavy(void) { Service::Ptr service = static_pointer_cast(GetObject()); /* groups */ Array::Ptr groups = service->GetGroups(); std::vector queries; DbQuery query1; query1.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members"; query1.Type = DbQueryDelete; query1.Category = DbCatConfig; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("service_object_id", service); queries.push_back(query1); if (groups) { ObjectLock olock(groups); for (const String& groupName : groups) { ServiceGroup::Ptr group = ServiceGroup::GetByName(groupName); DbQuery query2; query2.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members"; query2.Type = DbQueryInsert; query2.Category = DbCatConfig; query2.Fields = new Dictionary(); query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.Fields->Set("servicegroup_id", DbValue::FromObjectInsertID(group)); query2.Fields->Set("service_object_id", service); query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.WhereCriteria->Set("servicegroup_id", DbValue::FromObjectInsertID(group)); query2.WhereCriteria->Set("service_object_id", service); queries.push_back(query2); } } DbObject::OnMultipleQueries(queries); /* service dependencies */ Log(LogDebug, "ServiceDbObject") << "service dependencies for '" << service->GetName() << "'"; queries.clear(); DbQuery query2; query2.Table = GetType()->GetTable() + "dependencies"; query2.Type = DbQueryDelete; query2.Category = DbCatConfig; query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("dependent_service_object_id", service); queries.push_back(query2); for (const Dependency::Ptr& dep : service->GetDependencies()) { Checkable::Ptr parent = dep->GetParent(); if (!parent) { Log(LogDebug, "ServiceDbObject") << "Missing parent for dependency '" << dep->GetName() << "'."; continue; } Log(LogDebug, "ServiceDbObject") << "service parents: " << parent->GetName(); int state_filter = dep->GetStateFilter(); /* service dependencies */ Dictionary::Ptr fields1 = new Dictionary(); fields1->Set("service_object_id", parent); fields1->Set("dependent_service_object_id", service); fields1->Set("inherits_parent", 1); fields1->Set("timeperiod_object_id", dep->GetPeriod()); fields1->Set("fail_on_ok", (state_filter & StateFilterOK) ? 1 : 0); fields1->Set("fail_on_warning", (state_filter & StateFilterWarning) ? 1 : 0); fields1->Set("fail_on_critical", (state_filter & StateFilterCritical) ? 1 : 0); fields1->Set("fail_on_unknown", (state_filter & StateFilterUnknown) ? 1 : 0); fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query1; query1.Table = GetType()->GetTable() + "dependencies"; query1.Type = DbQueryInsert; query1.Category = DbCatConfig; query1.Fields = fields1; queries.push_back(query1); } DbObject::OnMultipleQueries(queries); /* service contacts, contactgroups */ Log(LogDebug, "ServiceDbObject") << "service contacts: " << service->GetName(); queries.clear(); DbQuery query3; query3.Table = GetType()->GetTable() + "_contacts"; query3.Type = DbQueryDelete; query3.Category = DbCatConfig; query3.WhereCriteria = new Dictionary(); query3.WhereCriteria->Set("service_id", DbValue::FromObjectInsertID(service)); queries.push_back(query3); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(service)) { Log(LogDebug, "ServiceDbObject") << "service contacts: " << user->GetName(); Dictionary::Ptr fields_contact = new Dictionary(); fields_contact->Set("service_id", DbValue::FromObjectInsertID(service)); fields_contact->Set("contact_object_id", user); fields_contact->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query_contact; query_contact.Table = GetType()->GetTable() + "_contacts"; query_contact.Type = DbQueryInsert; query_contact.Category = DbCatConfig; query_contact.Fields = fields_contact; queries.push_back(query_contact); } DbObject::OnMultipleQueries(queries); Log(LogDebug, "ServiceDbObject") << "service contactgroups: " << service->GetName(); queries.clear(); DbQuery query4; query4.Table = GetType()->GetTable() + "_contactgroups"; query4.Type = DbQueryDelete; query4.Category = DbCatConfig; query4.WhereCriteria = new Dictionary(); query4.WhereCriteria->Set("service_id", DbValue::FromObjectInsertID(service)); queries.push_back(query4); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(service)) { Log(LogDebug, "ServiceDbObject") << "service contactgroups: " << usergroup->GetName(); Dictionary::Ptr fields_contact = new Dictionary(); fields_contact->Set("service_id", DbValue::FromObjectInsertID(service)); fields_contact->Set("contactgroup_object_id", usergroup); fields_contact->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query_contact; query_contact.Table = GetType()->GetTable() + "_contactgroups"; query_contact.Type = DbQueryInsert; query_contact.Category = DbCatConfig; query_contact.Fields = fields_contact; queries.push_back(query_contact); } DbObject::OnMultipleQueries(queries); DoCommonConfigUpdate(); } void ServiceDbObject::OnConfigUpdateLight(void) { DoCommonConfigUpdate(); } void ServiceDbObject::DoCommonConfigUpdate(void) { Service::Ptr service = static_pointer_cast(GetObject()); /* update comments and downtimes on config change */ DbEvents::AddComments(service); DbEvents::AddDowntimes(service); } String ServiceDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const { String hashData = DbObject::CalculateConfigHash(configFields); Service::Ptr service = static_pointer_cast(GetObject()); Array::Ptr groups = service->GetGroups(); if (groups) hashData += DbObject::HashValue(groups); Array::Ptr dependencies = new Array(); /* dependencies */ for (const Dependency::Ptr& dep : service->GetDependencies()) { Checkable::Ptr parent = dep->GetParent(); if (!parent) continue; Array::Ptr depInfo = new Array(); depInfo->Add(parent->GetName()); depInfo->Add(dep->GetStateFilter()); depInfo->Add(dep->GetPeriodRaw()); dependencies->Add(depInfo); } dependencies->Sort(); hashData += DbObject::HashValue(dependencies); Array::Ptr users = new Array(); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(service)) { users->Add(user->GetName()); } users->Sort(); hashData += DbObject::HashValue(users); Array::Ptr userGroups = new Array(); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(service)) { userGroups->Add(usergroup->GetName()); } userGroups->Sort(); hashData += DbObject::HashValue(userGroups); return SHA256(hashData); } icinga2-2.8.1/lib/db_ido/servicedbobject.hpp000066400000000000000000000043511322762156600207070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICEDBOBJECT_H #define SERVICEDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" #include "icinga/service.hpp" namespace icinga { /** * A Service database object. * * @ingroup ido */ class ServiceDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(ServiceDbObject); ServiceDbObject(const DbType::Ptr& type, const String& name1, const String& name2); static void StaticInitialize(void); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; virtual void OnConfigUpdateHeavy(void) override; virtual void OnConfigUpdateLight(void) override; virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const override; private: void DoCommonConfigUpdate(void); }; } #endif /* SERVICEDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/servicegroupdbobject.cpp000066400000000000000000000045341322762156600217620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/servicegroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" using namespace icinga; REGISTER_DBTYPE(ServiceGroup, "servicegroup", DbObjectTypeServiceGroup, "servicegroup_object_id", ServiceGroupDbObject); ServiceGroupDbObject::ServiceGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr ServiceGroupDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); ServiceGroup::Ptr group = static_pointer_cast(GetObject()); fields->Set("alias", group->GetDisplayName()); fields->Set("notes", group->GetNotes()); fields->Set("notes_url", group->GetNotesUrl()); fields->Set("action_url", group->GetActionUrl()); return fields; } Dictionary::Ptr ServiceGroupDbObject::GetStatusFields(void) const { return Dictionary::Ptr(); } icinga2-2.8.1/lib/db_ido/servicegroupdbobject.hpp000066400000000000000000000040001322762156600217530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICEGROUPDBOBJECT_H #define SERVICEGROUPDBOBJECT_H #include "db_ido/dbobject.hpp" #include "icinga/servicegroup.hpp" #include "base/configobject.hpp" namespace icinga { /** * A ServiceGroup database object. * * @ingroup ido */ class ServiceGroupDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(ServiceGroupDbObject); ServiceGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; }; } #endif /* SERVICEGROUPDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/timeperioddbobject.cpp000066400000000000000000000073701322762156600214070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/timeperioddbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/timeperiod.hpp" #include "icinga/legacytimeperiod.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/objectlock.hpp" using namespace icinga; REGISTER_DBTYPE(TimePeriod, "timeperiod", DbObjectTypeTimePeriod, "timeperiod_object_id", TimePeriodDbObject); TimePeriodDbObject::TimePeriodDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr TimePeriodDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); TimePeriod::Ptr tp = static_pointer_cast(GetObject()); fields->Set("alias", tp->GetDisplayName()); return fields; } Dictionary::Ptr TimePeriodDbObject::GetStatusFields(void) const { return Empty; } void TimePeriodDbObject::OnConfigUpdateHeavy(void) { TimePeriod::Ptr tp = static_pointer_cast(GetObject()); DbQuery query_del1; query_del1.Table = GetType()->GetTable() + "_timeranges"; query_del1.Type = DbQueryDelete; query_del1.Category = DbCatConfig; query_del1.WhereCriteria = new Dictionary(); query_del1.WhereCriteria->Set("timeperiod_id", DbValue::FromObjectInsertID(tp)); OnQuery(query_del1); Dictionary::Ptr ranges = tp->GetRanges(); if (!ranges) return; time_t refts = Utility::GetTime(); ObjectLock olock(ranges); for (const Dictionary::Pair& kv : ranges) { int wday = LegacyTimePeriod::WeekdayFromString(kv.first); if (wday == -1) continue; tm reference = Utility::LocalTime(refts); Array::Ptr segments = new Array(); LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments); ObjectLock olock(segments); for (const Value& vsegment : segments) { Dictionary::Ptr segment = vsegment; int begin = segment->Get("begin"); int end = segment->Get("end"); DbQuery query; query.Table = GetType()->GetTable() + "_timeranges"; query.Type = DbQueryInsert; query.Category = DbCatConfig; query.Fields = new Dictionary(); query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query.Fields->Set("timeperiod_id", DbValue::FromObjectInsertID(tp)); query.Fields->Set("day", wday); query.Fields->Set("start_sec", begin % 86400); query.Fields->Set("end_sec", end % 86400); OnQuery(query); } } } icinga2-2.8.1/lib/db_ido/timeperioddbobject.hpp000066400000000000000000000040151322762156600214050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TIMEPERIODDBOBJECT_H #define TIMEPERIODDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" namespace icinga { /** * A TimePeriod database object. * * @ingroup ido */ class TimePeriodDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(TimePeriodDbObject); TimePeriodDbObject(const DbType::Ptr& type, const String& name1, const String& name2); protected: virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; virtual void OnConfigUpdateHeavy(void) override; }; } #endif /* TIMEPERIODDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/userdbobject.cpp000066400000000000000000000154741322762156600202300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/userdbobject.hpp" #include "db_ido/usergroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "icinga/user.hpp" #include "icinga/notification.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_DBTYPE(User, "contact", DbObjectTypeContact, "contact_object_id", UserDbObject); UserDbObject::UserDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr UserDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); User::Ptr user = static_pointer_cast(GetObject()); fields->Set("alias", user->GetDisplayName()); fields->Set("email_address", user->GetEmail()); fields->Set("pager_address", user->GetPager()); fields->Set("host_timeperiod_object_id", user->GetPeriod()); fields->Set("service_timeperiod_object_id", user->GetPeriod()); fields->Set("host_notifications_enabled", user->GetEnableNotifications()); fields->Set("service_notifications_enabled", user->GetEnableNotifications()); fields->Set("can_submit_commands", 1); int typeFilter = user->GetTypeFilter(); int stateFilter = user->GetStateFilter(); fields->Set("notify_service_recovery", (typeFilter & NotificationRecovery) != 0); fields->Set("notify_service_warning", (stateFilter & StateFilterWarning) != 0); fields->Set("notify_service_unknown", (stateFilter & StateFilterUnknown) != 0); fields->Set("notify_service_critical", (stateFilter & StateFilterCritical) != 0); fields->Set("notify_service_flapping", (typeFilter & (NotificationFlappingStart | NotificationFlappingEnd)) != 0); fields->Set("notify_service_downtime", (typeFilter & (NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved)) != 0); fields->Set("notify_host_recovery", (typeFilter & NotificationRecovery) != 0); fields->Set("notify_host_down", (stateFilter & StateFilterDown) != 0); fields->Set("notify_host_flapping", (typeFilter & (NotificationFlappingStart | NotificationFlappingEnd)) != 0); fields->Set("notify_host_downtime", (typeFilter & (NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved)) != 0); return fields; } Dictionary::Ptr UserDbObject::GetStatusFields(void) const { Dictionary::Ptr fields = new Dictionary(); User::Ptr user = static_pointer_cast(GetObject()); fields->Set("host_notifications_enabled", user->GetEnableNotifications()); fields->Set("service_notifications_enabled", user->GetEnableNotifications()); fields->Set("last_host_notification", DbValue::FromTimestamp(user->GetLastNotification())); fields->Set("last_service_notification", DbValue::FromTimestamp(user->GetLastNotification())); return fields; } void UserDbObject::OnConfigUpdateHeavy(void) { User::Ptr user = static_pointer_cast(GetObject()); /* groups */ Array::Ptr groups = user->GetGroups(); std::vector queries; DbQuery query1; query1.Table = DbType::GetByName("UserGroup")->GetTable() + "_members"; query1.Type = DbQueryDelete; query1.Category = DbCatConfig; query1.WhereCriteria = new Dictionary(); query1.WhereCriteria->Set("contact_object_id", user); queries.push_back(query1); if (groups) { ObjectLock olock(groups); for (const String& groupName : groups) { UserGroup::Ptr group = UserGroup::GetByName(groupName); DbQuery query2; query2.Table = DbType::GetByName("UserGroup")->GetTable() + "_members"; query2.Type = DbQueryInsert | DbQueryUpdate; query2.Category = DbCatConfig; query2.Fields = new Dictionary(); query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.Fields->Set("contactgroup_id", DbValue::FromObjectInsertID(group)); query2.Fields->Set("contact_object_id", user); query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */ query2.WhereCriteria->Set("contactgroup_id", DbValue::FromObjectInsertID(group)); query2.WhereCriteria->Set("contact_object_id", user); queries.push_back(query2); } } DbObject::OnMultipleQueries(queries); queries.clear(); DbQuery query2; query2.Table = "contact_addresses"; query2.Type = DbQueryDelete; query2.Category = DbCatConfig; query2.WhereCriteria = new Dictionary(); query2.WhereCriteria->Set("contact_id", DbValue::FromObjectInsertID(user)); queries.push_back(query2); Dictionary::Ptr vars = user->GetVars(); if (vars) { /* This is sparta. */ for (int i = 1; i <= 6; i++) { Dictionary::Ptr fields = new Dictionary(); String key = "address" + Convert::ToString(i); if (!vars->Contains(key)) continue; String val = vars->Get(key); fields->Set("contact_id", DbValue::FromObjectInsertID(user)); fields->Set("address_number", i); fields->Set("address", val); fields->Set("instance_id", 0); /* DbConnection class fills in real ID */ DbQuery query; query.Type = DbQueryInsert; query.Table = "contact_addresses"; query.Category = DbCatConfig; query.Fields = fields; queries.push_back(query); } } DbObject::OnMultipleQueries(queries); } String UserDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const { String hashData = DbObject::CalculateConfigHash(configFields); User::Ptr user = static_pointer_cast(GetObject()); Array::Ptr groups = user->GetGroups(); if (groups) hashData += DbObject::HashValue(groups); return SHA256(hashData); } icinga2-2.8.1/lib/db_ido/userdbobject.hpp000066400000000000000000000040751322762156600202300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef USERDBOBJECT_H #define USERDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" namespace icinga { /** * A User database object. * * @ingroup ido */ class UserDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(UserDbObject); UserDbObject(const DbType::Ptr& type, const String& name1, const String& name2); protected: virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; virtual void OnConfigUpdateHeavy(void) override; virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const override; }; } #endif /* USERDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/usergroupdbobject.cpp000066400000000000000000000043221322762156600212730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/usergroupdbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/objectlock.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" using namespace icinga; REGISTER_DBTYPE(UserGroup, "contactgroup", DbObjectTypeContactGroup, "contactgroup_object_id", UserGroupDbObject); UserGroupDbObject::UserGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr UserGroupDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); UserGroup::Ptr group = static_pointer_cast(GetObject()); fields->Set("alias", group->GetDisplayName()); return fields; } Dictionary::Ptr UserGroupDbObject::GetStatusFields(void) const { return Dictionary::Ptr(); } icinga2-2.8.1/lib/db_ido/usergroupdbobject.hpp000066400000000000000000000037501322762156600213040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef USERGROUPDBOBJECT_H #define USERGROUPDBOBJECT_H #include "db_ido/dbobject.hpp" #include "icinga/usergroup.hpp" #include "base/configobject.hpp" namespace icinga { /** * A UserGroup database object. * * @ingroup ido */ class UserGroupDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(UserGroupDbObject); UserGroupDbObject(const DbType::Ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; }; } #endif /* USERGROUPDBOBJECT_H */ icinga2-2.8.1/lib/db_ido/zonedbobject.cpp000066400000000000000000000045771322762156600202270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/zonedbobject.hpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_DBTYPE(Zone, "zone", DbObjectTypeZone, "zone_object_id", ZoneDbObject); ZoneDbObject::ZoneDbObject(const DbType::Ptr& type, const String& name1, const String& name2) : DbObject(type, name1, name2) { } Dictionary::Ptr ZoneDbObject::GetConfigFields(void) const { Dictionary::Ptr fields = new Dictionary(); Zone::Ptr zone = static_pointer_cast(GetObject()); fields->Set("is_global", zone->IsGlobal() ? 1 : 0); fields->Set("parent_zone_object_id", zone->GetParent()); return fields; } Dictionary::Ptr ZoneDbObject::GetStatusFields(void) const { Zone::Ptr zone = static_pointer_cast(GetObject()); Log(LogDebug, "ZoneDbObject") << "update status for zone '" << zone->GetName() << "'"; Dictionary::Ptr fields = new Dictionary(); fields->Set("parent_zone_object_id", zone->GetParent()); return fields; } icinga2-2.8.1/lib/db_ido/zonedbobject.hpp000066400000000000000000000037171322762156600202270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ZONEDBOBJECT_H #define ZONEDBOBJECT_H #include "db_ido/dbobject.hpp" #include "base/configobject.hpp" #include "remote/zone.hpp" namespace icinga { /** * An Endpoint database object. * * @ingroup ido */ class ZoneDbObject : public DbObject { public: DECLARE_PTR_TYPEDEFS(ZoneDbObject); ZoneDbObject(const intrusive_ptr& type, const String& name1, const String& name2); virtual Dictionary::Ptr GetConfigFields(void) const override; virtual Dictionary::Ptr GetStatusFields(void) const override; }; } #endif /* ZONEDBOBJECT_H */ icinga2-2.8.1/lib/db_ido_mysql/000077500000000000000000000000001322762156600162635ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_mysql/CMakeLists.txt000066400000000000000000000045031322762156600210250ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. find_package(MySQL) if(MYSQL_FOUND) mkclass_target(idomysqlconnection.ti idomysqlconnection.tcpp idomysqlconnection.thpp) set(db_ido_mysql_SOURCES idomysqlconnection.cpp idomysqlconnection.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(db_ido_mysql db_ido_mysql db_ido_mysql_SOURCES) endif() add_library(db_ido_mysql SHARED ${db_ido_mysql_SOURCES}) include_directories(${MYSQL_INCLUDE_DIR}) target_link_libraries(db_ido_mysql ${Boost_LIBRARIES} ${MYSQL_CLIENT_LIBS} base config icinga db_ido) set_target_properties ( db_ido_mysql PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_DB_IDO_MYSQL_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/ido-mysql.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install( TARGETS db_ido_mysql RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 ) install( DIRECTORY schema DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2-ido-mysql FILES_MATCHING PATTERN "*.sql" ) install( DIRECTORY schema/upgrade DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2-ido-mysql/schema FILES_MATCHING PATTERN "*.sql" ) set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) else() message(FATAL_ERROR "You have selected MySQL support, but MySQL could not be found. You can disable the MySQL IDO module using -DICINGA2_WITH_MYSQL=OFF.") endif() icinga2-2.8.1/lib/db_ido_mysql/idomysqlconnection.cpp000066400000000000000000001030371322762156600227140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido_mysql/idomysqlconnection.hpp" #include "db_ido_mysql/idomysqlconnection.tcpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/configtype.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(IdoMysqlConnection); REGISTER_STATSFUNCTION(IdoMysqlConnection, &IdoMysqlConnection::StatsFunc); IdoMysqlConnection::IdoMysqlConnection(void) : m_QueryQueue(10000000) { } void IdoMysqlConnection::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_QueryQueue.SetName("IdoMysqlConnection, " + GetName()); } void IdoMysqlConnection::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const IdoMysqlConnection::Ptr& idomysqlconnection : ConfigType::GetObjectsByType()) { size_t queryQueueItems = idomysqlconnection->m_QueryQueue.GetLength(); double queryQueueItemRate = idomysqlconnection->m_QueryQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr stats = new Dictionary(); stats->Set("version", idomysqlconnection->GetSchemaVersion()); stats->Set("instance_name", idomysqlconnection->GetInstanceName()); stats->Set("connected", idomysqlconnection->GetConnected()); stats->Set("query_queue_items", queryQueueItems); stats->Set("query_queue_item_rate", queryQueueItemRate); nodes->Set(idomysqlconnection->GetName(), stats); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_queries_rate", idomysqlconnection->GetQueryCount(60) / 60.0)); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_queries_1min", idomysqlconnection->GetQueryCount(60))); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_queries_5mins", idomysqlconnection->GetQueryCount(5 * 60))); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_queries_15mins", idomysqlconnection->GetQueryCount(15 * 60))); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_query_queue_items", queryQueueItems)); perfdata->Add(new PerfdataValue("idomysqlconnection_" + idomysqlconnection->GetName() + "_query_queue_item_rate", queryQueueItemRate)); } status->Set("idomysqlconnection", nodes); } void IdoMysqlConnection::Resume(void) { DbConnection::Resume(); Log(LogInformation, "IdoMysqlConnection") << "'" << GetName() << "' resumed."; SetConnected(false); m_QueryQueue.SetExceptionCallback(boost::bind(&IdoMysqlConnection::ExceptionHandler, this, _1)); m_TxTimer = new Timer(); m_TxTimer->SetInterval(1); m_TxTimer->OnTimerExpired.connect(boost::bind(&IdoMysqlConnection::TxTimerHandler, this)); m_TxTimer->Start(); m_ReconnectTimer = new Timer(); m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&IdoMysqlConnection::ReconnectTimerHandler, this)); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); ASSERT(mysql_thread_safe()); } void IdoMysqlConnection::Pause(void) { Log(LogInformation, "IdoMysqlConnection") << "'" << GetName() << "' paused."; m_ReconnectTimer.reset(); DbConnection::Pause(); #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Rescheduling disconnect task."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::Disconnect, this), PriorityHigh); m_QueryQueue.Join(); } void IdoMysqlConnection::ExceptionHandler(boost::exception_ptr exp) { Log(LogCritical, "IdoMysqlConnection", "Exception during database operation: Verify that your database is operational!"); Log(LogDebug, "IdoMysqlConnection") << "Exception during database operation: " << DiagnosticInformation(exp); if (GetConnected()) { mysql_close(&m_Connection); SetConnected(false); } } void IdoMysqlConnection::AssertOnWorkQueue(void) { ASSERT(m_QueryQueue.IsWorkerThread()); } void IdoMysqlConnection::Disconnect(void) { AssertOnWorkQueue(); if (!GetConnected()) return; Query("COMMIT"); mysql_close(&m_Connection); SetConnected(false); } void IdoMysqlConnection::TxTimerHandler(void) { NewTransaction(); } void IdoMysqlConnection::NewTransaction(void) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling new transaction and finishing async queries."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalNewTransaction, this), PriorityHigh); m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::FinishAsyncQueries, this), PriorityHigh); } void IdoMysqlConnection::InternalNewTransaction(void) { AssertOnWorkQueue(); if (!GetConnected()) return; AsyncQuery("COMMIT"); AsyncQuery("BEGIN"); } void IdoMysqlConnection::ReconnectTimerHandler(void) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling reconnect task."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::Reconnect, this), PriorityLow); } void IdoMysqlConnection::Reconnect(void) { AssertOnWorkQueue(); if (!IsActive()) return; CONTEXT("Reconnecting to MySQL IDO database '" + GetName() + "'"); double startTime = Utility::GetTime(); SetShouldConnect(true); bool reconnect = false; if (GetConnected()) { /* Check if we're really still connected */ if (mysql_ping(&m_Connection) == 0) return; mysql_close(&m_Connection); SetConnected(false); reconnect = true; } ClearIDCache(); String ihost, isocket_path, iuser, ipasswd, idb; String isslKey, isslCert, isslCa, isslCaPath, isslCipher; const char *host, *socket_path, *user , *passwd, *db; const char *sslKey, *sslCert, *sslCa, *sslCaPath, *sslCipher; bool enableSsl; long port; ihost = GetHost(); isocket_path = GetSocketPath(); iuser = GetUser(); ipasswd = GetPassword(); idb = GetDatabase(); enableSsl = GetEnableSsl(); isslKey = GetSslKey(); isslCert = GetSslCert(); isslCa = GetSslCa(); isslCaPath = GetSslCapath(); isslCipher = GetSslCipher(); host = (!ihost.IsEmpty()) ? ihost.CStr() : NULL; port = GetPort(); socket_path = (!isocket_path.IsEmpty()) ? isocket_path.CStr() : NULL; user = (!iuser.IsEmpty()) ? iuser.CStr() : NULL; passwd = (!ipasswd.IsEmpty()) ? ipasswd.CStr() : NULL; db = (!idb.IsEmpty()) ? idb.CStr() : NULL; sslKey = (!isslKey.IsEmpty()) ? isslKey.CStr() : NULL; sslCert = (!isslCert.IsEmpty()) ? isslCert.CStr() : NULL; sslCa = (!isslCa.IsEmpty()) ? isslCa.CStr() : NULL; sslCaPath = (!isslCaPath.IsEmpty()) ? isslCaPath.CStr() : NULL; sslCipher = (!isslCipher.IsEmpty()) ? isslCipher.CStr() : NULL; /* connection */ if (!mysql_init(&m_Connection)) { Log(LogCritical, "IdoMysqlConnection") << "mysql_init() failed: out of memory"; BOOST_THROW_EXCEPTION(std::bad_alloc()); } if (enableSsl) mysql_ssl_set(&m_Connection, sslKey, sslCert, sslCa, sslCaPath, sslCipher); if (!mysql_real_connect(&m_Connection, host, user, passwd, db, port, socket_path, CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS)) { Log(LogCritical, "IdoMysqlConnection") << "Connection to database '" << db << "' with user '" << user << "' on '" << host << ":" << port << "' " << (enableSsl ? "(SSL enabled) " : "") << "failed: \"" << mysql_error(&m_Connection) << "\""; BOOST_THROW_EXCEPTION(std::runtime_error(mysql_error(&m_Connection))); } SetConnected(true); IdoMysqlResult result = Query("SELECT @@global.max_allowed_packet AS max_allowed_packet"); Dictionary::Ptr row = FetchRow(result); if (row) m_MaxPacketSize = row->Get("max_allowed_packet"); else m_MaxPacketSize = 64 * 1024; DiscardRows(result); String dbVersionName = "idoutils"; result = Query("SELECT version FROM " + GetTablePrefix() + "dbversion WHERE name='" + Escape(dbVersionName) + "'"); row = FetchRow(result); if (!row) { mysql_close(&m_Connection); SetConnected(false); Log(LogCritical, "IdoMysqlConnection", "Schema does not provide any valid version! Verify your schema installation."); BOOST_THROW_EXCEPTION(std::runtime_error("Invalid schema.")); } DiscardRows(result); String version = row->Get("version"); SetSchemaVersion(version); if (Utility::CompareVersion(IDO_COMPAT_SCHEMA_VERSION, version) < 0) { mysql_close(&m_Connection); SetConnected(false); Log(LogCritical, "IdoMysqlConnection") << "Schema version '" << version << "' does not match the required version '" << IDO_COMPAT_SCHEMA_VERSION << "' (or newer)! Please check the upgrade documentation at " << "https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/upgrading-icinga-2#upgrading-mysql-db"; BOOST_THROW_EXCEPTION(std::runtime_error("Schema version mismatch.")); } String instanceName = GetInstanceName(); result = Query("SELECT instance_id FROM " + GetTablePrefix() + "instances WHERE instance_name = '" + Escape(instanceName) + "'"); row = FetchRow(result); if (!row) { Query("INSERT INTO " + GetTablePrefix() + "instances (instance_name, instance_description) VALUES ('" + Escape(instanceName) + "', '" + Escape(GetInstanceDescription()) + "')"); m_InstanceID = GetLastInsertID(); } else { m_InstanceID = DbReference(row->Get("instance_id")); } DiscardRows(result); Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint(); /* we have an endpoint in a cluster setup, so decide if we can proceed here */ if (my_endpoint && GetHAMode() == HARunOnce) { /* get the current endpoint writing to programstatus table */ result = Query("SELECT UNIX_TIMESTAMP(status_update_time) AS status_update_time, endpoint_name FROM " + GetTablePrefix() + "programstatus WHERE instance_id = " + Convert::ToString(m_InstanceID)); row = FetchRow(result); DiscardRows(result); String endpoint_name; if (row) endpoint_name = row->Get("endpoint_name"); else Log(LogNotice, "IdoMysqlConnection", "Empty program status table"); /* if we did not write into the database earlier, another instance is active */ if (endpoint_name != my_endpoint->GetName()) { double status_update_time; if (row) status_update_time = row->Get("status_update_time"); else status_update_time = 0; double status_update_age = Utility::GetTime() - status_update_time; Log(LogNotice, "IdoMysqlConnection") << "Last update by '" << endpoint_name << "' was " << status_update_age << "s ago."; if (status_update_age < GetFailoverTimeout()) { mysql_close(&m_Connection); SetConnected(false); SetShouldConnect(false); return; } /* activate the IDO only, if we're authoritative in this zone */ if (IsPaused()) { Log(LogNotice, "IdoMysqlConnection") << "Local endpoint '" << my_endpoint->GetName() << "' is not authoritative, bailing out."; mysql_close(&m_Connection); SetConnected(false); return; } } Log(LogNotice, "IdoMysqlConnection", "Enabling IDO connection."); } Log(LogInformation, "IdoMysqlConnection") << "MySQL IDO instance id: " << static_cast(m_InstanceID) << " (schema version: '" + version + "')"; /* set session time zone to utc */ Query("SET SESSION TIME_ZONE='+00:00'"); Query("SET SESSION SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"); Query("BEGIN"); /* update programstatus table */ UpdateProgramStatus(); /* record connection */ Query("INSERT INTO " + GetTablePrefix() + "conninfo " + "(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES (" + Convert::ToString(static_cast(m_InstanceID)) + ", NOW(), NOW(), 'icinga2 db_ido_mysql', '" + Escape(Application::GetAppVersion()) + "', '" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())"); /* clear config tables for the initial config dump */ PrepareDatabase(); std::ostringstream q1buf; q1buf << "SELECT object_id, objecttype_id, name1, name2, is_active FROM " + GetTablePrefix() + "objects WHERE instance_id = " << static_cast(m_InstanceID); result = Query(q1buf.str()); std::vector activeDbObjs; while ((row = FetchRow(result))) { DbType::Ptr dbtype = DbType::GetByID(row->Get("objecttype_id")); if (!dbtype) continue; DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2")); SetObjectID(dbobj, DbReference(row->Get("object_id"))); bool active = row->Get("is_active"); SetObjectActive(dbobj, active); if (active) activeDbObjs.push_back(dbobj); } SetIDCacheValid(true); EnableActiveChangedHandler(); for (const DbObject::Ptr& dbobj : activeDbObjs) { if (dbobj->GetObject()) continue; Log(LogNotice, "IdoMysqlConnection") << "Deactivate deleted object name1: '" << dbobj->GetName1() << "' name2: '" << dbobj->GetName2() + "'."; DeactivateObject(dbobj); } UpdateAllObjects(); #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling session table clear and finish connect task."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::ClearTablesBySession, this), PriorityLow); m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::FinishConnect, this, startTime), PriorityLow); } void IdoMysqlConnection::FinishConnect(double startTime) { AssertOnWorkQueue(); if (!GetConnected()) return; FinishAsyncQueries(); Log(LogInformation, "IdoMysqlConnection") << "Finished reconnecting to MySQL IDO database in " << std::setw(2) << Utility::GetTime() - startTime << " second(s)."; Query("COMMIT"); Query("BEGIN"); } void IdoMysqlConnection::ClearTablesBySession(void) { /* delete all comments and downtimes without current session token */ ClearTableBySession("comments"); ClearTableBySession("scheduleddowntime"); } void IdoMysqlConnection::ClearTableBySession(const String& table) { Query("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast(m_InstanceID)) + " AND session_token <> " + Convert::ToString(GetSessionToken())); } void IdoMysqlConnection::AsyncQuery(const String& query, const boost::function& callback) { AssertOnWorkQueue(); IdoAsyncQuery aq; aq.Query = query; /* XXX: Important: The callback must not immediately execute a query, but enqueue it! * See https://github.com/Icinga/icinga2/issues/4603 for details. */ aq.Callback = callback; m_AsyncQueries.push_back(aq); if (m_AsyncQueries.size() > 25000) { FinishAsyncQueries(); InternalNewTransaction(); } } void IdoMysqlConnection::FinishAsyncQueries(void) { std::vector queries; m_AsyncQueries.swap(queries); std::vector::size_type offset = 0; while (offset < queries.size()) { std::ostringstream querybuf; std::vector::size_type count = 0; size_t num_bytes = 0; for (std::vector::size_type i = offset; i < queries.size(); i++) { const IdoAsyncQuery& aq = queries[i]; size_t size_query = aq.Query.GetLength() + 1; if (num_bytes + size_query > m_MaxPacketSize - 512) break; if (count > 0) querybuf << ";"; IncreaseQueryCount(); count++; Log(LogDebug, "IdoMysqlConnection") << "Query: " << aq.Query; querybuf << aq.Query; num_bytes += size_query; } String query = querybuf.str(); if (mysql_query(&m_Connection, query.CStr()) != 0) { std::ostringstream msgbuf; String message = mysql_error(&m_Connection); msgbuf << "Error \"" << message << "\" when executing query \"" << query << "\""; Log(LogCritical, "IdoMysqlConnection", msgbuf.str()); BOOST_THROW_EXCEPTION( database_error() << errinfo_message(mysql_error(&m_Connection)) << errinfo_database_query(query) ); } for (std::vector::size_type i = offset; i < offset + count; i++) { const IdoAsyncQuery& aq = queries[i]; MYSQL_RES *result = mysql_store_result(&m_Connection); m_AffectedRows = mysql_affected_rows(&m_Connection); IdoMysqlResult iresult; if (!result) { if (mysql_field_count(&m_Connection) > 0) { std::ostringstream msgbuf; String message = mysql_error(&m_Connection); msgbuf << "Error \"" << message << "\" when executing query \"" << aq.Query << "\""; Log(LogCritical, "IdoMysqlConnection", msgbuf.str()); BOOST_THROW_EXCEPTION( database_error() << errinfo_message(mysql_error(&m_Connection)) << errinfo_database_query(query) ); } } else iresult = IdoMysqlResult(result, std::ptr_fun(mysql_free_result)); if (aq.Callback) aq.Callback(iresult); if (mysql_next_result(&m_Connection) > 0) { std::ostringstream msgbuf; String message = mysql_error(&m_Connection); msgbuf << "Error \"" << message << "\" when executing query \"" << query << "\""; Log(LogCritical, "IdoMysqlConnection", msgbuf.str()); BOOST_THROW_EXCEPTION( database_error() << errinfo_message(mysql_error(&m_Connection)) << errinfo_database_query(query) ); } } offset += count; } } IdoMysqlResult IdoMysqlConnection::Query(const String& query) { AssertOnWorkQueue(); /* finish all async queries to maintain the right order for queries */ FinishAsyncQueries(); Log(LogDebug, "IdoMysqlConnection") << "Query: " << query; IncreaseQueryCount(); if (mysql_query(&m_Connection, query.CStr()) != 0) { std::ostringstream msgbuf; String message = mysql_error(&m_Connection); msgbuf << "Error \"" << message << "\" when executing query \"" << query << "\""; Log(LogCritical, "IdoMysqlConnection", msgbuf.str()); BOOST_THROW_EXCEPTION( database_error() << errinfo_message(mysql_error(&m_Connection)) << errinfo_database_query(query) ); } MYSQL_RES *result = mysql_store_result(&m_Connection); m_AffectedRows = mysql_affected_rows(&m_Connection); if (!result) { if (mysql_field_count(&m_Connection) > 0) { std::ostringstream msgbuf; String message = mysql_error(&m_Connection); msgbuf << "Error \"" << message << "\" when executing query \"" << query << "\""; Log(LogCritical, "IdoMysqlConnection", msgbuf.str()); BOOST_THROW_EXCEPTION( database_error() << errinfo_message(mysql_error(&m_Connection)) << errinfo_database_query(query) ); } return IdoMysqlResult(); } return IdoMysqlResult(result, std::ptr_fun(mysql_free_result)); } DbReference IdoMysqlConnection::GetLastInsertID(void) { AssertOnWorkQueue(); return DbReference(mysql_insert_id(&m_Connection)); } int IdoMysqlConnection::GetAffectedRows(void) { AssertOnWorkQueue(); return m_AffectedRows; } String IdoMysqlConnection::Escape(const String& s) { AssertOnWorkQueue(); String utf8s = Utility::ValidateUTF8(s); size_t length = utf8s.GetLength(); char *to = new char[utf8s.GetLength() * 2 + 1]; mysql_real_escape_string(&m_Connection, to, utf8s.CStr(), length); String result = String(to); delete [] to; return result; } Dictionary::Ptr IdoMysqlConnection::FetchRow(const IdoMysqlResult& result) { AssertOnWorkQueue(); MYSQL_ROW row; MYSQL_FIELD *field; unsigned long *lengths, i; row = mysql_fetch_row(result.get()); if (!row) return Dictionary::Ptr(); lengths = mysql_fetch_lengths(result.get()); if (!lengths) return Dictionary::Ptr(); Dictionary::Ptr dict = new Dictionary(); mysql_field_seek(result.get(), 0); for (field = mysql_fetch_field(result.get()), i = 0; field; field = mysql_fetch_field(result.get()), i++) dict->Set(field->name, String(row[i], row[i] + lengths[i])); return dict; } void IdoMysqlConnection::DiscardRows(const IdoMysqlResult& result) { Dictionary::Ptr row; while ((row = FetchRow(result))) ; /* empty loop body */ } void IdoMysqlConnection::ActivateObject(const DbObject::Ptr& dbobj) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling object activation task for '" << dbobj->GetName1() << "!" << dbobj->GetName2() << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalActivateObject, this, dbobj), PriorityLow); } void IdoMysqlConnection::InternalActivateObject(const DbObject::Ptr& dbobj) { AssertOnWorkQueue(); if (!GetConnected()) return; DbReference dbref = GetObjectID(dbobj); std::ostringstream qbuf; if (!dbref.IsValid()) { if (!dbobj->GetName2().IsEmpty()) { qbuf << "INSERT INTO " + GetTablePrefix() + "objects (instance_id, objecttype_id, name1, name2, is_active) VALUES (" << static_cast(m_InstanceID) << ", " << dbobj->GetType()->GetTypeID() << ", " << "'" << Escape(dbobj->GetName1()) << "', '" << Escape(dbobj->GetName2()) << "', 1)"; } else { qbuf << "INSERT INTO " + GetTablePrefix() + "objects (instance_id, objecttype_id, name1, is_active) VALUES (" << static_cast(m_InstanceID) << ", " << dbobj->GetType()->GetTypeID() << ", " << "'" << Escape(dbobj->GetName1()) << "', 1)"; } Query(qbuf.str()); SetObjectID(dbobj, GetLastInsertID()); } else { qbuf << "UPDATE " + GetTablePrefix() + "objects SET is_active = 1 WHERE object_id = " << static_cast(dbref); AsyncQuery(qbuf.str()); } } void IdoMysqlConnection::DeactivateObject(const DbObject::Ptr& dbobj) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling object deactivation task for '" << dbobj->GetName1() << "!" << dbobj->GetName2() << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalDeactivateObject, this, dbobj), PriorityLow); } void IdoMysqlConnection::InternalDeactivateObject(const DbObject::Ptr& dbobj) { AssertOnWorkQueue(); if (!GetConnected()) return; DbReference dbref = GetObjectID(dbobj); if (!dbref.IsValid()) return; std::ostringstream qbuf; qbuf << "UPDATE " + GetTablePrefix() + "objects SET is_active = 0 WHERE object_id = " << static_cast(dbref); AsyncQuery(qbuf.str()); /* Note that we're _NOT_ clearing the db refs via SetReference/SetConfigUpdate/SetStatusUpdate * because the object is still in the database. */ } bool IdoMysqlConnection::FieldToEscapedString(const String& key, const Value& value, Value *result) { if (key == "instance_id") { *result = static_cast(m_InstanceID); return true; } else if (key == "session_token") { *result = GetSessionToken(); return true; } Value rawvalue = DbValue::ExtractValue(value); if (rawvalue.IsObjectType()) { DbObject::Ptr dbobjcol = DbObject::GetOrCreateByObject(rawvalue); if (!dbobjcol) { *result = 0; return true; } if (!IsIDCacheValid()) return false; DbReference dbrefcol; if (DbValue::IsObjectInsertID(value)) { dbrefcol = GetInsertID(dbobjcol); if (!dbrefcol.IsValid()) return false; } else { dbrefcol = GetObjectID(dbobjcol); if (!dbrefcol.IsValid()) { InternalActivateObject(dbobjcol); dbrefcol = GetObjectID(dbobjcol); if (!dbrefcol.IsValid()) return false; } } *result = static_cast(dbrefcol); } else if (DbValue::IsTimestamp(value)) { long ts = rawvalue; std::ostringstream msgbuf; msgbuf << "FROM_UNIXTIME(" << ts << ")"; *result = Value(msgbuf.str()); } else if (DbValue::IsTimestampNow(value)) { *result = "NOW()"; } else if (DbValue::IsObjectInsertID(value)) { long id = static_cast(rawvalue); if (id <= 0) return false; *result = id; return true; } else { Value fvalue; if (rawvalue.IsBoolean()) fvalue = Convert::ToLong(rawvalue); else fvalue = rawvalue; *result = "'" + Escape(fvalue) + "'"; } return true; } void IdoMysqlConnection::ExecuteQuery(const DbQuery& query) { ASSERT(query.Category != DbCatInvalid); #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling execute query task, type " << query.Type << ", table '" << query.Table << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteQuery, this, query, -1), query.Priority, true); } void IdoMysqlConnection::ExecuteMultipleQueries(const std::vector& queries) { if (queries.empty()) return; #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling multiple execute query task, type " << queries[0].Type << ", table '" << queries[0].Table << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteMultipleQueries, this, queries), queries[0].Priority, true); } bool IdoMysqlConnection::CanExecuteQuery(const DbQuery& query) { if (query.Object && !IsIDCacheValid()) return false; if (query.WhereCriteria) { ObjectLock olock(query.WhereCriteria); Value value; for (const Dictionary::Pair& kv : query.WhereCriteria) { if (!FieldToEscapedString(kv.first, kv.second, &value)) return false; } } if (query.Fields) { ObjectLock olock(query.Fields); for (const Dictionary::Pair& kv : query.Fields) { Value value; if (kv.second.IsEmpty() && !kv.second.IsString()) continue; if (!FieldToEscapedString(kv.first, kv.second, &value)) return false; } } return true; } void IdoMysqlConnection::InternalExecuteMultipleQueries(const std::vector& queries) { AssertOnWorkQueue(); if (!GetConnected()) return; for (const DbQuery& query : queries) { ASSERT(query.Type == DbQueryNewTransaction || query.Category != DbCatInvalid); if (!CanExecuteQuery(query)) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling multiple execute query task again: Cannot execute query now. Type '" << query.Type << "', table '" << query.Table << "', queue size: '" << GetPendingQueryCount() << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteMultipleQueries, this, queries), query.Priority); return; } } for (const DbQuery& query : queries) { InternalExecuteQuery(query); } } void IdoMysqlConnection::InternalExecuteQuery(const DbQuery& query, int typeOverride) { AssertOnWorkQueue(); if (!GetConnected()) return; if (query.Type == DbQueryNewTransaction) { InternalNewTransaction(); return; } /* check whether we're allowed to execute the query first */ if (GetCategoryFilter() != DbCatEverything && (query.Category & GetCategoryFilter()) == 0) return; if (query.Object && query.Object->GetObject()->GetExtension("agent_check").ToBool()) return; /* check if there are missing object/insert ids and re-enqueue the query */ if (!CanExecuteQuery(query)) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling execute query task again: Cannot execute query now. Type '" << typeOverride << "', table '" << query.Table << "', queue size: '" << GetPendingQueryCount() << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteQuery, this, query, typeOverride), query.Priority); return; } std::ostringstream qbuf, where; int type; if (query.WhereCriteria) { where << " WHERE "; ObjectLock olock(query.WhereCriteria); Value value; bool first = true; for (const Dictionary::Pair& kv : query.WhereCriteria) { if (!FieldToEscapedString(kv.first, kv.second, &value)) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling execute query task again: Cannot execute query now. Type '" << typeOverride << "', table '" << query.Table << "', queue size: '" << GetPendingQueryCount() << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteQuery, this, query, -1), query.Priority); return; } if (!first) where << " AND "; where << kv.first << " = " << value; if (first) first = false; } } type = (typeOverride != -1) ? typeOverride : query.Type; bool upsert = false; if ((type & DbQueryInsert) && (type & DbQueryUpdate)) { bool hasid = false; if (query.Object) { if (query.ConfigUpdate) hasid = GetConfigUpdate(query.Object); else if (query.StatusUpdate) hasid = GetStatusUpdate(query.Object); } if (!hasid) upsert = true; type = DbQueryUpdate; } if ((type & DbQueryInsert) && (type & DbQueryDelete)) { std::ostringstream qdel; qdel << "DELETE FROM " << GetTablePrefix() << query.Table << where.str(); AsyncQuery(qdel.str()); type = DbQueryInsert; } switch (type) { case DbQueryInsert: qbuf << "INSERT INTO " << GetTablePrefix() << query.Table; break; case DbQueryUpdate: qbuf << "UPDATE " << GetTablePrefix() << query.Table << " SET"; break; case DbQueryDelete: qbuf << "DELETE FROM " << GetTablePrefix() << query.Table; break; default: VERIFY(!"Invalid query type."); } if (type == DbQueryInsert || type == DbQueryUpdate) { std::ostringstream colbuf, valbuf; if (type == DbQueryUpdate && query.Fields->GetLength() == 0) return; ObjectLock olock(query.Fields); bool first = true; for (const Dictionary::Pair& kv : query.Fields) { Value value; if (kv.second.IsEmpty() && !kv.second.IsString()) continue; if (!FieldToEscapedString(kv.first, kv.second, &value)) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Scheduling execute query task again: Cannot extract required INSERT/UPDATE fields, key '" << kv.first << "', val '" << kv.second << "', type " << typeOverride << ", table '" << query.Table << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteQuery, this, query, -1), query.Priority); return; } if (type == DbQueryInsert) { if (!first) { colbuf << ", "; valbuf << ", "; } colbuf << kv.first; valbuf << value; } else { if (!first) qbuf << ", "; qbuf << " " << kv.first << " = " << value; } if (first) first = false; } if (type == DbQueryInsert) qbuf << " (" << colbuf.str() << ") VALUES (" << valbuf.str() << ")"; } if (type != DbQueryInsert) qbuf << where.str(); AsyncQuery(qbuf.str(), boost::bind(&IdoMysqlConnection::FinishExecuteQuery, this, query, type, upsert)); } void IdoMysqlConnection::FinishExecuteQuery(const DbQuery& query, int type, bool upsert) { if (upsert && GetAffectedRows() == 0) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Rescheduling DELETE/INSERT query: Upsert UPDATE did not affect rows, type " << type << ", table '" << query.Table << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalExecuteQuery, this, query, DbQueryDelete | DbQueryInsert), query.Priority); return; } if (type == DbQueryInsert && query.Object) { if (query.ConfigUpdate) { SetInsertID(query.Object, GetLastInsertID()); SetConfigUpdate(query.Object, true); } else if (query.StatusUpdate) SetStatusUpdate(query.Object, true); } if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationInsertID) query.NotificationInsertID->SetValue(static_cast(GetLastInsertID())); } void IdoMysqlConnection::CleanUpExecuteQuery(const String& table, const String& time_column, double max_age) { #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "IdoMysqlConnection") << "Rescheduling cleanup query for table '" << table << "' and column '" << time_column << "'. max_age is set to '" << max_age << "'."; #endif /* I2_DEBUG */ m_QueryQueue.Enqueue(boost::bind(&IdoMysqlConnection::InternalCleanUpExecuteQuery, this, table, time_column, max_age), PriorityLow, true); } void IdoMysqlConnection::InternalCleanUpExecuteQuery(const String& table, const String& time_column, double max_age) { AssertOnWorkQueue(); if (!GetConnected()) return; AsyncQuery("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast(m_InstanceID)) + " AND " + time_column + " < FROM_UNIXTIME(" + Convert::ToString(static_cast(max_age)) + ")"); } void IdoMysqlConnection::FillIDCache(const DbType::Ptr& type) { String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id, config_hash FROM " + GetTablePrefix() + type->GetTable() + "s"; IdoMysqlResult result = Query(query); Dictionary::Ptr row; while ((row = FetchRow(result))) { DbReference dbref(row->Get("object_id")); SetInsertID(type, dbref, DbReference(row->Get(type->GetTable() + "_id"))); SetConfigHash(type, dbref, row->Get("config_hash")); } } int IdoMysqlConnection::GetPendingQueryCount(void) const { return m_QueryQueue.GetLength(); } icinga2-2.8.1/lib/db_ido_mysql/idomysqlconnection.hpp000066400000000000000000000105431322762156600227200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef IDOMYSQLCONNECTION_H #define IDOMYSQLCONNECTION_H #include "db_ido_mysql/idomysqlconnection.thpp" #include "base/array.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include namespace icinga { typedef boost::shared_ptr IdoMysqlResult; typedef boost::function IdoAsyncCallback; struct IdoAsyncQuery { String Query; IdoAsyncCallback Callback; }; /** * An IDO MySQL database connection. * * @ingroup ido */ class IdoMysqlConnection : public ObjectImpl { public: DECLARE_OBJECT(IdoMysqlConnection); DECLARE_OBJECTNAME(IdoMysqlConnection); IdoMysqlConnection(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual int GetPendingQueryCount(void) const override; protected: virtual void OnConfigLoaded(void) override; virtual void Resume(void) override; virtual void Pause(void) override; virtual void ActivateObject(const DbObject::Ptr& dbobj) override; virtual void DeactivateObject(const DbObject::Ptr& dbobj) override; virtual void ExecuteQuery(const DbQuery& query) override; virtual void ExecuteMultipleQueries(const std::vector& queries) override; virtual void CleanUpExecuteQuery(const String& table, const String& time_key, double time_value) override; virtual void FillIDCache(const DbType::Ptr& type) override; virtual void NewTransaction(void) override; private: DbReference m_InstanceID; WorkQueue m_QueryQueue; MYSQL m_Connection; int m_AffectedRows; unsigned int m_MaxPacketSize; std::vector m_AsyncQueries; Timer::Ptr m_ReconnectTimer; Timer::Ptr m_TxTimer; IdoMysqlResult Query(const String& query); DbReference GetLastInsertID(void); int GetAffectedRows(void); String Escape(const String& s); Dictionary::Ptr FetchRow(const IdoMysqlResult& result); void DiscardRows(const IdoMysqlResult& result); void AsyncQuery(const String& query, const IdoAsyncCallback& callback = IdoAsyncCallback()); void FinishAsyncQueries(void); bool FieldToEscapedString(const String& key, const Value& value, Value *result); void InternalActivateObject(const DbObject::Ptr& dbobj); void InternalDeactivateObject(const DbObject::Ptr& dbobj); void Disconnect(void); void Reconnect(void); void AssertOnWorkQueue(void); void TxTimerHandler(void); void ReconnectTimerHandler(void); bool CanExecuteQuery(const DbQuery& query); void InternalExecuteQuery(const DbQuery& query, int typeOverride = -1); void InternalExecuteMultipleQueries(const std::vector& queries); void FinishExecuteQuery(const DbQuery& query, int type, bool upsert); void InternalCleanUpExecuteQuery(const String& table, const String& time_key, double time_value); void InternalNewTransaction(void); void ClearTableBySession(const String& table); void ClearTablesBySession(void); void ExceptionHandler(boost::exception_ptr exp); void FinishConnect(double startTime); }; } #endif /* IDOMYSQLCONNECTION_H */ icinga2-2.8.1/lib/db_ido_mysql/idomysqlconnection.ti000066400000000000000000000042211322762156600225410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbconnection.hpp" library db_ido_mysql; namespace icinga { class IdoMysqlConnection : DbConnection { [config] String host { default {{{ return "localhost"; }}} }; [config] int port { default {{{ return 3306; }}} }; [config] String socket_path; [config] String user { default {{{ return "icinga"; }}} }; [config] String password { default {{{ return "icinga"; }}} }; [config] String database { default {{{ return "icinga"; }}} }; [config] bool enable_ssl; [config] String ssl_key; [config] String ssl_cert; [config] String ssl_ca; [config] String ssl_capath; [config] String ssl_cipher; [config] String instance_name { default {{{ return "default"; }}} }; [config] String instance_description; }; } icinga2-2.8.1/lib/db_ido_mysql/schema/000077500000000000000000000000001322762156600175235ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_mysql/schema/mysql.sql000066400000000000000000002051141322762156600214140ustar00rootroot00000000000000-- -------------------------------------------------------- -- mysql.sql -- DB definition for IDO MySQL -- -- Copyright (c) 2009-2017 Icinga Development Team (https://www.icinga.com/) -- -- -- -------------------------------------------------------- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; -- -- Database: icinga -- -- -------------------------------------------------------- -- -- Table structure for table icinga_acknowledgements -- CREATE TABLE IF NOT EXISTS icinga_acknowledgements ( acknowledgement_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, entry_time timestamp NULL, entry_time_usec int default 0, acknowledgement_type smallint default 0, object_id bigint unsigned default 0, state smallint default 0, author_name varchar(64) character set latin1 default '', comment_data TEXT character set latin1, is_sticky smallint default 0, persistent_comment smallint default 0, notify_contacts smallint default 0, end_time timestamp NULL, PRIMARY KEY (acknowledgement_id) ) ENGINE=InnoDB COMMENT='Current and historical host and service acknowledgements'; -- -------------------------------------------------------- -- -- Table structure for table icinga_commands -- CREATE TABLE IF NOT EXISTS icinga_commands ( command_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, object_id bigint unsigned default 0, command_line TEXT character set latin1, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (command_id), UNIQUE KEY instance_id (instance_id,object_id,config_type) ) ENGINE=InnoDB COMMENT='Command definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_commenthistory -- CREATE TABLE IF NOT EXISTS icinga_commenthistory ( commenthistory_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, entry_time timestamp NULL, entry_time_usec int default 0, comment_type smallint default 0, entry_type smallint default 0, object_id bigint unsigned default 0, comment_time timestamp NULL, internal_comment_id bigint unsigned default 0, author_name varchar(64) character set latin1 default '', comment_data TEXT character set latin1, is_persistent smallint default 0, comment_source smallint default 0, expires smallint default 0, expiration_time timestamp NULL, deletion_time timestamp NULL, deletion_time_usec int default 0, name TEXT character set latin1 default NULL, PRIMARY KEY (commenthistory_id) ) ENGINE=InnoDB COMMENT='Historical host and service comments'; -- -------------------------------------------------------- -- -- Table structure for table icinga_comments -- CREATE TABLE IF NOT EXISTS icinga_comments ( comment_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, entry_time timestamp NULL, entry_time_usec int default 0, comment_type smallint default 0, entry_type smallint default 0, object_id bigint unsigned default 0, comment_time timestamp NULL, internal_comment_id bigint unsigned default 0, author_name varchar(64) character set latin1 default '', comment_data TEXT character set latin1, is_persistent smallint default 0, comment_source smallint default 0, expires smallint default 0, expiration_time timestamp NULL, name TEXT character set latin1 default NULL, session_token int default NULL, PRIMARY KEY (comment_id) ) ENGINE=InnoDB COMMENT='Usercomments on Icinga objects'; -- -------------------------------------------------------- -- -- Table structure for table icinga_configfiles -- CREATE TABLE IF NOT EXISTS icinga_configfiles ( configfile_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, configfile_type smallint default 0, configfile_path varchar(255) character set latin1 default '', PRIMARY KEY (configfile_id), UNIQUE KEY instance_id (instance_id,configfile_type,configfile_path) ) ENGINE=InnoDB COMMENT='Configuration files'; -- -------------------------------------------------------- -- -- Table structure for table icinga_configfilevariables -- CREATE TABLE IF NOT EXISTS icinga_configfilevariables ( configfilevariable_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, configfile_id bigint unsigned default 0, varname varchar(64) character set latin1 default '', varvalue TEXT character set latin1, PRIMARY KEY (configfilevariable_id) ) ENGINE=InnoDB COMMENT='Configuration file variables'; -- -------------------------------------------------------- -- -- Table structure for table icinga_conninfo -- CREATE TABLE IF NOT EXISTS icinga_conninfo ( conninfo_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, agent_name varchar(32) character set latin1 default '', agent_version varchar(32) character set latin1 default '', disposition varchar(32) character set latin1 default '', connect_source varchar(32) character set latin1 default '', connect_type varchar(32) character set latin1 default '', connect_time timestamp NULL, disconnect_time timestamp NULL, last_checkin_time timestamp NULL, data_start_time timestamp NULL, data_end_time timestamp NULL, bytes_processed bigint unsigned default '0', lines_processed bigint unsigned default '0', entries_processed bigint unsigned default '0', PRIMARY KEY (conninfo_id) ) ENGINE=InnoDB COMMENT='IDO2DB daemon connection information'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactgroups -- CREATE TABLE IF NOT EXISTS icinga_contactgroups ( contactgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, contactgroup_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (contactgroup_id), UNIQUE KEY instance_id (instance_id,config_type,contactgroup_object_id) ) ENGINE=InnoDB COMMENT='Contactgroup definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactgroup_members -- CREATE TABLE IF NOT EXISTS icinga_contactgroup_members ( contactgroup_member_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, contactgroup_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, PRIMARY KEY (contactgroup_member_id) ) ENGINE=InnoDB COMMENT='Contactgroup members'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactnotificationmethods -- CREATE TABLE IF NOT EXISTS icinga_contactnotificationmethods ( contactnotificationmethod_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, contactnotification_id bigint unsigned default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, command_object_id bigint unsigned default 0, command_args TEXT character set latin1, PRIMARY KEY (contactnotificationmethod_id), UNIQUE KEY instance_id (instance_id,contactnotification_id,start_time,start_time_usec) ) ENGINE=InnoDB COMMENT='Historical record of contact notification methods'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactnotifications -- CREATE TABLE IF NOT EXISTS icinga_contactnotifications ( contactnotification_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, notification_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, PRIMARY KEY (contactnotification_id), UNIQUE KEY instance_id (instance_id,contact_object_id,start_time,start_time_usec) ) ENGINE=InnoDB COMMENT='Historical record of contact notifications'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contacts -- CREATE TABLE IF NOT EXISTS icinga_contacts ( contact_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, contact_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', email_address varchar(255) character set latin1 default '', pager_address varchar(64) character set latin1 default '', host_timeperiod_object_id bigint unsigned default 0, service_timeperiod_object_id bigint unsigned default 0, host_notifications_enabled smallint default 0, service_notifications_enabled smallint default 0, can_submit_commands smallint default 0, notify_service_recovery smallint default 0, notify_service_warning smallint default 0, notify_service_unknown smallint default 0, notify_service_critical smallint default 0, notify_service_flapping smallint default 0, notify_service_downtime smallint default 0, notify_host_recovery smallint default 0, notify_host_down smallint default 0, notify_host_unreachable smallint default 0, notify_host_flapping smallint default 0, notify_host_downtime smallint default 0, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (contact_id), UNIQUE KEY instance_id (instance_id,config_type,contact_object_id) ) ENGINE=InnoDB COMMENT='Contact definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactstatus -- CREATE TABLE IF NOT EXISTS icinga_contactstatus ( contactstatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, status_update_time timestamp NULL, host_notifications_enabled smallint default 0, service_notifications_enabled smallint default 0, last_host_notification timestamp NULL, last_service_notification timestamp NULL, modified_attributes int default 0, modified_host_attributes int default 0, modified_service_attributes int default 0, PRIMARY KEY (contactstatus_id), UNIQUE KEY contact_object_id (contact_object_id) ) ENGINE=InnoDB COMMENT='Contact status'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contact_addresses -- CREATE TABLE IF NOT EXISTS icinga_contact_addresses ( contact_address_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, contact_id bigint unsigned default 0, address_number smallint default 0, address varchar(255) character set latin1 default '', PRIMARY KEY (contact_address_id), UNIQUE KEY contact_id (contact_id,address_number) ) ENGINE=InnoDB COMMENT='Contact addresses'; -- -------------------------------------------------------- -- -- Table structure for table icinga_contact_notificationcommands -- CREATE TABLE IF NOT EXISTS icinga_contact_notificationcommands ( contact_notificationcommand_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, contact_id bigint unsigned default 0, notification_type smallint default 0, command_object_id bigint unsigned default 0, command_args varchar(255) character set latin1 default '', PRIMARY KEY (contact_notificationcommand_id), UNIQUE KEY contact_id (contact_id,notification_type,command_object_id,command_args) ) ENGINE=InnoDB COMMENT='Contact host and service notification commands'; -- -------------------------------------------------------- -- -- Table structure for table icinga_customvariables -- CREATE TABLE IF NOT EXISTS icinga_customvariables ( customvariable_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, object_id bigint unsigned default 0, config_type smallint default 0, has_been_modified smallint default 0, varname varchar(255) character set latin1 collate latin1_general_cs default NULL, varvalue TEXT character set latin1, is_json smallint default 0, PRIMARY KEY (customvariable_id), UNIQUE KEY object_id_2 (object_id,config_type,varname), KEY varname (varname) ) ENGINE=InnoDB COMMENT='Custom variables'; -- -------------------------------------------------------- -- -- Table structure for table icinga_customvariablestatus -- CREATE TABLE IF NOT EXISTS icinga_customvariablestatus ( customvariablestatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, object_id bigint unsigned default 0, status_update_time timestamp NULL, has_been_modified smallint default 0, varname varchar(255) character set latin1 collate latin1_general_cs default NULL, varvalue TEXT character set latin1, is_json smallint default 0, PRIMARY KEY (customvariablestatus_id), UNIQUE KEY object_id_2 (object_id,varname), KEY varname (varname) ) ENGINE=InnoDB COMMENT='Custom variable status information'; -- -------------------------------------------------------- -- -- Table structure for table icinga_dbversion -- CREATE TABLE IF NOT EXISTS icinga_dbversion ( dbversion_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, name varchar(10) character set latin1 default '', version varchar(10) character set latin1 default '', create_time timestamp NULL, modify_time timestamp NULL, PRIMARY KEY (dbversion_id), UNIQUE KEY dbversion (name) ) ENGINE=InnoDB; -- -------------------------------------------------------- -- -- Table structure for table icinga_downtimehistory -- CREATE TABLE IF NOT EXISTS icinga_downtimehistory ( downtimehistory_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, downtime_type smallint default 0, object_id bigint unsigned default 0, entry_time timestamp NULL, author_name varchar(64) character set latin1 default '', comment_data TEXT character set latin1, internal_downtime_id bigint unsigned default 0, triggered_by_id bigint unsigned default 0, is_fixed smallint default 0, duration bigint(20) default 0, scheduled_start_time timestamp NULL, scheduled_end_time timestamp NULL, was_started smallint default 0, actual_start_time timestamp NULL, actual_start_time_usec int default 0, actual_end_time timestamp NULL, actual_end_time_usec int default 0, was_cancelled smallint default 0, is_in_effect smallint default 0, trigger_time timestamp NULL, name TEXT character set latin1 default NULL, PRIMARY KEY (downtimehistory_id) ) ENGINE=InnoDB COMMENT='Historical scheduled host and service downtime'; -- -------------------------------------------------------- -- -- Table structure for table icinga_eventhandlers -- CREATE TABLE IF NOT EXISTS icinga_eventhandlers ( eventhandler_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, eventhandler_type smallint default 0, object_id bigint unsigned default 0, state smallint default 0, state_type smallint default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, command_object_id bigint unsigned default 0, command_args TEXT character set latin1, command_line TEXT character set latin1, timeout smallint default 0, early_timeout smallint default 0, execution_time double default '0', return_code smallint default 0, output TEXT character set latin1, long_output TEXT, PRIMARY KEY (eventhandler_id), UNIQUE KEY instance_id (instance_id,object_id,start_time,start_time_usec) ) ENGINE=InnoDB COMMENT='Historical host and service event handlers'; -- -------------------------------------------------------- -- -- Table structure for table icinga_externalcommands -- CREATE TABLE IF NOT EXISTS icinga_externalcommands ( externalcommand_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, entry_time timestamp NULL, command_type smallint default 0, command_name varchar(128) character set latin1 default '', command_args TEXT character set latin1, PRIMARY KEY (externalcommand_id) ) ENGINE=InnoDB COMMENT='Historical record of processed external commands'; -- -------------------------------------------------------- -- -- Table structure for table icinga_flappinghistory -- CREATE TABLE IF NOT EXISTS icinga_flappinghistory ( flappinghistory_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, event_time timestamp NULL, event_time_usec int default 0, event_type smallint default 0, reason_type smallint default 0, flapping_type smallint default 0, object_id bigint unsigned default 0, percent_state_change double default '0', low_threshold double default '0', high_threshold double default '0', comment_time timestamp NULL, internal_comment_id bigint unsigned default 0, PRIMARY KEY (flappinghistory_id) ) ENGINE=InnoDB COMMENT='Current and historical record of host and service flapping'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostchecks -- CREATE TABLE IF NOT EXISTS icinga_hostchecks ( hostcheck_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, host_object_id bigint unsigned default 0, check_type smallint default 0, is_raw_check smallint default 0, current_check_attempt smallint default 0, max_check_attempts smallint default 0, state smallint default 0, state_type smallint default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, command_object_id bigint unsigned default 0, command_args TEXT character set latin1, command_line TEXT character set latin1, timeout smallint default 0, early_timeout smallint default 0, execution_time double default '0', latency double default '0', return_code smallint default 0, output TEXT character set latin1, long_output TEXT, perfdata TEXT character set latin1, PRIMARY KEY (hostcheck_id) ) ENGINE=InnoDB COMMENT='Historical host checks'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostdependencies -- CREATE TABLE IF NOT EXISTS icinga_hostdependencies ( hostdependency_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, host_object_id bigint unsigned default 0, dependent_host_object_id bigint unsigned default 0, dependency_type smallint default 0, inherits_parent smallint default 0, timeperiod_object_id bigint unsigned default 0, fail_on_up smallint default 0, fail_on_down smallint default 0, fail_on_unreachable smallint default 0, PRIMARY KEY (hostdependency_id), KEY instance_id (instance_id,config_type,host_object_id,dependent_host_object_id,dependency_type,inherits_parent,fail_on_up,fail_on_down,fail_on_unreachable) ) ENGINE=InnoDB COMMENT='Host dependency definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalations -- CREATE TABLE IF NOT EXISTS icinga_hostescalations ( hostescalation_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, host_object_id bigint unsigned default 0, timeperiod_object_id bigint unsigned default 0, first_notification smallint default 0, last_notification smallint default 0, notification_interval double default '0', escalate_on_recovery smallint default 0, escalate_on_down smallint default 0, escalate_on_unreachable smallint default 0, PRIMARY KEY (hostescalation_id), UNIQUE KEY instance_id (instance_id,config_type,host_object_id,timeperiod_object_id,first_notification,last_notification) ) ENGINE=InnoDB COMMENT='Host escalation definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalation_contactgroups -- CREATE TABLE IF NOT EXISTS icinga_hostescalation_contactgroups ( hostescalation_contactgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, hostescalation_id bigint unsigned default 0, contactgroup_object_id bigint unsigned default 0, PRIMARY KEY (hostescalation_contactgroup_id), UNIQUE KEY instance_id (hostescalation_id,contactgroup_object_id) ) ENGINE=InnoDB COMMENT='Host escalation contact groups'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalation_contacts -- CREATE TABLE IF NOT EXISTS icinga_hostescalation_contacts ( hostescalation_contact_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, hostescalation_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, PRIMARY KEY (hostescalation_contact_id), UNIQUE KEY instance_id (instance_id,hostescalation_id,contact_object_id) ) ENGINE=InnoDB COMMENT='Host escalation contacts'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostgroups -- CREATE TABLE IF NOT EXISTS icinga_hostgroups ( hostgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, hostgroup_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', notes TEXT character set latin1 default NULL, notes_url TEXT character set latin1 default NULL, action_url TEXT character set latin1 default NULL, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (hostgroup_id), UNIQUE KEY instance_id (instance_id,hostgroup_object_id) ) ENGINE=InnoDB COMMENT='Hostgroup definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostgroup_members -- CREATE TABLE IF NOT EXISTS icinga_hostgroup_members ( hostgroup_member_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, hostgroup_id bigint unsigned default 0, host_object_id bigint unsigned default 0, PRIMARY KEY (hostgroup_member_id) ) ENGINE=InnoDB COMMENT='Hostgroup members'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hosts -- CREATE TABLE IF NOT EXISTS icinga_hosts ( host_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, host_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', display_name varchar(255) character set latin1 collate latin1_general_cs default '', address varchar(128) character set latin1 default '', address6 varchar(128) character set latin1 default '', check_command_object_id bigint unsigned default 0, check_command_args TEXT character set latin1, eventhandler_command_object_id bigint unsigned default 0, eventhandler_command_args TEXT character set latin1, notification_timeperiod_object_id bigint unsigned default 0, check_timeperiod_object_id bigint unsigned default 0, failure_prediction_options varchar(128) character set latin1 default '', check_interval double default '0', retry_interval double default '0', max_check_attempts smallint default 0, first_notification_delay double default '0', notification_interval double default '0', notify_on_down smallint default 0, notify_on_unreachable smallint default 0, notify_on_recovery smallint default 0, notify_on_flapping smallint default 0, notify_on_downtime smallint default 0, stalk_on_up smallint default 0, stalk_on_down smallint default 0, stalk_on_unreachable smallint default 0, flap_detection_enabled smallint default 0, flap_detection_on_up smallint default 0, flap_detection_on_down smallint default 0, flap_detection_on_unreachable smallint default 0, low_flap_threshold double default '0', high_flap_threshold double default '0', process_performance_data smallint default 0, freshness_checks_enabled smallint default 0, freshness_threshold int default 0, passive_checks_enabled smallint default 0, event_handler_enabled smallint default 0, active_checks_enabled smallint default 0, retain_status_information smallint default 0, retain_nonstatus_information smallint default 0, notifications_enabled smallint default 0, obsess_over_host smallint default 0, failure_prediction_enabled smallint default 0, notes TEXT character set latin1, notes_url TEXT character set latin1, action_url TEXT character set latin1, icon_image TEXT character set latin1, icon_image_alt TEXT character set latin1, vrml_image TEXT character set latin1, statusmap_image TEXT character set latin1, have_2d_coords smallint default 0, x_2d smallint default 0, y_2d smallint default 0, have_3d_coords smallint default 0, x_3d double default '0', y_3d double default '0', z_3d double default '0', config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (host_id), UNIQUE KEY instance_id (instance_id,config_type,host_object_id), KEY host_object_id (host_object_id) ) ENGINE=InnoDB COMMENT='Host definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_hoststatus -- CREATE TABLE IF NOT EXISTS icinga_hoststatus ( hoststatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, host_object_id bigint unsigned default 0, status_update_time timestamp NULL, output TEXT character set latin1, long_output TEXT, perfdata TEXT character set latin1, check_source varchar(255) character set latin1 default '', current_state smallint default 0, has_been_checked smallint default 0, should_be_scheduled smallint default 0, current_check_attempt smallint default 0, max_check_attempts smallint default 0, last_check timestamp NULL, next_check timestamp NULL, check_type smallint default 0, last_state_change timestamp NULL, last_hard_state_change timestamp NULL, last_hard_state smallint default 0, last_time_up timestamp NULL, last_time_down timestamp NULL, last_time_unreachable timestamp NULL, state_type smallint default 0, last_notification timestamp NULL, next_notification timestamp NULL, no_more_notifications smallint default 0, notifications_enabled smallint default 0, problem_has_been_acknowledged smallint default 0, acknowledgement_type smallint default 0, current_notification_number int unsigned default 0, passive_checks_enabled smallint default 0, active_checks_enabled smallint default 0, event_handler_enabled smallint default 0, flap_detection_enabled smallint default 0, is_flapping smallint default 0, percent_state_change double default '0', latency double default '0', execution_time double default '0', scheduled_downtime_depth smallint default 0, failure_prediction_enabled smallint default 0, process_performance_data smallint default 0, obsess_over_host smallint default 0, modified_host_attributes int default 0, original_attributes TEXT character set latin1 default NULL, event_handler TEXT character set latin1, check_command TEXT character set latin1, normal_check_interval double default '0', retry_check_interval double default '0', check_timeperiod_object_id bigint unsigned default 0, is_reachable smallint default 0, PRIMARY KEY (hoststatus_id), UNIQUE KEY object_id (host_object_id) ) ENGINE=InnoDB COMMENT='Current host status information'; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_contactgroups -- CREATE TABLE IF NOT EXISTS icinga_host_contactgroups ( host_contactgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, host_id bigint unsigned default 0, contactgroup_object_id bigint unsigned default 0, PRIMARY KEY (host_contactgroup_id) ) ENGINE=InnoDB COMMENT='Host contact groups'; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_contacts -- CREATE TABLE IF NOT EXISTS icinga_host_contacts ( host_contact_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, host_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, PRIMARY KEY (host_contact_id) ) ENGINE=InnoDB COMMENT='Host contacts'; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_parenthosts -- CREATE TABLE IF NOT EXISTS icinga_host_parenthosts ( host_parenthost_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, host_id bigint unsigned default 0, parent_host_object_id bigint unsigned default 0, PRIMARY KEY (host_parenthost_id) ) ENGINE=InnoDB COMMENT='Parent hosts'; -- -------------------------------------------------------- -- -- Table structure for table icinga_instances -- CREATE TABLE IF NOT EXISTS icinga_instances ( instance_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_name varchar(64) character set latin1 default '', instance_description varchar(128) character set latin1 default '', PRIMARY KEY (instance_id) ) ENGINE=InnoDB COMMENT='Location names of various Icinga installations'; -- -------------------------------------------------------- -- -- Table structure for table icinga_logentries -- CREATE TABLE IF NOT EXISTS icinga_logentries ( logentry_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, logentry_time timestamp NULL, entry_time timestamp NULL, entry_time_usec int default 0, logentry_type int default 0, logentry_data TEXT character set latin1, realtime_data smallint default 0, inferred_data_extracted smallint default 0, object_id bigint unsigned default NULL, PRIMARY KEY (logentry_id) ) ENGINE=InnoDB COMMENT='Historical record of log entries'; -- -------------------------------------------------------- -- -- Table structure for table icinga_notifications -- CREATE TABLE IF NOT EXISTS icinga_notifications ( notification_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, notification_type smallint default 0, notification_reason smallint default 0, object_id bigint unsigned default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, state smallint default 0, output TEXT character set latin1, long_output TEXT, escalated smallint default 0, contacts_notified smallint default 0, PRIMARY KEY (notification_id), UNIQUE KEY instance_id (instance_id,object_id,start_time,start_time_usec) ) ENGINE=InnoDB COMMENT='Historical record of host and service notifications'; -- -------------------------------------------------------- -- -- Table structure for table icinga_objects -- CREATE TABLE IF NOT EXISTS icinga_objects ( object_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, objecttype_id bigint unsigned default 0, name1 varchar(128) character set latin1 collate latin1_general_cs default '', name2 varchar(128) character set latin1 collate latin1_general_cs default NULL, is_active smallint default 0, PRIMARY KEY (object_id), KEY objecttype_id (objecttype_id,name1,name2) ) ENGINE=InnoDB COMMENT='Current and historical objects of all kinds'; -- -------------------------------------------------------- -- -- Table structure for table icinga_processevents -- CREATE TABLE IF NOT EXISTS icinga_processevents ( processevent_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, event_type smallint default 0, event_time timestamp NULL, event_time_usec int default 0, process_id bigint unsigned default 0, program_name varchar(16) character set latin1 default '', program_version varchar(20) character set latin1 default '', program_date varchar(10) character set latin1 default '', PRIMARY KEY (processevent_id) ) ENGINE=InnoDB COMMENT='Historical Icinga process events'; -- -------------------------------------------------------- -- -- Table structure for table icinga_programstatus -- CREATE TABLE IF NOT EXISTS icinga_programstatus ( programstatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, program_version varchar(64) character set latin1 collate latin1_general_cs default NULL, status_update_time timestamp NULL, program_start_time timestamp NULL, program_end_time timestamp NULL, endpoint_name varchar(255) character set latin1 collate latin1_general_cs default NULL, is_currently_running smallint default 0, process_id bigint unsigned default 0, daemon_mode smallint default 0, last_command_check timestamp NULL, last_log_rotation timestamp NULL, notifications_enabled smallint default 0, disable_notif_expire_time timestamp NULL, active_service_checks_enabled smallint default 0, passive_service_checks_enabled smallint default 0, active_host_checks_enabled smallint default 0, passive_host_checks_enabled smallint default 0, event_handlers_enabled smallint default 0, flap_detection_enabled smallint default 0, failure_prediction_enabled smallint default 0, process_performance_data smallint default 0, obsess_over_hosts smallint default 0, obsess_over_services smallint default 0, modified_host_attributes int default 0, modified_service_attributes int default 0, global_host_event_handler TEXT character set latin1, global_service_event_handler TEXT character set latin1, config_dump_in_progress smallint default 0, PRIMARY KEY (programstatus_id), UNIQUE KEY instance_id (instance_id) ) ENGINE=InnoDB COMMENT='Current program status information'; -- -------------------------------------------------------- -- -- Table structure for table icinga_runtimevariables -- CREATE TABLE IF NOT EXISTS icinga_runtimevariables ( runtimevariable_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, varname varchar(64) character set latin1 default '', varvalue TEXT character set latin1, PRIMARY KEY (runtimevariable_id) ) ENGINE=InnoDB COMMENT='Runtime variables from the Icinga daemon'; -- -------------------------------------------------------- -- -- Table structure for table icinga_scheduleddowntime -- CREATE TABLE IF NOT EXISTS icinga_scheduleddowntime ( scheduleddowntime_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, downtime_type smallint default 0, object_id bigint unsigned default 0, entry_time timestamp NULL, author_name varchar(64) character set latin1 default '', comment_data TEXT character set latin1, internal_downtime_id bigint unsigned default 0, triggered_by_id bigint unsigned default 0, is_fixed smallint default 0, duration bigint(20) default 0, scheduled_start_time timestamp NULL, scheduled_end_time timestamp NULL, was_started smallint default 0, actual_start_time timestamp NULL, actual_start_time_usec int default 0, is_in_effect smallint default 0, trigger_time timestamp NULL, name TEXT character set latin1 default NULL, session_token int default NULL, PRIMARY KEY (scheduleddowntime_id) ) ENGINE=InnoDB COMMENT='Current scheduled host and service downtime'; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicechecks -- CREATE TABLE IF NOT EXISTS icinga_servicechecks ( servicecheck_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, service_object_id bigint unsigned default 0, check_type smallint default 0, current_check_attempt smallint default 0, max_check_attempts smallint default 0, state smallint default 0, state_type smallint default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, command_object_id bigint unsigned default 0, command_args TEXT character set latin1, command_line TEXT character set latin1, timeout smallint default 0, early_timeout smallint default 0, execution_time double default '0', latency double default '0', return_code smallint default 0, output TEXT character set latin1, long_output TEXT, perfdata TEXT character set latin1, PRIMARY KEY (servicecheck_id) ) ENGINE=InnoDB COMMENT='Historical service checks'; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicedependencies -- CREATE TABLE IF NOT EXISTS icinga_servicedependencies ( servicedependency_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, service_object_id bigint unsigned default 0, dependent_service_object_id bigint unsigned default 0, dependency_type smallint default 0, inherits_parent smallint default 0, timeperiod_object_id bigint unsigned default 0, fail_on_ok smallint default 0, fail_on_warning smallint default 0, fail_on_unknown smallint default 0, fail_on_critical smallint default 0, PRIMARY KEY (servicedependency_id), KEY instance_id (instance_id,config_type,service_object_id,dependent_service_object_id,dependency_type,inherits_parent,fail_on_ok,fail_on_warning,fail_on_unknown,fail_on_critical) ) ENGINE=InnoDB COMMENT='Service dependency definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalations -- CREATE TABLE IF NOT EXISTS icinga_serviceescalations ( serviceescalation_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, service_object_id bigint unsigned default 0, timeperiod_object_id bigint unsigned default 0, first_notification smallint default 0, last_notification smallint default 0, notification_interval double default '0', escalate_on_recovery smallint default 0, escalate_on_warning smallint default 0, escalate_on_unknown smallint default 0, escalate_on_critical smallint default 0, PRIMARY KEY (serviceescalation_id), UNIQUE KEY instance_id (instance_id,config_type,service_object_id,timeperiod_object_id,first_notification,last_notification) ) ENGINE=InnoDB COMMENT='Service escalation definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalation_contactgroups -- CREATE TABLE IF NOT EXISTS icinga_serviceescalation_contactgroups ( serviceescalation_contactgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, serviceescalation_id bigint unsigned default 0, contactgroup_object_id bigint unsigned default 0, PRIMARY KEY (serviceescalation_contactgroup_id), UNIQUE KEY instance_id (serviceescalation_id,contactgroup_object_id) ) ENGINE=InnoDB COMMENT='Service escalation contact groups'; -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalation_contacts -- CREATE TABLE IF NOT EXISTS icinga_serviceescalation_contacts ( serviceescalation_contact_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, serviceescalation_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, PRIMARY KEY (serviceescalation_contact_id), UNIQUE KEY instance_id (instance_id,serviceescalation_id,contact_object_id) ) ENGINE=InnoDB COMMENT='Service escalation contacts'; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicegroups -- CREATE TABLE IF NOT EXISTS icinga_servicegroups ( servicegroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, servicegroup_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', notes TEXT character set latin1 default NULL, notes_url TEXT character set latin1 default NULL, action_url TEXT character set latin1 default NULL, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (servicegroup_id), UNIQUE KEY instance_id (instance_id,config_type,servicegroup_object_id) ) ENGINE=InnoDB COMMENT='Servicegroup definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicegroup_members -- CREATE TABLE IF NOT EXISTS icinga_servicegroup_members ( servicegroup_member_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, servicegroup_id bigint unsigned default 0, service_object_id bigint unsigned default 0, PRIMARY KEY (servicegroup_member_id) ) ENGINE=InnoDB COMMENT='Servicegroup members'; -- -------------------------------------------------------- -- -- Table structure for table icinga_services -- CREATE TABLE IF NOT EXISTS icinga_services ( service_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, host_object_id bigint unsigned default 0, service_object_id bigint unsigned default 0, display_name varchar(255) character set latin1 collate latin1_general_cs default '', check_command_object_id bigint unsigned default 0, check_command_args TEXT character set latin1, eventhandler_command_object_id bigint unsigned default 0, eventhandler_command_args TEXT character set latin1, notification_timeperiod_object_id bigint unsigned default 0, check_timeperiod_object_id bigint unsigned default 0, failure_prediction_options varchar(64) character set latin1 default '', check_interval double default '0', retry_interval double default '0', max_check_attempts smallint default 0, first_notification_delay double default '0', notification_interval double default '0', notify_on_warning smallint default 0, notify_on_unknown smallint default 0, notify_on_critical smallint default 0, notify_on_recovery smallint default 0, notify_on_flapping smallint default 0, notify_on_downtime smallint default 0, stalk_on_ok smallint default 0, stalk_on_warning smallint default 0, stalk_on_unknown smallint default 0, stalk_on_critical smallint default 0, is_volatile smallint default 0, flap_detection_enabled smallint default 0, flap_detection_on_ok smallint default 0, flap_detection_on_warning smallint default 0, flap_detection_on_unknown smallint default 0, flap_detection_on_critical smallint default 0, low_flap_threshold double default '0', high_flap_threshold double default '0', process_performance_data smallint default 0, freshness_checks_enabled smallint default 0, freshness_threshold int default 0, passive_checks_enabled smallint default 0, event_handler_enabled smallint default 0, active_checks_enabled smallint default 0, retain_status_information smallint default 0, retain_nonstatus_information smallint default 0, notifications_enabled smallint default 0, obsess_over_service smallint default 0, failure_prediction_enabled smallint default 0, notes TEXT character set latin1, notes_url TEXT character set latin1, action_url TEXT character set latin1, icon_image TEXT character set latin1, icon_image_alt TEXT character set latin1, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (service_id), UNIQUE KEY instance_id (instance_id,config_type,service_object_id), KEY service_object_id (service_object_id) ) ENGINE=InnoDB COMMENT='Service definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicestatus -- CREATE TABLE IF NOT EXISTS icinga_servicestatus ( servicestatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, service_object_id bigint unsigned default 0, status_update_time timestamp NULL, output TEXT character set latin1, long_output TEXT, perfdata TEXT character set latin1, check_source varchar(255) character set latin1 default '', current_state smallint default 0, has_been_checked smallint default 0, should_be_scheduled smallint default 0, current_check_attempt smallint default 0, max_check_attempts smallint default 0, last_check timestamp NULL, next_check timestamp NULL, check_type smallint default 0, last_state_change timestamp NULL, last_hard_state_change timestamp NULL, last_hard_state smallint default 0, last_time_ok timestamp NULL, last_time_warning timestamp NULL, last_time_unknown timestamp NULL, last_time_critical timestamp NULL, state_type smallint default 0, last_notification timestamp NULL, next_notification timestamp NULL, no_more_notifications smallint default 0, notifications_enabled smallint default 0, problem_has_been_acknowledged smallint default 0, acknowledgement_type smallint default 0, current_notification_number int unsigned default 0, passive_checks_enabled smallint default 0, active_checks_enabled smallint default 0, event_handler_enabled smallint default 0, flap_detection_enabled smallint default 0, is_flapping smallint default 0, percent_state_change double default '0', latency double default '0', execution_time double default '0', scheduled_downtime_depth smallint default 0, failure_prediction_enabled smallint default 0, process_performance_data smallint default 0, obsess_over_service smallint default 0, modified_service_attributes int default 0, original_attributes TEXT character set latin1 default NULL, event_handler TEXT character set latin1, check_command TEXT character set latin1, normal_check_interval double default '0', retry_check_interval double default '0', check_timeperiod_object_id bigint unsigned default 0, is_reachable smallint default 0, PRIMARY KEY (servicestatus_id), UNIQUE KEY object_id (service_object_id) ) ENGINE=InnoDB COMMENT='Current service status information'; -- -------------------------------------------------------- -- -- Table structure for table icinga_service_contactgroups -- CREATE TABLE IF NOT EXISTS icinga_service_contactgroups ( service_contactgroup_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, service_id bigint unsigned default 0, contactgroup_object_id bigint unsigned default 0, PRIMARY KEY (service_contactgroup_id) ) ENGINE=InnoDB COMMENT='Service contact groups'; -- -------------------------------------------------------- -- -- Table structure for table icinga_service_contacts -- CREATE TABLE IF NOT EXISTS icinga_service_contacts ( service_contact_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, service_id bigint unsigned default 0, contact_object_id bigint unsigned default 0, PRIMARY KEY (service_contact_id) ) ENGINE=InnoDB COMMENT='Service contacts'; -- -------------------------------------------------------- -- -- Table structure for table icinga_statehistory -- CREATE TABLE IF NOT EXISTS icinga_statehistory ( statehistory_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, state_time timestamp NULL, state_time_usec int default 0, object_id bigint unsigned default 0, state_change smallint default 0, state smallint default 0, state_type smallint default 0, current_check_attempt smallint default 0, max_check_attempts smallint default 0, last_state smallint default 0, last_hard_state smallint default 0, output TEXT character set latin1, long_output TEXT, check_source varchar(255) character set latin1 default NULL, PRIMARY KEY (statehistory_id) ) ENGINE=InnoDB COMMENT='Historical host and service state changes'; -- -------------------------------------------------------- -- -- Table structure for table icinga_systemcommands -- CREATE TABLE IF NOT EXISTS icinga_systemcommands ( systemcommand_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, start_time timestamp NULL, start_time_usec int default 0, end_time timestamp NULL, end_time_usec int default 0, command_line TEXT character set latin1, timeout smallint default 0, early_timeout smallint default 0, execution_time double default '0', return_code smallint default 0, output TEXT character set latin1, long_output TEXT, PRIMARY KEY (systemcommand_id), UNIQUE KEY instance_id (instance_id,start_time,start_time_usec) ) ENGINE=InnoDB COMMENT='Historical system commands that are executed'; -- -------------------------------------------------------- -- -- Table structure for table icinga_timeperiods -- CREATE TABLE IF NOT EXISTS icinga_timeperiods ( timeperiod_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, config_type smallint default 0, timeperiod_object_id bigint unsigned default 0, alias varchar(255) character set latin1 default '', config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (timeperiod_id), UNIQUE KEY instance_id (instance_id,config_type,timeperiod_object_id) ) ENGINE=InnoDB COMMENT='Timeperiod definitions'; -- -------------------------------------------------------- -- -- Table structure for table icinga_timeperiod_timeranges -- CREATE TABLE IF NOT EXISTS icinga_timeperiod_timeranges ( timeperiod_timerange_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, timeperiod_id bigint unsigned default 0, day smallint default 0, start_sec int default 0, end_sec int default 0, PRIMARY KEY (timeperiod_timerange_id) ) ENGINE=InnoDB COMMENT='Timeperiod definitions'; -- -------------------------------------------------------- -- Icinga 2 specific schema extensions -- -------------------------------------------------------- -- -- Table structure for table icinga_endpoints -- CREATE TABLE IF NOT EXISTS icinga_endpoints ( endpoint_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, endpoint_object_id bigint(20) unsigned DEFAULT '0', zone_object_id bigint(20) unsigned DEFAULT '0', config_type smallint(6) DEFAULT '0', identity varchar(255) DEFAULT NULL, node varchar(255) DEFAULT NULL, config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (endpoint_id) ) ENGINE=InnoDB COMMENT='Endpoint configuration'; -- -------------------------------------------------------- -- -- Table structure for table icinga_endpointstatus -- CREATE TABLE IF NOT EXISTS icinga_endpointstatus ( endpointstatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, endpoint_object_id bigint(20) unsigned DEFAULT '0', zone_object_id bigint(20) unsigned DEFAULT '0', status_update_time timestamp NULL, identity varchar(255) DEFAULT NULL, node varchar(255) DEFAULT NULL, is_connected smallint(6), PRIMARY KEY (endpointstatus_id) ) ENGINE=InnoDB COMMENT='Endpoint status'; -- -- Table structure for table icinga_zones -- CREATE TABLE IF NOT EXISTS icinga_zones ( zone_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, zone_object_id bigint(20) unsigned DEFAULT '0', config_type smallint(6) DEFAULT '0', parent_zone_object_id bigint(20) unsigned DEFAULT '0', is_global smallint(6), config_hash varchar(64) DEFAULT NULL, PRIMARY KEY (zone_id) ) ENGINE=InnoDB COMMENT='Zone configuration'; -- -------------------------------------------------------- -- -- Table structure for table icinga_zonestatus -- CREATE TABLE IF NOT EXISTS icinga_zonestatus ( zonestatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, zone_object_id bigint(20) unsigned DEFAULT '0', status_update_time timestamp NULL, parent_zone_object_id bigint(20) unsigned DEFAULT '0', PRIMARY KEY (zonestatus_id) ) ENGINE=InnoDB COMMENT='Zone status'; ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_contactstatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_programstatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_comments ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_runtimevariables ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_customvariablestatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_contactnotifications ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_downtimehistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_eventhandlers ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_externalcommands ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_flappinghistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_hostchecks ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_logentries ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_notifications ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_processevents ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_servicechecks ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL; -- ----------------------------------------- -- add index (delete) -- ----------------------------------------- -- for periodic delete -- instance_id and -- SYSTEMCOMMANDS, SERVICECHECKS, HOSTCHECKS, EVENTHANDLERS => start_time -- EXTERNALCOMMANDS => entry_time -- instance_id CREATE INDEX systemcommands_i_id_idx on icinga_systemcommands(instance_id); CREATE INDEX servicechecks_i_id_idx on icinga_servicechecks(instance_id); CREATE INDEX hostchecks_i_id_idx on icinga_hostchecks(instance_id); CREATE INDEX eventhandlers_i_id_idx on icinga_eventhandlers(instance_id); CREATE INDEX externalcommands_i_id_idx on icinga_externalcommands(instance_id); -- time CREATE INDEX systemcommands_time_id_idx on icinga_systemcommands(start_time); CREATE INDEX servicechecks_time_id_idx on icinga_servicechecks(start_time); CREATE INDEX hostchecks_time_id_idx on icinga_hostchecks(start_time); CREATE INDEX eventhandlers_time_id_idx on icinga_eventhandlers(start_time); CREATE INDEX externalcommands_time_id_idx on icinga_externalcommands(entry_time); -- for starting cleanup - referenced in dbhandler.c:882 -- instance_id only -- realtime data CREATE INDEX programstatus_i_id_idx on icinga_programstatus(instance_id); CREATE INDEX hoststatus_i_id_idx on icinga_hoststatus(instance_id); CREATE INDEX servicestatus_i_id_idx on icinga_servicestatus(instance_id); CREATE INDEX contactstatus_i_id_idx on icinga_contactstatus(instance_id); CREATE INDEX comments_i_id_idx on icinga_comments(instance_id); CREATE INDEX scheduleddowntime_i_id_idx on icinga_scheduleddowntime(instance_id); CREATE INDEX runtimevariables_i_id_idx on icinga_runtimevariables(instance_id); CREATE INDEX customvariablestatus_i_id_idx on icinga_customvariablestatus(instance_id); -- config data CREATE INDEX configfiles_i_id_idx on icinga_configfiles(instance_id); CREATE INDEX configfilevariables_i_id_idx on icinga_configfilevariables(instance_id); CREATE INDEX customvariables_i_id_idx on icinga_customvariables(instance_id); CREATE INDEX commands_i_id_idx on icinga_commands(instance_id); CREATE INDEX timeperiods_i_id_idx on icinga_timeperiods(instance_id); CREATE INDEX timeperiod_timeranges_i_id_idx on icinga_timeperiod_timeranges(instance_id); CREATE INDEX contactgroups_i_id_idx on icinga_contactgroups(instance_id); CREATE INDEX contactgroup_members_i_id_idx on icinga_contactgroup_members(instance_id); CREATE INDEX hostgroups_i_id_idx on icinga_hostgroups(instance_id); CREATE INDEX hostgroup_members_i_id_idx on icinga_hostgroup_members(instance_id); CREATE INDEX servicegroups_i_id_idx on icinga_servicegroups(instance_id); CREATE INDEX servicegroup_members_i_id_idx on icinga_servicegroup_members(instance_id); CREATE INDEX hostesc_i_id_idx on icinga_hostescalations(instance_id); CREATE INDEX hostesc_contacts_i_id_idx on icinga_hostescalation_contacts(instance_id); CREATE INDEX serviceesc_i_id_idx on icinga_serviceescalations(instance_id); CREATE INDEX serviceesc_contacts_i_id_idx on icinga_serviceescalation_contacts(instance_id); CREATE INDEX hostdependencies_i_id_idx on icinga_hostdependencies(instance_id); CREATE INDEX contacts_i_id_idx on icinga_contacts(instance_id); CREATE INDEX contact_addresses_i_id_idx on icinga_contact_addresses(instance_id); CREATE INDEX contact_notifcommands_i_id_idx on icinga_contact_notificationcommands(instance_id); CREATE INDEX hosts_i_id_idx on icinga_hosts(instance_id); CREATE INDEX host_parenthosts_i_id_idx on icinga_host_parenthosts(instance_id); CREATE INDEX host_contacts_i_id_idx on icinga_host_contacts(instance_id); CREATE INDEX services_i_id_idx on icinga_services(instance_id); CREATE INDEX service_contacts_i_id_idx on icinga_service_contacts(instance_id); CREATE INDEX service_contactgroups_i_id_idx on icinga_service_contactgroups(instance_id); CREATE INDEX host_contactgroups_i_id_idx on icinga_host_contactgroups(instance_id); CREATE INDEX hostesc_cgroups_i_id_idx on icinga_hostescalation_contactgroups(instance_id); CREATE INDEX serviceesc_cgroups_i_id_idx on icinga_serviceescalation_contactgroups(instance_id); -- ----------------------------------------- -- more index stuff (WHERE clauses) -- ----------------------------------------- -- hosts CREATE INDEX hosts_host_object_id_idx on icinga_hosts(host_object_id); -- hoststatus CREATE INDEX hoststatus_stat_upd_time_idx on icinga_hoststatus(status_update_time); CREATE INDEX hoststatus_current_state_idx on icinga_hoststatus(current_state); CREATE INDEX hoststatus_check_type_idx on icinga_hoststatus(check_type); CREATE INDEX hoststatus_state_type_idx on icinga_hoststatus(state_type); CREATE INDEX hoststatus_last_state_chg_idx on icinga_hoststatus(last_state_change); CREATE INDEX hoststatus_notif_enabled_idx on icinga_hoststatus(notifications_enabled); CREATE INDEX hoststatus_problem_ack_idx on icinga_hoststatus(problem_has_been_acknowledged); CREATE INDEX hoststatus_act_chks_en_idx on icinga_hoststatus(active_checks_enabled); CREATE INDEX hoststatus_pas_chks_en_idx on icinga_hoststatus(passive_checks_enabled); CREATE INDEX hoststatus_event_hdl_en_idx on icinga_hoststatus(event_handler_enabled); CREATE INDEX hoststatus_flap_det_en_idx on icinga_hoststatus(flap_detection_enabled); CREATE INDEX hoststatus_is_flapping_idx on icinga_hoststatus(is_flapping); CREATE INDEX hoststatus_p_state_chg_idx on icinga_hoststatus(percent_state_change); CREATE INDEX hoststatus_latency_idx on icinga_hoststatus(latency); CREATE INDEX hoststatus_ex_time_idx on icinga_hoststatus(execution_time); CREATE INDEX hoststatus_sch_downt_d_idx on icinga_hoststatus(scheduled_downtime_depth); -- services CREATE INDEX services_host_object_id_idx on icinga_services(host_object_id); -- servicestatus CREATE INDEX srvcstatus_stat_upd_time_idx on icinga_servicestatus(status_update_time); CREATE INDEX srvcstatus_current_state_idx on icinga_servicestatus(current_state); CREATE INDEX srvcstatus_check_type_idx on icinga_servicestatus(check_type); CREATE INDEX srvcstatus_state_type_idx on icinga_servicestatus(state_type); CREATE INDEX srvcstatus_last_state_chg_idx on icinga_servicestatus(last_state_change); CREATE INDEX srvcstatus_notif_enabled_idx on icinga_servicestatus(notifications_enabled); CREATE INDEX srvcstatus_problem_ack_idx on icinga_servicestatus(problem_has_been_acknowledged); CREATE INDEX srvcstatus_act_chks_en_idx on icinga_servicestatus(active_checks_enabled); CREATE INDEX srvcstatus_pas_chks_en_idx on icinga_servicestatus(passive_checks_enabled); CREATE INDEX srvcstatus_event_hdl_en_idx on icinga_servicestatus(event_handler_enabled); CREATE INDEX srvcstatus_flap_det_en_idx on icinga_servicestatus(flap_detection_enabled); CREATE INDEX srvcstatus_is_flapping_idx on icinga_servicestatus(is_flapping); CREATE INDEX srvcstatus_p_state_chg_idx on icinga_servicestatus(percent_state_change); CREATE INDEX srvcstatus_latency_idx on icinga_servicestatus(latency); CREATE INDEX srvcstatus_ex_time_idx on icinga_servicestatus(execution_time); CREATE INDEX srvcstatus_sch_downt_d_idx on icinga_servicestatus(scheduled_downtime_depth); -- hostchecks CREATE INDEX hostchks_h_obj_id_idx on icinga_hostchecks(host_object_id); -- servicechecks CREATE INDEX servicechks_s_obj_id_idx on icinga_servicechecks(service_object_id); -- objects CREATE INDEX objects_objtype_id_idx ON icinga_objects(objecttype_id); CREATE INDEX objects_name1_idx ON icinga_objects(name1); CREATE INDEX objects_name2_idx ON icinga_objects(name2); CREATE INDEX objects_inst_id_idx ON icinga_objects(instance_id); -- instances -- CREATE INDEX instances_name_idx on icinga_instances(instance_name); -- logentries -- CREATE INDEX loge_instance_id_idx on icinga_logentries(instance_id); -- #236 CREATE INDEX loge_time_idx on icinga_logentries(logentry_time); -- CREATE INDEX loge_data_idx on icinga_logentries(logentry_data); CREATE INDEX loge_inst_id_time_idx on icinga_logentries (instance_id ASC, logentry_time DESC); -- commenthistory -- CREATE INDEX c_hist_instance_id_idx on icinga_logentries(instance_id); -- CREATE INDEX c_hist_c_time_idx on icinga_logentries(comment_time); -- CREATE INDEX c_hist_i_c_id_idx on icinga_logentries(internal_comment_id); -- downtimehistory -- CREATE INDEX d_t_hist_nstance_id_idx on icinga_downtimehistory(instance_id); -- CREATE INDEX d_t_hist_type_idx on icinga_downtimehistory(downtime_type); -- CREATE INDEX d_t_hist_object_id_idx on icinga_downtimehistory(object_id); -- CREATE INDEX d_t_hist_entry_time_idx on icinga_downtimehistory(entry_time); -- CREATE INDEX d_t_hist_sched_start_idx on icinga_downtimehistory(scheduled_start_time); -- CREATE INDEX d_t_hist_sched_end_idx on icinga_downtimehistory(scheduled_end_time); -- scheduleddowntime -- CREATE INDEX sched_d_t_downtime_type_idx on icinga_scheduleddowntime(downtime_type); -- CREATE INDEX sched_d_t_object_id_idx on icinga_scheduleddowntime(object_id); -- CREATE INDEX sched_d_t_entry_time_idx on icinga_scheduleddowntime(entry_time); -- CREATE INDEX sched_d_t_start_time_idx on icinga_scheduleddowntime(scheduled_start_time); -- CREATE INDEX sched_d_t_end_time_idx on icinga_scheduleddowntime(scheduled_end_time); -- statehistory CREATE INDEX statehist_i_id_o_id_s_ty_s_ti on icinga_statehistory(instance_id, object_id, state_type, state_time); -- #2274 create index statehist_state_idx on icinga_statehistory(object_id,state); -- Icinga Web Notifications CREATE INDEX notification_idx ON icinga_notifications(notification_type, object_id, start_time); CREATE INDEX notification_object_id_idx ON icinga_notifications(object_id); CREATE INDEX contact_notification_idx ON icinga_contactnotifications(notification_id, contact_object_id); CREATE INDEX contacts_object_id_idx ON icinga_contacts(contact_object_id); CREATE INDEX contact_notif_meth_notif_idx ON icinga_contactnotificationmethods(contactnotification_id, command_object_id); CREATE INDEX command_object_idx ON icinga_commands(object_id); CREATE INDEX services_combined_object_idx ON icinga_services(service_object_id, host_object_id); -- #2618 CREATE INDEX cntgrpmbrs_cgid_coid ON icinga_contactgroup_members (contactgroup_id,contact_object_id); CREATE INDEX hstgrpmbrs_hgid_hoid ON icinga_hostgroup_members (hostgroup_id,host_object_id); CREATE INDEX hstcntgrps_hid_cgoid ON icinga_host_contactgroups (host_id,contactgroup_object_id); CREATE INDEX hstprnthsts_hid_phoid ON icinga_host_parenthosts (host_id,parent_host_object_id); CREATE INDEX runtimevars_iid_varn ON icinga_runtimevariables (instance_id,varname); CREATE INDEX sgmbrs_sgid_soid ON icinga_servicegroup_members (servicegroup_id,service_object_id); CREATE INDEX scgrps_sid_cgoid ON icinga_service_contactgroups (service_id,contactgroup_object_id); CREATE INDEX tperiod_tid_d_ss_es ON icinga_timeperiod_timeranges (timeperiod_id,day,start_sec,end_sec); -- #3649 CREATE INDEX sla_idx_sthist ON icinga_statehistory (object_id, state_time DESC); CREATE INDEX sla_idx_dohist ON icinga_downtimehistory (object_id, actual_start_time, actual_end_time); CREATE INDEX sla_idx_obj ON icinga_objects (objecttype_id, is_active, name1); -- #4985 CREATE INDEX commenthistory_delete_idx ON icinga_commenthistory (instance_id, comment_time, internal_comment_id); -- #10070 CREATE INDEX idx_comments_object_id on icinga_comments(object_id); CREATE INDEX idx_scheduleddowntime_object_id on icinga_scheduleddowntime(object_id); -- #10066 CREATE INDEX idx_endpoints_object_id on icinga_endpoints(endpoint_object_id); CREATE INDEX idx_endpointstatus_object_id on icinga_endpointstatus(endpoint_object_id); CREATE INDEX idx_endpoints_zone_object_id on icinga_endpoints(zone_object_id); CREATE INDEX idx_endpointstatus_zone_object_id on icinga_endpointstatus(zone_object_id); CREATE INDEX idx_zones_object_id on icinga_zones(zone_object_id); CREATE INDEX idx_zonestatus_object_id on icinga_zonestatus(zone_object_id); CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id); CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id); -- #12210 CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token); CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token); -- #12107 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time); -- #12435 CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id); CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id); CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id); CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id); CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id); CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id); CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id); CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id); -- #5458 create index idx_downtimehistory_remove on icinga_downtimehistory (object_id, entry_time, scheduled_start_time, scheduled_end_time); create index idx_scheduleddowntime_remove on icinga_scheduleddowntime (object_id, entry_time, scheduled_start_time, scheduled_end_time); -- #5492 CREATE INDEX idx_commenthistory_remove ON icinga_commenthistory (object_id, entry_time); CREATE INDEX idx_comments_remove ON icinga_comments (object_id, entry_time); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.3', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.3', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/000077500000000000000000000000001322762156600211525ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.0.2.sql000066400000000000000000000016471322762156600223420ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.0.2 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- UPDATE icinga_objects SET name2 = NULL WHERE name2 = ''; ALTER TABLE `icinga_customvariables` MODIFY COLUMN `varname` varchar(255) character set latin1 collate latin1_general_cs default NULL; ALTER TABLE `icinga_customvariablestatus` MODIFY COLUMN `varname` varchar(255) character set latin1 collate latin1_general_cs default NULL; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.11.6', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.11.6', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.1.0.sql000066400000000000000000000013421322762156600223310ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.1.0 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE `icinga_programstatus` ADD COLUMN `endpoint_name` varchar(255) character set latin1 collate latin1_general_cs default NULL; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.11.7', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.11.7', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.2.0.sql000066400000000000000000000020031322762156600223250ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.2.0 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE `icinga_programstatus` ADD COLUMN `program_version` varchar(64) character set latin1 collate latin1_general_cs default NULL; ALTER TABLE icinga_contacts MODIFY alias TEXT character set latin1; ALTER TABLE icinga_hosts MODIFY alias TEXT character set latin1; ALTER TABLE icinga_customvariables ADD COLUMN is_json smallint default 0; ALTER TABLE icinga_customvariablestatus ADD COLUMN is_json smallint default 0; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.12.0', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.12.0', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.3.0.sql000066400000000000000000000023651322762156600223410ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.3.0 -- -- ----------------------------------------- -- Copyright (c) 2015 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #7765 drop unique constraint -- ----------------------------------------- ALTER TABLE icinga_servicedependencies DROP KEY instance_id; ALTER TABLE icinga_hostdependencies DROP KEY instance_id; ALTER TABLE icinga_servicedependencies ADD KEY instance_id (instance_id,config_type,service_object_id,dependent_service_object_id,dependency_type,inherits_parent,fail_on_ok,fail_on_warning,fail_on_unknown,fail_on_critical); ALTER TABLE icinga_hostdependencies ADD KEY instance_id (instance_id,config_type,host_object_id,dependent_host_object_id,dependency_type,inherits_parent,fail_on_up,fail_on_down,fail_on_unreachable); -- ----------------------------------------- -- update dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.13.0', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.13.0', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.4.0.sql000066400000000000000000000061041322762156600223350ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.4.0 -- -- ----------------------------------------- -- Copyright (c) 2015 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #9286 - zone tables -- ----------------------------------------- ALTER TABLE icinga_endpoints ADD COLUMN zone_object_id bigint(20) unsigned DEFAULT '0'; ALTER TABLE icinga_endpointstatus ADD COLUMN zone_object_id bigint(20) unsigned DEFAULT '0'; CREATE TABLE IF NOT EXISTS icinga_zones ( zone_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, zone_object_id bigint(20) unsigned DEFAULT '0', config_type smallint(6) DEFAULT '0', parent_zone_object_id bigint(20) unsigned DEFAULT '0', is_global smallint(6), PRIMARY KEY (zone_id) ) ENGINE=InnoDB COMMENT='Zone configuration'; CREATE TABLE IF NOT EXISTS icinga_zonestatus ( zonestatus_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, instance_id bigint unsigned default 0, zone_object_id bigint(20) unsigned DEFAULT '0', status_update_time timestamp NOT NULL, parent_zone_object_id bigint(20) unsigned DEFAULT '0', PRIMARY KEY (zonestatus_id) ) ENGINE=InnoDB COMMENT='Zone status'; -- ----------------------------------------- -- #9576 - freshness_threshold -- ----------------------------------------- ALTER TABLE icinga_services MODIFY freshness_threshold int; ALTER TABLE icinga_hosts MODIFY freshness_threshold int; -- ----------------------------------------- -- #10392 - original attributes -- ----------------------------------------- ALTER TABLE icinga_servicestatus ADD COLUMN original_attributes TEXT character set latin1 default NULL; ALTER TABLE icinga_hoststatus ADD COLUMN original_attributes TEXT character set latin1 default NULL; -- ----------------------------------------- -- #10436 deleted custom vars -- ----------------------------------------- ALTER TABLE icinga_customvariables ADD COLUMN session_token int default NULL; ALTER TABLE icinga_customvariablestatus ADD COLUMN session_token int default NULL; CREATE INDEX cv_session_del_idx ON icinga_customvariables (session_token); CREATE INDEX cvs_session_del_idx ON icinga_customvariablestatus (session_token); -- ----------------------------------------- -- #10431 comment/downtime name -- ----------------------------------------- ALTER TABLE icinga_comments ADD COLUMN name TEXT character set latin1 default NULL; ALTER TABLE icinga_commenthistory ADD COLUMN name TEXT character set latin1 default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN name TEXT character set latin1 default NULL; ALTER TABLE icinga_downtimehistory ADD COLUMN name TEXT character set latin1 default NULL; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.0', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.0', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.5.0.sql000066400000000000000000000122711322762156600223400ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.5.0 -- -- ----------------------------------------- -- Copyright (c) 2016 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- ----------------------------------------- -- #10069 IDO: check_source should not be a TEXT field -- ----------------------------------------- ALTER TABLE icinga_hoststatus MODIFY COLUMN check_source varchar(255) character set latin1 default ''; ALTER TABLE icinga_servicestatus MODIFY COLUMN check_source varchar(255) character set latin1 default ''; -- ----------------------------------------- -- #10070 -- ----------------------------------------- CREATE INDEX idx_comments_object_id on icinga_comments(object_id); CREATE INDEX idx_scheduleddowntime_object_id on icinga_scheduleddowntime(object_id); -- ----------------------------------------- -- #11962 -- ----------------------------------------- ALTER TABLE icinga_hoststatus MODIFY COLUMN current_notification_number int unsigned default 0; ALTER TABLE icinga_servicestatus MODIFY COLUMN current_notification_number int unsigned default 0; -- ----------------------------------------- -- #10061 -- ----------------------------------------- ALTER TABLE icinga_contactgroups MODIFY COLUMN alias varchar(255) character set latin1 default ''; ALTER TABLE icinga_contacts MODIFY COLUMN alias varchar(255) character set latin1 default ''; ALTER TABLE icinga_hostgroups MODIFY COLUMN alias varchar(255) character set latin1 default ''; ALTER TABLE icinga_hosts MODIFY COLUMN alias varchar(255) character set latin1 default ''; ALTER TABLE icinga_servicegroups MODIFY COLUMN alias varchar(255) character set latin1 default ''; ALTER TABLE icinga_timeperiods MODIFY COLUMN alias varchar(255) character set latin1 default ''; -- ----------------------------------------- -- #10066 -- ----------------------------------------- CREATE INDEX idx_endpoints_object_id on icinga_endpoints(endpoint_object_id); CREATE INDEX idx_endpointstatus_object_id on icinga_endpointstatus(endpoint_object_id); CREATE INDEX idx_endpoints_zone_object_id on icinga_endpoints(zone_object_id); CREATE INDEX idx_endpointstatus_zone_object_id on icinga_endpointstatus(zone_object_id); CREATE INDEX idx_zones_object_id on icinga_zones(zone_object_id); CREATE INDEX idx_zonestatus_object_id on icinga_zonestatus(zone_object_id); CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id); CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id); -- ----------------------------------------- -- #12107 -- ----------------------------------------- CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time); -- ----------------------------------------- -- #12258 -- ----------------------------------------- ALTER TABLE icinga_comments ADD COLUMN session_token INTEGER default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN session_token INTEGER default NULL; CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token); CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token); -- ----------------------------------------- -- #12435 -- ----------------------------------------- ALTER TABLE icinga_commands ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_contactgroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_contacts ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_hostgroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_hosts ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_servicegroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_services ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_timeperiods ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_endpoints ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_zones ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_customvariables DROP session_token; ALTER TABLE icinga_customvariablestatus DROP session_token; CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id); CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id); CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id); CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id); CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id); CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id); CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id); CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.1', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.1', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.6.0.sql000066400000000000000000000125241322762156600223420ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.6.0 -- -- ----------------------------------------- -- Copyright (c) 2016 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #10502 IDO: Support NO_ZERO_DATE and NO_ZERO_IN_DATE SQL modes -- ----------------------------------------- ALTER TABLE icinga_acknowledgements MODIFY COLUMN entry_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_commenthistory MODIFY COLUMN entry_time timestamp NULL, MODIFY COLUMN comment_time timestamp NULL, MODIFY COLUMN expiration_time timestamp NULL, MODIFY COLUMN deletion_time timestamp NULL; ALTER TABLE icinga_comments MODIFY COLUMN entry_time timestamp NULL, MODIFY COLUMN comment_time timestamp NULL, MODIFY COLUMN expiration_time timestamp NULL; ALTER TABLE icinga_conninfo MODIFY COLUMN connect_time timestamp NULL, MODIFY COLUMN disconnect_time timestamp NULL, MODIFY COLUMN last_checkin_time timestamp NULL, MODIFY COLUMN data_start_time timestamp NULL, MODIFY COLUMN data_end_time timestamp NULL; ALTER TABLE icinga_contactnotificationmethods MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_contactnotifications MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_contactstatus MODIFY COLUMN status_update_time timestamp NULL, MODIFY COLUMN last_host_notification timestamp NULL, MODIFY COLUMN last_service_notification timestamp NULL; ALTER TABLE icinga_customvariablestatus MODIFY COLUMN status_update_time timestamp NULL; ALTER TABLE icinga_dbversion MODIFY COLUMN create_time timestamp NULL, MODIFY COLUMN modify_time timestamp NULL; ALTER TABLE icinga_downtimehistory MODIFY COLUMN entry_time timestamp NULL, MODIFY COLUMN scheduled_start_time timestamp NULL, MODIFY COLUMN scheduled_end_time timestamp NULL, MODIFY COLUMN actual_start_time timestamp NULL, MODIFY COLUMN actual_end_time timestamp NULL, MODIFY COLUMN trigger_time timestamp NULL; ALTER TABLE icinga_eventhandlers MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_externalcommands MODIFY COLUMN entry_time timestamp NULL; ALTER TABLE icinga_flappinghistory MODIFY COLUMN event_time timestamp NULL, MODIFY COLUMN comment_time timestamp NULL; ALTER TABLE icinga_hostchecks MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_hoststatus MODIFY COLUMN status_update_time timestamp NULL, MODIFY COLUMN last_check timestamp NULL, MODIFY COLUMN next_check timestamp NULL, MODIFY COLUMN last_state_change timestamp NULL, MODIFY COLUMN last_hard_state_change timestamp NULL, MODIFY COLUMN last_time_up timestamp NULL, MODIFY COLUMN last_time_down timestamp NULL, MODIFY COLUMN last_time_unreachable timestamp NULL, MODIFY COLUMN last_notification timestamp NULL, MODIFY COLUMN next_notification timestamp NULL; ALTER TABLE icinga_logentries MODIFY COLUMN logentry_time timestamp NULL, MODIFY COLUMN entry_time timestamp NULL; ALTER TABLE icinga_notifications MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_processevents MODIFY COLUMN event_time timestamp NULL; ALTER TABLE icinga_programstatus MODIFY COLUMN status_update_time timestamp NULL, MODIFY COLUMN program_start_time timestamp NULL, MODIFY COLUMN program_end_time timestamp NULL, MODIFY COLUMN last_command_check timestamp NULL, MODIFY COLUMN last_log_rotation timestamp NULL, MODIFY COLUMN disable_notif_expire_time timestamp NULL; ALTER TABLE icinga_scheduleddowntime MODIFY COLUMN entry_time timestamp NULL, MODIFY COLUMN scheduled_start_time timestamp NULL, MODIFY COLUMN scheduled_end_time timestamp NULL, MODIFY COLUMN actual_start_time timestamp NULL, MODIFY COLUMN trigger_time timestamp NULL; ALTER TABLE icinga_servicechecks MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_servicestatus MODIFY COLUMN status_update_time timestamp NULL, MODIFY COLUMN last_check timestamp NULL, MODIFY COLUMN next_check timestamp NULL, MODIFY COLUMN last_state_change timestamp NULL, MODIFY COLUMN last_hard_state_change timestamp NULL, MODIFY COLUMN last_time_ok timestamp NULL, MODIFY COLUMN last_time_warning timestamp NULL, MODIFY COLUMN last_time_unknown timestamp NULL, MODIFY COLUMN last_time_critical timestamp NULL, MODIFY COLUMN last_notification timestamp NULL, MODIFY COLUMN next_notification timestamp NULL; ALTER TABLE icinga_statehistory MODIFY COLUMN state_time timestamp NULL; ALTER TABLE icinga_systemcommands MODIFY COLUMN start_time timestamp NULL, MODIFY COLUMN end_time timestamp NULL; ALTER TABLE icinga_endpointstatus MODIFY COLUMN status_update_time timestamp NULL; ALTER TABLE icinga_zonestatus MODIFY COLUMN status_update_time timestamp NULL; -- ----------------------------------------- -- set dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.2', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.2', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.8.0.sql000066400000000000000000000056061322762156600223470ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.8.0 -- -- ----------------------------------------- -- Copyright (c) 2017 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- -------------------------------------------------------- -- Helper functions and procedures for DROP INDEX IF EXISTS -- -------------------------------------------------------- DELIMITER // DROP FUNCTION IF EXISTS ido_index_exists // CREATE FUNCTION ido_index_exists( f_table_name varchar(64), f_index_name varchar(64) ) RETURNS BOOL DETERMINISTIC READS SQL DATA BEGIN DECLARE index_exists BOOL DEFAULT FALSE; SELECT EXISTS ( SELECT 1 FROM information_schema.statistics WHERE table_schema = SCHEMA() AND table_name = f_table_name AND index_name = f_index_name ) INTO index_exists; RETURN index_exists; END // DROP PROCEDURE IF EXISTS ido_drop_index_if_exists // CREATE PROCEDURE ido_drop_index_if_exists ( IN p_table_name varchar(64), IN p_index_name varchar(64) ) DETERMINISTIC MODIFIES SQL DATA BEGIN IF ido_index_exists(p_table_name, p_index_name) THEN SET @ido_drop_index_sql = CONCAT('ALTER TABLE `', SCHEMA(), '`.`', p_table_name, '` DROP INDEX `', p_index_name, '`'); PREPARE stmt FROM @ido_drop_index_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ido_drop_index_sql = NULL; END IF; END // DELIMITER ; CALL ido_drop_index_if_exists('icinga_downtimehistory', 'instance_id'); CALL ido_drop_index_if_exists('icinga_scheduleddowntime', 'instance_id'); CALL ido_drop_index_if_exists('icinga_commenthistory', 'instance_id'); CALL ido_drop_index_if_exists('icinga_comments', 'instance_id'); DROP FUNCTION ido_index_exists; DROP PROCEDURE ido_drop_index_if_exists; -- ----------------------------------------- -- #5458 IDO: Improve downtime removal/cancel -- ----------------------------------------- CREATE INDEX idx_downtimehistory_remove ON icinga_downtimehistory (object_id, entry_time, scheduled_start_time, scheduled_end_time); CREATE INDEX idx_scheduleddowntime_remove ON icinga_scheduleddowntime (object_id, entry_time, scheduled_start_time, scheduled_end_time); -- ----------------------------------------- -- #5492 IDO: Improve comment removal -- ----------------------------------------- CREATE INDEX idx_commenthistory_remove ON icinga_commenthistory (object_id, entry_time); CREATE INDEX idx_comments_remove ON icinga_comments (object_id, entry_time); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.3', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.3', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_mysql/schema/upgrade/2.8.1.sql000066400000000000000000000043761322762156600223530ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.8.1 (fix for fresh 2.8.0 installation only) -- -- ----------------------------------------- -- Copyright (c) 2018 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- -------------------------------------------------------- -- Helper functions and procedures for DROP INDEX IF EXISTS -- -------------------------------------------------------- DELIMITER // DROP FUNCTION IF EXISTS ido_index_exists // CREATE FUNCTION ido_index_exists( f_table_name varchar(64), f_index_name varchar(64) ) RETURNS BOOL DETERMINISTIC READS SQL DATA BEGIN DECLARE index_exists BOOL DEFAULT FALSE; SELECT EXISTS ( SELECT 1 FROM information_schema.statistics WHERE table_schema = SCHEMA() AND table_name = f_table_name AND index_name = f_index_name ) INTO index_exists; RETURN index_exists; END // DROP PROCEDURE IF EXISTS ido_drop_index_if_exists // CREATE PROCEDURE ido_drop_index_if_exists ( IN p_table_name varchar(64), IN p_index_name varchar(64) ) DETERMINISTIC MODIFIES SQL DATA BEGIN IF ido_index_exists(p_table_name, p_index_name) THEN SET @ido_drop_index_sql = CONCAT('ALTER TABLE `', SCHEMA(), '`.`', p_table_name, '` DROP INDEX `', p_index_name, '`'); PREPARE stmt FROM @ido_drop_index_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ido_drop_index_sql = NULL; END IF; END // DELIMITER ; CALL ido_drop_index_if_exists('icinga_downtimehistory', 'instance_id'); CALL ido_drop_index_if_exists('icinga_scheduleddowntime', 'instance_id'); CALL ido_drop_index_if_exists('icinga_commenthistory', 'instance_id'); CALL ido_drop_index_if_exists('icinga_comments', 'instance_id'); DROP FUNCTION ido_index_exists; DROP PROCEDURE ido_drop_index_if_exists; -- ----------------------------------------- -- set dbversion (same as 2.8.0) -- ----------------------------------------- INSERT INTO icinga_dbversion (name, version, create_time, modify_time) VALUES ('idoutils', '1.14.3', NOW(), NOW()) ON DUPLICATE KEY UPDATE version='1.14.3', modify_time=NOW(); icinga2-2.8.1/lib/db_ido_pgsql/000077500000000000000000000000001322762156600162445ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_pgsql/CMakeLists.txt000066400000000000000000000046251322762156600210130ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. find_package(PostgreSQL) if(PostgreSQL_FOUND) mkclass_target(idopgsqlconnection.ti idopgsqlconnection.tcpp idopgsqlconnection.thpp) link_directories(${PostgreSQL_LIBRARY_DIRS}) include_directories(${PostgreSQL_INCLUDE_DIRS}) set(db_ido_pgsql_SOURCES idopgsqlconnection.cpp idopgsqlconnection.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(db_ido_pgsql db_ido_pgsql db_ido_pgsql_SOURCES) endif() add_library(db_ido_pgsql SHARED ${db_ido_pgsql_SOURCES}) target_link_libraries(db_ido_pgsql ${Boost_LIBRARIES} ${PostgreSQL_LIBRARIES} base config icinga db_ido) set_target_properties ( db_ido_pgsql PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_DB_IDO_PGSQL_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/ido-pgsql.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install( TARGETS db_ido_pgsql RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 ) install( DIRECTORY schema DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2-ido-pgsql FILES_MATCHING PATTERN "*.sql" ) install( DIRECTORY schema/upgrade DESTINATION ${CMAKE_INSTALL_DATADIR}/icinga2-ido-pgsql/schema FILES_MATCHING PATTERN "*.sql" ) set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) else() message(FATAL_ERROR "You have selected PostgreSQL support, but PostgreSQL could not be found. You can disable the PostgreSQL IDO module using -DICINGA2_WITH_PGSQL=OFF.") endif() icinga2-2.8.1/lib/db_ido_pgsql/idopgsqlconnection.cpp000066400000000000000000000650461322762156600226650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido_pgsql/idopgsqlconnection.hpp" #include "db_ido_pgsql/idopgsqlconnection.tcpp" #include "db_ido/dbtype.hpp" #include "db_ido/dbvalue.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/configtype.hpp" #include "base/exception.hpp" #include "base/context.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(IdoPgsqlConnection); REGISTER_STATSFUNCTION(IdoPgsqlConnection, &IdoPgsqlConnection::StatsFunc); IdoPgsqlConnection::IdoPgsqlConnection(void) : m_QueryQueue(1000000) { m_QueryQueue.SetName("IdoPgsqlConnection, " + GetName()); } void IdoPgsqlConnection::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_QueryQueue.SetName("IdoPgsqlConnection, " + GetName()); } void IdoPgsqlConnection::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const IdoPgsqlConnection::Ptr& idopgsqlconnection : ConfigType::GetObjectsByType()) { size_t queryQueueItems = idopgsqlconnection->m_QueryQueue.GetLength(); double queryQueueItemRate = idopgsqlconnection->m_QueryQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr stats = new Dictionary(); stats->Set("version", idopgsqlconnection->GetSchemaVersion()); stats->Set("instance_name", idopgsqlconnection->GetInstanceName()); stats->Set("connected", idopgsqlconnection->GetConnected()); stats->Set("query_queue_items", queryQueueItems); stats->Set("query_queue_item_rate", queryQueueItemRate); nodes->Set(idopgsqlconnection->GetName(), stats); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_rate", idopgsqlconnection->GetQueryCount(60) / 60.0)); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_1min", idopgsqlconnection->GetQueryCount(60))); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_5mins", idopgsqlconnection->GetQueryCount(5 * 60))); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_15mins", idopgsqlconnection->GetQueryCount(15 * 60))); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_query_queue_items", queryQueueItems)); perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_query_queue_item_rate", queryQueueItemRate)); } status->Set("idopgsqlconnection", nodes); } void IdoPgsqlConnection::Resume(void) { DbConnection::Resume(); Log(LogInformation, "IdoPgsqlConnection") << "'" << GetName() << "' resumed."; SetConnected(false); m_QueryQueue.SetExceptionCallback(boost::bind(&IdoPgsqlConnection::ExceptionHandler, this, _1)); m_TxTimer = new Timer(); m_TxTimer->SetInterval(1); m_TxTimer->OnTimerExpired.connect(boost::bind(&IdoPgsqlConnection::TxTimerHandler, this)); m_TxTimer->Start(); m_ReconnectTimer = new Timer(); m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&IdoPgsqlConnection::ReconnectTimerHandler, this)); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); ASSERT(PQisthreadsafe()); } void IdoPgsqlConnection::Pause(void) { Log(LogInformation, "IdoPgsqlConnection") << "'" << GetName() << "' paused."; m_ReconnectTimer.reset(); DbConnection::Pause(); m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::Disconnect, this), PriorityHigh); m_QueryQueue.Join(); } void IdoPgsqlConnection::ExceptionHandler(boost::exception_ptr exp) { Log(LogWarning, "IdoPgsqlConnection", "Exception during database operation: Verify that your database is operational!"); Log(LogDebug, "IdoPgsqlConnection") << "Exception during database operation: " << DiagnosticInformation(exp); if (GetConnected()) { PQfinish(m_Connection); SetConnected(false); } } void IdoPgsqlConnection::AssertOnWorkQueue(void) { ASSERT(m_QueryQueue.IsWorkerThread()); } void IdoPgsqlConnection::Disconnect(void) { AssertOnWorkQueue(); if (!GetConnected()) return; Query("COMMIT"); PQfinish(m_Connection); SetConnected(false); } void IdoPgsqlConnection::TxTimerHandler(void) { NewTransaction(); } void IdoPgsqlConnection::NewTransaction(void) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalNewTransaction, this), PriorityHigh, true); } void IdoPgsqlConnection::InternalNewTransaction(void) { AssertOnWorkQueue(); if (!GetConnected()) return; Query("COMMIT"); Query("BEGIN"); } void IdoPgsqlConnection::ReconnectTimerHandler(void) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::Reconnect, this), PriorityLow); } void IdoPgsqlConnection::Reconnect(void) { AssertOnWorkQueue(); CONTEXT("Reconnecting to PostgreSQL IDO database '" + GetName() + "'"); double startTime = Utility::GetTime(); SetShouldConnect(true); bool reconnect = false; if (GetConnected()) { /* Check if we're really still connected */ try { Query("SELECT 1"); return; } catch (const std::exception&) { PQfinish(m_Connection); SetConnected(false); reconnect = true; } } ClearIDCache(); String ihost, iport, iuser, ipasswd, idb; const char *host, *port, *user , *passwd, *db; ihost = GetHost(); iport = GetPort(); iuser = GetUser(); ipasswd = GetPassword(); idb = GetDatabase(); host = (!ihost.IsEmpty()) ? ihost.CStr() : NULL; port = (!iport.IsEmpty()) ? iport.CStr() : NULL; user = (!iuser.IsEmpty()) ? iuser.CStr() : NULL; passwd = (!ipasswd.IsEmpty()) ? ipasswd.CStr() : NULL; db = (!idb.IsEmpty()) ? idb.CStr() : NULL; m_Connection = PQsetdbLogin(host, port, NULL, NULL, db, user, passwd); if (!m_Connection) return; if (PQstatus(m_Connection) != CONNECTION_OK) { String message = PQerrorMessage(m_Connection); PQfinish(m_Connection); SetConnected(false); Log(LogCritical, "IdoPgsqlConnection") << "Connection to database '" << db << "' with user '" << user << "' on '" << host << ":" << port << "' failed: \"" << message << "\""; BOOST_THROW_EXCEPTION(std::runtime_error(message)); } SetConnected(true); IdoPgsqlResult result; /* explicitely require legacy mode for string escaping in PostgreSQL >= 9.1 * changing standard_conforming_strings to on by default */ if (PQserverVersion(m_Connection) >= 90100) result = Query("SET standard_conforming_strings TO off"); String dbVersionName = "idoutils"; result = Query("SELECT version FROM " + GetTablePrefix() + "dbversion WHERE name=E'" + Escape(dbVersionName) + "'"); Dictionary::Ptr row = FetchRow(result, 0); if (!row) { PQfinish(m_Connection); SetConnected(false); Log(LogCritical, "IdoPgsqlConnection", "Schema does not provide any valid version! Verify your schema installation."); BOOST_THROW_EXCEPTION(std::runtime_error("Invalid schema.")); } String version = row->Get("version"); SetSchemaVersion(version); if (Utility::CompareVersion(IDO_COMPAT_SCHEMA_VERSION, version) < 0) { PQfinish(m_Connection); SetConnected(false); Log(LogCritical, "IdoPgsqlConnection") << "Schema version '" << version << "' does not match the required version '" << IDO_COMPAT_SCHEMA_VERSION << "' (or newer)! Please check the upgrade documentation at " << "https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/upgrading-icinga-2#upgrading-postgresql-db"; BOOST_THROW_EXCEPTION(std::runtime_error("Schema version mismatch.")); } String instanceName = GetInstanceName(); result = Query("SELECT instance_id FROM " + GetTablePrefix() + "instances WHERE instance_name = E'" + Escape(instanceName) + "'"); row = FetchRow(result, 0); if (!row) { Query("INSERT INTO " + GetTablePrefix() + "instances (instance_name, instance_description) VALUES (E'" + Escape(instanceName) + "', E'" + Escape(GetInstanceDescription()) + "')"); m_InstanceID = GetSequenceValue(GetTablePrefix() + "instances", "instance_id"); } else { m_InstanceID = DbReference(row->Get("instance_id")); } Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint(); /* we have an endpoint in a cluster setup, so decide if we can proceed here */ if (my_endpoint && GetHAMode() == HARunOnce) { /* get the current endpoint writing to programstatus table */ result = Query("SELECT UNIX_TIMESTAMP(status_update_time) AS status_update_time, endpoint_name FROM " + GetTablePrefix() + "programstatus WHERE instance_id = " + Convert::ToString(m_InstanceID)); row = FetchRow(result, 0); String endpoint_name; if (row) endpoint_name = row->Get("endpoint_name"); else Log(LogNotice, "IdoPgsqlConnection", "Empty program status table"); /* if we did not write into the database earlier, another instance is active */ if (endpoint_name != my_endpoint->GetName()) { double status_update_time; if (row) status_update_time = row->Get("status_update_time"); else status_update_time = 0; double status_update_age = Utility::GetTime() - status_update_time; Log(LogNotice, "IdoPgsqlConnection") << "Last update by '" << endpoint_name << "' was " << status_update_age << "s ago."; if (status_update_age < GetFailoverTimeout()) { PQfinish(m_Connection); SetConnected(false); SetShouldConnect(false); return; } /* activate the IDO only, if we're authoritative in this zone */ if (IsPaused()) { Log(LogNotice, "IdoPgsqlConnection") << "Local endpoint '" << my_endpoint->GetName() << "' is not authoritative, bailing out."; PQfinish(m_Connection); SetConnected(false); return; } } Log(LogNotice, "IdoPgsqlConnection", "Enabling IDO connection."); } Log(LogInformation, "IdoPgsqlConnection") << "pgSQL IDO instance id: " << static_cast(m_InstanceID) << " (schema version: '" + version + "')"; Query("BEGIN"); /* update programstatus table */ UpdateProgramStatus(); /* record connection */ Query("INSERT INTO " + GetTablePrefix() + "conninfo " + "(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES (" + Convert::ToString(static_cast(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetAppVersion()) + "', E'" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())"); /* clear config tables for the initial config dump */ PrepareDatabase(); std::ostringstream q1buf; q1buf << "SELECT object_id, objecttype_id, name1, name2, is_active FROM " + GetTablePrefix() + "objects WHERE instance_id = " << static_cast(m_InstanceID); result = Query(q1buf.str()); std::vector activeDbObjs; int index = 0; while ((row = FetchRow(result, index))) { index++; DbType::Ptr dbtype = DbType::GetByID(row->Get("objecttype_id")); if (!dbtype) continue; DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2")); SetObjectID(dbobj, DbReference(row->Get("object_id"))); bool active = row->Get("is_active"); SetObjectActive(dbobj, active); if (active) activeDbObjs.push_back(dbobj); } SetIDCacheValid(true); EnableActiveChangedHandler(); for (const DbObject::Ptr& dbobj : activeDbObjs) { if (dbobj->GetObject()) continue; Log(LogNotice, "IdoPgsqlConnection") << "Deactivate deleted object name1: '" << dbobj->GetName1() << "' name2: '" << dbobj->GetName2() + "'."; DeactivateObject(dbobj); } UpdateAllObjects(); m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::ClearTablesBySession, this), PriorityLow); m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::FinishConnect, this, startTime), PriorityLow); } void IdoPgsqlConnection::FinishConnect(double startTime) { AssertOnWorkQueue(); if (!GetConnected()) return; Log(LogInformation, "IdoPgsqlConnection") << "Finished reconnecting to PostgreSQL IDO database in " << std::setw(2) << Utility::GetTime() - startTime << " second(s)."; Query("COMMIT"); Query("BEGIN"); } void IdoPgsqlConnection::ClearTablesBySession(void) { /* delete all comments and downtimes without current session token */ ClearTableBySession("comments"); ClearTableBySession("scheduleddowntime"); } void IdoPgsqlConnection::ClearTableBySession(const String& table) { Query("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast(m_InstanceID)) + " AND session_token <> " + Convert::ToString(GetSessionToken())); } IdoPgsqlResult IdoPgsqlConnection::Query(const String& query) { AssertOnWorkQueue(); Log(LogDebug, "IdoPgsqlConnection") << "Query: " << query; IncreaseQueryCount(); PGresult *result = PQexec(m_Connection, query.CStr()); if (!result) { String message = PQerrorMessage(m_Connection); Log(LogCritical, "IdoPgsqlConnection") << "Error \"" << message << "\" when executing query \"" << query << "\""; BOOST_THROW_EXCEPTION( database_error() << errinfo_message(message) << errinfo_database_query(query) ); } char *rowCount = PQcmdTuples(result); m_AffectedRows = atoi(rowCount); if (PQresultStatus(result) == PGRES_COMMAND_OK) { PQclear(result); return IdoPgsqlResult(); } if (PQresultStatus(result) != PGRES_TUPLES_OK) { String message = PQresultErrorMessage(result); PQclear(result); Log(LogCritical, "IdoPgsqlConnection") << "Error \"" << message << "\" when executing query \"" << query << "\""; BOOST_THROW_EXCEPTION( database_error() << errinfo_message(message) << errinfo_database_query(query) ); } return IdoPgsqlResult(result, std::ptr_fun(PQclear)); } DbReference IdoPgsqlConnection::GetSequenceValue(const String& table, const String& column) { AssertOnWorkQueue(); IdoPgsqlResult result = Query("SELECT CURRVAL(pg_get_serial_sequence(E'" + Escape(table) + "', E'" + Escape(column) + "')) AS id"); Dictionary::Ptr row = FetchRow(result, 0); ASSERT(row); Log(LogDebug, "IdoPgsqlConnection") << "Sequence Value: " << row->Get("id"); return DbReference(Convert::ToLong(row->Get("id"))); } int IdoPgsqlConnection::GetAffectedRows(void) { AssertOnWorkQueue(); return m_AffectedRows; } String IdoPgsqlConnection::Escape(const String& s) { AssertOnWorkQueue(); String utf8s = Utility::ValidateUTF8(s); size_t length = utf8s.GetLength(); char *to = new char[utf8s.GetLength() * 2 + 1]; PQescapeStringConn(m_Connection, to, utf8s.CStr(), length, NULL); String result = String(to); delete [] to; return result; } Dictionary::Ptr IdoPgsqlConnection::FetchRow(const IdoPgsqlResult& result, int row) { AssertOnWorkQueue(); if (row >= PQntuples(result.get())) return Dictionary::Ptr(); int columns = PQnfields(result.get()); Dictionary::Ptr dict = new Dictionary(); for (int column = 0; column < columns; column++) { Value value; if (!PQgetisnull(result.get(), row, column)) value = PQgetvalue(result.get(), row, column); dict->Set(PQfname(result.get(), column), value); } return dict; } void IdoPgsqlConnection::ActivateObject(const DbObject::Ptr& dbobj) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalActivateObject, this, dbobj), PriorityLow); } void IdoPgsqlConnection::InternalActivateObject(const DbObject::Ptr& dbobj) { AssertOnWorkQueue(); if (!GetConnected()) return; DbReference dbref = GetObjectID(dbobj); std::ostringstream qbuf; if (!dbref.IsValid()) { if (!dbobj->GetName2().IsEmpty()) { qbuf << "INSERT INTO " + GetTablePrefix() + "objects (instance_id, objecttype_id, name1, name2, is_active) VALUES (" << static_cast(m_InstanceID) << ", " << dbobj->GetType()->GetTypeID() << ", " << "E'" << Escape(dbobj->GetName1()) << "', E'" << Escape(dbobj->GetName2()) << "', 1)"; } else { qbuf << "INSERT INTO " + GetTablePrefix() + "objects (instance_id, objecttype_id, name1, is_active) VALUES (" << static_cast(m_InstanceID) << ", " << dbobj->GetType()->GetTypeID() << ", " << "E'" << Escape(dbobj->GetName1()) << "', 1)"; } Query(qbuf.str()); SetObjectID(dbobj, GetSequenceValue(GetTablePrefix() + "objects", "object_id")); } else { qbuf << "UPDATE " + GetTablePrefix() + "objects SET is_active = 1 WHERE object_id = " << static_cast(dbref); Query(qbuf.str()); } } void IdoPgsqlConnection::DeactivateObject(const DbObject::Ptr& dbobj) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalDeactivateObject, this, dbobj), PriorityLow); } void IdoPgsqlConnection::InternalDeactivateObject(const DbObject::Ptr& dbobj) { AssertOnWorkQueue(); if (!GetConnected()) return; DbReference dbref = GetObjectID(dbobj); if (!dbref.IsValid()) return; std::ostringstream qbuf; qbuf << "UPDATE " + GetTablePrefix() + "objects SET is_active = 0 WHERE object_id = " << static_cast(dbref); Query(qbuf.str()); /* Note that we're _NOT_ clearing the db refs via SetReference/SetConfigUpdate/SetStatusUpdate * because the object is still in the database. */ } bool IdoPgsqlConnection::FieldToEscapedString(const String& key, const Value& value, Value *result) { if (key == "instance_id") { *result = static_cast(m_InstanceID); return true; } else if (key == "session_token") { *result = GetSessionToken(); return true; } Value rawvalue = DbValue::ExtractValue(value); if (rawvalue.IsObjectType()) { DbObject::Ptr dbobjcol = DbObject::GetOrCreateByObject(rawvalue); if (!dbobjcol) { *result = 0; return true; } if (!IsIDCacheValid()) return false; DbReference dbrefcol; if (DbValue::IsObjectInsertID(value)) { dbrefcol = GetInsertID(dbobjcol); if (!dbrefcol.IsValid()) return false; } else { dbrefcol = GetObjectID(dbobjcol); if (!dbrefcol.IsValid()) { InternalActivateObject(dbobjcol); dbrefcol = GetObjectID(dbobjcol); if (!dbrefcol.IsValid()) return false; } } *result = static_cast(dbrefcol); } else if (DbValue::IsTimestamp(value)) { long ts = rawvalue; std::ostringstream msgbuf; msgbuf << "TO_TIMESTAMP(" << ts << ") AT TIME ZONE 'UTC'"; *result = Value(msgbuf.str()); } else if (DbValue::IsTimestampNow(value)) { *result = "NOW()"; } else if (DbValue::IsObjectInsertID(value)) { long id = static_cast(rawvalue); if (id <= 0) return false; *result = id; return true; } else { Value fvalue; if (rawvalue.IsBoolean()) fvalue = Convert::ToLong(rawvalue); else fvalue = rawvalue; *result = "E'" + Escape(fvalue) + "'"; } return true; } void IdoPgsqlConnection::ExecuteQuery(const DbQuery& query) { ASSERT(query.Category != DbCatInvalid); m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteQuery, this, query, -1), query.Priority, true); } void IdoPgsqlConnection::ExecuteMultipleQueries(const std::vector& queries) { if (queries.empty()) return; m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteMultipleQueries, this, queries), queries[0].Priority, true); } bool IdoPgsqlConnection::CanExecuteQuery(const DbQuery& query) { if (query.Object && !IsIDCacheValid()) return false; if (query.WhereCriteria) { ObjectLock olock(query.WhereCriteria); Value value; for (const Dictionary::Pair& kv : query.WhereCriteria) { if (!FieldToEscapedString(kv.first, kv.second, &value)) return false; } } if (query.Fields) { ObjectLock olock(query.Fields); for (const Dictionary::Pair& kv : query.Fields) { Value value; if (kv.second.IsEmpty() && !kv.second.IsString()) continue; if (!FieldToEscapedString(kv.first, kv.second, &value)) return false; } } return true; } void IdoPgsqlConnection::InternalExecuteMultipleQueries(const std::vector& queries) { AssertOnWorkQueue(); if (!GetConnected()) return; for (const DbQuery& query : queries) { ASSERT(query.Type == DbQueryNewTransaction || query.Category != DbCatInvalid); if (!CanExecuteQuery(query)) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteMultipleQueries, this, queries), query.Priority); return; } } for (const DbQuery& query : queries) { InternalExecuteQuery(query); } } void IdoPgsqlConnection::InternalExecuteQuery(const DbQuery& query, int typeOverride) { AssertOnWorkQueue(); if (!GetConnected()) return; if (query.Type == DbQueryNewTransaction) { InternalNewTransaction(); return; } /* check whether we're allowed to execute the query first */ if (GetCategoryFilter() != DbCatEverything && (query.Category & GetCategoryFilter()) == 0) return; if (query.Object && query.Object->GetObject()->GetExtension("agent_check").ToBool()) return; /* check if there are missing object/insert ids and re-enqueue the query */ if (!CanExecuteQuery(query)) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteQuery, this, query, typeOverride), query.Priority); return; } std::ostringstream qbuf, where; int type; if (query.WhereCriteria) { where << " WHERE "; ObjectLock olock(query.WhereCriteria); Value value; bool first = true; for (const Dictionary::Pair& kv : query.WhereCriteria) { if (!FieldToEscapedString(kv.first, kv.second, &value)) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteQuery, this, query, -1), query.Priority); return; } if (!first) where << " AND "; where << kv.first << " = " << value; if (first) first = false; } } type = (typeOverride != -1) ? typeOverride : query.Type; bool upsert = false; if ((type & DbQueryInsert) && (type & DbQueryUpdate)) { bool hasid = false; if (query.Object) { if (query.ConfigUpdate) hasid = GetConfigUpdate(query.Object); else if (query.StatusUpdate) hasid = GetStatusUpdate(query.Object); } if (!hasid) upsert = true; type = DbQueryUpdate; } if ((type & DbQueryInsert) && (type & DbQueryDelete)) { std::ostringstream qdel; qdel << "DELETE FROM " << GetTablePrefix() << query.Table << where.str(); Query(qdel.str()); type = DbQueryInsert; } switch (type) { case DbQueryInsert: qbuf << "INSERT INTO " << GetTablePrefix() << query.Table; break; case DbQueryUpdate: qbuf << "UPDATE " << GetTablePrefix() << query.Table << " SET"; break; case DbQueryDelete: qbuf << "DELETE FROM " << GetTablePrefix() << query.Table; break; default: VERIFY(!"Invalid query type."); } if (type == DbQueryInsert || type == DbQueryUpdate) { std::ostringstream colbuf, valbuf; if (type == DbQueryUpdate && query.Fields->GetLength() == 0) return; ObjectLock olock(query.Fields); Value value; bool first = true; for (const Dictionary::Pair& kv : query.Fields) { if (kv.second.IsEmpty() && !kv.second.IsString()) continue; if (!FieldToEscapedString(kv.first, kv.second, &value)) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalExecuteQuery, this, query, -1), query.Priority); return; } if (type == DbQueryInsert) { if (!first) { colbuf << ", "; valbuf << ", "; } colbuf << kv.first; valbuf << value; } else { if (!first) qbuf << ", "; qbuf << " " << kv.first << " = " << value; } if (first) first = false; } if (type == DbQueryInsert) qbuf << " (" << colbuf.str() << ") VALUES (" << valbuf.str() << ")"; } if (type != DbQueryInsert) qbuf << where.str(); Query(qbuf.str()); if (upsert && GetAffectedRows() == 0) { InternalExecuteQuery(query, DbQueryDelete | DbQueryInsert); return; } if (type == DbQueryInsert && query.Object) { if (query.ConfigUpdate) { String idField = query.IdColumn; if (idField.IsEmpty()) idField = query.Table.SubStr(0, query.Table.GetLength() - 1) + "_id"; SetInsertID(query.Object, GetSequenceValue(GetTablePrefix() + query.Table, idField)); SetConfigUpdate(query.Object, true); } else if (query.StatusUpdate) SetStatusUpdate(query.Object, true); } if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationInsertID) { DbReference seqval = GetSequenceValue(GetTablePrefix() + query.Table, "notification_id"); query.NotificationInsertID->SetValue(static_cast(seqval)); } } void IdoPgsqlConnection::CleanUpExecuteQuery(const String& table, const String& time_column, double max_age) { m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::InternalCleanUpExecuteQuery, this, table, time_column, max_age), PriorityLow, true); } void IdoPgsqlConnection::InternalCleanUpExecuteQuery(const String& table, const String& time_column, double max_age) { AssertOnWorkQueue(); if (!GetConnected()) return; Query("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast(m_InstanceID)) + " AND " + time_column + " < TO_TIMESTAMP(" + Convert::ToString(static_cast(max_age)) + ")"); } void IdoPgsqlConnection::FillIDCache(const DbType::Ptr& type) { String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id, config_hash FROM " + GetTablePrefix() + type->GetTable() + "s"; IdoPgsqlResult result = Query(query); Dictionary::Ptr row; int index = 0; while ((row = FetchRow(result, index))) { index++; DbReference dbref(row->Get("object_id")); SetInsertID(type, dbref, DbReference(row->Get(type->GetTable() + "_id"))); SetConfigHash(type, dbref, row->Get("config_hash")); } } int IdoPgsqlConnection::GetPendingQueryCount(void) const { return m_QueryQueue.GetLength(); } icinga2-2.8.1/lib/db_ido_pgsql/idopgsqlconnection.hpp000066400000000000000000000077511322762156600226710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef IDOPGSQLCONNECTION_H #define IDOPGSQLCONNECTION_H #include "db_ido_pgsql/idopgsqlconnection.thpp" #include "base/array.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include namespace icinga { typedef boost::shared_ptr IdoPgsqlResult; /** * An IDO pgSQL database connection. * * @ingroup ido */ class IdoPgsqlConnection : public ObjectImpl { public: DECLARE_OBJECT(IdoPgsqlConnection); DECLARE_OBJECTNAME(IdoPgsqlConnection); IdoPgsqlConnection(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual int GetPendingQueryCount(void) const override; protected: virtual void OnConfigLoaded(void) override; virtual void Resume(void) override; virtual void Pause(void) override; virtual void ActivateObject(const DbObject::Ptr& dbobj) override; virtual void DeactivateObject(const DbObject::Ptr& dbobj) override; virtual void ExecuteQuery(const DbQuery& query) override; virtual void ExecuteMultipleQueries(const std::vector& queries) override; virtual void CleanUpExecuteQuery(const String& table, const String& time_key, double time_value) override; virtual void FillIDCache(const DbType::Ptr& type) override; virtual void NewTransaction(void) override; private: DbReference m_InstanceID; WorkQueue m_QueryQueue; PGconn *m_Connection; int m_AffectedRows; Timer::Ptr m_ReconnectTimer; Timer::Ptr m_TxTimer; IdoPgsqlResult Query(const String& query); DbReference GetSequenceValue(const String& table, const String& column); int GetAffectedRows(void); String Escape(const String& s); Dictionary::Ptr FetchRow(const IdoPgsqlResult& result, int row); bool FieldToEscapedString(const String& key, const Value& value, Value *result); void InternalActivateObject(const DbObject::Ptr& dbobj); void InternalDeactivateObject(const DbObject::Ptr& dbobj); void Disconnect(void); void InternalNewTransaction(void); void Reconnect(void); void AssertOnWorkQueue(void); void TxTimerHandler(void); void ReconnectTimerHandler(void); void StatsLoggerTimerHandler(void); bool CanExecuteQuery(const DbQuery& query); void InternalExecuteQuery(const DbQuery& query, int typeOverride = -1); void InternalExecuteMultipleQueries(const std::vector& queries); void InternalCleanUpExecuteQuery(const String& table, const String& time_key, double time_value); void ClearTableBySession(const String& table); void ClearTablesBySession(void); void ExceptionHandler(boost::exception_ptr exp); void FinishConnect(double startTime); }; } #endif /* IDOPGSQLCONNECTION_H */ icinga2-2.8.1/lib/db_ido_pgsql/idopgsqlconnection.ti000066400000000000000000000037251322762156600225130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "db_ido/dbconnection.hpp" library db_ido_pgsql; namespace icinga { class IdoPgsqlConnection : DbConnection { [config] String host { default {{{ return "localhost"; }}} }; [config] String port { default {{{ return "5432"; }}} }; [config] String user { default {{{ return "icinga"; }}} }; [config] String password { default {{{ return "icinga"; }}} }; [config] String database { default {{{ return "icinga"; }}} }; [config] String instance_name { default {{{ return "default"; }}} }; [config] String instance_description; }; } icinga2-2.8.1/lib/db_ido_pgsql/schema/000077500000000000000000000000001322762156600175045ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_pgsql/schema/pgsql.sql000066400000000000000000001711741322762156600213660ustar00rootroot00000000000000-- -------------------------------------------------------- -- pgsql.sql -- DB definition for IDO Postgresql -- -- Copyright (c) 2009-2017 Icinga Development Team (https://www.icinga.com/) -- -- -------------------------------------------------------- -- -- Functions -- DROP FUNCTION IF EXISTS from_unixtime(bigint); CREATE FUNCTION from_unixtime(bigint) RETURNS timestamp AS $$ SELECT to_timestamp($1) AT TIME ZONE 'UTC' AS result $$ LANGUAGE sql; DROP FUNCTION IF EXISTS unix_timestamp(timestamp WITH TIME ZONE); CREATE OR REPLACE FUNCTION unix_timestamp(timestamp) RETURNS bigint AS ' SELECT CAST(EXTRACT(EPOCH FROM $1) AS bigint) AS result; ' LANGUAGE sql; -- ----------------------------------------- -- set dbversion -- ----------------------------------------- CREATE OR REPLACE FUNCTION updatedbversion(version_i TEXT) RETURNS void AS $$ BEGIN IF EXISTS( SELECT * FROM icinga_dbversion WHERE name='idoutils') THEN UPDATE icinga_dbversion SET version=version_i, modify_time=NOW() WHERE name='idoutils'; ELSE INSERT INTO icinga_dbversion (dbversion_id, name, version, create_time, modify_time) VALUES ('1', 'idoutils', version_i, NOW(), NOW()); END IF; RETURN; END; $$ LANGUAGE plpgsql; -- HINT: su - postgres; createlang plpgsql icinga; -- -- Database: icinga -- -- -------------------------------------------------------- -- -- Table structure for table icinga_acknowledgements -- CREATE TABLE icinga_acknowledgements ( acknowledgement_id bigserial, instance_id bigint default 0, entry_time timestamp, entry_time_usec INTEGER default 0, acknowledgement_type INTEGER default 0, object_id bigint default 0, state INTEGER default 0, author_name TEXT default '', comment_data TEXT default '', is_sticky INTEGER default 0, persistent_comment INTEGER default 0, notify_contacts INTEGER default 0, end_time timestamp, CONSTRAINT PK_acknowledgement_id PRIMARY KEY (acknowledgement_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_commands -- CREATE TABLE icinga_commands ( command_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, object_id bigint default 0, command_line TEXT default '', config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_command_id PRIMARY KEY (command_id) , CONSTRAINT UQ_commands UNIQUE (instance_id,object_id,config_type) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_commenthistory -- CREATE TABLE icinga_commenthistory ( commenthistory_id bigserial, instance_id bigint default 0, entry_time timestamp, entry_time_usec INTEGER default 0, comment_type INTEGER default 0, entry_type INTEGER default 0, object_id bigint default 0, comment_time timestamp, internal_comment_id bigint default 0, author_name TEXT default '', comment_data TEXT default '', is_persistent INTEGER default 0, comment_source INTEGER default 0, expires INTEGER default 0, expiration_time timestamp, deletion_time timestamp, deletion_time_usec INTEGER default 0, name TEXT default NULL, CONSTRAINT PK_commenthistory_id PRIMARY KEY (commenthistory_id) ); -- -------------------------------------------------------- -- -- Table structure for table icinga_comments -- CREATE TABLE icinga_comments ( comment_id bigserial, instance_id bigint default 0, entry_time timestamp, entry_time_usec INTEGER default 0, comment_type INTEGER default 0, entry_type INTEGER default 0, object_id bigint default 0, comment_time timestamp, internal_comment_id bigint default 0, author_name TEXT default '', comment_data TEXT default '', is_persistent INTEGER default 0, comment_source INTEGER default 0, expires INTEGER default 0, expiration_time timestamp, name TEXT default NULL, session_token INTEGER default NULL, CONSTRAINT PK_comment_id PRIMARY KEY (comment_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_configfiles -- CREATE TABLE icinga_configfiles ( configfile_id bigserial, instance_id bigint default 0, configfile_type INTEGER default 0, configfile_path TEXT default '', CONSTRAINT PK_configfile_id PRIMARY KEY (configfile_id) , CONSTRAINT UQ_configfiles UNIQUE (instance_id,configfile_type,configfile_path) ); -- -------------------------------------------------------- -- -- Table structure for table icinga_configfilevariables -- CREATE TABLE icinga_configfilevariables ( configfilevariable_id bigserial, instance_id bigint default 0, configfile_id bigint default 0, varname TEXT default '', varvalue TEXT default '', CONSTRAINT PK_configfilevariable_id PRIMARY KEY (configfilevariable_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_conninfo -- CREATE TABLE icinga_conninfo ( conninfo_id bigserial, instance_id bigint default 0, agent_name TEXT default '', agent_version TEXT default '', disposition TEXT default '', connect_source TEXT default '', connect_type TEXT default '', connect_time timestamp, disconnect_time timestamp, last_checkin_time timestamp, data_start_time timestamp, data_end_time timestamp, bytes_processed bigint default 0, lines_processed bigint default 0, entries_processed bigint default 0, CONSTRAINT PK_conninfo_id PRIMARY KEY (conninfo_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactgroups -- CREATE TABLE icinga_contactgroups ( contactgroup_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, contactgroup_object_id bigint default 0, alias TEXT default '', config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_contactgroup_id PRIMARY KEY (contactgroup_id) , CONSTRAINT UQ_contactgroups UNIQUE (instance_id,config_type,contactgroup_object_id) ); -- -------------------------------------------------------- -- -- Table structure for table icinga_contactgroup_members -- CREATE TABLE icinga_contactgroup_members ( contactgroup_member_id bigserial, instance_id bigint default 0, contactgroup_id bigint default 0, contact_object_id bigint default 0, session_token INTEGER default NULL, CONSTRAINT PK_contactgroup_member_id PRIMARY KEY (contactgroup_member_id) ); -- -------------------------------------------------------- -- -- Table structure for table icinga_contactnotificationmethods -- CREATE TABLE icinga_contactnotificationmethods ( contactnotificationmethod_id bigserial, instance_id bigint default 0, contactnotification_id bigint default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, command_object_id bigint default 0, command_args TEXT default '', CONSTRAINT PK_contactnotificationmethod_id PRIMARY KEY (contactnotificationmethod_id) , CONSTRAINT UQ_contactnotificationmethods UNIQUE (instance_id,contactnotification_id,start_time,start_time_usec) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactnotifications -- CREATE TABLE icinga_contactnotifications ( contactnotification_id bigserial, instance_id bigint default 0, notification_id bigint default 0, contact_object_id bigint default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, CONSTRAINT PK_contactnotification_id PRIMARY KEY (contactnotification_id) , CONSTRAINT UQ_contactnotifications UNIQUE (instance_id,contact_object_id,start_time,start_time_usec) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contacts -- CREATE TABLE icinga_contacts ( contact_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, contact_object_id bigint default 0, alias TEXT default '', email_address TEXT default '', pager_address TEXT default '', host_timeperiod_object_id bigint default 0, service_timeperiod_object_id bigint default 0, host_notifications_enabled INTEGER default 0, service_notifications_enabled INTEGER default 0, can_submit_commands INTEGER default 0, notify_service_recovery INTEGER default 0, notify_service_warning INTEGER default 0, notify_service_unknown INTEGER default 0, notify_service_critical INTEGER default 0, notify_service_flapping INTEGER default 0, notify_service_downtime INTEGER default 0, notify_host_recovery INTEGER default 0, notify_host_down INTEGER default 0, notify_host_unreachable INTEGER default 0, notify_host_flapping INTEGER default 0, notify_host_downtime INTEGER default 0, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_contact_id PRIMARY KEY (contact_id) , CONSTRAINT UQ_contacts UNIQUE (instance_id,config_type,contact_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contactstatus -- CREATE TABLE icinga_contactstatus ( contactstatus_id bigserial, instance_id bigint default 0, contact_object_id bigint default 0, status_update_time timestamp, host_notifications_enabled INTEGER default 0, service_notifications_enabled INTEGER default 0, last_host_notification timestamp, last_service_notification timestamp, modified_attributes INTEGER default 0, modified_host_attributes INTEGER default 0, modified_service_attributes INTEGER default 0, CONSTRAINT PK_contactstatus_id PRIMARY KEY (contactstatus_id) , CONSTRAINT UQ_contactstatus UNIQUE (contact_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contact_addresses -- CREATE TABLE icinga_contact_addresses ( contact_address_id bigserial, instance_id bigint default 0, contact_id bigint default 0, address_number INTEGER default 0, address TEXT default '', CONSTRAINT PK_contact_address_id PRIMARY KEY (contact_address_id) , CONSTRAINT UQ_contact_addresses UNIQUE (contact_id,address_number) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_contact_notificationcommands -- CREATE TABLE icinga_contact_notificationcommands ( contact_notificationcommand_id bigserial, instance_id bigint default 0, contact_id bigint default 0, notification_type INTEGER default 0, command_object_id bigint default 0, command_args TEXT default '', CONSTRAINT PK_contact_notificationcommand_id PRIMARY KEY (contact_notificationcommand_id) , CONSTRAINT UQ_contact_notificationcommands UNIQUE (contact_id,notification_type,command_object_id,command_args) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_customvariables -- CREATE TABLE icinga_customvariables ( customvariable_id bigserial, instance_id bigint default 0, object_id bigint default 0, config_type INTEGER default 0, has_been_modified INTEGER default 0, varname TEXT default '', varvalue TEXT default '', is_json INTEGER default 0, session_token INTEGER default NULL, CONSTRAINT PK_customvariable_id PRIMARY KEY (customvariable_id) , CONSTRAINT UQ_customvariables UNIQUE (object_id,config_type,varname) ) ; CREATE INDEX icinga_customvariables_i ON icinga_customvariables(varname); -- -------------------------------------------------------- -- -- Table structure for table icinga_customvariablestatus -- CREATE TABLE icinga_customvariablestatus ( customvariablestatus_id bigserial, instance_id bigint default 0, object_id bigint default 0, status_update_time timestamp, has_been_modified INTEGER default 0, varname TEXT default '', varvalue TEXT default '', is_json INTEGER default 0, session_token INTEGER default NULL, CONSTRAINT PK_customvariablestatus_id PRIMARY KEY (customvariablestatus_id) , CONSTRAINT UQ_customvariablestatus UNIQUE (object_id,varname) ) ; CREATE INDEX icinga_customvariablestatus_i ON icinga_customvariablestatus(varname); -- -------------------------------------------------------- -- -- Table structure for table icinga_dbversion -- CREATE TABLE icinga_dbversion ( dbversion_id bigserial, name TEXT default '', version TEXT default '', create_time timestamp, modify_time timestamp, CONSTRAINT PK_dbversion_id PRIMARY KEY (dbversion_id) , CONSTRAINT UQ_dbversion UNIQUE (name) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_downtimehistory -- CREATE TABLE icinga_downtimehistory ( downtimehistory_id bigserial, instance_id bigint default 0, downtime_type INTEGER default 0, object_id bigint default 0, entry_time timestamp, author_name TEXT default '', comment_data TEXT default '', internal_downtime_id bigint default 0, triggered_by_id bigint default 0, is_fixed INTEGER default 0, duration BIGINT default 0, scheduled_start_time timestamp, scheduled_end_time timestamp, was_started INTEGER default 0, actual_start_time timestamp, actual_start_time_usec INTEGER default 0, actual_end_time timestamp, actual_end_time_usec INTEGER default 0, was_cancelled INTEGER default 0, is_in_effect INTEGER default 0, trigger_time timestamp, name TEXT default NULL, CONSTRAINT PK_downtimehistory_id PRIMARY KEY (downtimehistory_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_eventhandlers -- CREATE TABLE icinga_eventhandlers ( eventhandler_id bigserial, instance_id bigint default 0, eventhandler_type INTEGER default 0, object_id bigint default 0, state INTEGER default 0, state_type INTEGER default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, command_object_id bigint default 0, command_args TEXT default '', command_line TEXT default '', timeout INTEGER default 0, early_timeout INTEGER default 0, execution_time double precision default 0, return_code INTEGER default 0, output TEXT default '', long_output TEXT default '', CONSTRAINT PK_eventhandler_id PRIMARY KEY (eventhandler_id) , CONSTRAINT UQ_eventhandlers UNIQUE (instance_id,object_id,start_time,start_time_usec) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_externalcommands -- CREATE TABLE icinga_externalcommands ( externalcommand_id bigserial, instance_id bigint default 0, entry_time timestamp, command_type INTEGER default 0, command_name TEXT default '', command_args TEXT default '', CONSTRAINT PK_externalcommand_id PRIMARY KEY (externalcommand_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_flappinghistory -- CREATE TABLE icinga_flappinghistory ( flappinghistory_id bigserial, instance_id bigint default 0, event_time timestamp, event_time_usec INTEGER default 0, event_type INTEGER default 0, reason_type INTEGER default 0, flapping_type INTEGER default 0, object_id bigint default 0, percent_state_change double precision default 0, low_threshold double precision default 0, high_threshold double precision default 0, comment_time timestamp, internal_comment_id bigint default 0, CONSTRAINT PK_flappinghistory_id PRIMARY KEY (flappinghistory_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostchecks -- CREATE TABLE icinga_hostchecks ( hostcheck_id bigserial, instance_id bigint default 0, host_object_id bigint default 0, check_type INTEGER default 0, is_raw_check INTEGER default 0, current_check_attempt INTEGER default 0, max_check_attempts INTEGER default 0, state INTEGER default 0, state_type INTEGER default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, command_object_id bigint default 0, command_args TEXT default '', command_line TEXT default '', timeout INTEGER default 0, early_timeout INTEGER default 0, execution_time double precision default 0, latency double precision default 0, return_code INTEGER default 0, output TEXT default '', long_output TEXT default '', perfdata TEXT default '', CONSTRAINT PK_hostcheck_id PRIMARY KEY (hostcheck_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostdependencies -- CREATE TABLE icinga_hostdependencies ( hostdependency_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, host_object_id bigint default 0, dependent_host_object_id bigint default 0, dependency_type INTEGER default 0, inherits_parent INTEGER default 0, timeperiod_object_id bigint default 0, fail_on_up INTEGER default 0, fail_on_down INTEGER default 0, fail_on_unreachable INTEGER default 0, CONSTRAINT PK_hostdependency_id PRIMARY KEY (hostdependency_id) ) ; CREATE INDEX idx_hostdependencies ON icinga_hostdependencies(instance_id,config_type,host_object_id,dependent_host_object_id,dependency_type,inherits_parent,fail_on_up,fail_on_down,fail_on_unreachable); -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalations -- CREATE TABLE icinga_hostescalations ( hostescalation_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, host_object_id bigint default 0, timeperiod_object_id bigint default 0, first_notification INTEGER default 0, last_notification INTEGER default 0, notification_interval double precision default 0, escalate_on_recovery INTEGER default 0, escalate_on_down INTEGER default 0, escalate_on_unreachable INTEGER default 0, CONSTRAINT PK_hostescalation_id PRIMARY KEY (hostescalation_id) , CONSTRAINT UQ_hostescalations UNIQUE (instance_id,config_type,host_object_id,timeperiod_object_id,first_notification,last_notification) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalation_contactgroups -- CREATE TABLE icinga_hostescalation_contactgroups ( hostescalation_contactgroup_id bigserial, instance_id bigint default 0, hostescalation_id bigint default 0, contactgroup_object_id bigint default 0, CONSTRAINT PK_hostescalation_contactgroup_id PRIMARY KEY (hostescalation_contactgroup_id) , CONSTRAINT UQ_hostescalation_contactgroups UNIQUE (hostescalation_id,contactgroup_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostescalation_contacts -- CREATE TABLE icinga_hostescalation_contacts ( hostescalation_contact_id bigserial, instance_id bigint default 0, hostescalation_id bigint default 0, contact_object_id bigint default 0, CONSTRAINT PK_hostescalation_contact_id PRIMARY KEY (hostescalation_contact_id) , CONSTRAINT UQ_hostescalation_contacts UNIQUE (instance_id,hostescalation_id,contact_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostgroups -- CREATE TABLE icinga_hostgroups ( hostgroup_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, hostgroup_object_id bigint default 0, alias TEXT default '', notes TEXT default NULL, notes_url TEXT default NULL, action_url TEXT default NULL, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_hostgroup_id PRIMARY KEY (hostgroup_id) , CONSTRAINT UQ_hostgroups UNIQUE (instance_id,hostgroup_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hostgroup_members -- CREATE TABLE icinga_hostgroup_members ( hostgroup_member_id bigserial, instance_id bigint default 0, hostgroup_id bigint default 0, host_object_id bigint default 0, session_token INTEGER default NULL, CONSTRAINT PK_hostgroup_member_id PRIMARY KEY (hostgroup_member_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hosts -- CREATE TABLE icinga_hosts ( host_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, host_object_id bigint default 0, alias TEXT default '', display_name TEXT default '', address TEXT default '', address6 TEXT default '', check_command_object_id bigint default 0, check_command_args TEXT default '', eventhandler_command_object_id bigint default 0, eventhandler_command_args TEXT default '', notification_timeperiod_object_id bigint default 0, check_timeperiod_object_id bigint default 0, failure_prediction_options TEXT default '', check_interval double precision default 0, retry_interval double precision default 0, max_check_attempts INTEGER default 0, first_notification_delay double precision default 0, notification_interval double precision default 0, notify_on_down INTEGER default 0, notify_on_unreachable INTEGER default 0, notify_on_recovery INTEGER default 0, notify_on_flapping INTEGER default 0, notify_on_downtime INTEGER default 0, stalk_on_up INTEGER default 0, stalk_on_down INTEGER default 0, stalk_on_unreachable INTEGER default 0, flap_detection_enabled INTEGER default 0, flap_detection_on_up INTEGER default 0, flap_detection_on_down INTEGER default 0, flap_detection_on_unreachable INTEGER default 0, low_flap_threshold double precision default 0, high_flap_threshold double precision default 0, process_performance_data INTEGER default 0, freshness_checks_enabled INTEGER default 0, freshness_threshold INTEGER default 0, passive_checks_enabled INTEGER default 0, event_handler_enabled INTEGER default 0, active_checks_enabled INTEGER default 0, retain_status_information INTEGER default 0, retain_nonstatus_information INTEGER default 0, notifications_enabled INTEGER default 0, obsess_over_host INTEGER default 0, failure_prediction_enabled INTEGER default 0, notes TEXT default '', notes_url TEXT default '', action_url TEXT default '', icon_image TEXT default '', icon_image_alt TEXT default '', vrml_image TEXT default '', statusmap_image TEXT default '', have_2d_coords INTEGER default 0, x_2d INTEGER default 0, y_2d INTEGER default 0, have_3d_coords INTEGER default 0, x_3d double precision default 0, y_3d double precision default 0, z_3d double precision default 0, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_host_id PRIMARY KEY (host_id) , CONSTRAINT UQ_hosts UNIQUE (instance_id,config_type,host_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_hoststatus -- CREATE TABLE icinga_hoststatus ( hoststatus_id bigserial, instance_id bigint default 0, host_object_id bigint default 0, status_update_time timestamp, output TEXT default '', long_output TEXT default '', perfdata TEXT default '', check_source varchar(255) default '', current_state INTEGER default 0, has_been_checked INTEGER default 0, should_be_scheduled INTEGER default 0, current_check_attempt INTEGER default 0, max_check_attempts INTEGER default 0, last_check timestamp, next_check timestamp, check_type INTEGER default 0, last_state_change timestamp, last_hard_state_change timestamp, last_hard_state INTEGER default 0, last_time_up timestamp, last_time_down timestamp, last_time_unreachable timestamp, state_type INTEGER default 0, last_notification timestamp, next_notification timestamp, no_more_notifications INTEGER default 0, notifications_enabled INTEGER default 0, problem_has_been_acknowledged INTEGER default 0, acknowledgement_type INTEGER default 0, current_notification_number INTEGER default 0, passive_checks_enabled INTEGER default 0, active_checks_enabled INTEGER default 0, event_handler_enabled INTEGER default 0, flap_detection_enabled INTEGER default 0, is_flapping INTEGER default 0, percent_state_change double precision default 0, latency double precision default 0, execution_time double precision default 0, scheduled_downtime_depth INTEGER default 0, failure_prediction_enabled INTEGER default 0, process_performance_data INTEGER default 0, obsess_over_host INTEGER default 0, modified_host_attributes INTEGER default 0, original_attributes TEXT default NULL, event_handler TEXT default '', check_command TEXT default '', normal_check_interval double precision default 0, retry_check_interval double precision default 0, check_timeperiod_object_id bigint default 0, is_reachable INTEGER default 0, CONSTRAINT PK_hoststatus_id PRIMARY KEY (hoststatus_id) , CONSTRAINT UQ_hoststatus UNIQUE (host_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_contactgroups -- CREATE TABLE icinga_host_contactgroups ( host_contactgroup_id bigserial, instance_id bigint default 0, host_id bigint default 0, contactgroup_object_id bigint default 0, CONSTRAINT PK_host_contactgroup_id PRIMARY KEY (host_contactgroup_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_contacts -- CREATE TABLE icinga_host_contacts ( host_contact_id bigserial, instance_id bigint default 0, host_id bigint default 0, contact_object_id bigint default 0, CONSTRAINT PK_host_contact_id PRIMARY KEY (host_contact_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_host_parenthosts -- CREATE TABLE icinga_host_parenthosts ( host_parenthost_id bigserial, instance_id bigint default 0, host_id bigint default 0, parent_host_object_id bigint default 0, CONSTRAINT PK_host_parenthost_id PRIMARY KEY (host_parenthost_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_instances -- CREATE TABLE icinga_instances ( instance_id bigserial, instance_name TEXT default '', instance_description TEXT default '', CONSTRAINT PK_instance_id PRIMARY KEY (instance_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_logentries -- CREATE TABLE icinga_logentries ( logentry_id bigserial, instance_id bigint default 0, logentry_time timestamp, entry_time timestamp, entry_time_usec INTEGER default 0, logentry_type INTEGER default 0, logentry_data TEXT default '', realtime_data INTEGER default 0, inferred_data_extracted INTEGER default 0, object_id bigint default NULL, CONSTRAINT PK_logentry_id PRIMARY KEY (logentry_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_notifications -- CREATE TABLE icinga_notifications ( notification_id bigserial, instance_id bigint default 0, notification_type INTEGER default 0, notification_reason INTEGER default 0, object_id bigint default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, state INTEGER default 0, output TEXT default '', long_output TEXT default '', escalated INTEGER default 0, contacts_notified INTEGER default 0, CONSTRAINT PK_notification_id PRIMARY KEY (notification_id) , CONSTRAINT UQ_notifications UNIQUE (instance_id,object_id,start_time,start_time_usec) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_objects -- CREATE TABLE icinga_objects ( object_id bigserial, instance_id bigint default 0, objecttype_id bigint default 0, name1 TEXT, name2 TEXT, is_active INTEGER default 0, CONSTRAINT PK_object_id PRIMARY KEY (object_id) -- UNIQUE (objecttype_id,name1,name2) ) ; CREATE INDEX icinga_objects_i ON icinga_objects(objecttype_id,name1,name2); -- -------------------------------------------------------- -- -- Table structure for table icinga_processevents -- CREATE TABLE icinga_processevents ( processevent_id bigserial, instance_id bigint default 0, event_type INTEGER default 0, event_time timestamp, event_time_usec INTEGER default 0, process_id bigint default 0, program_name TEXT default '', program_version TEXT default '', program_date TEXT default '', CONSTRAINT PK_processevent_id PRIMARY KEY (processevent_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_programstatus -- CREATE TABLE icinga_programstatus ( programstatus_id bigserial, instance_id bigint default 0, program_version TEXT default NULL, status_update_time timestamp, program_start_time timestamp, program_end_time timestamp, is_currently_running INTEGER default 0, endpoint_name TEXT default '', process_id bigint default 0, daemon_mode INTEGER default 0, last_command_check timestamp, last_log_rotation timestamp, notifications_enabled INTEGER default 0, disable_notif_expire_time timestamp, active_service_checks_enabled INTEGER default 0, passive_service_checks_enabled INTEGER default 0, active_host_checks_enabled INTEGER default 0, passive_host_checks_enabled INTEGER default 0, event_handlers_enabled INTEGER default 0, flap_detection_enabled INTEGER default 0, failure_prediction_enabled INTEGER default 0, process_performance_data INTEGER default 0, obsess_over_hosts INTEGER default 0, obsess_over_services INTEGER default 0, modified_host_attributes INTEGER default 0, modified_service_attributes INTEGER default 0, global_host_event_handler TEXT default '', global_service_event_handler TEXT default '', config_dump_in_progress INTEGER default 0, CONSTRAINT PK_programstatus_id PRIMARY KEY (programstatus_id) , CONSTRAINT UQ_programstatus UNIQUE (instance_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_runtimevariables -- CREATE TABLE icinga_runtimevariables ( runtimevariable_id bigserial, instance_id bigint default 0, varname TEXT default '', varvalue TEXT default '', CONSTRAINT PK_runtimevariable_id PRIMARY KEY (runtimevariable_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_scheduleddowntime -- CREATE TABLE icinga_scheduleddowntime ( scheduleddowntime_id bigserial, instance_id bigint default 0, downtime_type INTEGER default 0, object_id bigint default 0, entry_time timestamp, author_name TEXT default '', comment_data TEXT default '', internal_downtime_id bigint default 0, triggered_by_id bigint default 0, is_fixed INTEGER default 0, duration BIGINT default 0, scheduled_start_time timestamp, scheduled_end_time timestamp, was_started INTEGER default 0, actual_start_time timestamp, actual_start_time_usec INTEGER default 0, is_in_effect INTEGER default 0, trigger_time timestamp, name TEXT default NULL, session_token INTEGER default NULL, CONSTRAINT PK_scheduleddowntime_id PRIMARY KEY (scheduleddowntime_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicechecks -- CREATE TABLE icinga_servicechecks ( servicecheck_id bigserial, instance_id bigint default 0, service_object_id bigint default 0, check_type INTEGER default 0, current_check_attempt INTEGER default 0, max_check_attempts INTEGER default 0, state INTEGER default 0, state_type INTEGER default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, command_object_id bigint default 0, command_args TEXT default '', command_line TEXT default '', timeout INTEGER default 0, early_timeout INTEGER default 0, execution_time double precision default 0, latency double precision default 0, return_code INTEGER default 0, output TEXT default '', long_output TEXT default '', perfdata TEXT default '', CONSTRAINT PK_servicecheck_id PRIMARY KEY (servicecheck_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicedependencies -- CREATE TABLE icinga_servicedependencies ( servicedependency_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, service_object_id bigint default 0, dependent_service_object_id bigint default 0, dependency_type INTEGER default 0, inherits_parent INTEGER default 0, timeperiod_object_id bigint default 0, fail_on_ok INTEGER default 0, fail_on_warning INTEGER default 0, fail_on_unknown INTEGER default 0, fail_on_critical INTEGER default 0, CONSTRAINT PK_servicedependency_id PRIMARY KEY (servicedependency_id) ) ; CREATE INDEX idx_servicedependencies ON icinga_servicedependencies(instance_id,config_type,service_object_id,dependent_service_object_id,dependency_type,inherits_parent,fail_on_ok,fail_on_warning,fail_on_unknown,fail_on_critical); -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalations -- CREATE TABLE icinga_serviceescalations ( serviceescalation_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, service_object_id bigint default 0, timeperiod_object_id bigint default 0, first_notification INTEGER default 0, last_notification INTEGER default 0, notification_interval double precision default 0, escalate_on_recovery INTEGER default 0, escalate_on_warning INTEGER default 0, escalate_on_unknown INTEGER default 0, escalate_on_critical INTEGER default 0, CONSTRAINT PK_serviceescalation_id PRIMARY KEY (serviceescalation_id) , CONSTRAINT UQ_serviceescalations UNIQUE (instance_id,config_type,service_object_id,timeperiod_object_id,first_notification,last_notification) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalation_contactgroups -- CREATE TABLE icinga_serviceescalation_contactgroups ( serviceescalation_contactgroup_id bigserial, instance_id bigint default 0, serviceescalation_id bigint default 0, contactgroup_object_id bigint default 0, CONSTRAINT PK_serviceescalation_contactgroup_id PRIMARY KEY (serviceescalation_contactgroup_id) , CONSTRAINT UQ_serviceescalation_contactgro UNIQUE (serviceescalation_id,contactgroup_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_serviceescalation_contacts -- CREATE TABLE icinga_serviceescalation_contacts ( serviceescalation_contact_id bigserial, instance_id bigint default 0, serviceescalation_id bigint default 0, contact_object_id bigint default 0, CONSTRAINT PK_serviceescalation_contact_id PRIMARY KEY (serviceescalation_contact_id) , CONSTRAINT UQ_serviceescalation_contacts UNIQUE (instance_id,serviceescalation_id,contact_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicegroups -- CREATE TABLE icinga_servicegroups ( servicegroup_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, servicegroup_object_id bigint default 0, alias TEXT default '', notes TEXT default NULL, notes_url TEXT default NULL, action_url TEXT default NULL, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_servicegroup_id PRIMARY KEY (servicegroup_id) , CONSTRAINT UQ_servicegroups UNIQUE (instance_id,config_type,servicegroup_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicegroup_members -- CREATE TABLE icinga_servicegroup_members ( servicegroup_member_id bigserial, instance_id bigint default 0, servicegroup_id bigint default 0, service_object_id bigint default 0, session_token INTEGER default NULL, CONSTRAINT PK_servicegroup_member_id PRIMARY KEY (servicegroup_member_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_services -- CREATE TABLE icinga_services ( service_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, host_object_id bigint default 0, service_object_id bigint default 0, display_name TEXT default '', check_command_object_id bigint default 0, check_command_args TEXT default '', eventhandler_command_object_id bigint default 0, eventhandler_command_args TEXT default '', notification_timeperiod_object_id bigint default 0, check_timeperiod_object_id bigint default 0, failure_prediction_options TEXT default '', check_interval double precision default 0, retry_interval double precision default 0, max_check_attempts INTEGER default 0, first_notification_delay double precision default 0, notification_interval double precision default 0, notify_on_warning INTEGER default 0, notify_on_unknown INTEGER default 0, notify_on_critical INTEGER default 0, notify_on_recovery INTEGER default 0, notify_on_flapping INTEGER default 0, notify_on_downtime INTEGER default 0, stalk_on_ok INTEGER default 0, stalk_on_warning INTEGER default 0, stalk_on_unknown INTEGER default 0, stalk_on_critical INTEGER default 0, is_volatile INTEGER default 0, flap_detection_enabled INTEGER default 0, flap_detection_on_ok INTEGER default 0, flap_detection_on_warning INTEGER default 0, flap_detection_on_unknown INTEGER default 0, flap_detection_on_critical INTEGER default 0, low_flap_threshold double precision default 0, high_flap_threshold double precision default 0, process_performance_data INTEGER default 0, freshness_checks_enabled INTEGER default 0, freshness_threshold INTEGER default 0, passive_checks_enabled INTEGER default 0, event_handler_enabled INTEGER default 0, active_checks_enabled INTEGER default 0, retain_status_information INTEGER default 0, retain_nonstatus_information INTEGER default 0, notifications_enabled INTEGER default 0, obsess_over_service INTEGER default 0, failure_prediction_enabled INTEGER default 0, notes TEXT default '', notes_url TEXT default '', action_url TEXT default '', icon_image TEXT default '', icon_image_alt TEXT default '', config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_service_id PRIMARY KEY (service_id) , CONSTRAINT UQ_services UNIQUE (instance_id,config_type,service_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_servicestatus -- CREATE TABLE icinga_servicestatus ( servicestatus_id bigserial, instance_id bigint default 0, service_object_id bigint default 0, status_update_time timestamp, output TEXT default '', long_output TEXT default '', perfdata TEXT default '', check_source varchar(255) default '', current_state INTEGER default 0, has_been_checked INTEGER default 0, should_be_scheduled INTEGER default 0, current_check_attempt INTEGER default 0, max_check_attempts INTEGER default 0, last_check timestamp, next_check timestamp, check_type INTEGER default 0, last_state_change timestamp, last_hard_state_change timestamp, last_hard_state INTEGER default 0, last_time_ok timestamp, last_time_warning timestamp, last_time_unknown timestamp, last_time_critical timestamp, state_type INTEGER default 0, last_notification timestamp, next_notification timestamp, no_more_notifications INTEGER default 0, notifications_enabled INTEGER default 0, problem_has_been_acknowledged INTEGER default 0, acknowledgement_type INTEGER default 0, current_notification_number INTEGER default 0, passive_checks_enabled INTEGER default 0, active_checks_enabled INTEGER default 0, event_handler_enabled INTEGER default 0, flap_detection_enabled INTEGER default 0, is_flapping INTEGER default 0, percent_state_change double precision default 0, latency double precision default 0, execution_time double precision default 0, scheduled_downtime_depth INTEGER default 0, failure_prediction_enabled INTEGER default 0, process_performance_data INTEGER default 0, obsess_over_service INTEGER default 0, modified_service_attributes INTEGER default 0, original_attributes TEXT default NULL, event_handler TEXT default '', check_command TEXT default '', normal_check_interval double precision default 0, retry_check_interval double precision default 0, check_timeperiod_object_id bigint default 0, is_reachable INTEGER default 0, CONSTRAINT PK_servicestatus_id PRIMARY KEY (servicestatus_id) , CONSTRAINT UQ_servicestatus UNIQUE (service_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_service_contactgroups -- CREATE TABLE icinga_service_contactgroups ( service_contactgroup_id bigserial, instance_id bigint default 0, service_id bigint default 0, contactgroup_object_id bigint default 0, CONSTRAINT PK_service_contactgroup_id PRIMARY KEY (service_contactgroup_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_service_contacts -- CREATE TABLE icinga_service_contacts ( service_contact_id bigserial, instance_id bigint default 0, service_id bigint default 0, contact_object_id bigint default 0, CONSTRAINT PK_service_contact_id PRIMARY KEY (service_contact_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_statehistory -- CREATE TABLE icinga_statehistory ( statehistory_id bigserial, instance_id bigint default 0, state_time timestamp, state_time_usec INTEGER default 0, object_id bigint default 0, state_change INTEGER default 0, state INTEGER default 0, state_type INTEGER default 0, current_check_attempt INTEGER default 0, max_check_attempts INTEGER default 0, last_state INTEGER default '-1', last_hard_state INTEGER default '-1', output TEXT default '', long_output TEXT default '', check_source varchar(255) default '', CONSTRAINT PK_statehistory_id PRIMARY KEY (statehistory_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_systemcommands -- CREATE TABLE icinga_systemcommands ( systemcommand_id bigserial, instance_id bigint default 0, start_time timestamp, start_time_usec INTEGER default 0, end_time timestamp, end_time_usec INTEGER default 0, command_line TEXT default '', timeout INTEGER default 0, early_timeout INTEGER default 0, execution_time double precision default 0, return_code INTEGER default 0, output TEXT default '', long_output TEXT default '', CONSTRAINT PK_systemcommand_id PRIMARY KEY (systemcommand_id) , CONSTRAINT UQ_systemcommands UNIQUE (instance_id,start_time,start_time_usec) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_timeperiods -- CREATE TABLE icinga_timeperiods ( timeperiod_id bigserial, instance_id bigint default 0, config_type INTEGER default 0, timeperiod_object_id bigint default 0, alias TEXT default '', config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_timeperiod_id PRIMARY KEY (timeperiod_id) , CONSTRAINT UQ_timeperiods UNIQUE (instance_id,config_type,timeperiod_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_timeperiod_timeranges -- CREATE TABLE icinga_timeperiod_timeranges ( timeperiod_timerange_id bigserial, instance_id bigint default 0, timeperiod_id bigint default 0, day INTEGER default 0, start_sec INTEGER default 0, end_sec INTEGER default 0, CONSTRAINT PK_timeperiod_timerange_id PRIMARY KEY (timeperiod_timerange_id) ) ; -- -------------------------------------------------------- -- Icinga 2 specific schema extensions -- -------------------------------------------------------- -- -- Table structure for table icinga_endpoints -- CREATE TABLE icinga_endpoints ( endpoint_id bigserial, instance_id bigint default 0, endpoint_object_id bigint default 0, zone_object_id bigint default 0, config_type integer default 0, identity text DEFAULT NULL, node text DEFAULT NULL, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_endpoint_id PRIMARY KEY (endpoint_id) , CONSTRAINT UQ_endpoints UNIQUE (instance_id,config_type,endpoint_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_endpointstatus -- CREATE TABLE icinga_endpointstatus ( endpointstatus_id bigserial, instance_id bigint default 0, endpoint_object_id bigint default 0, zone_object_id bigint default 0, status_update_time timestamp, identity text DEFAULT NULL, node text DEFAULT NULL, is_connected integer default 0, CONSTRAINT PK_endpointstatus_id PRIMARY KEY (endpointstatus_id) , CONSTRAINT UQ_endpointstatus UNIQUE (endpoint_object_id) ) ; -- -- Table structure for table icinga_zones -- CREATE TABLE icinga_zones ( zone_id bigserial, instance_id bigint default 0, zone_object_id bigint default 0, parent_zone_object_id bigint default 0, config_type integer default 0, is_global integer default 0, config_hash varchar(64) DEFAULT NULL, CONSTRAINT PK_zone_id PRIMARY KEY (zone_id) , CONSTRAINT UQ_zones UNIQUE (instance_id,config_type,zone_object_id) ) ; -- -------------------------------------------------------- -- -- Table structure for table icinga_zonestatus -- CREATE TABLE icinga_zonestatus ( zonestatus_id bigserial, instance_id bigint default 0, zone_object_id bigint default 0, parent_zone_object_id bigint default 0, status_update_time timestamp, CONSTRAINT PK_zonestatus_id PRIMARY KEY (zonestatus_id) , CONSTRAINT UQ_zonestatus UNIQUE (zone_object_id) ) ; ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_contactstatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_programstatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_comments ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_runtimevariables ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_customvariablestatus ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_contactnotifications ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_downtimehistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_eventhandlers ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_externalcommands ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_flappinghistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_hostchecks ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_logentries ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_notifications ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_processevents ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_servicechecks ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL; ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL; -- ----------------------------------------- -- add index (delete) -- ----------------------------------------- -- for periodic delete -- instance_id and -- TIMEDEVENTS => scheduled_time -- SYSTEMCOMMANDS, SERVICECHECKS, HOSTCHECKS, EVENTHANDLERS => start_time -- EXTERNALCOMMANDS => entry_time -- instance_id CREATE INDEX systemcommands_i_id_idx on icinga_systemcommands(instance_id); CREATE INDEX servicechecks_i_id_idx on icinga_servicechecks(instance_id); CREATE INDEX hostchecks_i_id_idx on icinga_hostchecks(instance_id); CREATE INDEX eventhandlers_i_id_idx on icinga_eventhandlers(instance_id); CREATE INDEX externalcommands_i_id_idx on icinga_externalcommands(instance_id); -- time CREATE INDEX systemcommands_time_id_idx on icinga_systemcommands(start_time); CREATE INDEX servicechecks_time_id_idx on icinga_servicechecks(start_time); CREATE INDEX hostchecks_time_id_idx on icinga_hostchecks(start_time); CREATE INDEX eventhandlers_time_id_idx on icinga_eventhandlers(start_time); CREATE INDEX externalcommands_time_id_idx on icinga_externalcommands(entry_time); -- for starting cleanup - referenced in dbhandler.c:882 -- instance_id only -- realtime data CREATE INDEX programstatus_i_id_idx on icinga_programstatus(instance_id); CREATE INDEX hoststatus_i_id_idx on icinga_hoststatus(instance_id); CREATE INDEX servicestatus_i_id_idx on icinga_servicestatus(instance_id); CREATE INDEX contactstatus_i_id_idx on icinga_contactstatus(instance_id); CREATE INDEX comments_i_id_idx on icinga_comments(instance_id); CREATE INDEX scheduleddowntime_i_id_idx on icinga_scheduleddowntime(instance_id); CREATE INDEX runtimevariables_i_id_idx on icinga_runtimevariables(instance_id); CREATE INDEX customvariablestatus_i_id_idx on icinga_customvariablestatus(instance_id); -- config data CREATE INDEX configfiles_i_id_idx on icinga_configfiles(instance_id); CREATE INDEX configfilevariables_i_id_idx on icinga_configfilevariables(instance_id); CREATE INDEX customvariables_i_id_idx on icinga_customvariables(instance_id); CREATE INDEX commands_i_id_idx on icinga_commands(instance_id); CREATE INDEX timeperiods_i_id_idx on icinga_timeperiods(instance_id); CREATE INDEX timeperiod_timeranges_i_id_idx on icinga_timeperiod_timeranges(instance_id); CREATE INDEX contactgroups_i_id_idx on icinga_contactgroups(instance_id); CREATE INDEX contactgroup_members_i_id_idx on icinga_contactgroup_members(instance_id); CREATE INDEX hostgroups_i_id_idx on icinga_hostgroups(instance_id); CREATE INDEX hostgroup_members_i_id_idx on icinga_hostgroup_members(instance_id); CREATE INDEX servicegroups_i_id_idx on icinga_servicegroups(instance_id); CREATE INDEX servicegroup_members_i_id_idx on icinga_servicegroup_members(instance_id); CREATE INDEX hostesc_i_id_idx on icinga_hostescalations(instance_id); CREATE INDEX hostesc_contacts_i_id_idx on icinga_hostescalation_contacts(instance_id); CREATE INDEX serviceesc_i_id_idx on icinga_serviceescalations(instance_id); CREATE INDEX serviceesc_contacts_i_id_idx on icinga_serviceescalation_contacts(instance_id); CREATE INDEX hostdependencies_i_id_idx on icinga_hostdependencies(instance_id); CREATE INDEX contacts_i_id_idx on icinga_contacts(instance_id); CREATE INDEX contact_addresses_i_id_idx on icinga_contact_addresses(instance_id); CREATE INDEX contact_notifcommands_i_id_idx on icinga_contact_notificationcommands(instance_id); CREATE INDEX hosts_i_id_idx on icinga_hosts(instance_id); CREATE INDEX host_parenthosts_i_id_idx on icinga_host_parenthosts(instance_id); CREATE INDEX host_contacts_i_id_idx on icinga_host_contacts(instance_id); CREATE INDEX services_i_id_idx on icinga_services(instance_id); CREATE INDEX service_contacts_i_id_idx on icinga_service_contacts(instance_id); CREATE INDEX service_contactgroups_i_id_idx on icinga_service_contactgroups(instance_id); CREATE INDEX host_contactgroups_i_id_idx on icinga_host_contactgroups(instance_id); CREATE INDEX hostesc_cgroups_i_id_idx on icinga_hostescalation_contactgroups(instance_id); CREATE INDEX serviceesc_cgroups_i_id_idx on icinga_serviceescalation_contactgroups(instance_id); -- ----------------------------------------- -- more index stuff (WHERE clauses) -- ----------------------------------------- -- hosts CREATE INDEX hosts_host_object_id_idx on icinga_hosts(host_object_id); -- hoststatus CREATE INDEX hoststatus_stat_upd_time_idx on icinga_hoststatus(status_update_time); CREATE INDEX hoststatus_current_state_idx on icinga_hoststatus(current_state); CREATE INDEX hoststatus_check_type_idx on icinga_hoststatus(check_type); CREATE INDEX hoststatus_state_type_idx on icinga_hoststatus(state_type); CREATE INDEX hoststatus_last_state_chg_idx on icinga_hoststatus(last_state_change); CREATE INDEX hoststatus_notif_enabled_idx on icinga_hoststatus(notifications_enabled); CREATE INDEX hoststatus_problem_ack_idx on icinga_hoststatus(problem_has_been_acknowledged); CREATE INDEX hoststatus_act_chks_en_idx on icinga_hoststatus(active_checks_enabled); CREATE INDEX hoststatus_pas_chks_en_idx on icinga_hoststatus(passive_checks_enabled); CREATE INDEX hoststatus_event_hdl_en_idx on icinga_hoststatus(event_handler_enabled); CREATE INDEX hoststatus_flap_det_en_idx on icinga_hoststatus(flap_detection_enabled); CREATE INDEX hoststatus_is_flapping_idx on icinga_hoststatus(is_flapping); CREATE INDEX hoststatus_p_state_chg_idx on icinga_hoststatus(percent_state_change); CREATE INDEX hoststatus_latency_idx on icinga_hoststatus(latency); CREATE INDEX hoststatus_ex_time_idx on icinga_hoststatus(execution_time); CREATE INDEX hoststatus_sch_downt_d_idx on icinga_hoststatus(scheduled_downtime_depth); -- services CREATE INDEX services_host_object_id_idx on icinga_services(host_object_id); --servicestatus CREATE INDEX srvcstatus_stat_upd_time_idx on icinga_servicestatus(status_update_time); CREATE INDEX srvcstatus_current_state_idx on icinga_servicestatus(current_state); CREATE INDEX srvcstatus_check_type_idx on icinga_servicestatus(check_type); CREATE INDEX srvcstatus_state_type_idx on icinga_servicestatus(state_type); CREATE INDEX srvcstatus_last_state_chg_idx on icinga_servicestatus(last_state_change); CREATE INDEX srvcstatus_notif_enabled_idx on icinga_servicestatus(notifications_enabled); CREATE INDEX srvcstatus_problem_ack_idx on icinga_servicestatus(problem_has_been_acknowledged); CREATE INDEX srvcstatus_act_chks_en_idx on icinga_servicestatus(active_checks_enabled); CREATE INDEX srvcstatus_pas_chks_en_idx on icinga_servicestatus(passive_checks_enabled); CREATE INDEX srvcstatus_event_hdl_en_idx on icinga_servicestatus(event_handler_enabled); CREATE INDEX srvcstatus_flap_det_en_idx on icinga_servicestatus(flap_detection_enabled); CREATE INDEX srvcstatus_is_flapping_idx on icinga_servicestatus(is_flapping); CREATE INDEX srvcstatus_p_state_chg_idx on icinga_servicestatus(percent_state_change); CREATE INDEX srvcstatus_latency_idx on icinga_servicestatus(latency); CREATE INDEX srvcstatus_ex_time_idx on icinga_servicestatus(execution_time); CREATE INDEX srvcstatus_sch_downt_d_idx on icinga_servicestatus(scheduled_downtime_depth); -- hostchecks CREATE INDEX hostchks_h_obj_id_idx on icinga_hostchecks(host_object_id); -- servicechecks CREATE INDEX servicechks_s_obj_id_idx on icinga_servicechecks(service_object_id); -- objects CREATE INDEX objects_objtype_id_idx ON icinga_objects(objecttype_id); CREATE INDEX objects_name1_idx ON icinga_objects(name1); CREATE INDEX objects_name2_idx ON icinga_objects(name2); CREATE INDEX objects_inst_id_idx ON icinga_objects(instance_id); -- instances -- CREATE INDEX instances_name_idx on icinga_instances(instance_name); -- logentries -- CREATE INDEX loge_instance_id_idx on icinga_logentries(instance_id); -- #236 CREATE INDEX loge_time_idx on icinga_logentries(logentry_time); -- CREATE INDEX loge_data_idx on icinga_logentries(logentry_data); CREATE INDEX loge_inst_id_time_idx on icinga_logentries (instance_id, logentry_time); -- commenthistory -- CREATE INDEX c_hist_instance_id_idx on icinga_logentries(instance_id); -- CREATE INDEX c_hist_c_time_idx on icinga_logentries(comment_time); -- CREATE INDEX c_hist_i_c_id_idx on icinga_logentries(internal_comment_id); -- downtimehistory -- CREATE INDEX d_t_hist_nstance_id_idx on icinga_downtimehistory(instance_id); -- CREATE INDEX d_t_hist_type_idx on icinga_downtimehistory(downtime_type); -- CREATE INDEX d_t_hist_object_id_idx on icinga_downtimehistory(object_id); -- CREATE INDEX d_t_hist_entry_time_idx on icinga_downtimehistory(entry_time); -- CREATE INDEX d_t_hist_sched_start_idx on icinga_downtimehistory(scheduled_start_time); -- CREATE INDEX d_t_hist_sched_end_idx on icinga_downtimehistory(scheduled_end_time); -- scheduleddowntime -- CREATE INDEX sched_d_t_downtime_type_idx on icinga_scheduleddowntime(downtime_type); -- CREATE INDEX sched_d_t_object_id_idx on icinga_scheduleddowntime(object_id); -- CREATE INDEX sched_d_t_entry_time_idx on icinga_scheduleddowntime(entry_time); -- CREATE INDEX sched_d_t_start_time_idx on icinga_scheduleddowntime(scheduled_start_time); -- CREATE INDEX sched_d_t_end_time_idx on icinga_scheduleddowntime(scheduled_end_time); -- Icinga Web Notifications CREATE INDEX notification_idx ON icinga_notifications(notification_type, object_id, start_time); CREATE INDEX notification_object_id_idx ON icinga_notifications(object_id); CREATE INDEX contact_notification_idx ON icinga_contactnotifications(notification_id, contact_object_id); CREATE INDEX contacts_object_id_idx ON icinga_contacts(contact_object_id); CREATE INDEX contact_notif_meth_notif_idx ON icinga_contactnotificationmethods(contactnotification_id, command_object_id); CREATE INDEX command_object_idx ON icinga_commands(object_id); CREATE INDEX services_combined_object_idx ON icinga_services(service_object_id, host_object_id); -- statehistory CREATE INDEX statehist_i_id_o_id_s_ty_s_ti on icinga_statehistory(instance_id, object_id, state_type, state_time); --#2274 create index statehist_state_idx on icinga_statehistory(object_id,state); -- #2618 CREATE INDEX cntgrpmbrs_cgid_coid ON icinga_contactgroup_members (contactgroup_id,contact_object_id); CREATE INDEX hstgrpmbrs_hgid_hoid ON icinga_hostgroup_members (hostgroup_id,host_object_id); CREATE INDEX hstcntgrps_hid_cgoid ON icinga_host_contactgroups (host_id,contactgroup_object_id); CREATE INDEX hstprnthsts_hid_phoid ON icinga_host_parenthosts (host_id,parent_host_object_id); CREATE INDEX runtimevars_iid_varn ON icinga_runtimevariables (instance_id,varname); CREATE INDEX sgmbrs_sgid_soid ON icinga_servicegroup_members (servicegroup_id,service_object_id); CREATE INDEX scgrps_sid_cgoid ON icinga_service_contactgroups (service_id,contactgroup_object_id); CREATE INDEX tperiod_tid_d_ss_es ON icinga_timeperiod_timeranges (timeperiod_id,day,start_sec,end_sec); -- #3649 CREATE INDEX sla_idx_sthist ON icinga_statehistory (object_id, state_time DESC); CREATE INDEX sla_idx_dohist ON icinga_downtimehistory (object_id, actual_start_time, actual_end_time); CREATE INDEX sla_idx_obj ON icinga_objects (objecttype_id, is_active, name1); -- #4985 CREATE INDEX commenthistory_delete_idx ON icinga_commenthistory (instance_id, comment_time, internal_comment_id); -- #10070 CREATE INDEX idx_comments_object_id on icinga_comments(object_id); CREATE INDEX idx_scheduleddowntime_object_id on icinga_scheduleddowntime(object_id); -- #10066 CREATE INDEX idx_endpoints_object_id on icinga_endpoints(endpoint_object_id); CREATE INDEX idx_endpointstatus_object_id on icinga_endpointstatus(endpoint_object_id); CREATE INDEX idx_endpoints_zone_object_id on icinga_endpoints(zone_object_id); CREATE INDEX idx_endpointstatus_zone_object_id on icinga_endpointstatus(zone_object_id); CREATE INDEX idx_zones_object_id on icinga_zones(zone_object_id); CREATE INDEX idx_zonestatus_object_id on icinga_zonestatus(zone_object_id); CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id); CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id); -- #12210 CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token); CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token); -- #12107 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time); -- #12435 CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id); CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id); CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id); CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id); CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id); CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id); CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id); CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id); -- #5458 CREATE INDEX idx_downtimehistory_remove ON icinga_downtimehistory (object_id, entry_time, scheduled_start_time, scheduled_end_time); CREATE INDEX idx_scheduleddowntime_remove ON icinga_scheduleddowntime (object_id, entry_time, scheduled_start_time, scheduled_end_time); -- #5492 CREATE INDEX idx_commenthistory_remove ON icinga_commenthistory (object_id, entry_time); CREATE INDEX idx_comments_remove ON icinga_comments (object_id, entry_time); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- SELECT updatedbversion('1.14.3'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/000077500000000000000000000000001322762156600211335ustar00rootroot00000000000000icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.0.2.sql000066400000000000000000000010051322762156600223070ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.0.2 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- UPDATE icinga_objects SET name2 = NULL WHERE name2 = ''; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- SELECT updatedbversion('1.11.6'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.1.0.sql000066400000000000000000000010311322762156600223050ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.1.0 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE icinga_programstatus ADD COLUMN endpoint_name TEXT default NULL; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- SELECT updatedbversion('1.11.7'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.2.0.sql000066400000000000000000000012641322762156600223160ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.2.0 -- -- ----------------------------------------- -- Copyright (c) 2014 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE icinga_programstatus ADD COLUMN program_version TEXT default NULL; ALTER TABLE icinga_customvariables ADD COLUMN is_json INTEGER default 0; ALTER TABLE icinga_customvariablestatus ADD COLUMN is_json INTEGER default 0; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- SELECT updatedbversion('1.12.0'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.3.0.sql000066400000000000000000000022231322762156600223130ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.3.0 -- -- ----------------------------------------- -- Copyright (c) 2015 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #7765 drop unique constraint -- ----------------------------------------- ALTER TABLE icinga_servicedependencies DROP CONSTRAINT uq_servicedependencies; ALTER TABLE icinga_hostdependencies DROP CONSTRAINT uq_hostdependencies; CREATE INDEX idx_servicedependencies ON icinga_servicedependencies(instance_id,config_type,service_object_id,dependent_service_object_id,dependency_type,inherits_parent,fail_on_ok,fail_on_warning,fail_on_unknown,fail_on_critical); CREATE INDEX idx_hostdependencies ON icinga_hostdependencies(instance_id,config_type,host_object_id,dependent_host_object_id,dependency_type,inherits_parent,fail_on_up,fail_on_down,fail_on_unreachable); -- ----------------------------------------- -- update dbversion -- ----------------------------------------- SELECT updatedbversion('1.13.0'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.4.0.sql000066400000000000000000000252451322762156600223250ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.4.0 -- -- ----------------------------------------- -- Copyright (c) 2015 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #9027 Default timestamps lack time zone -- ----------------------------------------- ALTER TABLE icinga_acknowledgements ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_acknowledgements ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_commenthistory ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_commenthistory ALTER COLUMN comment_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_commenthistory ALTER COLUMN expiration_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_commenthistory ALTER COLUMN deletion_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_comments ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_comments ALTER COLUMN comment_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_comments ALTER COLUMN expiration_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_conninfo ALTER COLUMN connect_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_conninfo ALTER COLUMN disconnect_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_conninfo ALTER COLUMN last_checkin_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_conninfo ALTER COLUMN data_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_conninfo ALTER COLUMN data_end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactnotificationmethods ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactnotificationmethods ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactnotifications ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactnotifications ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactstatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactstatus ALTER COLUMN last_host_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_contactstatus ALTER COLUMN last_service_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_customvariablestatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_dbversion ALTER COLUMN create_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_dbversion ALTER COLUMN modify_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN scheduled_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN scheduled_end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN actual_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN actual_end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_downtimehistory ALTER COLUMN trigger_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_eventhandlers ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_eventhandlers ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_externalcommands ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_flappinghistory ALTER COLUMN event_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_flappinghistory ALTER COLUMN comment_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hostchecks ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hostchecks ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_check SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN next_check SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_state_change SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_hard_state_change SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_time_up SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_time_down SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_time_unreachable SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN last_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_hoststatus ALTER COLUMN next_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_logentries ALTER COLUMN logentry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_logentries ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_notifications ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_notifications ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_processevents ALTER COLUMN event_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN program_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN program_end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN last_command_check SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN last_log_rotation SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_programstatus ALTER COLUMN disable_notif_expire_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN entry_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN scheduled_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN scheduled_end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN actual_start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN trigger_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicechecks ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicechecks ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_check SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN next_check SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_state_change SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_hard_state_change SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_time_ok SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_time_warning SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_time_unknown SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_time_critical SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN last_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_servicestatus ALTER COLUMN next_notification SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_statehistory ALTER COLUMN state_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_systemcommands ALTER COLUMN start_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_systemcommands ALTER COLUMN end_time SET DEFAULT '1970-01-01 00:00:00+00'; ALTER TABLE icinga_endpointstatus ALTER COLUMN status_update_time SET DEFAULT '1970-01-01 00:00:00+00'; -- ----------------------------------------- -- #9455 check_source data type -- ----------------------------------------- ALTER TABLE icinga_statehistory ALTER COLUMN check_source TYPE TEXT; ALTER TABLE icinga_statehistory ALTER COLUMN check_source SET default ''; -- ----------------------------------------- -- #9286 zones table -- ----------------------------------------- ALTER TABLE icinga_endpoints ADD COLUMN zone_object_id bigint default 0; ALTER TABLE icinga_endpointstatus ADD COLUMN zone_object_id bigint default 0; CREATE TABLE icinga_zones ( zone_id bigserial, instance_id bigint default 0, zone_object_id bigint default 0, parent_zone_object_id bigint default 0, config_type integer default 0, is_global integer default 0, CONSTRAINT PK_zone_id PRIMARY KEY (zone_id) , CONSTRAINT UQ_zones UNIQUE (instance_id,config_type,zone_object_id) ) ; CREATE TABLE icinga_zonestatus ( zonestatus_id bigserial, instance_id bigint default 0, zone_object_id bigint default 0, parent_zone_object_id bigint default 0, status_update_time timestamp with time zone default '1970-01-01 00:00:00+00', CONSTRAINT PK_zonestatus_id PRIMARY KEY (zonestatus_id) , CONSTRAINT UQ_zonestatus UNIQUE (zone_object_id) ) ; -- ----------------------------------------- -- #10392 original attributes -- ----------------------------------------- ALTER TABLE icinga_servicestatus ADD COLUMN original_attributes TEXT default NULL; ALTER TABLE icinga_hoststatus ADD COLUMN original_attributes TEXT default NULL; -- ----------------------------------------- -- #10436 deleted custom vars -- ----------------------------------------- ALTER TABLE icinga_customvariables ADD COLUMN session_token INTEGER default NULL; ALTER TABLE icinga_customvariablestatus ADD COLUMN session_token INTEGER default NULL; CREATE INDEX cv_session_del_idx ON icinga_customvariables (session_token); CREATE INDEX cvs_session_del_idx ON icinga_customvariablestatus (session_token); -- ----------------------------------------- -- #10431 comment/downtime name -- ----------------------------------------- ALTER TABLE icinga_comments ADD COLUMN name TEXT default NULL; ALTER TABLE icinga_commenthistory ADD COLUMN name TEXT default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN name TEXT default NULL; ALTER TABLE icinga_downtimehistory ADD COLUMN name TEXT default NULL; -- ----------------------------------------- -- update dbversion -- ----------------------------------------- SELECT updatedbversion('1.14.0'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.5.0.sql000066400000000000000000000101031322762156600223110ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.5.0 -- -- ----------------------------------------- -- Copyright (c) 2016 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #10069 IDO: check_source should not be a TEXT field -- ----------------------------------------- ALTER TABLE icinga_hoststatus ALTER COLUMN check_source TYPE varchar(255); ALTER TABLE icinga_servicestatus ALTER COLUMN check_source TYPE varchar(255); ALTER TABLE icinga_statehistory ALTER COLUMN check_source TYPE varchar(255); -- ----------------------------------------- -- #10070 -- ----------------------------------------- CREATE INDEX idx_comments_object_id on icinga_comments(object_id); CREATE INDEX idx_scheduleddowntime_object_id on icinga_scheduleddowntime(object_id); -- ----------------------------------------- -- #10066 -- ----------------------------------------- CREATE INDEX idx_endpoints_object_id on icinga_endpoints(endpoint_object_id); CREATE INDEX idx_endpointstatus_object_id on icinga_endpointstatus(endpoint_object_id); CREATE INDEX idx_endpoints_zone_object_id on icinga_endpoints(zone_object_id); CREATE INDEX idx_endpointstatus_zone_object_id on icinga_endpointstatus(zone_object_id); CREATE INDEX idx_zones_object_id on icinga_zones(zone_object_id); CREATE INDEX idx_zonestatus_object_id on icinga_zonestatus(zone_object_id); CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id); CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id); -- ----------------------------------------- -- #12258 -- ----------------------------------------- ALTER TABLE icinga_comments ADD COLUMN session_token INTEGER default NULL; ALTER TABLE icinga_scheduleddowntime ADD COLUMN session_token INTEGER default NULL; CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token); CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token); -- ----------------------------------------- -- #12107 -- ----------------------------------------- CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time); -- ----------------------------------------- -- #12435 -- ----------------------------------------- ALTER TABLE icinga_commands ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_contactgroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_contacts ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_hostgroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_hosts ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_servicegroups ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_services ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_timeperiods ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_endpoints ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_zones ADD config_hash VARCHAR(64) DEFAULT NULL; ALTER TABLE icinga_customvariables DROP session_token; ALTER TABLE icinga_customvariablestatus DROP session_token; CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id); CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id); CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id); CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id); CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id); CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id); CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id); CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- SELECT updatedbversion('1.14.1'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.6.0.sql000066400000000000000000000215421322762156600223230ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.6.0 -- -- ----------------------------------------- -- Copyright (c) 2016 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- -- ----------------------------------------- -- #13221 IDO: PostgreSQL: Don't use timestamp with timezone for unix timestamp columns -- ----------------------------------------- DROP FUNCTION IF EXISTS from_unixtime(bigint); CREATE FUNCTION from_unixtime(bigint) RETURNS timestamp AS $$ SELECT to_timestamp($1) AT TIME ZONE 'UTC' AS result $$ LANGUAGE sql; DROP FUNCTION IF EXISTS unix_timestamp(timestamp WITH TIME ZONE); CREATE OR REPLACE FUNCTION unix_timestamp(timestamp) RETURNS bigint AS ' SELECT CAST(EXTRACT(EPOCH FROM $1) AS bigint) AS result; ' LANGUAGE sql; ALTER TABLE icinga_acknowledgements ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_commenthistory ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp, ALTER COLUMN comment_time DROP DEFAULT, ALTER COLUMN comment_time TYPE timestamp, ALTER COLUMN expiration_time DROP DEFAULT, ALTER COLUMN expiration_time TYPE timestamp, ALTER COLUMN deletion_time DROP DEFAULT, ALTER COLUMN deletion_time TYPE timestamp; ALTER TABLE icinga_comments ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp, ALTER COLUMN comment_time DROP DEFAULT, ALTER COLUMN comment_time TYPE timestamp, ALTER COLUMN expiration_time DROP DEFAULT, ALTER COLUMN expiration_time TYPE timestamp; ALTER TABLE icinga_conninfo ALTER COLUMN connect_time DROP DEFAULT, ALTER COLUMN connect_time TYPE timestamp, ALTER COLUMN disconnect_time DROP DEFAULT, ALTER COLUMN disconnect_time TYPE timestamp, ALTER COLUMN last_checkin_time DROP DEFAULT, ALTER COLUMN last_checkin_time TYPE timestamp, ALTER COLUMN data_start_time DROP DEFAULT, ALTER COLUMN data_start_time TYPE timestamp, ALTER COLUMN data_end_time DROP DEFAULT, ALTER COLUMN data_end_time TYPE timestamp; ALTER TABLE icinga_contactnotificationmethods ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_contactnotifications ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_contactstatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp, ALTER COLUMN last_host_notification DROP DEFAULT, ALTER COLUMN last_host_notification TYPE timestamp, ALTER COLUMN last_service_notification DROP DEFAULT, ALTER COLUMN last_service_notification TYPE timestamp; ALTER TABLE icinga_customvariablestatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp; ALTER TABLE icinga_dbversion ALTER COLUMN create_time DROP DEFAULT, ALTER COLUMN create_time TYPE timestamp, ALTER COLUMN modify_time DROP DEFAULT, ALTER COLUMN modify_time TYPE timestamp; ALTER TABLE icinga_downtimehistory ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp, ALTER COLUMN scheduled_start_time DROP DEFAULT, ALTER COLUMN scheduled_start_time TYPE timestamp, ALTER COLUMN scheduled_end_time DROP DEFAULT, ALTER COLUMN scheduled_end_time TYPE timestamp, ALTER COLUMN actual_start_time DROP DEFAULT, ALTER COLUMN actual_start_time TYPE timestamp, ALTER COLUMN actual_end_time DROP DEFAULT, ALTER COLUMN actual_end_time TYPE timestamp, ALTER COLUMN trigger_time DROP DEFAULT, ALTER COLUMN trigger_time TYPE timestamp; ALTER TABLE icinga_eventhandlers ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_externalcommands ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp; ALTER TABLE icinga_flappinghistory ALTER COLUMN event_time DROP DEFAULT, ALTER COLUMN event_time TYPE timestamp, ALTER COLUMN comment_time DROP DEFAULT, ALTER COLUMN comment_time TYPE timestamp; ALTER TABLE icinga_hostchecks ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_hoststatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp, ALTER COLUMN last_check DROP DEFAULT, ALTER COLUMN last_check TYPE timestamp, ALTER COLUMN next_check DROP DEFAULT, ALTER COLUMN next_check TYPE timestamp, ALTER COLUMN last_state_change DROP DEFAULT, ALTER COLUMN last_state_change TYPE timestamp, ALTER COLUMN last_hard_state_change DROP DEFAULT, ALTER COLUMN last_hard_state_change TYPE timestamp, ALTER COLUMN last_time_up DROP DEFAULT, ALTER COLUMN last_time_up TYPE timestamp, ALTER COLUMN last_time_down DROP DEFAULT, ALTER COLUMN last_time_down TYPE timestamp, ALTER COLUMN last_time_unreachable DROP DEFAULT, ALTER COLUMN last_time_unreachable TYPE timestamp, ALTER COLUMN last_notification DROP DEFAULT, ALTER COLUMN last_notification TYPE timestamp, ALTER COLUMN next_notification DROP DEFAULT, ALTER COLUMN next_notification TYPE timestamp; ALTER TABLE icinga_logentries ALTER COLUMN logentry_time DROP DEFAULT, ALTER COLUMN logentry_time TYPE timestamp, ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp; ALTER TABLE icinga_notifications ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_processevents ALTER COLUMN event_time DROP DEFAULT, ALTER COLUMN event_time TYPE timestamp; ALTER TABLE icinga_programstatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp, ALTER COLUMN program_start_time DROP DEFAULT, ALTER COLUMN program_start_time TYPE timestamp, ALTER COLUMN program_end_time DROP DEFAULT, ALTER COLUMN program_end_time TYPE timestamp, ALTER COLUMN last_command_check DROP DEFAULT, ALTER COLUMN last_command_check TYPE timestamp, ALTER COLUMN last_log_rotation DROP DEFAULT, ALTER COLUMN last_log_rotation TYPE timestamp, ALTER COLUMN disable_notif_expire_time DROP DEFAULT, ALTER COLUMN disable_notif_expire_time TYPE timestamp; ALTER TABLE icinga_scheduleddowntime ALTER COLUMN entry_time DROP DEFAULT, ALTER COLUMN entry_time TYPE timestamp, ALTER COLUMN scheduled_start_time DROP DEFAULT, ALTER COLUMN scheduled_start_time TYPE timestamp, ALTER COLUMN scheduled_end_time DROP DEFAULT, ALTER COLUMN scheduled_end_time TYPE timestamp, ALTER COLUMN actual_start_time DROP DEFAULT, ALTER COLUMN actual_start_time TYPE timestamp, ALTER COLUMN trigger_time DROP DEFAULT, ALTER COLUMN trigger_time TYPE timestamp; ALTER TABLE icinga_servicechecks ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_servicestatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp, ALTER COLUMN last_check DROP DEFAULT, ALTER COLUMN last_check TYPE timestamp, ALTER COLUMN next_check DROP DEFAULT, ALTER COLUMN next_check TYPE timestamp, ALTER COLUMN last_state_change DROP DEFAULT, ALTER COLUMN last_state_change TYPE timestamp, ALTER COLUMN last_hard_state_change DROP DEFAULT, ALTER COLUMN last_hard_state_change TYPE timestamp, ALTER COLUMN last_time_ok DROP DEFAULT, ALTER COLUMN last_time_ok TYPE timestamp, ALTER COLUMN last_time_warning DROP DEFAULT, ALTER COLUMN last_time_warning TYPE timestamp, ALTER COLUMN last_time_unknown DROP DEFAULT, ALTER COLUMN last_time_unknown TYPE timestamp, ALTER COLUMN last_time_critical DROP DEFAULT, ALTER COLUMN last_time_critical TYPE timestamp, ALTER COLUMN last_notification DROP DEFAULT, ALTER COLUMN last_notification TYPE timestamp, ALTER COLUMN next_notification DROP DEFAULT, ALTER COLUMN next_notification TYPE timestamp; ALTER TABLE icinga_statehistory ALTER COLUMN state_time DROP DEFAULT, ALTER COLUMN state_time TYPE timestamp; ALTER TABLE icinga_systemcommands ALTER COLUMN start_time DROP DEFAULT, ALTER COLUMN start_time TYPE timestamp, ALTER COLUMN end_time DROP DEFAULT, ALTER COLUMN end_time TYPE timestamp; ALTER TABLE icinga_endpointstatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp; ALTER TABLE icinga_zonestatus ALTER COLUMN status_update_time DROP DEFAULT, ALTER COLUMN status_update_time TYPE timestamp; -- ----------------------------------------- -- set dbversion -- ----------------------------------------- SELECT updatedbversion('1.14.2'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.8.0.sql000066400000000000000000000026421322762156600223250ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.8.0 -- -- ----------------------------------------- -- Copyright (c) 2017 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE icinga_downtimehistory DROP CONSTRAINT IF EXISTS UQ_downtimehistory; ALTER TABLE icinga_scheduleddowntime DROP CONSTRAINT IF EXISTS UQ_scheduleddowntime; ALTER TABLE icinga_commenthistory DROP CONSTRAINT IF EXISTS UQ_commenthistory; ALTER TABLE icinga_comments DROP CONSTRAINT IF EXISTS UQ_comments; -- ----------------------------------------- -- #5458 IDO: Improve downtime removal/cancel -- ----------------------------------------- CREATE INDEX idx_downtimehistory_remove ON icinga_downtimehistory (object_id, entry_time, scheduled_start_time, scheduled_end_time); CREATE INDEX idx_scheduleddowntime_remove ON icinga_scheduleddowntime (object_id, entry_time, scheduled_start_time, scheduled_end_time); -- ----------------------------------------- -- #5492 -- ----------------------------------------- CREATE INDEX idx_commenthistory_remove ON icinga_commenthistory (object_id, entry_time); CREATE INDEX idx_comments_remove ON icinga_comments (object_id, entry_time); -- ----------------------------------------- -- set dbversion -- ----------------------------------------- SELECT updatedbversion('1.14.3'); icinga2-2.8.1/lib/db_ido_pgsql/schema/upgrade/2.8.1.sql000066400000000000000000000014701322762156600223240ustar00rootroot00000000000000-- ----------------------------------------- -- upgrade path for Icinga 2.8.1 (fix for fresh 2.8.0 installation only) -- -- ----------------------------------------- -- Copyright (c) 2018 Icinga Development Team (https://www.icinga.com) -- -- Please check https://docs.icinga.com for upgrading information! -- ----------------------------------------- ALTER TABLE icinga_downtimehistory DROP CONSTRAINT IF EXISTS UQ_downtimehistory; ALTER TABLE icinga_scheduleddowntime DROP CONSTRAINT IF EXISTS UQ_scheduleddowntime; ALTER TABLE icinga_commenthistory DROP CONSTRAINT IF EXISTS UQ_commenthistory; ALTER TABLE icinga_comments DROP CONSTRAINT IF EXISTS UQ_comments; -- ----------------------------------------- -- set dbversion (same as 2.8.0) -- ----------------------------------------- SELECT updatedbversion('1.14.3'); icinga2-2.8.1/lib/demo/000077500000000000000000000000001322762156600145425ustar00rootroot00000000000000icinga2-2.8.1/lib/demo/CMakeLists.txt000066400000000000000000000025311322762156600173030ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(demo.ti demo.tcpp demo.thpp) set(demo_SOURCES demo.cpp demo.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(demo demo demo_SOURCES) endif() add_library(demo SHARED ${demo_SOURCES}) target_link_libraries(demo ${Boost_LIBRARIES} base config icinga remote) set_target_properties ( demo PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_DEMO_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install( TARGETS demo RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/demo/demo.cpp000066400000000000000000000052001322762156600161670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "demo/demo.hpp" #include "demo/demo.tcpp" #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_TYPE(Demo); REGISTER_APIFUNCTION(HelloWorld, demo, &Demo::DemoMessageHandler); /** * Starts the component. */ void Demo::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); m_DemoTimer = new Timer(); m_DemoTimer->SetInterval(5); m_DemoTimer->OnTimerExpired.connect(boost::bind(&Demo::DemoTimerHandler, this)); m_DemoTimer->Start(); } /** * Periodically broadcasts an API message. */ void Demo::DemoTimerHandler(void) { Dictionary::Ptr message = new Dictionary(); message->Set("method", "demo::HelloWorld"); ApiListener::Ptr listener = ApiListener::GetInstance(); if (listener) { MessageOrigin::Ptr origin = new MessageOrigin(); listener->RelayMessage(origin, ConfigObject::Ptr(), message, true); Log(LogInformation, "Demo", "Sent demo::HelloWorld message"); } } Value Demo::DemoMessageHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr&) { Log(LogInformation, "Demo") << "Got demo message from '" << origin->FromClient->GetEndpoint()->GetName() << "'"; return Empty; } icinga2-2.8.1/lib/demo/demo.hpp000066400000000000000000000036361322762156600162070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DEMO_H #define DEMO_H #include "demo/demo.thpp" #include "remote/messageorigin.hpp" #include "base/timer.hpp" namespace icinga { /** * @ingroup demo */ class Demo : public ObjectImpl { public: DECLARE_OBJECT(Demo); DECLARE_OBJECTNAME(Demo); virtual void Start(bool runtimeCreated) override; static Value DemoMessageHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); private: Timer::Ptr m_DemoTimer; void DemoTimerHandler(void); }; } #endif /* DEMO_H */ icinga2-2.8.1/lib/demo/demo.ti000066400000000000000000000030111322762156600160170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library demo; namespace icinga { class Demo : ConfigObject { }; } icinga2-2.8.1/lib/hello/000077500000000000000000000000001322762156600147215ustar00rootroot00000000000000icinga2-2.8.1/lib/hello/CMakeLists.txt000066400000000000000000000026121322762156600174620ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(helloapplication.ti helloapplication.tcpp helloapplication.thpp) set(hello_SOURCES helloapplication.cpp helloapplication.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(hello hello hello_SOURCES) endif() add_library(hello SHARED ${hello_SOURCES}) target_link_libraries(hello ${Boost_LIBRARIES} base config) set_target_properties ( hello PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_HELLO_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS hello RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/hello/helloapplication.cpp000066400000000000000000000036351322762156600207630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "hello/helloapplication.hpp" #include "hello/helloapplication.tcpp" #include "base/initialize.hpp" #include "base/logger.hpp" #include "base/scriptglobal.hpp" using namespace icinga; REGISTER_TYPE(HelloApplication); INITIALIZE_ONCE([]() { ScriptGlobal::Set("ApplicationType", "HelloApplication"); }); /** * The entry point for the hello application. * * @returns An exit status. */ int HelloApplication::Main(void) { Log(LogInformation, "HelloApplication", "Hello World!"); return 0; } icinga2-2.8.1/lib/hello/helloapplication.hpp000066400000000000000000000034471322762156600207710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HELLOAPPLICATION_H #define HELLOAPPLICATION_H #include "hello/helloapplication.thpp" namespace icinga { /** * The hello application. * * @ingroup hello */ class HelloApplication : public ObjectImpl { public: DECLARE_OBJECT(HelloApplication); DECLARE_OBJECTNAME(HelloApplication); virtual int Main(void) override; }; } #endif /* HELLOAPPLICATION_H */ icinga2-2.8.1/lib/hello/helloapplication.ti000066400000000000000000000030241322762156600206050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" library hello; namespace icinga { class HelloApplication : Application { }; } icinga2-2.8.1/lib/icinga/000077500000000000000000000000001322762156600150505ustar00rootroot00000000000000icinga2-2.8.1/lib/icinga/CMakeLists.txt000066400000000000000000000072641322762156600176210ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(checkable.ti checkable.tcpp checkable.thpp) mkclass_target(checkcommand.ti checkcommand.tcpp checkcommand.thpp) mkclass_target(checkresult.ti checkresult.tcpp checkresult.thpp) mkclass_target(command.ti command.tcpp command.thpp) mkclass_target(comment.ti comment.tcpp comment.thpp) mkclass_target(dependency.ti dependency.tcpp dependency.thpp) mkclass_target(downtime.ti downtime.tcpp downtime.thpp) mkclass_target(eventcommand.ti eventcommand.tcpp eventcommand.thpp) mkclass_target(hostgroup.ti hostgroup.tcpp hostgroup.thpp) mkclass_target(host.ti host.tcpp host.thpp) mkclass_target(icingaapplication.ti icingaapplication.tcpp icingaapplication.thpp) mkclass_target(customvarobject.ti customvarobject.tcpp customvarobject.thpp) mkclass_target(notificationcommand.ti notificationcommand.tcpp notificationcommand.thpp) mkclass_target(notification.ti notification.tcpp notification.thpp) mkclass_target(scheduleddowntime.ti scheduleddowntime.tcpp scheduleddowntime.thpp) mkclass_target(servicegroup.ti servicegroup.tcpp servicegroup.thpp) mkclass_target(service.ti service.tcpp service.thpp) mkclass_target(timeperiod.ti timeperiod.tcpp timeperiod.thpp) mkclass_target(usergroup.ti usergroup.tcpp usergroup.thpp) mkclass_target(user.ti user.tcpp user.thpp) mkembedconfig_target(icinga-itl.conf icinga-itl.cpp) set(icinga_SOURCES apiactions.cpp apievents.cpp checkable.cpp checkable.thpp checkable-dependency.cpp checkable-downtime.cpp checkable-event.cpp checkable-flapping.cpp checkable-script.cpp checkcommand.cpp checkcommand.thpp checkresult.cpp checkresult.thpp cib.cpp clusterevents.cpp command.cpp command.thpp comment.cpp comment.thpp compatutility.cpp dependency.cpp dependency.thpp dependency-apply.cpp downtime.cpp downtime.thpp eventcommand.cpp eventcommand.thpp externalcommandprocessor.cpp host.cpp host.thpp hostgroup.cpp hostgroup.thpp icingaapplication.cpp icingaapplication.thpp icinga-itl.cpp customvarobject.cpp customvarobject.thpp legacytimeperiod.cpp macroprocessor.cpp notificationcommand.cpp notificationcommand.thpp notification.cpp notification.thpp notification-apply.cpp objectutils.cpp pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.thpp scheduleddowntime-apply.cpp service-apply.cpp checkable-check.cpp checkable-comment.cpp service.cpp service.thpp servicegroup.cpp servicegroup.thpp checkable-notification.cpp timeperiod.cpp timeperiod.thpp user.cpp user.thpp usergroup.cpp usergroup.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(icinga icinga icinga_SOURCES) endif() add_library(icinga SHARED ${icinga_SOURCES}) target_link_libraries(icinga ${Boost_LIBRARIES} base config remote) set_target_properties ( icinga PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_ICINGA_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS icinga RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/icinga/apiactions.cpp000066400000000000000000000421231322762156600177100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/apiactions.hpp" #include "icinga/service.hpp" #include "icinga/servicegroup.hpp" #include "icinga/hostgroup.hpp" #include "icinga/pluginutility.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "remote/apiaction.hpp" #include "remote/apilistener.hpp" #include "remote/pkiutility.hpp" #include "remote/httputility.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include using namespace icinga; REGISTER_APIACTION(process_check_result, "Service;Host", &ApiActions::ProcessCheckResult); REGISTER_APIACTION(reschedule_check, "Service;Host", &ApiActions::RescheduleCheck); REGISTER_APIACTION(send_custom_notification, "Service;Host", &ApiActions::SendCustomNotification); REGISTER_APIACTION(delay_notification, "Service;Host", &ApiActions::DelayNotification); REGISTER_APIACTION(acknowledge_problem, "Service;Host", &ApiActions::AcknowledgeProblem); REGISTER_APIACTION(remove_acknowledgement, "Service;Host", &ApiActions::RemoveAcknowledgement); REGISTER_APIACTION(add_comment, "Service;Host", &ApiActions::AddComment); REGISTER_APIACTION(remove_comment, "Service;Host;Comment", &ApiActions::RemoveComment); REGISTER_APIACTION(schedule_downtime, "Service;Host", &ApiActions::ScheduleDowntime); REGISTER_APIACTION(remove_downtime, "Service;Host;Downtime", &ApiActions::RemoveDowntime); REGISTER_APIACTION(shutdown_process, "", &ApiActions::ShutdownProcess); REGISTER_APIACTION(restart_process, "", &ApiActions::RestartProcess); REGISTER_APIACTION(generate_ticket, "", &ApiActions::GenerateTicket); Dictionary::Ptr ApiActions::CreateResult(int code, const String& status, const Dictionary::Ptr& additional) { Dictionary::Ptr result = new Dictionary(); result->Set("code", code); result->Set("status", status); if (additional) additional->CopyTo(result); return result; } Dictionary::Ptr ApiActions::ProcessCheckResult(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot process passive check result for non-existent object."); if (!checkable->GetEnablePassiveChecks()) return ApiActions::CreateResult(403, "Passive checks are disabled for object '" + checkable->GetName() + "'."); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); if (!params->Contains("exit_status")) return ApiActions::CreateResult(403, "Parameter 'exit_status' is required."); int exitStatus = HttpUtility::GetLastParameter(params, "exit_status"); ServiceState state; if (!service) { if (exitStatus == 0) state = ServiceOK; else if (exitStatus == 1) state = ServiceCritical; else return ApiActions::CreateResult(403, "Invalid 'exit_status' for Host " + checkable->GetName() + "."); } else { state = PluginUtility::ExitStatusToState(exitStatus); } if (!params->Contains("plugin_output")) return ApiActions::CreateResult(403, "Parameter 'plugin_output' is required"); CheckResult::Ptr cr = new CheckResult(); cr->SetOutput(HttpUtility::GetLastParameter(params, "plugin_output")); cr->SetState(state); if (params->Contains("execution_start")) cr->SetExecutionStart(HttpUtility::GetLastParameter(params, "execution_start")); if (params->Contains("execution_end")) cr->SetExecutionEnd(HttpUtility::GetLastParameter(params, "execution_end")); cr->SetCheckSource(HttpUtility::GetLastParameter(params, "check_source")); cr->SetPerformanceData(params->Get("performance_data")); cr->SetCommand(params->Get("check_command")); /* Mark this check result as passive. */ cr->SetActive(false); checkable->ProcessCheckResult(cr); return ApiActions::CreateResult(200, "Successfully processed check result for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::RescheduleCheck(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot reschedule check for non-existent object."); if (Convert::ToBool(HttpUtility::GetLastParameter(params, "force"))) checkable->SetForceNextCheck(true); double nextCheck; if (params->Contains("next_check")) nextCheck = HttpUtility::GetLastParameter(params, "next_check"); else nextCheck = Utility::GetTime(); checkable->SetNextCheck(nextCheck); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(checkable); return ApiActions::CreateResult(200, "Successfully rescheduled check for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::SendCustomNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot send notification for non-existent object."); if (!params->Contains("author")) return ApiActions::CreateResult(403, "Parameter 'author' is required."); if (!params->Contains("comment")) return ApiActions::CreateResult(403, "Parameter 'comment' is required."); if (Convert::ToBool(HttpUtility::GetLastParameter(params, "force"))) checkable->SetForceNextNotification(true); Checkable::OnNotificationsRequested(checkable, NotificationCustom, checkable->GetLastCheckResult(), HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), MessageOrigin::Ptr()); return ApiActions::CreateResult(200, "Successfully sent custom notification for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::DelayNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot delay notifications for non-existent object"); if (!params->Contains("timestamp")) return ApiActions::CreateResult(403, "A timestamp is required to delay notifications"); for (const Notification::Ptr& notification : checkable->GetNotifications()) { notification->SetNextNotification(HttpUtility::GetLastParameter(params, "timestamp")); } return ApiActions::CreateResult(200, "Successfully delayed notifications for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::AcknowledgeProblem(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot acknowledge problem for non-existent object."); if (!params->Contains("author") || !params->Contains("comment")) return ApiActions::CreateResult(403, "Acknowledgements require author and comment."); AcknowledgementType sticky = AcknowledgementNormal; bool notify = false; bool persistent = false; double timestamp = 0.0; if (params->Contains("sticky") && HttpUtility::GetLastParameter(params, "sticky")) sticky = AcknowledgementSticky; if (params->Contains("notify")) notify = HttpUtility::GetLastParameter(params, "notify"); if (params->Contains("persistent")) persistent = HttpUtility::GetLastParameter(params, "persistent"); if (params->Contains("expiry")) { timestamp = HttpUtility::GetLastParameter(params, "expiry"); if (timestamp <= Utility::GetTime()) return ApiActions::CreateResult(409, "Acknowledgement 'expiry' timestamp must be in the future for object " + checkable->GetName()); } else timestamp = 0; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); if (!service) { if (host->GetState() == HostUp) return ApiActions::CreateResult(409, "Host " + checkable->GetName() + " is UP."); } else { if (service->GetState() == ServiceOK) return ApiActions::CreateResult(409, "Service " + checkable->GetName() + " is OK."); } Comment::AddComment(checkable, CommentAcknowledgement, HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), persistent, timestamp); checkable->AcknowledgeProblem(HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), sticky, notify, persistent, timestamp); return ApiActions::CreateResult(200, "Successfully acknowledged problem for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::RemoveAcknowledgement(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot remove acknowlegement for non-existent checkable object " + object->GetName() + "."); checkable->ClearAcknowledgement(); checkable->RemoveCommentsByType(CommentAcknowledgement); return ApiActions::CreateResult(200, "Successfully removed acknowledgement for object '" + checkable->GetName() + "'."); } Dictionary::Ptr ApiActions::AddComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Cannot add comment for non-existent object"); if (!params->Contains("author") || !params->Contains("comment")) return ApiActions::CreateResult(403, "Comments require author and comment."); String commentName = Comment::AddComment(checkable, CommentUser, HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), false, 0); Comment::Ptr comment = Comment::GetByName(commentName); Dictionary::Ptr additional = new Dictionary(); additional->Set("name", commentName); additional->Set("legacy_id", comment->GetLegacyId()); return ApiActions::CreateResult(200, "Successfully added comment '" + commentName + "' for object '" + checkable->GetName() + "'.", additional); } Dictionary::Ptr ApiActions::RemoveComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = dynamic_pointer_cast(object); if (checkable) { std::set comments = checkable->GetComments(); for (const Comment::Ptr& comment : comments) { Comment::RemoveComment(comment->GetName()); } return ApiActions::CreateResult(200, "Successfully removed all comments for object '" + checkable->GetName() + "'."); } Comment::Ptr comment = static_pointer_cast(object); if (!comment) return ApiActions::CreateResult(404, "Cannot remove non-existent comment object."); String commentName = comment->GetName(); Comment::RemoveComment(commentName); return ApiActions::CreateResult(200, "Successfully removed comment '" + commentName + "'."); } Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast(object); if (!checkable) return ApiActions::CreateResult(404, "Can't schedule downtime for non-existent object."); if (!params->Contains("start_time") || !params->Contains("end_time") || !params->Contains("author") || !params->Contains("comment")) { return ApiActions::CreateResult(404, "Options 'start_time', 'end_time', 'author' and 'comment' are required"); } bool fixed = true; if (params->Contains("fixed")) fixed = HttpUtility::GetLastParameter(params, "fixed"); if (!fixed && !params->Contains("duration")) return ApiActions::CreateResult(404, "Option 'duration' is required for flexible downtime"); double duration = 0.0; if (params->Contains("duration")) duration = HttpUtility::GetLastParameter(params, "duration"); String triggerName; if (params->Contains("trigger_name")) triggerName = HttpUtility::GetLastParameter(params, "trigger_name"); String author = HttpUtility::GetLastParameter(params, "author"); String comment = HttpUtility::GetLastParameter(params, "comment"); double startTime = HttpUtility::GetLastParameter(params, "start_time"); double endTime = HttpUtility::GetLastParameter(params, "end_time"); String downtimeName = Downtime::AddDowntime(checkable, author, comment, startTime, endTime, fixed, triggerName, duration); Downtime::Ptr downtime = Downtime::GetByName(downtimeName); Dictionary::Ptr additional = new Dictionary(); additional->Set("name", downtimeName); additional->Set("legacy_id", downtime->GetLegacyId()); /* Schedule downtime for all child objects. */ int childOptions = 0; if (params->Contains("child_options")) childOptions = HttpUtility::GetLastParameter(params, "child_options"); if (childOptions > 0) { /* '1' schedules child downtimes triggered by the parent downtime. * '2' schedules non-triggered downtimes for all children. */ if (childOptions == 1) triggerName = downtimeName; Array::Ptr childDowntimes = new Array(); Log(LogCritical, "ApiActions") << "Processing child options " << childOptions << " for downtime " << downtimeName; for (const Checkable::Ptr& child : checkable->GetAllChildren()) { Log(LogCritical, "ApiActions") << "Scheduling downtime for child object " << child->GetName(); String childDowntimeName = Downtime::AddDowntime(child, author, comment, startTime, endTime, fixed, triggerName, duration); Log(LogCritical, "ApiActions") << "Add child downtime '" << childDowntimeName << "'."; Downtime::Ptr childDowntime = Downtime::GetByName(childDowntimeName); Dictionary::Ptr additionalChild = new Dictionary(); additionalChild->Set("name", childDowntimeName); additionalChild->Set("legacy_id", childDowntime->GetLegacyId()); childDowntimes->Add(additionalChild); } additional->Set("child_downtimes", childDowntimes); } return ApiActions::CreateResult(200, "Successfully scheduled downtime '" + downtimeName + "' for object '" + checkable->GetName() + "'.", additional); } Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = dynamic_pointer_cast(object); if (checkable) { std::set downtimes = checkable->GetDowntimes(); for (const Downtime::Ptr& downtime : downtimes) { Downtime::RemoveDowntime(downtime->GetName(), true); } return ApiActions::CreateResult(200, "Successfully removed all downtimes for object '" + checkable->GetName() + "'."); } Downtime::Ptr downtime = static_pointer_cast(object); if (!downtime) return ApiActions::CreateResult(404, "Cannot remove non-existent downtime object."); String downtimeName = downtime->GetName(); Downtime::RemoveDowntime(downtimeName, true); return ApiActions::CreateResult(200, "Successfully removed downtime '" + downtimeName + "'."); } Dictionary::Ptr ApiActions::ShutdownProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Application::RequestShutdown(); return ApiActions::CreateResult(200, "Shutting down Icinga 2."); } Dictionary::Ptr ApiActions::RestartProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Application::RequestRestart(); return ApiActions::CreateResult(200, "Restarting Icinga 2."); } Dictionary::Ptr ApiActions::GenerateTicket(const ConfigObject::Ptr&, const Dictionary::Ptr& params) { if (!params->Contains("cn")) return ApiActions::CreateResult(404, "Option 'cn' is required"); String cn = HttpUtility::GetLastParameter(params, "cn"); ApiListener::Ptr listener = ApiListener::GetInstance(); String salt = listener->GetTicketSalt(); if (salt.IsEmpty()) return ApiActions::CreateResult(500, "Ticket salt is not configured in ApiListener object"); String ticket = PBKDF2_SHA1(cn, salt, 50000); Dictionary::Ptr additional = new Dictionary(); additional->Set("ticket", ticket); return ApiActions::CreateResult(200, "Generated PKI ticket '" + ticket + "' for common name '" + cn + "'.", additional); } icinga2-2.8.1/lib/icinga/apiactions.hpp000066400000000000000000000062171322762156600177210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APIACTIONS_H #define APIACTIONS_H #include "icinga/i2-icinga.hpp" #include "base/configobject.hpp" #include "base/dictionary.hpp" namespace icinga { /** * @ingroup icinga */ class I2_ICINGA_API ApiActions { public: static Dictionary::Ptr ProcessCheckResult(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr RescheduleCheck(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr SendCustomNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr DelayNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr AcknowledgeProblem(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr RemoveAcknowledgement(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr AddComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr RemoveComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr ScheduleDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr RemoveDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr ShutdownProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr RestartProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); static Dictionary::Ptr GenerateTicket(const ConfigObject::Ptr& object, const Dictionary::Ptr& params); private: static Dictionary::Ptr CreateResult(int code, const String& status, const Dictionary::Ptr& additional = Dictionary::Ptr()); }; } #endif /* APIACTIONS_H */ icinga2-2.8.1/lib/icinga/apievents.cpp000066400000000000000000000276751322762156600175730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/apievents.hpp" #include "icinga/service.hpp" #include "remote/eventqueue.hpp" #include "base/initialize.hpp" #include "base/serializer.hpp" #include "base/logger.hpp" using namespace icinga; INITIALIZE_ONCE(&ApiEvents::StaticInitialize); void ApiEvents::StaticInitialize(void) { Checkable::OnNewCheckResult.connect(&ApiEvents::CheckResultHandler); Checkable::OnStateChange.connect(&ApiEvents::StateChangeHandler); Checkable::OnNotificationSentToAllUsers.connect(&ApiEvents::NotificationSentToAllUsersHandler); Checkable::OnFlappingChanged.connect(&ApiEvents::FlappingChangedHandler); Checkable::OnAcknowledgementSet.connect(&ApiEvents::AcknowledgementSetHandler); Checkable::OnAcknowledgementCleared.connect(&ApiEvents::AcknowledgementClearedHandler); Comment::OnCommentAdded.connect(&ApiEvents::CommentAddedHandler); Comment::OnCommentRemoved.connect(&ApiEvents::CommentRemovedHandler); Downtime::OnDowntimeAdded.connect(&ApiEvents::DowntimeAddedHandler); Downtime::OnDowntimeRemoved.connect(&ApiEvents::DowntimeRemovedHandler); Downtime::OnDowntimeStarted.connect(&ApiEvents::DowntimeStartedHandler); Downtime::OnDowntimeTriggered.connect(&ApiEvents::DowntimeTriggeredHandler); } void ApiEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("CheckResult"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'CheckResult'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "CheckResult"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); result->Set("check_result", Serialize(cr)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("StateChange"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'StateChange'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "StateChange"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); result->Set("state", service ? static_cast(service->GetState()) : static_cast(host->GetState())); result->Set("state_type", checkable->GetStateType()); result->Set("check_result", Serialize(cr)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("Notification"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'Notification'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "Notification"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); Array::Ptr userNames = new Array(); for (const User::Ptr& user : users) { userNames->Add(user->GetName()); } result->Set("users", userNames); result->Set("notification_type", Notification::NotificationTypeToString(type)); result->Set("author", author); result->Set("text", text); result->Set("check_result", Serialize(cr)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::FlappingChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("Flapping"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'Flapping'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "Flapping"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); result->Set("state", service ? static_cast(service->GetState()) : static_cast(host->GetState())); result->Set("state_type", checkable->GetStateType()); result->Set("is_flapping", checkable->IsFlapping()); result->Set("flapping_current", checkable->GetFlappingCurrent()); result->Set("threshold_low", checkable->GetFlappingThresholdLow()); result->Set("threshold_high", checkable->GetFlappingThresholdHigh()); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("AcknowledgementSet"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'AcknowledgementSet'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "AcknowledgementSet"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); result->Set("state", service ? static_cast(service->GetState()) : static_cast(host->GetState())); result->Set("state_type", checkable->GetStateType()); result->Set("author", author); result->Set("comment", comment); result->Set("acknowledgement_type", type); result->Set("notify", notify); result->Set("persistent", persistent); result->Set("expiry", expiry); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { std::vector queues = EventQueue::GetQueuesForType("AcknowledgementCleared"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'AcknowledgementCleared'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "AcknowledgementCleared"); result->Set("timestamp", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); result->Set("host", host->GetName()); if (service) result->Set("service", service->GetShortName()); result->Set("state", service ? static_cast(service->GetState()) : static_cast(host->GetState())); result->Set("state_type", checkable->GetStateType()); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } result->Set("acknowledgement_type", AcknowledgementNone); } void ApiEvents::CommentAddedHandler(const Comment::Ptr& comment) { std::vector queues = EventQueue::GetQueuesForType("CommentAdded"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'CommentAdded'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "CommentAdded"); result->Set("timestamp", Utility::GetTime()); result->Set("comment", Serialize(comment, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::CommentRemovedHandler(const Comment::Ptr& comment) { std::vector queues = EventQueue::GetQueuesForType("CommentRemoved"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'CommentRemoved'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "CommentRemoved"); result->Set("timestamp", Utility::GetTime()); result->Set("comment", Serialize(comment, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::DowntimeAddedHandler(const Downtime::Ptr& downtime) { std::vector queues = EventQueue::GetQueuesForType("DowntimeAdded"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'DowntimeAdded'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "DowntimeAdded"); result->Set("timestamp", Utility::GetTime()); result->Set("downtime", Serialize(downtime, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::DowntimeRemovedHandler(const Downtime::Ptr& downtime) { std::vector queues = EventQueue::GetQueuesForType("DowntimeRemoved"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'DowntimeRemoved'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "DowntimeRemoved"); result->Set("timestamp", Utility::GetTime()); result->Set("downtime", Serialize(downtime, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::DowntimeStartedHandler(const Downtime::Ptr& downtime) { std::vector queues = EventQueue::GetQueuesForType("DowntimeStarted"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'DowntimeStarted'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "DowntimeStarted"); result->Set("timestamp", Utility::GetTime()); result->Set("downtime", Serialize(downtime, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } void ApiEvents::DowntimeTriggeredHandler(const Downtime::Ptr& downtime) { std::vector queues = EventQueue::GetQueuesForType("DowntimeTriggered"); if (queues.empty()) return; Log(LogDebug, "ApiEvents", "Processing event type 'DowntimeTriggered'."); Dictionary::Ptr result = new Dictionary(); result->Set("type", "DowntimeTriggered"); result->Set("timestamp", Utility::GetTime()); result->Set("downtime", Serialize(downtime, FAConfig | FAState)); for (const EventQueue::Ptr& queue : queues) { queue->ProcessEvent(result); } } icinga2-2.8.1/lib/icinga/apievents.hpp000066400000000000000000000060551322762156600175650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APIEVENTS_H #define APIEVENTS_H #include "icinga/checkable.hpp" #include "icinga/host.hpp" namespace icinga { /** * @ingroup icinga */ class I2_ICINGA_API ApiEvents { public: static void StaticInitialize(void); static void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin); static void StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type, const MessageOrigin::Ptr& origin); static void NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin); static void FlappingChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin); static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static void CommentAddedHandler(const Comment::Ptr& comment); static void CommentRemovedHandler(const Comment::Ptr& comment); static void DowntimeAddedHandler(const Downtime::Ptr& downtime); static void DowntimeRemovedHandler(const Downtime::Ptr& downtime); static void DowntimeStartedHandler(const Downtime::Ptr& downtime); static void DowntimeTriggeredHandler(const Downtime::Ptr& downtime); }; } #endif /* APIEVENTS_H */ icinga2-2.8.1/lib/icinga/checkable-check.cpp000066400000000000000000000416211322762156600205340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/service.hpp" #include "icinga/host.hpp" #include "icinga/checkcommand.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "icinga/clusterevents.hpp" #include "remote/messageorigin.hpp" #include "remote/apilistener.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/context.hpp" using namespace icinga; boost::signals2::signal Checkable::OnNewCheckResult; boost::signals2::signal Checkable::OnStateChange; boost::signals2::signal, const MessageOrigin::Ptr&)> Checkable::OnReachabilityChanged; boost::signals2::signal Checkable::OnNotificationsRequested; boost::signals2::signal Checkable::OnNextCheckUpdated; boost::mutex Checkable::m_StatsMutex; int Checkable::m_PendingChecks = 0; CheckCommand::Ptr Checkable::GetCheckCommand(void) const { return dynamic_pointer_cast(NavigateCheckCommandRaw()); } TimePeriod::Ptr Checkable::GetCheckPeriod(void) const { return TimePeriod::GetByName(GetCheckPeriodRaw()); } void Checkable::SetSchedulingOffset(long offset) { m_SchedulingOffset = offset; } long Checkable::GetSchedulingOffset(void) { return m_SchedulingOffset; } void Checkable::UpdateNextCheck(const MessageOrigin::Ptr& origin) { double interval; if (GetStateType() == StateTypeSoft && GetLastCheckResult() != NULL) interval = GetRetryInterval(); else interval = GetCheckInterval(); double now = Utility::GetTime(); double adj = 0; if (interval > 1) adj = fmod(now * 100 + GetSchedulingOffset(), interval * 100) / 100.0; adj = std::min(0.5 + fmod(GetSchedulingOffset(), interval * 5) / 100.0, adj); SetNextCheck(now - adj + interval, false, origin); } bool Checkable::HasBeenChecked(void) const { return GetLastCheckResult() != NULL; } double Checkable::GetLastCheck(void) const { CheckResult::Ptr cr = GetLastCheckResult(); double schedule_end = -1; if (cr) schedule_end = cr->GetScheduleEnd(); return schedule_end; } void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin) { { ObjectLock olock(this); m_CheckRunning = false; } if (!cr) return; double now = Utility::GetTime(); if (cr->GetScheduleStart() == 0) cr->SetScheduleStart(now); if (cr->GetScheduleEnd() == 0) cr->SetScheduleEnd(now); if (cr->GetExecutionStart() == 0) cr->SetExecutionStart(now); if (cr->GetExecutionEnd() == 0) cr->SetExecutionEnd(now); if (!origin || origin->IsLocal()) cr->SetCheckSource(IcingaApplication::GetInstance()->GetNodeName()); Endpoint::Ptr command_endpoint = GetCommandEndpoint(); /* override check source if command_endpoint was defined */ if (command_endpoint && !GetExtension("agent_check")) cr->SetCheckSource(command_endpoint->GetName()); /* agent checks go through the api */ if (command_endpoint && GetExtension("agent_check")) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (listener) { /* send message back to its origin */ Dictionary::Ptr message = ClusterEvents::MakeCheckResultMessage(this, cr); listener->SyncSendMessage(command_endpoint, message); } return; } bool reachable = IsReachable(); bool notification_reachable = IsReachable(DependencyNotification); ObjectLock olock(this); CheckResult::Ptr old_cr = GetLastCheckResult(); ServiceState old_state = GetStateRaw(); StateType old_stateType = GetStateType(); long old_attempt = GetCheckAttempt(); bool recovery = false; /* Ignore check results older than the current one. */ if (old_cr && cr->GetExecutionStart() < old_cr->GetExecutionStart()) return; /* The ExecuteCheck function already sets the old state, but we need to do it again * in case this was a passive check result. */ SetLastStateRaw(old_state); SetLastStateType(old_stateType); SetLastReachable(reachable); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(this); CheckableType checkableType = CheckableHost; if (service) checkableType = CheckableService; long attempt = 1; std::set children = GetChildren(); if (IsStateOK(cr->GetState())) { SetStateType(StateTypeHard); // NOT-OK -> HARD OK if (!IsStateOK(old_state)) recovery = true; ResetNotificationNumbers(); SaveLastState(ServiceOK, Utility::GetTime()); /* update reachability for child objects in OK state */ if (!children.empty()) OnReachabilityChanged(this, cr, children, origin); } else { /* OK -> NOT-OK change, first SOFT state. Reset attempt counter. */ if (IsStateOK(old_state)) { SetStateType(StateTypeSoft); attempt = 1; } /* SOFT state change, increase attempt counter. */ if (old_stateType == StateTypeSoft && !IsStateOK(old_state)) { SetStateType(StateTypeSoft); attempt = old_attempt + 1; } /* HARD state change (e.g. previously 2/3 and this next attempt). Reset attempt counter. */ if (attempt >= GetMaxCheckAttempts()) { SetStateType(StateTypeHard); attempt = 1; } if (!IsStateOK(cr->GetState())) { SaveLastState(cr->GetState(), Utility::GetTime()); } /* update reachability for child objects in NOT-OK state */ if (!children.empty()) OnReachabilityChanged(this, cr, children, origin); } if (!reachable) SetLastStateUnreachable(Utility::GetTime()); SetCheckAttempt(attempt); ServiceState new_state = cr->GetState(); SetStateRaw(new_state); bool stateChange; /* Exception on state change calculation for hosts. */ if (checkableType == CheckableService) stateChange = (old_state != new_state); else stateChange = (Host::CalculateState(old_state) != Host::CalculateState(new_state)); if (stateChange) { SetLastStateChange(now); /* remove acknowledgements */ if (GetAcknowledgement() == AcknowledgementNormal || (GetAcknowledgement() == AcknowledgementSticky && IsStateOK(new_state))) { ClearAcknowledgement(); } /* reschedule direct parents */ for (const Checkable::Ptr& parent : GetParents()) { if (parent.get() == this) continue; ObjectLock olock(parent); parent->SetNextCheck(Utility::GetTime()); } } bool remove_acknowledgement_comments = false; if (GetAcknowledgement() == AcknowledgementNone) remove_acknowledgement_comments = true; bool hardChange = (GetStateType() == StateTypeHard && old_stateType == StateTypeSoft); if (stateChange && old_stateType == StateTypeHard && GetStateType() == StateTypeHard) hardChange = true; bool is_volatile = GetVolatile(); if (hardChange || is_volatile) { SetLastHardStateRaw(new_state); SetLastHardStateChange(now); } if (!IsStateOK(new_state)) TriggerDowntimes(); /* statistics for external tools */ Checkable::UpdateStatistics(cr, checkableType); bool in_downtime = IsInDowntime(); bool send_notification = false; if (notification_reachable && !in_downtime && !IsAcknowledged()) { /* Send notifications whether when a hard state change occured. */ if (hardChange && !(old_stateType == StateTypeSoft && IsStateOK(new_state))) send_notification = true; /* Or if the checkable is volatile and in a HARD state. */ else if (is_volatile && GetStateType() == StateTypeHard) send_notification = true; } if (IsStateOK(old_state) && old_stateType == StateTypeSoft) send_notification = false; /* Don't send notifications for SOFT-OK -> HARD-OK. */ if (is_volatile && IsStateOK(old_state) && IsStateOK(new_state)) send_notification = false; /* Don't send notifications for volatile OK -> OK changes. */ olock.Unlock(); if (remove_acknowledgement_comments) RemoveCommentsByType(CommentAcknowledgement); Dictionary::Ptr vars_after = new Dictionary(); vars_after->Set("state", new_state); vars_after->Set("state_type", GetStateType()); vars_after->Set("attempt", GetCheckAttempt()); vars_after->Set("reachable", reachable); if (old_cr) cr->SetVarsBefore(old_cr->GetVarsAfter()); cr->SetVarsAfter(vars_after); olock.Lock(); SetLastCheckResult(cr); bool was_flapping = IsFlapping(); UpdateFlappingStatus(old_state != cr->GetState()); bool is_flapping = IsFlapping(); if (cr->GetActive()) { UpdateNextCheck(origin); } else { /* Reschedule the next check for passive check results. The side effect of * this is that for as long as we receive passive results for a service we * won't execute any active checks. */ SetNextCheck(Utility::GetTime() + GetCheckInterval(), false, origin); } olock.Unlock(); #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "Checkable") << "Flapping: Checkable " << GetName() << " was: " << was_flapping << " is: " << is_flapping << " threshold low: " << GetFlappingThresholdLow() << " threshold high: " << GetFlappingThresholdHigh() << "% current: " << GetFlappingCurrent() << "%."; #endif /* I2_DEBUG */ OnNewCheckResult(this, cr, origin); /* signal status updates to for example db_ido */ OnStateChanged(this); String old_state_str = (service ? Service::StateToString(old_state) : Host::StateToString(Host::CalculateState(old_state))); String new_state_str = (service ? Service::StateToString(new_state) : Host::StateToString(Host::CalculateState(new_state))); /* Whether a hard state change or a volatile state change except OK -> OK happened. */ if (hardChange || (is_volatile && !(IsStateOK(old_state) && IsStateOK(new_state)))) { OnStateChange(this, cr, StateTypeHard, origin); Log(LogNotice, "Checkable") << "State Change: Checkable '" << GetName() << "' hard state change from " << old_state_str << " to " << new_state_str << " detected." << (is_volatile ? " Checkable is volatile." : ""); } /* Whether a state change happened or the state type is SOFT (must be logged too). */ else if (stateChange || GetStateType() == StateTypeSoft) { OnStateChange(this, cr, StateTypeSoft, origin); Log(LogNotice, "Checkable") << "State Change: Checkable '" << GetName() << "' soft state change from " << old_state_str << " to " << new_state_str << " detected."; } if (GetStateType() == StateTypeSoft || hardChange || recovery || (is_volatile && !(IsStateOK(old_state) && IsStateOK(new_state)))) ExecuteEventHandler(); /* Flapping start/end notifications */ if (!in_downtime && !was_flapping && is_flapping) { /* FlappingStart notifications happen on state changes, not in downtimes */ if (!IsPaused()) OnNotificationsRequested(this, NotificationFlappingStart, cr, "", "", MessageOrigin::Ptr()); Log(LogNotice, "Checkable") << "Flapping Start: Checkable '" << GetName() << "' started flapping (Current flapping value " << GetFlappingCurrent() << "% > high threshold " << GetFlappingThresholdHigh() << "%)."; NotifyFlapping(origin); } else if (!in_downtime && was_flapping && !is_flapping) { /* FlappingEnd notifications are independent from state changes, must not happen in downtine */ if (!IsPaused()) OnNotificationsRequested(this, NotificationFlappingEnd, cr, "", "", MessageOrigin::Ptr()); Log(LogNotice, "Checkable") << "Flapping Stop: Checkable '" << GetName() << "' stopped flapping (Current flapping value " << GetFlappingCurrent() << "% < low threshold " << GetFlappingThresholdLow() << "%)."; NotifyFlapping(origin); } if (send_notification && !is_flapping) { if (!IsPaused()) OnNotificationsRequested(this, recovery ? NotificationRecovery : NotificationProblem, cr, "", "", MessageOrigin::Ptr()); } } void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) { CONTEXT("Executing remote check for object '" + GetName() + "'"); double scheduled_start = GetNextCheck(); double before_check = Utility::GetTime(); CheckResult::Ptr cr = new CheckResult(); cr->SetScheduleStart(scheduled_start); cr->SetExecutionStart(before_check); GetCheckCommand()->Execute(this, cr, resolvedMacros, true); } void Checkable::ExecuteCheck(void) { CONTEXT("Executing check for object '" + GetName() + "'"); /* keep track of scheduling info in case the check type doesn't provide its own information */ double scheduled_start = GetNextCheck(); double before_check = Utility::GetTime(); UpdateNextCheck(); bool reachable = IsReachable(); { ObjectLock olock(this); /* don't run another check if there is one pending */ if (m_CheckRunning) return; m_CheckRunning = true; SetLastStateRaw(GetStateRaw()); SetLastStateType(GetLastStateType()); SetLastReachable(reachable); } CheckResult::Ptr cr = new CheckResult(); cr->SetScheduleStart(scheduled_start); cr->SetExecutionStart(before_check); Endpoint::Ptr endpoint = GetCommandEndpoint(); bool local = !endpoint || endpoint == Endpoint::GetLocalEndpoint(); if (local) { GetCheckCommand()->Execute(this, cr, NULL, false); } else { Dictionary::Ptr macros = new Dictionary(); GetCheckCommand()->Execute(this, cr, macros, false); if (endpoint->GetConnected()) { /* perform check on remote endpoint */ Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::ExecuteCommand"); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(this); Dictionary::Ptr params = new Dictionary(); message->Set("params", params); params->Set("command_type", "check_command"); params->Set("command", GetCheckCommand()->GetName()); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("macros", macros); ApiListener::Ptr listener = ApiListener::GetInstance(); if (listener) listener->SyncSendMessage(endpoint, message); /* Re-schedule the check so we don't run it again until after we've received a check result from the remote instance. The check will be re-scheduled using the proper check interval once we've received a check result. */ SetNextCheck(Utility::GetTime() + GetCheckCommand()->GetTimeout() + 30); } else if (!endpoint->GetSyncing() && Application::GetInstance()->GetStartTime() < Utility::GetTime() - 300) { /* fail to perform check on unconnected endpoint */ cr->SetState(ServiceUnknown); String output = "Remote Icinga instance '" + endpoint->GetName() + "' is not connected to "; Endpoint::Ptr localEndpoint = Endpoint::GetLocalEndpoint(); if (localEndpoint) output += "'" + localEndpoint->GetName() + "'"; else output += "this instance"; cr->SetOutput(output); ProcessCheckResult(cr); } { ObjectLock olock(this); m_CheckRunning = false; } } } void Checkable::UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type) { time_t ts = cr->GetScheduleEnd(); if (type == CheckableHost) { if (cr->GetActive()) CIB::UpdateActiveHostChecksStatistics(ts, 1); else CIB::UpdatePassiveHostChecksStatistics(ts, 1); } else if (type == CheckableService) { if (cr->GetActive()) CIB::UpdateActiveServiceChecksStatistics(ts, 1); else CIB::UpdatePassiveServiceChecksStatistics(ts, 1); } else { Log(LogWarning, "Checkable", "Unknown checkable type for statistic update."); } } void Checkable::IncreasePendingChecks(void) { boost::mutex::scoped_lock lock(m_StatsMutex); m_PendingChecks++; } void Checkable::DecreasePendingChecks(void) { boost::mutex::scoped_lock lock(m_StatsMutex); m_PendingChecks--; } int Checkable::GetPendingChecks(void) { boost::mutex::scoped_lock lock(m_StatsMutex); return m_PendingChecks; } icinga2-2.8.1/lib/icinga/checkable-comment.cpp000066400000000000000000000050621322762156600211200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/service.hpp" #include "remote/configobjectutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include "base/logger.hpp" using namespace icinga; void Checkable::RemoveAllComments(void) { for (const Comment::Ptr& comment : GetComments()) { Comment::RemoveComment(comment->GetName()); } } void Checkable::RemoveCommentsByType(int type) { for (const Comment::Ptr& comment : GetComments()) { /* Do not remove persistent comments from an acknowledgement */ if (comment->GetEntryType() == CommentAcknowledgement && comment->GetPersistent()) continue; if (comment->GetEntryType() == type) Comment::RemoveComment(comment->GetName()); } } std::set Checkable::GetComments(void) const { boost::mutex::scoped_lock lock(m_CommentMutex); return m_Comments; } void Checkable::RegisterComment(const Comment::Ptr& comment) { boost::mutex::scoped_lock lock(m_CommentMutex); m_Comments.insert(comment); } void Checkable::UnregisterComment(const Comment::Ptr& comment) { boost::mutex::scoped_lock lock(m_CommentMutex); m_Comments.erase(comment); } icinga2-2.8.1/lib/icinga/checkable-dependency.cpp000066400000000000000000000113631322762156600215750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/service.hpp" #include "icinga/dependency.hpp" #include "base/logger.hpp" using namespace icinga; void Checkable::AddDependency(const Dependency::Ptr& dep) { boost::mutex::scoped_lock lock(m_DependencyMutex); m_Dependencies.insert(dep); } void Checkable::RemoveDependency(const Dependency::Ptr& dep) { boost::mutex::scoped_lock lock(m_DependencyMutex); m_Dependencies.erase(dep); } std::set Checkable::GetDependencies(void) const { boost::mutex::scoped_lock lock(m_DependencyMutex); return m_Dependencies; } void Checkable::AddReverseDependency(const Dependency::Ptr& dep) { boost::mutex::scoped_lock lock(m_DependencyMutex); m_ReverseDependencies.insert(dep); } void Checkable::RemoveReverseDependency(const Dependency::Ptr& dep) { boost::mutex::scoped_lock lock(m_DependencyMutex); m_ReverseDependencies.erase(dep); } std::set Checkable::GetReverseDependencies(void) const { boost::mutex::scoped_lock lock(m_DependencyMutex); return m_ReverseDependencies; } bool Checkable::IsReachable(DependencyType dt, Dependency::Ptr *failedDependency, int rstack) const { if (rstack > 20) { Log(LogWarning, "Checkable") << "Too many nested dependencies for service '" << GetName() << "': Dependency failed."; return false; } for (const Checkable::Ptr& checkable : GetParents()) { if (!checkable->IsReachable(dt, failedDependency, rstack + 1)) return false; } /* implicit dependency on host if this is a service */ const Service *service = dynamic_cast(this); if (service && (dt == DependencyState || dt == DependencyNotification)) { Host::Ptr host = service->GetHost(); if (host && host->GetState() != HostUp && host->GetStateType() == StateTypeHard) { if (failedDependency) *failedDependency = Dependency::Ptr(); return false; } } for (const Dependency::Ptr& dep : GetDependencies()) { if (!dep->IsAvailable(dt)) { if (failedDependency) *failedDependency = dep; return false; } } if (failedDependency) *failedDependency = Dependency::Ptr(); return true; } std::set Checkable::GetParents(void) const { std::set parents; for (const Dependency::Ptr& dep : GetDependencies()) { Checkable::Ptr parent = dep->GetParent(); if (parent && parent.get() != this) parents.insert(parent); } return parents; } std::set Checkable::GetChildren(void) const { std::set parents; for (const Dependency::Ptr& dep : GetReverseDependencies()) { Checkable::Ptr service = dep->GetChild(); if (service && service.get() != this) parents.insert(service); } return parents; } std::set Checkable::GetAllChildren(void) const { std::set children = GetChildren(); GetAllChildrenInternal(children, 0); return children; } void Checkable::GetAllChildrenInternal(std::set& children, int level) const { if (level > 32) return; std::set localChildren; for (const Checkable::Ptr& checkable : children) { std::set cChildren = checkable->GetChildren(); if (!checkable->GetChildren().empty()) { GetAllChildrenInternal(cChildren, level + 1); localChildren.insert(cChildren.begin(), cChildren.end()); } localChildren.insert(checkable); } children.insert(localChildren.begin(), localChildren.end()); } icinga2-2.8.1/lib/icinga/checkable-downtime.cpp000066400000000000000000000053041322762156600213030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/service.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/convert.hpp" using namespace icinga; void Checkable::RemoveAllDowntimes(void) { for (const Downtime::Ptr& downtime : GetDowntimes()) { Downtime::RemoveDowntime(downtime->GetName(), true, true); } } void Checkable::TriggerDowntimes(void) { for (const Downtime::Ptr& downtime : GetDowntimes()) { downtime->TriggerDowntime(); } } bool Checkable::IsInDowntime(void) const { for (const Downtime::Ptr& downtime : GetDowntimes()) { if (downtime->IsInEffect()) return true; } return false; } int Checkable::GetDowntimeDepth(void) const { int downtime_depth = 0; for (const Downtime::Ptr& downtime : GetDowntimes()) { if (downtime->IsInEffect()) downtime_depth++; } return downtime_depth; } std::set Checkable::GetDowntimes(void) const { boost::mutex::scoped_lock lock(m_DowntimeMutex); return m_Downtimes; } void Checkable::RegisterDowntime(const Downtime::Ptr& downtime) { boost::mutex::scoped_lock lock(m_DowntimeMutex); m_Downtimes.insert(downtime); } void Checkable::UnregisterDowntime(const Downtime::Ptr& downtime) { boost::mutex::scoped_lock lock(m_DowntimeMutex); m_Downtimes.erase(downtime); } icinga2-2.8.1/lib/icinga/checkable-event.cpp000066400000000000000000000063731322762156600206050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/eventcommand.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/service.hpp" #include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/context.hpp" using namespace icinga; boost::signals2::signal Checkable::OnEventCommandExecuted; EventCommand::Ptr Checkable::GetEventCommand(void) const { return EventCommand::GetByName(GetEventCommandRaw()); } void Checkable::ExecuteEventHandler(const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CONTEXT("Executing event handler for object '" + GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnableEventHandlers() || !GetEnableEventHandler()) return; EventCommand::Ptr ec = GetEventCommand(); if (!ec) return; Log(LogNotice, "Checkable") << "Executing event handler '" << ec->GetName() << "' for service '" << GetName() << "'"; Dictionary::Ptr macros; Endpoint::Ptr endpoint = GetCommandEndpoint(); if (endpoint && !useResolvedMacros) macros = new Dictionary(); else macros = resolvedMacros; ec->Execute(this, macros, useResolvedMacros); if (endpoint) { Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::ExecuteCommand"); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(this); Dictionary::Ptr params = new Dictionary(); message->Set("params", params); params->Set("command_type", "event_command"); params->Set("command", GetEventCommand()->GetName()); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("macros", macros); ApiListener::Ptr listener = ApiListener::GetInstance(); if (listener) listener->SyncSendMessage(endpoint, message); return; } OnEventCommandExecuted(this); } icinga2-2.8.1/lib/icinga/checkable-flapping.cpp000066400000000000000000000052751322762156600212640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include "icinga/checkable.hpp" #include "icinga/icingaapplication.hpp" #include "base/utility.hpp" using namespace icinga; void Checkable::UpdateFlappingStatus(bool stateChange) { /* TODO: Add support for Windows satellites/masters. */ #ifndef _WIN32 /* _WIN32 */ std::bitset<20> stateChangeBuf = GetFlappingBuffer(); int oldestIndex = GetFlappingIndex(); stateChangeBuf[oldestIndex] = stateChange; oldestIndex = (oldestIndex + 1) % 20; double stateChanges = 0; /* Iterate over our state array and compute a weighted total */ for (int i = 0; i < 20; i++) { if (stateChangeBuf[(oldestIndex + i) % 20]) stateChanges += 0.8 + (0.02 * i); } double flappingValue = 100.0 * stateChanges / 20.0; bool flapping; if (GetFlapping()) flapping = flappingValue > GetFlappingThresholdLow(); else flapping = flappingValue > GetFlappingThresholdHigh(); SetFlappingBuffer(stateChangeBuf.to_ulong()); SetFlappingIndex(oldestIndex); SetFlappingCurrent(flappingValue); SetFlapping(flapping, true); if (flapping != GetFlapping()) SetFlappingLastChange(Utility::GetTime()); #endif /* _WIN32 */ } bool Checkable::IsFlapping(void) const { if (!GetEnableFlapping() || !IcingaApplication::GetInstance()->GetEnableFlapping()) return false; else return GetFlapping(); } icinga2-2.8.1/lib/icinga/checkable-notification.cpp000066400000000000000000000102561322762156600221450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/icingaapplication.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/context.hpp" #include "base/convert.hpp" using namespace icinga; boost::signals2::signal&, const NotificationType&, const CheckResult::Ptr&, const String&, const String&, const MessageOrigin::Ptr&)> Checkable::OnNotificationSentToAllUsers; boost::signals2::signal Checkable::OnNotificationSentToUser; void Checkable::ResetNotificationNumbers(void) { for (const Notification::Ptr& notification : GetNotifications()) { ObjectLock olock(notification); notification->ResetNotificationNumber(); } } void Checkable::SendNotifications(NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { CONTEXT("Sending notifications for object '" + GetName() + "'"); bool force = GetForceNextNotification(); SetForceNextNotification(false); if (!IcingaApplication::GetInstance()->GetEnableNotifications() || !GetEnableNotifications()) { if (!force) { Log(LogInformation, "Checkable") << "Notifications are disabled for service '" << GetName() << "'."; return; } } Log(LogInformation, "Checkable") << "Checking for configured notifications for object '" << GetName() << "'"; std::set notifications = GetNotifications(); if (notifications.empty()) Log(LogInformation, "Checkable") << "Checkable '" << GetName() << "' does not have any notifications."; Log(LogDebug, "Checkable") << "Checkable '" << GetName() << "' has " << notifications.size() << " notification(s)."; for (const Notification::Ptr& notification : notifications) { try { if (!notification->IsPaused()) notification->BeginExecuteNotification(type, cr, force, false, author, text); } catch (const std::exception& ex) { Log(LogWarning, "Checkable") << "Exception occured during notification for service '" << GetName() << "': " << DiagnosticInformation(ex); } } } std::set Checkable::GetNotifications(void) const { boost::mutex::scoped_lock lock(m_NotificationMutex); return m_Notifications; } void Checkable::RegisterNotification(const Notification::Ptr& notification) { boost::mutex::scoped_lock lock(m_NotificationMutex); m_Notifications.insert(notification); } void Checkable::UnregisterNotification(const Notification::Ptr& notification) { boost::mutex::scoped_lock lock(m_NotificationMutex); m_Notifications.erase(notification); } icinga2-2.8.1/lib/icinga/checkable-script.cpp000066400000000000000000000041641322762156600207640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "base/configobject.hpp" #include "base/dictionary.hpp" #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" using namespace icinga; static void CheckableProcessCheckResult(const CheckResult::Ptr& cr) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Checkable::Ptr self = vframe->Self; self->ProcessCheckResult(cr); } Object::Ptr Checkable::GetPrototype(void) { static Dictionary::Ptr prototype; if (!prototype) { prototype = new Dictionary(); prototype->Set("process_check_result", new Function("Checkable#process_check_result", WrapFunction(CheckableProcessCheckResult), { "cr" }, false)); } return prototype; } icinga2-2.8.1/lib/icinga/checkable.cpp000066400000000000000000000153611322762156600174630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/checkable.tcpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_TYPE_WITH_PROTOTYPE(Checkable, Checkable::GetPrototype()); INITIALIZE_ONCE(&Checkable::StaticInitialize); boost::signals2::signal Checkable::OnAcknowledgementSet; boost::signals2::signal Checkable::OnAcknowledgementCleared; void Checkable::StaticInitialize(void) { /* fixed downtime start */ Downtime::OnDowntimeStarted.connect(boost::bind(&Checkable::NotifyFixedDowntimeStart, _1)); /* flexible downtime start */ Downtime::OnDowntimeTriggered.connect(boost::bind(&Checkable::NotifyFlexibleDowntimeStart, _1)); /* fixed/flexible downtime end */ Downtime::OnDowntimeRemoved.connect(boost::bind(&Checkable::NotifyDowntimeEnd, _1)); } Checkable::Checkable(void) : m_CheckRunning(false) { SetSchedulingOffset(Utility::Random()); } void Checkable::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); Endpoint::Ptr endpoint = GetCommandEndpoint(); if (endpoint) { Zone::Ptr checkableZone = static_pointer_cast(GetZone()); if (!checkableZone) checkableZone = Zone::GetLocalZone(); Zone::Ptr cmdZone = endpoint->GetZone(); if (checkableZone && cmdZone != checkableZone && cmdZone->GetParent() != checkableZone) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("command_endpoint"), "Command endpoint must be in zone '" + checkableZone->GetName() + "' or in a direct child zone thereof.")); } } } void Checkable::Start(bool runtimeCreated) { double now = Utility::GetTime(); if (GetNextCheck() < now + 300) UpdateNextCheck(); ObjectImpl::Start(runtimeCreated); } void Checkable::AddGroup(const String& name) { boost::mutex::scoped_lock lock(m_CheckableMutex); Array::Ptr groups; Host *host = dynamic_cast(this); if (host) groups = host->GetGroups(); else groups = static_cast(this)->GetGroups(); if (groups && groups->Contains(name)) return; if (!groups) groups = new Array(); groups->Add(name); } AcknowledgementType Checkable::GetAcknowledgement(void) { AcknowledgementType avalue = static_cast(GetAcknowledgementRaw()); if (avalue != AcknowledgementNone) { double expiry = GetAcknowledgementExpiry(); if (expiry != 0 && expiry < Utility::GetTime()) { avalue = AcknowledgementNone; ClearAcknowledgement(); } } return avalue; } bool Checkable::IsAcknowledged(void) const { return const_cast(this)->GetAcknowledgement() != AcknowledgementNone; } void Checkable::AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin) { SetAcknowledgementRaw(type); SetAcknowledgementExpiry(expiry); if (notify && !IsPaused()) OnNotificationsRequested(this, NotificationAcknowledgement, GetLastCheckResult(), author, comment, MessageOrigin::Ptr()); OnAcknowledgementSet(this, author, comment, type, notify, persistent, expiry, origin); } void Checkable::ClearAcknowledgement(const MessageOrigin::Ptr& origin) { SetAcknowledgementRaw(AcknowledgementNone); SetAcknowledgementExpiry(0); OnAcknowledgementCleared(this, origin); } Endpoint::Ptr Checkable::GetCommandEndpoint(void) const { return Endpoint::GetByName(GetCommandEndpointRaw()); } int Checkable::GetSeverity(void) const { /* overridden in Host/Service class. */ return 0; } void Checkable::NotifyFixedDowntimeStart(const Downtime::Ptr& downtime) { if (!downtime->GetFixed()) return; NotifyDowntimeInternal(downtime); } void Checkable::NotifyFlexibleDowntimeStart(const Downtime::Ptr& downtime) { if (downtime->GetFixed()) return; NotifyDowntimeInternal(downtime); } void Checkable::NotifyDowntimeInternal(const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); if (!checkable->IsPaused()) OnNotificationsRequested(checkable, NotificationDowntimeStart, checkable->GetLastCheckResult(), downtime->GetAuthor(), downtime->GetComment(), MessageOrigin::Ptr()); } void Checkable::NotifyDowntimeEnd(const Downtime::Ptr& downtime) { /* don't send notifications for flexible downtimes which never triggered */ if (!downtime->GetFixed() && !downtime->IsTriggered()) return; Checkable::Ptr checkable = downtime->GetCheckable(); if (!checkable->IsPaused()) OnNotificationsRequested(checkable, NotificationDowntimeEnd, checkable->GetLastCheckResult(), downtime->GetAuthor(), downtime->GetComment(), MessageOrigin::Ptr()); } void Checkable::ValidateCheckInterval(double value, const ValidationUtils& utils) { ObjectImpl::ValidateCheckInterval(value, utils); if (value <= 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("check_interval"), "Interval must be greater than 0.")); } void Checkable::ValidateMaxCheckAttempts(int value, const ValidationUtils& utils) { ObjectImpl::ValidateMaxCheckAttempts(value, utils); if (value <= 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("max_check_attempts"), "Value must be greater than 0.")); } icinga2-2.8.1/lib/icinga/checkable.hpp000066400000000000000000000214521322762156600174660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECKABLE_H #define CHECKABLE_H #include "icinga/i2-icinga.hpp" #include "icinga/checkable.thpp" #include "icinga/timeperiod.hpp" #include "icinga/notification.hpp" #include "icinga/comment.hpp" #include "icinga/downtime.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" namespace icinga { /** * @ingroup icinga */ enum DependencyType { DependencyState, DependencyCheckExecution, DependencyNotification }; /** * Checkable Types * * @ingroup icinga */ enum CheckableType { CheckableHost, CheckableService }; /** * Severity Flags * * @ingroup icinga */ enum SeverityFlag { SeverityFlagDowntime = 1, SeverityFlagAcknowledgement = 2, SeverityFlagUnhandled = 8, SeverityFlagPending = 16, SeverityFlagWarning = 32, SeverityFlagUnknown = 64, SeverityFlagCritical = 128, }; class CheckCommand; class EventCommand; class Dependency; /** * An Icinga service. * * @ingroup icinga */ class I2_ICINGA_API Checkable : public ObjectImpl { public: DECLARE_OBJECT(Checkable); DECLARE_OBJECTNAME(Checkable); static void StaticInitialize(void); Checkable(void); std::set GetParents(void) const; std::set GetChildren(void) const; std::set GetAllChildren(void) const; void AddGroup(const String& name); bool IsReachable(DependencyType dt = DependencyState, intrusive_ptr *failedDependency = NULL, int rstack = 0) const; AcknowledgementType GetAcknowledgement(void); void AcknowledgeProblem(const String& author, const String& comment, AcknowledgementType type, bool notify = true, bool persistent = false, double expiry = 0, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); void ClearAcknowledgement(const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); virtual int GetSeverity(void) const override; /* Checks */ intrusive_ptr GetCheckCommand(void) const; TimePeriod::Ptr GetCheckPeriod(void) const; long GetSchedulingOffset(void); void SetSchedulingOffset(long offset); void UpdateNextCheck(const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); bool HasBeenChecked(void) const; virtual bool IsStateOK(ServiceState state) = 0; virtual double GetLastCheck(void) const override; virtual void SaveLastState(ServiceState state, double timestamp) = 0; static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr()); void ExecuteCheck(); void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); Endpoint::Ptr GetCommandEndpoint(void) const; static boost::signals2::signal OnNewCheckResult; static boost::signals2::signal OnStateChange; static boost::signals2::signal, const MessageOrigin::Ptr&)> OnReachabilityChanged; static boost::signals2::signal OnNotificationsRequested; static boost::signals2::signal OnNotificationSentToUser; static boost::signals2::signal&, const NotificationType&, const CheckResult::Ptr&, const String&, const String&, const MessageOrigin::Ptr&)> OnNotificationSentToAllUsers; static boost::signals2::signal OnAcknowledgementSet; static boost::signals2::signal OnAcknowledgementCleared; static boost::signals2::signal OnNextCheckUpdated; static boost::signals2::signal OnEventCommandExecuted; /* Downtimes */ virtual int GetDowntimeDepth(void) const override; void RemoveAllDowntimes(void); void TriggerDowntimes(void); bool IsInDowntime(void) const; bool IsAcknowledged(void) const; std::set GetDowntimes(void) const; void RegisterDowntime(const Downtime::Ptr& downtime); void UnregisterDowntime(const Downtime::Ptr& downtime); /* Comments */ void RemoveAllComments(void); void RemoveCommentsByType(int type); std::set GetComments(void) const; void RegisterComment(const Comment::Ptr& comment); void UnregisterComment(const Comment::Ptr& comment); /* Notifications */ void SendNotifications(NotificationType type, const CheckResult::Ptr& cr, const String& author = "", const String& text = ""); std::set GetNotifications(void) const; void RegisterNotification(const Notification::Ptr& notification); void UnregisterNotification(const Notification::Ptr& notification); void ResetNotificationNumbers(void); /* Event Handler */ void ExecuteEventHandler(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), bool useResolvedMacros = false); intrusive_ptr GetEventCommand(void) const; /* Flapping Detection */ bool IsFlapping(void) const; /* Dependencies */ void AddDependency(const intrusive_ptr& dep); void RemoveDependency(const intrusive_ptr& dep); std::set > GetDependencies(void) const; void AddReverseDependency(const intrusive_ptr& dep); void RemoveReverseDependency(const intrusive_ptr& dep); std::set > GetReverseDependencies(void) const; virtual void ValidateCheckInterval(double value, const ValidationUtils& utils) override; virtual void ValidateMaxCheckAttempts(int value, const ValidationUtils& utils) override; static void IncreasePendingChecks(void); static void DecreasePendingChecks(void); static int GetPendingChecks(void); static Object::Ptr GetPrototype(void); protected: virtual void Start(bool runtimeCreated) override; virtual void OnAllConfigLoaded(void) override; private: mutable boost::mutex m_CheckableMutex; bool m_CheckRunning; long m_SchedulingOffset; static boost::mutex m_StatsMutex; static int m_PendingChecks; /* Downtimes */ std::set m_Downtimes; mutable boost::mutex m_DowntimeMutex; static void NotifyFixedDowntimeStart(const Downtime::Ptr& downtime); static void NotifyFlexibleDowntimeStart(const Downtime::Ptr& downtime); static void NotifyDowntimeInternal(const Downtime::Ptr& downtime); static void NotifyDowntimeEnd(const Downtime::Ptr& downtime); /* Comments */ std::set m_Comments; mutable boost::mutex m_CommentMutex; /* Notifications */ std::set m_Notifications; mutable boost::mutex m_NotificationMutex; /* Dependencies */ mutable boost::mutex m_DependencyMutex; std::set > m_Dependencies; std::set > m_ReverseDependencies; void GetAllChildrenInternal(std::set& children, int level = 0) const; /* Flapping */ void UpdateFlappingStatus(bool stateChange); }; } #endif /* CHECKABLE_H */ #include "icinga/dependency.hpp" icinga2-2.8.1/lib/icinga/checkable.ti000066400000000000000000000120661322762156600173140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/icingaapplication.hpp" #include "icinga/customvarobject.hpp" #include "base/array.hpp" #impl_include "icinga/checkcommand.hpp" #impl_include "icinga/eventcommand.hpp" library icinga; namespace icinga { code {{{ /** * The acknowledgement type of a service. * * @ingroup icinga */ enum AcknowledgementType { AcknowledgementNone = 0, AcknowledgementNormal = 1, AcknowledgementSticky = 2 }; }}} abstract class Checkable : CustomVarObject { [config, required, navigation] name(CheckCommand) check_command (CheckCommandRaw) { navigate {{{ return CheckCommand::GetByName(GetCheckCommandRaw()); }}} }; [config] int max_check_attempts { default {{{ return 3; }}} }; [config, navigation] name(TimePeriod) check_period (CheckPeriodRaw) { navigate {{{ return TimePeriod::GetByName(GetCheckPeriodRaw()); }}} }; [config] Value check_timeout; [config] double check_interval { default {{{ return 5 * 60; }}} }; [config] double retry_interval { default {{{ return 60; }}} }; [config, navigation] name(EventCommand) event_command (EventCommandRaw) { navigate {{{ return EventCommand::GetByName(GetEventCommandRaw()); }}} }; [config] bool volatile; [config] bool enable_active_checks { default {{{ return true; }}} }; [config] bool enable_passive_checks { default {{{ return true; }}} }; [config] bool enable_event_handler { default {{{ return true; }}} }; [config] bool enable_notifications { default {{{ return true; }}} }; [config] bool enable_flapping { default {{{ return false; }}} }; [config] bool enable_perfdata { default {{{ return true; }}} }; [config, deprecated] double flapping_threshold; [config] double flapping_threshold_low { default {{{ return 25; }}} }; [config] double flapping_threshold_high{ default {{{ return 30; }}} }; [config] String notes; [config] String notes_url; [config] String action_url; [config] String icon_image; [config] String icon_image_alt; [state] Timestamp next_check; [state] int check_attempt { default {{{ return 1; }}} }; [state, enum, no_user_view, no_user_modify] ServiceState state_raw { default {{{ return ServiceUnknown; }}} }; [state, enum] StateType state_type { default {{{ return StateTypeSoft; }}} }; [state, enum, no_user_view, no_user_modify] ServiceState last_state_raw { default {{{ return ServiceUnknown; }}} }; [state, enum, no_user_view, no_user_modify] ServiceState last_hard_state_raw { default {{{ return ServiceUnknown; }}} }; [state, enum] StateType last_state_type { default {{{ return StateTypeSoft; }}} }; [state] bool last_reachable { default {{{ return true; }}} }; [state] CheckResult::Ptr last_check_result; [state] Timestamp last_state_change { default {{{ return Application::GetStartTime(); }}} }; [state] Timestamp last_hard_state_change { default {{{ return Application::GetStartTime(); }}} }; [state] Timestamp last_state_unreachable; [no_storage] int severity { get; }; [state] bool force_next_check; [state] int acknowledgement (AcknowledgementRaw) { default {{{ return AcknowledgementNone; }}} }; [state] Timestamp acknowledgement_expiry; [state] bool force_next_notification; [no_storage] Timestamp last_check { get; }; [no_storage] int downtime_depth { get; }; [state] double flapping_current { default {{{ return 0; }}} }; [state] Timestamp flapping_last_change; [state, no_user_view, no_user_modify] int flapping_buffer; [state, no_user_view, no_user_modify] int flapping_index; [state, protected] bool flapping; [config, navigation] name(Endpoint) command_endpoint (CommandEndpointRaw) { navigate {{{ return Endpoint::GetByName(GetCommandEndpointRaw()); }}} }; }; } icinga2-2.8.1/lib/icinga/checkcommand.cpp000066400000000000000000000036521322762156600201760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkcommand.hpp" #include "icinga/checkcommand.tcpp" #include "base/configtype.hpp" using namespace icinga; REGISTER_TYPE(CheckCommand); void CheckCommand::Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { std::vector arguments; arguments.push_back(checkable); arguments.push_back(cr); arguments.push_back(resolvedMacros); arguments.push_back(useResolvedMacros); GetExecute()->Invoke(arguments); } icinga2-2.8.1/lib/icinga/checkcommand.hpp000066400000000000000000000037021322762156600201770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECKCOMMAND_H #define CHECKCOMMAND_H #include "icinga/checkcommand.thpp" #include "icinga/checkable.hpp" namespace icinga { /** * A command. * * @ingroup icinga */ class I2_ICINGA_API CheckCommand : public ObjectImpl { public: DECLARE_OBJECT(CheckCommand); DECLARE_OBJECTNAME(CheckCommand); virtual void Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), bool useResolvedMacros = false); }; } #endif /* CHECKCOMMAND_H */ icinga2-2.8.1/lib/icinga/checkcommand.ti000066400000000000000000000030131322762156600200170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/command.hpp" library icinga; namespace icinga { class CheckCommand : Command { }; } icinga2-2.8.1/lib/icinga/checkresult.cpp000066400000000000000000000043531322762156600200750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkresult.hpp" #include "icinga/checkresult.tcpp" #include "base/scriptglobal.hpp" using namespace icinga; REGISTER_TYPE(CheckResult); INITIALIZE_ONCE(&CheckResult::StaticInitialize); void CheckResult::StaticInitialize(void) { ScriptGlobal::Set("ServiceOK", ServiceOK); ScriptGlobal::Set("ServiceWarning", ServiceWarning); ScriptGlobal::Set("ServiceCritical", ServiceCritical); ScriptGlobal::Set("ServiceUnknown", ServiceUnknown); ScriptGlobal::Set("HostUp", HostUp); ScriptGlobal::Set("HostDown", HostDown); } double CheckResult::CalculateExecutionTime(void) const { return GetExecutionEnd() - GetExecutionStart(); } double CheckResult::CalculateLatency(void) const { double latency = (GetScheduleEnd() - GetScheduleStart()) - CalculateExecutionTime(); if (latency < 0) latency = 0; return latency; } icinga2-2.8.1/lib/icinga/checkresult.hpp000066400000000000000000000035341322762156600201020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECKRESULT_H #define CHECKRESULT_H #include "icinga/i2-icinga.hpp" #include "icinga/checkresult.thpp" namespace icinga { /** * A check result. * * @ingroup icinga */ class I2_ICINGA_API CheckResult : public ObjectImpl { public: DECLARE_OBJECT(CheckResult); double CalculateExecutionTime(void) const; double CalculateLatency(void) const; static void StaticInitialize(void); }; } #endif /* CHECKRESULT_H */ icinga2-2.8.1/lib/icinga/checkresult.ti000066400000000000000000000044751322762156600177340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ library icinga; namespace icinga { code {{{ /** * The state of a host. * * @ingroup icinga */ enum HostState { HostUp = 0, HostDown = 1 }; /** * The state of a service. * * @ingroup icinga */ enum ServiceState { ServiceOK = 0, ServiceWarning = 1, ServiceCritical = 2, ServiceUnknown = 3 }; /** * The state type of a host or service. * * @ingroup icinga */ enum StateType { StateTypeSoft = 0, StateTypeHard = 1 }; }}} class CheckResult { [state] Timestamp schedule_start; [state] Timestamp schedule_end; [state] Timestamp execution_start; [state] Timestamp execution_end; [state] Value command; [state] int exit_status; [state, enum] ServiceState "state"; [state] String output; [state] Array::Ptr performance_data; [state] bool active { default {{{ return true; }}} }; [state] String check_source; [state] Dictionary::Ptr vars_before; [state] Dictionary::Ptr vars_after; }; } icinga2-2.8.1/lib/icinga/cib.cpp000066400000000000000000000252611322762156600163170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/cib.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/configtype.hpp" #include "base/statsfunction.hpp" using namespace icinga; RingBuffer CIB::m_ActiveHostChecksStatistics(15 * 60); RingBuffer CIB::m_ActiveServiceChecksStatistics(15 * 60); RingBuffer CIB::m_PassiveHostChecksStatistics(15 * 60); RingBuffer CIB::m_PassiveServiceChecksStatistics(15 * 60); void CIB::UpdateActiveHostChecksStatistics(long tv, int num) { m_ActiveHostChecksStatistics.InsertValue(tv, num); } void CIB::UpdateActiveServiceChecksStatistics(long tv, int num) { m_ActiveServiceChecksStatistics.InsertValue(tv, num); } int CIB::GetActiveHostChecksStatistics(long timespan) { return m_ActiveHostChecksStatistics.GetValues(timespan); } int CIB::GetActiveServiceChecksStatistics(long timespan) { return m_ActiveServiceChecksStatistics.GetValues(timespan); } void CIB::UpdatePassiveHostChecksStatistics(long tv, int num) { m_PassiveServiceChecksStatistics.InsertValue(tv, num); } void CIB::UpdatePassiveServiceChecksStatistics(long tv, int num) { m_PassiveServiceChecksStatistics.InsertValue(tv, num); } int CIB::GetPassiveHostChecksStatistics(long timespan) { return m_PassiveHostChecksStatistics.GetValues(timespan); } int CIB::GetPassiveServiceChecksStatistics(long timespan) { return m_PassiveServiceChecksStatistics.GetValues(timespan); } CheckableCheckStatistics CIB::CalculateHostCheckStats(void) { double min_latency = -1, max_latency = 0, sum_latency = 0; int count_latency = 0; double min_execution_time = -1, max_execution_time = 0, sum_execution_time = 0; int count_execution_time = 0; bool checkresult = false; for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { ObjectLock olock(host); CheckResult::Ptr cr = host->GetLastCheckResult(); if (!cr) continue; /* set to true, we have a checkresult */ checkresult = true; /* latency */ double latency = cr->CalculateLatency(); if (min_latency == -1 || latency < min_latency) min_latency = latency; if (latency > max_latency) max_latency = latency; sum_latency += latency; count_latency++; /* execution_time */ double execution_time = cr->CalculateExecutionTime(); if (min_execution_time == -1 || execution_time < min_execution_time) min_execution_time = execution_time; if (execution_time > max_execution_time) max_execution_time = execution_time; sum_execution_time += execution_time; count_execution_time++; } if (!checkresult) { min_latency = 0; min_execution_time = 0; } CheckableCheckStatistics ccs; ccs.min_latency = min_latency; ccs.max_latency = max_latency; ccs.avg_latency = sum_latency / count_latency; ccs.min_execution_time = min_execution_time; ccs.max_execution_time = max_execution_time; ccs.avg_execution_time = sum_execution_time / count_execution_time; return ccs; } CheckableCheckStatistics CIB::CalculateServiceCheckStats(void) { double min_latency = -1, max_latency = 0, sum_latency = 0; int count_latency = 0; double min_execution_time = -1, max_execution_time = 0, sum_execution_time = 0; int count_execution_time = 0; bool checkresult = false; for (const Service::Ptr& service : ConfigType::GetObjectsByType()) { ObjectLock olock(service); CheckResult::Ptr cr = service->GetLastCheckResult(); if (!cr) continue; /* set to true, we have a checkresult */ checkresult = true; /* latency */ double latency = cr->CalculateLatency(); if (min_latency == -1 || latency < min_latency) min_latency = latency; if (latency > max_latency) max_latency = latency; sum_latency += latency; count_latency++; /* execution_time */ double execution_time = cr->CalculateExecutionTime(); if (min_execution_time == -1 || execution_time < min_execution_time) min_execution_time = execution_time; if (execution_time > max_execution_time) max_execution_time = execution_time; sum_execution_time += execution_time; count_execution_time++; } if (!checkresult) { min_latency = 0; min_execution_time = 0; } CheckableCheckStatistics ccs; ccs.min_latency = min_latency; ccs.max_latency = max_latency; ccs.avg_latency = sum_latency / count_latency; ccs.min_execution_time = min_execution_time; ccs.max_execution_time = max_execution_time; ccs.avg_execution_time = sum_execution_time / count_execution_time; return ccs; } ServiceStatistics CIB::CalculateServiceStats(void) { ServiceStatistics ss = {}; for (const Service::Ptr& service : ConfigType::GetObjectsByType()) { ObjectLock olock(service); CheckResult::Ptr cr = service->GetLastCheckResult(); if (service->GetState() == ServiceOK) ss.services_ok++; if (service->GetState() == ServiceWarning) ss.services_warning++; if (service->GetState() == ServiceCritical) ss.services_critical++; if (service->GetState() == ServiceUnknown) ss.services_unknown++; if (!cr) ss.services_pending++; if (!service->IsReachable()) ss.services_unreachable++; if (service->IsFlapping()) ss.services_flapping++; if (service->IsInDowntime()) ss.services_in_downtime++; if (service->IsAcknowledged()) ss.services_acknowledged++; } return ss; } HostStatistics CIB::CalculateHostStats(void) { HostStatistics hs = {}; for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { ObjectLock olock(host); if (host->IsReachable()) { if (host->GetState() == HostUp) hs.hosts_up++; if (host->GetState() == HostDown) hs.hosts_down++; } else hs.hosts_unreachable++; if (!host->GetLastCheckResult()) hs.hosts_pending++; if (host->IsFlapping()) hs.hosts_flapping++; if (host->IsInDowntime()) hs.hosts_in_downtime++; if (host->IsAcknowledged()) hs.hosts_acknowledged++; } return hs; } /* * 'perfdata' must be a flat dictionary with double values * 'status' dictionary can contain multiple levels of dictionaries */ std::pair CIB::GetFeatureStats(void) { Dictionary::Ptr status = new Dictionary(); Array::Ptr perfdata = new Array(); String name; for (const auto& kv : StatsFunctionRegistry::GetInstance()->GetItems()) { kv.second->Invoke(status, perfdata); } return std::make_pair(status, perfdata); } REGISTER_STATSFUNCTION(CIB, &CIB::StatsFunc); void CIB::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { double interval = Utility::GetTime() - Application::GetStartTime(); if (interval > 60) interval = 60; status->Set("active_host_checks", GetActiveHostChecksStatistics(interval) / interval); status->Set("passive_host_checks", GetPassiveHostChecksStatistics(interval) / interval); status->Set("active_host_checks_1min", GetActiveHostChecksStatistics(60)); status->Set("passive_host_checks_1min", GetPassiveHostChecksStatistics(60)); status->Set("active_host_checks_5min", GetActiveHostChecksStatistics(60 * 5)); status->Set("passive_host_checks_5min", GetPassiveHostChecksStatistics(60 * 5)); status->Set("active_host_checks_15min", GetActiveHostChecksStatistics(60 * 15)); status->Set("passive_host_checks_15min", GetPassiveHostChecksStatistics(60 * 15)); status->Set("active_service_checks", GetActiveServiceChecksStatistics(interval) / interval); status->Set("passive_service_checks", GetPassiveServiceChecksStatistics(interval) / interval); status->Set("active_service_checks_1min", GetActiveServiceChecksStatistics(60)); status->Set("passive_service_checks_1min", GetPassiveServiceChecksStatistics(60)); status->Set("active_service_checks_5min", GetActiveServiceChecksStatistics(60 * 5)); status->Set("passive_service_checks_5min", GetPassiveServiceChecksStatistics(60 * 5)); status->Set("active_service_checks_15min", GetActiveServiceChecksStatistics(60 * 15)); status->Set("passive_service_checks_15min", GetPassiveServiceChecksStatistics(60 * 15)); CheckableCheckStatistics scs = CalculateServiceCheckStats(); status->Set("min_latency", scs.min_latency); status->Set("max_latency", scs.max_latency); status->Set("avg_latency", scs.avg_latency); status->Set("min_execution_time", scs.min_execution_time); status->Set("max_execution_time", scs.max_execution_time); status->Set("avg_execution_time", scs.avg_execution_time); ServiceStatistics ss = CalculateServiceStats(); status->Set("num_services_ok", ss.services_ok); status->Set("num_services_warning", ss.services_warning); status->Set("num_services_critical", ss.services_critical); status->Set("num_services_unknown", ss.services_unknown); status->Set("num_services_pending", ss.services_pending); status->Set("num_services_unreachable", ss.services_unreachable); status->Set("num_services_flapping", ss.services_flapping); status->Set("num_services_in_downtime", ss.services_in_downtime); status->Set("num_services_acknowledged", ss.services_acknowledged); double uptime = Utility::GetTime() - Application::GetStartTime(); status->Set("uptime", uptime); HostStatistics hs = CalculateHostStats(); status->Set("num_hosts_up", hs.hosts_up); status->Set("num_hosts_down", hs.hosts_down); status->Set("num_hosts_pending", hs.hosts_pending); status->Set("num_hosts_unreachable", hs.hosts_unreachable); status->Set("num_hosts_flapping", hs.hosts_flapping); status->Set("num_hosts_in_downtime", hs.hosts_in_downtime); status->Set("num_hosts_acknowledged", hs.hosts_acknowledged); } icinga2-2.8.1/lib/icinga/cib.hpp000066400000000000000000000070621322762156600163230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CIB_H #define CIB_H #include "icinga/i2-icinga.hpp" #include "base/ringbuffer.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" namespace icinga { struct CheckableCheckStatistics { double min_latency; double max_latency; double avg_latency; double min_execution_time; double max_execution_time; double avg_execution_time; }; struct ServiceStatistics { double services_ok; double services_warning; double services_critical; double services_unknown; double services_pending; double services_unreachable; double services_flapping; double services_in_downtime; double services_acknowledged; }; struct HostStatistics { double hosts_up; double hosts_down; double hosts_unreachable; double hosts_pending; double hosts_flapping; double hosts_in_downtime; double hosts_acknowledged; }; /** * Common Information Base class. Holds some statistics (and will likely be * removed/refactored). * * @ingroup icinga */ class I2_ICINGA_API CIB { public: static void UpdateActiveHostChecksStatistics(long tv, int num); static int GetActiveHostChecksStatistics(long timespan); static void UpdateActiveServiceChecksStatistics(long tv, int num); static int GetActiveServiceChecksStatistics(long timespan); static void UpdatePassiveHostChecksStatistics(long tv, int num); static int GetPassiveHostChecksStatistics(long timespan); static void UpdatePassiveServiceChecksStatistics(long tv, int num); static int GetPassiveServiceChecksStatistics(long timespan); static CheckableCheckStatistics CalculateHostCheckStats(void); static CheckableCheckStatistics CalculateServiceCheckStats(void); static HostStatistics CalculateHostStats(void); static ServiceStatistics CalculateServiceStats(void); static std::pair GetFeatureStats(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); private: CIB(void); static boost::mutex m_Mutex; static RingBuffer m_ActiveHostChecksStatistics; static RingBuffer m_PassiveHostChecksStatistics; static RingBuffer m_ActiveServiceChecksStatistics; static RingBuffer m_PassiveServiceChecksStatistics; }; } #endif /* CIB_H */ icinga2-2.8.1/lib/icinga/clusterevents.cpp000066400000000000000000000755161322762156600205000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/clusterevents.hpp" #include "icinga/service.hpp" #include "remote/apilistener.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include "remote/zone.hpp" #include "remote/apifunction.hpp" #include "remote/eventqueue.hpp" #include "base/application.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/exception.hpp" #include "base/initialize.hpp" #include "base/serializer.hpp" #include "base/json.hpp" #include using namespace icinga; INITIALIZE_ONCE(&ClusterEvents::StaticInitialize); REGISTER_APIFUNCTION(CheckResult, event, &ClusterEvents::CheckResultAPIHandler); REGISTER_APIFUNCTION(SetNextCheck, event, &ClusterEvents::NextCheckChangedAPIHandler); REGISTER_APIFUNCTION(SetNextNotification, event, &ClusterEvents::NextNotificationChangedAPIHandler); REGISTER_APIFUNCTION(SetForceNextCheck, event, &ClusterEvents::ForceNextCheckChangedAPIHandler); REGISTER_APIFUNCTION(SetForceNextNotification, event, &ClusterEvents::ForceNextNotificationChangedAPIHandler); REGISTER_APIFUNCTION(SetAcknowledgement, event, &ClusterEvents::AcknowledgementSetAPIHandler); REGISTER_APIFUNCTION(ClearAcknowledgement, event, &ClusterEvents::AcknowledgementClearedAPIHandler); REGISTER_APIFUNCTION(ExecuteCommand, event, &ClusterEvents::ExecuteCommandAPIHandler); REGISTER_APIFUNCTION(SendNotifications, event, &ClusterEvents::SendNotificationsAPIHandler); REGISTER_APIFUNCTION(NotificationSentUser, event, &ClusterEvents::NotificationSentUserAPIHandler); REGISTER_APIFUNCTION(NotificationSentToAllUsers, event, &ClusterEvents::NotificationSentToAllUsersAPIHandler); void ClusterEvents::StaticInitialize(void) { Checkable::OnNewCheckResult.connect(&ClusterEvents::CheckResultHandler); Checkable::OnNextCheckChanged.connect(&ClusterEvents::NextCheckChangedHandler); Notification::OnNextNotificationChanged.connect(&ClusterEvents::NextNotificationChangedHandler); Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler); Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler); Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler); Checkable::OnNotificationSentToUser.connect(&ClusterEvents::NotificationSentUserHandler); Checkable::OnNotificationSentToAllUsers.connect(&ClusterEvents::NotificationSentToAllUsersHandler); Checkable::OnAcknowledgementSet.connect(&ClusterEvents::AcknowledgementSetHandler); Checkable::OnAcknowledgementCleared.connect(&ClusterEvents::AcknowledgementClearedHandler); } Dictionary::Ptr ClusterEvents::MakeCheckResultMessage(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::CheckResult"); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); else { Value agent_service_name = checkable->GetExtension("agent_service_name"); if (!agent_service_name.IsEmpty()) params->Set("service", agent_service_name); } params->Set("cr", Serialize(cr)); message->Set("params", params); return message; } void ClusterEvents::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Dictionary::Ptr message = MakeCheckResultMessage(checkable, cr); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::CheckResultAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'check result' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; CheckResult::Ptr cr; Array::Ptr vperf; if (params->Contains("cr")) { cr = new CheckResult(); Dictionary::Ptr vcr = params->Get("cr"); if (vcr && vcr->Contains("performance_data")) { vperf = vcr->Get("performance_data"); if (vperf) vcr->Remove("performance_data"); Deserialize(cr, vcr, true); } } if (!cr) return Empty; Array::Ptr rperf = new Array(); if (vperf) { ObjectLock olock(vperf); for (const Value& vp : vperf) { Value p; if (vp.IsObjectType()) { PerfdataValue::Ptr val = new PerfdataValue(); Deserialize(val, vp, true); rperf->Add(val); } else rperf->Add(vp); } } cr->SetPerformanceData(rperf); Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable) && endpoint != checkable->GetCommandEndpoint()) { Log(LogNotice, "ClusterEvents") << "Discarding 'check result' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } if (!checkable->IsPaused() && Zone::GetLocalZone() == checkable->GetZone() && endpoint == checkable->GetCommandEndpoint()) checkable->ProcessCheckResult(cr); else checkable->ProcessCheckResult(cr, origin); return Empty; } void ClusterEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("next_check", checkable->GetNextCheck()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::SetNextCheck"); message->Set("params", params); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::NextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'next check changed' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") << "Discarding 'next check changed' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } double nextCheck = params->Get("next_check"); if (nextCheck < Application::GetStartTime() + 60) return Empty; checkable->SetNextCheck(params->Get("next_check"), false, origin); return Empty; } void ClusterEvents::NextNotificationChangedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Dictionary::Ptr params = new Dictionary(); params->Set("notification", notification->GetName()); params->Set("next_notification", notification->GetNextNotification()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::SetNextNotification"); message->Set("params", params); listener->RelayMessage(origin, notification, message, true); } Value ClusterEvents::NextNotificationChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'next notification changed' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Notification::Ptr notification = Notification::GetByName(params->Get("notification")); if (!notification) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(notification)) { Log(LogNotice, "ClusterEvents") << "Discarding 'next notification changed' message for notification '" << notification->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } double nextNotification = params->Get("next_notification"); if (nextNotification < Utility::GetTime()) return Empty; notification->SetNextNotification(nextNotification, false, origin); return Empty; } void ClusterEvents::ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("forced", checkable->GetForceNextCheck()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::SetForceNextCheck"); message->Set("params", params); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::ForceNextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'force next check changed' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") << "Discarding 'force next check' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } checkable->SetForceNextCheck(params->Get("forced"), false, origin); return Empty; } void ClusterEvents::ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("forced", checkable->GetForceNextNotification()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::SetForceNextNotification"); message->Set("params", params); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::ForceNextNotificationChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'force next notification changed' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") << "Discarding 'force next notification' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } checkable->SetForceNextNotification(params->Get("forced"), false, origin); return Empty; } void ClusterEvents::AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("author", author); params->Set("comment", comment); params->Set("acktype", type); params->Set("notify", notify); params->Set("expiry", expiry); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::SetAcknowledgement"); message->Set("params", params); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::AcknowledgementSetAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'acknowledgement set' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") << "Discarding 'acknowledgement set' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } checkable->AcknowledgeProblem(params->Get("author"), params->Get("comment"), static_cast(static_cast(params->Get("acktype"))), params->Get("notify"), params->Get("persistent"), params->Get("expiry"), origin); return Empty; } void ClusterEvents::AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::ClearAcknowledgement"); message->Set("params", params); listener->RelayMessage(origin, checkable, message, true); } Value ClusterEvents::AcknowledgementClearedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'acknowledgement cleared' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") << "Discarding 'acknowledgement cleared' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } checkable->ClearAcknowledgement(origin); return Empty; } Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr sourceEndpoint = origin->FromClient->GetEndpoint(); if (!sourceEndpoint || (origin->FromZone && !Zone::GetLocalZone()->IsChildOf(origin->FromZone))) { Log(LogNotice, "ClusterEvents") << "Discarding 'execute command' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { Log(LogCritical, "ApiListener", "No instance available."); return Empty; } if (!listener->GetAcceptCommands()) { Log(LogWarning, "ApiListener") << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); attrs->Set("__name", params->Get("host")); attrs->Set("type", "Host"); attrs->Set("enable_active_checks", false); Deserialize(host, attrs, false, FAConfig); if (params->Contains("service")) host->SetExtension("agent_service_name", params->Get("service")); CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); cr->SetOutput("Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); return Empty; } /* use a virtual host object for executing the command */ Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); attrs->Set("__name", params->Get("host")); attrs->Set("type", "Host"); Deserialize(host, attrs, false, FAConfig); if (params->Contains("service")) host->SetExtension("agent_service_name", params->Get("service")); String command = params->Get("command"); String command_type = params->Get("command_type"); if (command_type == "check_command") { if (!CheckCommand::GetByName(command)) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); cr->SetOutput("Check command '" + command + "' does not exist."); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); return Empty; } } else if (command_type == "event_command") { if (!EventCommand::GetByName(command)) { Log(LogWarning, "ClusterEvents") << "Event command '" << command << "' does not exist."; return Empty; } } else return Empty; attrs->Set(command_type, params->Get("command")); attrs->Set("command_endpoint", sourceEndpoint->GetName()); Deserialize(host, attrs, false, FAConfig); host->SetExtension("agent_check", true); Dictionary::Ptr macros = params->Get("macros"); if (command_type == "check_command") { try { host->ExecuteRemoteCheck(macros); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); String output = "Exception occured while checking '" + host->GetName() + "': " + DiagnosticInformation(ex); cr->SetOutput(output); double now = Utility::GetTime(); cr->SetScheduleStart(now); cr->SetScheduleEnd(now); cr->SetExecutionStart(now); cr->SetExecutionEnd(now); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); Log(LogCritical, "checker", output); } } else if (command_type == "event_command") { host->ExecuteEventHandler(macros, true); } return Empty; } void ClusterEvents::SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Dictionary::Ptr message = MakeCheckResultMessage(checkable, cr); message->Set("method", "event::SendNotifications"); Dictionary::Ptr params = message->Get("params"); params->Set("type", type); params->Set("author", author); params->Set("text", text); listener->RelayMessage(origin, ConfigObject::Ptr(), message, true); } Value ClusterEvents::SendNotificationsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'send notification' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && origin->FromZone != Zone::GetLocalZone()) { Log(LogNotice, "ClusterEvents") << "Discarding 'send custom notification' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } CheckResult::Ptr cr; Array::Ptr vperf; if (params->Contains("cr")) { cr = new CheckResult(); Dictionary::Ptr vcr = params->Get("cr"); if (vcr && vcr->Contains("performance_data")) { vperf = vcr->Get("performance_data"); if (vperf) vcr->Remove("performance_data"); Deserialize(cr, vcr, true); } } NotificationType type = static_cast(static_cast(params->Get("type"))); String author = params->Get("author"); String text = params->Get("text"); Checkable::OnNotificationsRequested(checkable, type, cr, author, text, origin); return Empty; } void ClusterEvents::NotificationSentUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const String& command, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("notification", notification->GetName()); params->Set("user", user->GetName()); params->Set("type", notificationType); params->Set("cr", Serialize(cr)); params->Set("author", author); params->Set("text", commentText); params->Set("command", command); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::NotificationSentUser"); message->Set("params", params); listener->RelayMessage(origin, ConfigObject::Ptr(), message, true); } Value ClusterEvents::NotificationSentUserAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'sent notification to user' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && origin->FromZone != Zone::GetLocalZone()) { Log(LogNotice, "ClusterEvents") << "Discarding 'send notification to user' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } CheckResult::Ptr cr; Array::Ptr vperf; if (params->Contains("cr")) { cr = new CheckResult(); Dictionary::Ptr vcr = params->Get("cr"); if (vcr && vcr->Contains("performance_data")) { vperf = vcr->Get("performance_data"); if (vperf) vcr->Remove("performance_data"); Deserialize(cr, vcr, true); } } NotificationType type = static_cast(static_cast(params->Get("type"))); String author = params->Get("author"); String text = params->Get("text"); Notification::Ptr notification = Notification::GetByName(params->Get("notification")); if (!notification) return Empty; User::Ptr user = User::GetByName(params->Get("user")); if (!user) return Empty; String command = params->Get("command"); Checkable::OnNotificationSentToUser(notification, checkable, user, type, cr, author, text, command, origin); return Empty; } void ClusterEvents::NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const MessageOrigin::Ptr& origin) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr params = new Dictionary(); params->Set("host", host->GetName()); if (service) params->Set("service", service->GetShortName()); params->Set("notification", notification->GetName()); Array::Ptr ausers = new Array(); for (const User::Ptr& user : users) { ausers->Add(user->GetName()); } params->Set("users", ausers); params->Set("type", notificationType); params->Set("cr", Serialize(cr)); params->Set("author", author); params->Set("text", commentText); params->Set("last_notification", notification->GetLastNotification()); params->Set("next_notification", notification->GetNextNotification()); params->Set("notification_number", notification->GetNotificationNumber()); params->Set("last_problem_notification", notification->GetLastProblemNotification()); params->Set("no_more_notifications", notification->GetNoMoreNotifications()); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::NotificationSentToAllUsers"); message->Set("params", params); listener->RelayMessage(origin, ConfigObject::Ptr(), message, true); } Value ClusterEvents::NotificationSentToAllUsersAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ClusterEvents") << "Discarding 'sent notification to all users' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } if (!params) return Empty; Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) return Empty; Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else checkable = host; if (!checkable) return Empty; if (origin->FromZone && origin->FromZone != Zone::GetLocalZone()) { Log(LogNotice, "ClusterEvents") << "Discarding 'sent notification to all users' message for checkable '" << checkable->GetName() << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } CheckResult::Ptr cr; Array::Ptr vperf; if (params->Contains("cr")) { cr = new CheckResult(); Dictionary::Ptr vcr = params->Get("cr"); if (vcr && vcr->Contains("performance_data")) { vperf = vcr->Get("performance_data"); if (vperf) vcr->Remove("performance_data"); Deserialize(cr, vcr, true); } } NotificationType type = static_cast(static_cast(params->Get("type"))); String author = params->Get("author"); String text = params->Get("text"); Notification::Ptr notification = Notification::GetByName(params->Get("notification")); if (!notification) return Empty; Array::Ptr ausers = params->Get("users"); if (!ausers) return Empty; std::set users; { ObjectLock olock(ausers); for (const String& auser : ausers) { User::Ptr user = User::GetByName(auser); if (!user) continue; users.insert(user); } } notification->SetLastNotification(params->Get("last_notification")); notification->SetNextNotification(params->Get("next_notification")); notification->SetNotificationNumber(params->Get("notification_number")); notification->SetLastProblemNotification(params->Get("last_problem_notification")); notification->SetNoMoreNotifications(params->Get("no_more_notifications")); Array::Ptr notifiedProblemUsers = new Array(); for (const User::Ptr& user : users) { notifiedProblemUsers->Add(user->GetName()); } notification->SetNotifiedProblemUsers(notifiedProblemUsers); Checkable::OnNotificationSentToAllUsers(notification, checkable, users, type, cr, author, text, origin); return Empty; } icinga2-2.8.1/lib/icinga/clusterevents.hpp000066400000000000000000000114461322762156600204750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLUSTEREVENTS_H #define CLUSTEREVENTS_H #include "icinga/checkable.hpp" #include "icinga/host.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" namespace icinga { /** * @ingroup icinga */ class I2_ICINGA_API ClusterEvents { public: static void StaticInitialize(void); static void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin); static Value CheckResultAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void NextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static Value NextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void NextNotificationChangedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin); static Value NextNotificationChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static Value ForceNextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static Value ForceNextNotificationChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void AcknowledgementSetHandler(const Checkable::Ptr& checkable, const String& author, const String& comment, AcknowledgementType type, bool notify, bool persistent, double expiry, const MessageOrigin::Ptr& origin); static Value AcknowledgementSetAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void AcknowledgementClearedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static Value AcknowledgementClearedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Value ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Dictionary::Ptr MakeCheckResultMessage(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); static void SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin); static Value SendNotificationsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void NotificationSentUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const String& command, const MessageOrigin::Ptr& origin); static Value NotificationSentUserAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const MessageOrigin::Ptr& origin); static Value NotificationSentToAllUsersAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); }; } #endif /* CLUSTEREVENTS_H */ icinga2-2.8.1/lib/icinga/command.cpp000066400000000000000000000072271322762156600172020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/command.hpp" #include "icinga/command.tcpp" #include "icinga/macroprocessor.hpp" #include "base/exception.hpp" #include "base/objectlock.hpp" using namespace icinga; REGISTER_TYPE(Command); void Command::Validate(int types, const ValidationUtils& utils) { ObjectImpl::Validate(types, utils); Dictionary::Ptr arguments = GetArguments(); if (!(types & FAConfig)) return; if (arguments) { if (!GetCommandLine().IsObjectType()) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("command"), "Attribute 'command' must be an array if the 'arguments' attribute is set.")); ObjectLock olock(arguments); for (const Dictionary::Pair& kv : arguments) { const Value& arginfo = kv.second; Value argval; if (arginfo.IsObjectType()) { Dictionary::Ptr argdict = arginfo; if (argdict->Contains("value")) { Value argvalue = argdict->Get("value"); if (argvalue.IsString() && !MacroProcessor::ValidateMacroString(argvalue)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("arguments")(kv.first)("value"), "Validation failed: Closing $ not found in macro format string '" + argvalue + "'.")); } if (argdict->Contains("set_if")) { Value argsetif = argdict->Get("set_if"); if (argsetif.IsString() && !MacroProcessor::ValidateMacroString(argsetif)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("arguments")(kv.first)("set_if"), "Closing $ not found in macro format string '" + argsetif + "'.")); } } else if (arginfo.IsString()) { if (!MacroProcessor::ValidateMacroString(arginfo)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("arguments")(kv.first), "Closing $ not found in macro format string '" + arginfo + "'.")); } } } Dictionary::Ptr env = GetEnv(); if (env) { ObjectLock olock(env); for (const Dictionary::Pair& kv : env) { const Value& envval = kv.second; if (!envval.IsString() || envval.IsEmpty()) continue; if (!MacroProcessor::ValidateMacroString(envval)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("env")(kv.first), "Closing $ not found in macro format string '" + envval + "'.")); } } } icinga2-2.8.1/lib/icinga/command.hpp000066400000000000000000000035661322762156600172110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMMAND_H #define COMMAND_H #include "icinga/i2-icinga.hpp" #include "icinga/command.thpp" #include "remote/messageorigin.hpp" namespace icinga { /** * A command. * * @ingroup icinga */ class I2_ICINGA_API Command : public ObjectImpl { public: DECLARE_OBJECT(Command); //virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0; virtual void Validate(int types, const ValidationUtils& utils) override; }; } #endif /* COMMAND_H */ icinga2-2.8.1/lib/icinga/command.ti000066400000000000000000000042711322762156600170300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #include "base/function.hpp" library icinga; namespace icinga { abstract class Command : CustomVarObject { [config] Value command (CommandLine); [config] Value arguments; [config] int timeout { default {{{ return 60; }}} }; [config] Dictionary::Ptr env; [config, required] Function::Ptr execute; }; validator Command { String command; Function command; Array command { String "*"; Function "*"; }; Dictionary arguments { String "*"; Function "*"; Dictionary "*" { String key; String value; Function value; String description; Number "required"; Number skip_key; Number repeat_key; String set_if; Function set_if; Number order; }; }; Dictionary env { String "*"; Function "*"; }; }; } icinga2-2.8.1/lib/icinga/comment.cpp000066400000000000000000000167301322762156600172250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/comment.hpp" #include "icinga/comment.tcpp" #include "icinga/host.hpp" #include "remote/configobjectutility.hpp" #include "base/utility.hpp" #include "base/configtype.hpp" #include "base/timer.hpp" #include #include using namespace icinga; static int l_NextCommentID = 1; static boost::mutex l_CommentMutex; static std::map l_LegacyCommentsCache; static Timer::Ptr l_CommentsExpireTimer; boost::signals2::signal Comment::OnCommentAdded; boost::signals2::signal Comment::OnCommentRemoved; INITIALIZE_ONCE(&Comment::StaticInitialize); REGISTER_TYPE(Comment); void Comment::StaticInitialize(void) { l_CommentsExpireTimer = new Timer(); l_CommentsExpireTimer->SetInterval(60); l_CommentsExpireTimer->OnTimerExpired.connect(boost::bind(&Comment::CommentsExpireTimerHandler)); l_CommentsExpireTimer->Start(); } String CommentNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Comment::Ptr comment = dynamic_pointer_cast(context); if (!comment) return ""; String name = comment->GetHostName(); if (!comment->GetServiceName().IsEmpty()) name += "!" + comment->GetServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr CommentNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Comment name.")); Dictionary::Ptr result = new Dictionary(); result->Set("host_name", tokens[0]); if (tokens.size() > 2) { result->Set("service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void Comment::OnAllConfigLoaded(void) { ConfigObject::OnAllConfigLoaded(); Host::Ptr host = Host::GetByName(GetHostName()); if (GetServiceName().IsEmpty()) m_Checkable = host; else m_Checkable = host->GetServiceByShortName(GetServiceName()); if (!m_Checkable) BOOST_THROW_EXCEPTION(ScriptError("Comment '" + GetName() + "' references a host/service which doesn't exist.", GetDebugInfo())); } void Comment::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); { boost::mutex::scoped_lock lock(l_CommentMutex); SetLegacyId(l_NextCommentID); l_LegacyCommentsCache[l_NextCommentID] = GetName(); l_NextCommentID++; } GetCheckable()->RegisterComment(this); if (runtimeCreated) OnCommentAdded(this); } void Comment::Stop(bool runtimeRemoved) { GetCheckable()->UnregisterComment(this); if (runtimeRemoved) OnCommentRemoved(this); ObjectImpl::Stop(runtimeRemoved); } Checkable::Ptr Comment::GetCheckable(void) const { return static_pointer_cast(m_Checkable); } bool Comment::IsExpired(void) const { double expire_time = GetExpireTime(); return (expire_time != 0 && expire_time < Utility::GetTime()); } int Comment::GetNextCommentID(void) { boost::mutex::scoped_lock lock(l_CommentMutex); return l_NextCommentID; } String Comment::AddComment(const Checkable::Ptr& checkable, CommentType entryType, const String& author, const String& text, bool persistent, double expireTime, const String& id, const MessageOrigin::Ptr& origin) { String fullName; if (id.IsEmpty()) fullName = checkable->GetName() + "!" + Utility::NewUniqueID(); else fullName = id; Dictionary::Ptr attrs = new Dictionary(); attrs->Set("author", author); attrs->Set("text", text); attrs->Set("persistent", persistent); attrs->Set("expire_time", expireTime); attrs->Set("entry_type", entryType); attrs->Set("entry_time", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); attrs->Set("host_name", host->GetName()); if (service) attrs->Set("service_name", service->GetShortName()); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) attrs->Set("zone", zone); String config = ConfigObjectUtility::CreateObjectConfig(Comment::TypeInstance, fullName, true, Array::Ptr(), attrs); Array::Ptr errors = new Array(); if (!ConfigObjectUtility::CreateObject(Comment::TypeInstance, fullName, config, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Comment", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not create comment.")); } Comment::Ptr comment = Comment::GetByName(fullName); if (!comment) BOOST_THROW_EXCEPTION(std::runtime_error("Could not create comment.")); Log(LogNotice, "Comment") << "Added comment '" << comment->GetName() << "'."; return fullName; } void Comment::RemoveComment(const String& id, const MessageOrigin::Ptr& origin) { Comment::Ptr comment = Comment::GetByName(id); if (!comment || comment->GetPackage() != "_api") return; Log(LogNotice, "Comment") << "Removed comment '" << comment->GetName() << "' from object '" << comment->GetCheckable()->GetName() << "'."; Array::Ptr errors = new Array(); if (!ConfigObjectUtility::DeleteObject(comment, false, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Comment", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not remove comment.")); } } String Comment::GetCommentIDFromLegacyID(int id) { boost::mutex::scoped_lock lock(l_CommentMutex); auto it = l_LegacyCommentsCache.find(id); if (it == l_LegacyCommentsCache.end()) return Empty; return it->second; } void Comment::CommentsExpireTimerHandler(void) { std::vector comments; for (const Comment::Ptr& comment : ConfigType::GetObjectsByType()) { comments.push_back(comment); } for (const Comment::Ptr& comment : comments) { /* Only remove comments which are activated after daemon start. */ if (comment->IsActive() && comment->IsExpired()) { /* Do not remove persistent comments from an acknowledgement */ if (comment->GetEntryType() == CommentAcknowledgement && comment->GetPersistent()) continue; RemoveComment(comment->GetName()); } } } icinga2-2.8.1/lib/icinga/comment.hpp000066400000000000000000000054101322762156600172230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMMENT_H #define COMMENT_H #include "icinga/i2-icinga.hpp" #include "icinga/comment.thpp" #include "icinga/checkable.thpp" #include "remote/messageorigin.hpp" namespace icinga { /** * A comment. * * @ingroup icinga */ class I2_ICINGA_API Comment : public ObjectImpl { public: DECLARE_OBJECT(Comment); DECLARE_OBJECTNAME(Comment); static boost::signals2::signal OnCommentAdded; static boost::signals2::signal OnCommentRemoved; intrusive_ptr GetCheckable(void) const; bool IsExpired(void) const; static int GetNextCommentID(void); static String AddComment(const intrusive_ptr& checkable, CommentType entryType, const String& author, const String& text, bool persistent, double expireTime, const String& id = String(), const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); static void RemoveComment(const String& id, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); static String GetCommentIDFromLegacyID(int id); static void StaticInitialize(void); protected: virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: ObjectImpl::Ptr m_Checkable; static void CommentsExpireTimerHandler(void); }; } #endif /* COMMENT_H */ icinga2-2.8.1/lib/icinga/comment.ti000066400000000000000000000061341322762156600170540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/utility.hpp" #impl_include "icinga/service.hpp" library icinga; namespace icinga { code {{{ /** * The type of a service comment. * * @ingroup icinga */ enum CommentType { CommentUser = 1, CommentDowntime = 2, CommentFlapping = 3, CommentAcknowledgement = 4 }; class I2_ICINGA_API CommentNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class Comment : ConfigObject < CommentNameComposer { load_after Host; load_after Service; [config, protected, required, navigation(host)] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; [config, protected, navigation(service)] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetHostName()); return host->GetServiceByShortName(GetServiceName()); }}} }; [config] Timestamp entry_time { default {{{ return Utility::GetTime(); }}} }; [config, enum] CommentType entry_type { default {{{ return CommentUser; }}} }; [config, required] String author; [config, required] String text; [config] bool persistent; [config] Timestamp expire_time; [state] int legacy_id; }; } icinga2-2.8.1/lib/icinga/compatutility.cpp000066400000000000000000000724661322762156600205020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/compatutility.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/pluginutility.hpp" #include "icinga/service.hpp" #include "base/utility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include #include using namespace icinga; /* command */ String CompatUtility::GetCommandLine(const Command::Ptr& command) { Value commandLine = command->GetCommandLine(); String result; if (commandLine.IsObjectType()) { Array::Ptr args = commandLine; ObjectLock olock(args); for (const String& arg : args) { // This is obviously incorrect for non-trivial cases. result += " \"" + EscapeString(arg) + "\""; } } else if (!commandLine.IsEmpty()) { result = EscapeString(Convert::ToString(commandLine)); } else { result = ""; } return result; } String CompatUtility::GetCommandNamePrefix(const Command::Ptr command) { if (!command) return Empty; String prefix; if (command->GetReflectionType() == CheckCommand::TypeInstance) prefix = "check_"; else if (command->GetReflectionType() == NotificationCommand::TypeInstance) prefix = "notification_"; else if (command->GetReflectionType() == EventCommand::TypeInstance) prefix = "event_"; return prefix; } String CompatUtility::GetCommandName(const Command::Ptr command) { if (!command) return Empty; return GetCommandNamePrefix(command) + command->GetName(); } /* host */ int CompatUtility::GetHostCurrentState(const Host::Ptr& host) { if (host->GetState() != HostUp && !host->IsReachable()) return 2; /* hardcoded compat state */ return host->GetState(); } String CompatUtility::GetHostStateString(const Host::Ptr& host) { if (host->GetState() != HostUp && !host->IsReachable()) return "UNREACHABLE"; /* hardcoded compat state */ return Host::StateToString(host->GetState()); } String CompatUtility::GetHostAlias(const Host::Ptr& host) { if (!host->GetDisplayName().IsEmpty()) return host->GetName(); else return host->GetDisplayName(); } int CompatUtility::GetHostNotifyOnDown(const Host::Ptr& host) { unsigned long notification_state_filter = GetCheckableNotificationStateFilter(host); if ((notification_state_filter & ServiceCritical) || (notification_state_filter & ServiceWarning)) return 1; return 0; } int CompatUtility::GetHostNotifyOnUnreachable(const Host::Ptr& host) { unsigned long notification_state_filter = GetCheckableNotificationStateFilter(host); if (notification_state_filter & ServiceUnknown) return 1; return 0; } /* service */ String CompatUtility::GetCheckableCommandArgs(const Checkable::Ptr& checkable) { CheckCommand::Ptr command = checkable->GetCheckCommand(); Dictionary::Ptr args = new Dictionary(); if (command) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); String command_line = GetCommandLine(command); Dictionary::Ptr command_vars = command->GetVars(); if (command_vars) { ObjectLock olock(command_vars); for (const Dictionary::Pair& kv : command_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); } } Dictionary::Ptr host_vars = host->GetVars(); if (host_vars) { ObjectLock olock(host_vars); for (const Dictionary::Pair& kv : host_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); macro = "$host.vars." + kv.first + "$"; if (command_line.Contains(macro)) args->Set(kv.first, kv.second); } } if (service) { Dictionary::Ptr service_vars = service->GetVars(); if (service_vars) { ObjectLock olock(service_vars); for (const Dictionary::Pair& kv : service_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); macro = "$service.vars." + kv.first + "$"; if (command_line.Contains(macro)) args->Set(kv.first, kv.second); } } } String arg_string; ObjectLock olock(args); for (const Dictionary::Pair& kv : args) { arg_string += Convert::ToString(kv.first) + "=" + Convert::ToString(kv.second) + "!"; } return arg_string; } return Empty; } int CompatUtility::GetCheckableCheckType(const Checkable::Ptr& checkable) { return (checkable->GetEnableActiveChecks() ? 0 : 1); } double CompatUtility::GetCheckableCheckInterval(const Checkable::Ptr& checkable) { return checkable->GetCheckInterval() / 60.0; } double CompatUtility::GetCheckableRetryInterval(const Checkable::Ptr& checkable) { return checkable->GetRetryInterval() / 60.0; } String CompatUtility::GetCheckableCheckPeriod(const Checkable::Ptr& checkable) { TimePeriod::Ptr check_period = checkable->GetCheckPeriod(); if (check_period) return check_period->GetName(); else return "24x7"; } int CompatUtility::GetCheckableHasBeenChecked(const Checkable::Ptr& checkable) { return (checkable->GetLastCheckResult() ? 1 : 0); } int CompatUtility::GetCheckableProblemHasBeenAcknowledged(const Checkable::Ptr& checkable) { return (checkable->GetAcknowledgement() != AcknowledgementNone ? 1 : 0); } int CompatUtility::GetCheckableAcknowledgementType(const Checkable::Ptr& checkable) { return static_cast(checkable->GetAcknowledgement()); } int CompatUtility::GetCheckablePassiveChecksEnabled(const Checkable::Ptr& checkable) { return (checkable->GetEnablePassiveChecks() ? 1 : 0); } int CompatUtility::GetCheckableActiveChecksEnabled(const Checkable::Ptr& checkable) { return (checkable->GetEnableActiveChecks() ? 1 : 0); } int CompatUtility::GetCheckableEventHandlerEnabled(const Checkable::Ptr& checkable) { return (checkable->GetEnableEventHandler() ? 1 : 0); } int CompatUtility::GetCheckableFlapDetectionEnabled(const Checkable::Ptr& checkable) { return (checkable->GetEnableFlapping() ? 1 : 0); } int CompatUtility::GetCheckableIsFlapping(const Checkable::Ptr& checkable) { return (checkable->IsFlapping() ? 1 : 0); } int CompatUtility::GetCheckableIsReachable(const Checkable::Ptr& checkable) { return (checkable->IsReachable() ? 1 : 0); } double CompatUtility::GetCheckablePercentStateChange(const Checkable::Ptr& checkable) { return checkable->GetFlappingCurrent(); } int CompatUtility::GetCheckableProcessPerformanceData(const Checkable::Ptr& checkable) { return (checkable->GetEnablePerfdata() ? 1 : 0); } String CompatUtility::GetCheckableEventHandler(const Checkable::Ptr& checkable) { String event_command_str; EventCommand::Ptr eventcommand = checkable->GetEventCommand(); if (eventcommand) event_command_str = eventcommand->GetName(); return event_command_str; } String CompatUtility::GetCheckableCheckCommand(const Checkable::Ptr& checkable) { String check_command_str; CheckCommand::Ptr checkcommand = checkable->GetCheckCommand(); if (checkcommand) check_command_str = checkcommand->GetName(); return check_command_str; } int CompatUtility::GetCheckableIsVolatile(const Checkable::Ptr& checkable) { return (checkable->GetVolatile() ? 1 : 0); } double CompatUtility::GetCheckableLowFlapThreshold(const Checkable::Ptr& checkable) { return checkable->GetFlappingThresholdLow(); } double CompatUtility::GetCheckableHighFlapThreshold(const Checkable::Ptr& checkable) { return checkable->GetFlappingThresholdHigh(); } int CompatUtility::GetCheckableFreshnessChecksEnabled(const Checkable::Ptr& checkable) { return (checkable->GetCheckInterval() > 0 ? 1 : 0); } int CompatUtility::GetCheckableFreshnessThreshold(const Checkable::Ptr& checkable) { return static_cast(checkable->GetCheckInterval()); } double CompatUtility::GetCheckableStaleness(const Checkable::Ptr& checkable) { if (checkable->HasBeenChecked() && checkable->GetLastCheck() > 0) return (Utility::GetTime() - checkable->GetLastCheck()) / (checkable->GetCheckInterval() * 3600); return 0.0; } int CompatUtility::GetCheckableIsAcknowledged(const Checkable::Ptr& checkable) { return (checkable->IsAcknowledged() ? 1 : 0); } int CompatUtility::GetCheckableNoMoreNotifications(const Checkable::Ptr& checkable) { if (CompatUtility::GetCheckableNotificationNotificationInterval(checkable) == 0 && !checkable->GetVolatile()) return 1; return 0; } int CompatUtility::GetCheckableInCheckPeriod(const Checkable::Ptr& checkable) { TimePeriod::Ptr timeperiod = checkable->GetCheckPeriod(); /* none set means always checked */ if (!timeperiod) return 1; return (timeperiod->IsInside(Utility::GetTime()) ? 1 : 0); } int CompatUtility::GetCheckableInNotificationPeriod(const Checkable::Ptr& checkable) { for (const Notification::Ptr& notification : checkable->GetNotifications()) { TimePeriod::Ptr timeperiod = notification->GetPeriod(); if (!timeperiod || timeperiod->IsInside(Utility::GetTime())) return 1; } return 0; } /* vars attr */ Dictionary::Ptr CompatUtility::GetCustomAttributeConfig(const CustomVarObject::Ptr& object) { Dictionary::Ptr vars = object->GetVars(); if (!vars) return Dictionary::Ptr(); return vars; } String CompatUtility::GetCustomAttributeConfig(const CustomVarObject::Ptr& object, const String& name) { Dictionary::Ptr vars = object->GetVars(); if (!vars) return Empty; return vars->Get(name); } /* notifications */ int CompatUtility::GetCheckableNotificationsEnabled(const Checkable::Ptr& checkable) { return (checkable->GetEnableNotifications() ? 1 : 0); } int CompatUtility::GetCheckableNotificationLastNotification(const Checkable::Ptr& checkable) { double last_notification = 0.0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { if (notification->GetLastNotification() > last_notification) last_notification = notification->GetLastNotification(); } return static_cast(last_notification); } int CompatUtility::GetCheckableNotificationNextNotification(const Checkable::Ptr& checkable) { double next_notification = 0.0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { if (next_notification == 0 || notification->GetNextNotification() < next_notification) next_notification = notification->GetNextNotification(); } return static_cast(next_notification); } int CompatUtility::GetCheckableNotificationNotificationNumber(const Checkable::Ptr& checkable) { int notification_number = 0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { if (notification->GetNotificationNumber() > notification_number) notification_number = notification->GetNotificationNumber(); } return notification_number; } double CompatUtility::GetCheckableNotificationNotificationInterval(const Checkable::Ptr& checkable) { double notification_interval = -1; for (const Notification::Ptr& notification : checkable->GetNotifications()) { if (notification_interval == -1 || notification->GetInterval() < notification_interval) notification_interval = notification->GetInterval(); } if (notification_interval == -1) notification_interval = 60; return notification_interval / 60.0; } String CompatUtility::GetCheckableNotificationNotificationOptions(const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); unsigned long notification_type_filter = 0; unsigned long notification_state_filter = 0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { notification_type_filter |= notification->GetTypeFilter(); notification_state_filter |= notification->GetStateFilter(); } std::vector notification_options; /* notification state filters */ if (service) { if (notification_state_filter & ServiceWarning) { notification_options.push_back("w"); } if (notification_state_filter & ServiceUnknown) { notification_options.push_back("u"); } if (notification_state_filter & ServiceCritical) { notification_options.push_back("c"); } } else { if (notification_state_filter & HostDown) { notification_options.push_back("d"); } } /* notification type filters */ if (notification_type_filter & NotificationRecovery) { notification_options.push_back("r"); } if ((notification_type_filter & NotificationFlappingStart) || (notification_type_filter & NotificationFlappingEnd)) { notification_options.push_back("f"); } if ((notification_type_filter & NotificationDowntimeStart) || (notification_type_filter & NotificationDowntimeEnd) || (notification_type_filter & NotificationDowntimeRemoved)) { notification_options.push_back("s"); } return boost::algorithm::join(notification_options, ","); } int CompatUtility::GetCheckableNotificationTypeFilter(const Checkable::Ptr& checkable) { unsigned long notification_type_filter = 0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { ObjectLock olock(notification); notification_type_filter |= notification->GetTypeFilter(); } return notification_type_filter; } int CompatUtility::GetCheckableNotificationStateFilter(const Checkable::Ptr& checkable) { unsigned long notification_state_filter = 0; for (const Notification::Ptr& notification : checkable->GetNotifications()) { ObjectLock olock(notification); notification_state_filter |= notification->GetStateFilter(); } return notification_state_filter; } int CompatUtility::GetCheckableNotifyOnWarning(const Checkable::Ptr& checkable) { if (GetCheckableNotificationStateFilter(checkable) & ServiceWarning) return 1; return 0; } int CompatUtility::GetCheckableNotifyOnCritical(const Checkable::Ptr& checkable) { if (GetCheckableNotificationStateFilter(checkable) & ServiceCritical) return 1; return 0; } int CompatUtility::GetCheckableNotifyOnUnknown(const Checkable::Ptr& checkable) { if (GetCheckableNotificationStateFilter(checkable) & ServiceUnknown) return 1; return 0; } int CompatUtility::GetCheckableNotifyOnRecovery(const Checkable::Ptr& checkable) { if (GetCheckableNotificationTypeFilter(checkable) & NotificationRecovery) return 1; return 0; } int CompatUtility::GetCheckableNotifyOnFlapping(const Checkable::Ptr& checkable) { unsigned long notification_type_filter = GetCheckableNotificationTypeFilter(checkable); if ((notification_type_filter & NotificationFlappingStart) || (notification_type_filter & NotificationFlappingEnd)) return 1; return 0; } int CompatUtility::GetCheckableNotifyOnDowntime(const Checkable::Ptr& checkable) { unsigned long notification_type_filter = GetCheckableNotificationTypeFilter(checkable); if ((notification_type_filter & NotificationDowntimeStart) || (notification_type_filter & NotificationDowntimeEnd) || (notification_type_filter & NotificationDowntimeRemoved)) return 1; return 0; } std::set CompatUtility::GetCheckableNotificationUsers(const Checkable::Ptr& checkable) { /* Service -> Notifications -> (Users + UserGroups -> Users) */ std::set allUsers; std::set users; for (const Notification::Ptr& notification : checkable->GetNotifications()) { ObjectLock olock(notification); users = notification->GetUsers(); std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin())); for (const UserGroup::Ptr& ug : notification->GetUserGroups()) { std::set members = ug->GetMembers(); std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin())); } } return allUsers; } std::set CompatUtility::GetCheckableNotificationUserGroups(const Checkable::Ptr& checkable) { std::set usergroups; /* Service -> Notifications -> UserGroups */ for (const Notification::Ptr& notification : checkable->GetNotifications()) { ObjectLock olock(notification); for (const UserGroup::Ptr& ug : notification->GetUserGroups()) { usergroups.insert(ug); } } return usergroups; } String CompatUtility::GetCheckResultOutput(const CheckResult::Ptr& cr) { if (!cr) return Empty; String output; String raw_output = cr->GetOutput(); /* * replace semi-colons with colons in output * semi-colon is used as delimiter in various interfaces */ boost::algorithm::replace_all(raw_output, ";", ":"); size_t line_end = raw_output.Find("\n"); return raw_output.SubStr(0, line_end); } String CompatUtility::GetCheckResultLongOutput(const CheckResult::Ptr& cr) { if (!cr) return Empty; String long_output; String output; String raw_output = cr->GetOutput(); /* * replace semi-colons with colons in output * semi-colon is used as delimiter in various interfaces */ boost::algorithm::replace_all(raw_output, ";", ":"); size_t line_end = raw_output.Find("\n"); if (line_end > 0 && line_end != String::NPos) { long_output = raw_output.SubStr(line_end+1, raw_output.GetLength()); return EscapeString(long_output); } return Empty; } String CompatUtility::GetCheckResultPerfdata(const CheckResult::Ptr& cr) { if (!cr) return String(); return PluginUtility::FormatPerfdata(cr->GetPerformanceData()); } String CompatUtility::EscapeString(const String& str) { String result = str; boost::algorithm::replace_all(result, "\n", "\\n"); return result; } String CompatUtility::UnEscapeString(const String& str) { String result = str; boost::algorithm::replace_all(result, "\\n", "\n"); return result; } std::pair CompatUtility::ConvertTimestamp(double time) { unsigned long time_sec = static_cast(time); unsigned long time_usec = (time - time_sec) * 1000 * 1000; return std::make_pair(time_sec, time_usec); } int CompatUtility::MapNotificationReasonType(NotificationType type) { switch (type) { case NotificationDowntimeStart: return 5; case NotificationDowntimeEnd: return 6; case NotificationDowntimeRemoved: return 7; case NotificationCustom: return 8; case NotificationAcknowledgement: return 1; case NotificationProblem: return 0; case NotificationRecovery: return 0; case NotificationFlappingStart: return 2; case NotificationFlappingEnd: return 3; default: return 0; } } int CompatUtility::MapExternalCommandType(const String& name) { if (name == "NONE") return 0; if (name == "ADD_HOST_COMMENT") return 1; if (name == "DEL_HOST_COMMENT") return 2; if (name == "ADD_SVC_COMMENT") return 3; if (name == "DEL_SVC_COMMENT") return 4; if (name == "ENABLE_SVC_CHECK") return 5; if (name == "DISABLE_SVC_CHECK") return 6; if (name == "SCHEDULE_SVC_CHECK") return 7; if (name == "DELAY_SVC_NOTIFICATION") return 9; if (name == "DELAY_HOST_NOTIFICATION") return 10; if (name == "DISABLE_NOTIFICATIONS") return 11; if (name == "ENABLE_NOTIFICATIONS") return 12; if (name == "RESTART_PROCESS") return 13; if (name == "SHUTDOWN_PROCESS") return 14; if (name == "ENABLE_HOST_SVC_CHECKS") return 15; if (name == "DISABLE_HOST_SVC_CHECKS") return 16; if (name == "SCHEDULE_HOST_SVC_CHECKS") return 17; if (name == "DELAY_HOST_SVC_NOTIFICATIONS") return 19; if (name == "DEL_ALL_HOST_COMMENTS") return 20; if (name == "DEL_ALL_SVC_COMMENTS") return 21; if (name == "ENABLE_SVC_NOTIFICATIONS") return 22; if (name == "DISABLE_SVC_NOTIFICATIONS") return 23; if (name == "ENABLE_HOST_NOTIFICATIONS") return 24; if (name == "DISABLE_HOST_NOTIFICATIONS") return 25; if (name == "ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST") return 26; if (name == "DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST") return 27; if (name == "ENABLE_HOST_SVC_NOTIFICATIONS") return 28; if (name == "DISABLE_HOST_SVC_NOTIFICATIONS") return 29; if (name == "PROCESS_SERVICE_CHECK_RESULT") return 30; if (name == "SAVE_STATE_INFORMATION") return 31; if (name == "READ_STATE_INFORMATION") return 32; if (name == "ACKNOWLEDGE_HOST_PROBLEM") return 33; if (name == "ACKNOWLEDGE_SVC_PROBLEM") return 34; if (name == "START_EXECUTING_SVC_CHECKS") return 35; if (name == "STOP_EXECUTING_SVC_CHECKS") return 36; if (name == "START_ACCEPTING_PASSIVE_SVC_CHECKS") return 37; if (name == "STOP_ACCEPTING_PASSIVE_SVC_CHECKS") return 38; if (name == "ENABLE_PASSIVE_SVC_CHECKS") return 39; if (name == "DISABLE_PASSIVE_SVC_CHECKS") return 40; if (name == "ENABLE_EVENT_HANDLERS") return 41; if (name == "DISABLE_EVENT_HANDLERS") return 42; if (name == "ENABLE_HOST_EVENT_HANDLER") return 43; if (name == "DISABLE_HOST_EVENT_HANDLER") return 44; if (name == "ENABLE_SVC_EVENT_HANDLER") return 45; if (name == "DISABLE_SVC_EVENT_HANDLER") return 46; if (name == "ENABLE_HOST_CHECK") return 47; if (name == "DISABLE_HOST_CHECK") return 48; if (name == "START_OBSESSING_OVER_SVC_CHECKS") return 49; if (name == "STOP_OBSESSING_OVER_SVC_CHECKS") return 50; if (name == "REMOVE_HOST_ACKNOWLEDGEMENT") return 51; if (name == "REMOVE_SVC_ACKNOWLEDGEMENT") return 52; if (name == "SCHEDULE_FORCED_HOST_SVC_CHECKS") return 53; if (name == "SCHEDULE_FORCED_SVC_CHECK") return 54; if (name == "SCHEDULE_HOST_DOWNTIME") return 55; if (name == "SCHEDULE_SVC_DOWNTIME") return 56; if (name == "ENABLE_HOST_FLAP_DETECTION") return 57; if (name == "DISABLE_HOST_FLAP_DETECTION") return 58; if (name == "ENABLE_SVC_FLAP_DETECTION") return 59; if (name == "DISABLE_SVC_FLAP_DETECTION") return 60; if (name == "ENABLE_FLAP_DETECTION") return 61; if (name == "DISABLE_FLAP_DETECTION") return 62; if (name == "ENABLE_HOSTGROUP_SVC_NOTIFICATIONS") return 63; if (name == "DISABLE_HOSTGROUP_SVC_NOTIFICATIONS") return 64; if (name == "ENABLE_HOSTGROUP_HOST_NOTIFICATIONS") return 65; if (name == "DISABLE_HOSTGROUP_HOST_NOTIFICATIONS") return 66; if (name == "ENABLE_HOSTGROUP_SVC_CHECKS") return 67; if (name == "DISABLE_HOSTGROUP_SVC_CHECKS") return 68; if (name == "CANCEL_HOST_DOWNTIME") return 69; if (name == "CANCEL_SVC_DOWNTIME") return 70; if (name == "CANCEL_ACTIVE_HOST_DOWNTIME") return 71; if (name == "CANCEL_PENDING_HOST_DOWNTIME") return 72; if (name == "CANCEL_ACTIVE_SVC_DOWNTIME") return 73; if (name == "CANCEL_PENDING_SVC_DOWNTIME") return 74; if (name == "CANCEL_ACTIVE_HOST_SVC_DOWNTIME") return 75; if (name == "CANCEL_PENDING_HOST_SVC_DOWNTIME") return 76; if (name == "FLUSH_PENDING_COMMANDS") return 77; if (name == "DEL_HOST_DOWNTIME") return 78; if (name == "DEL_SVC_DOWNTIME") return 79; if (name == "ENABLE_FAILURE_PREDICTION") return 80; if (name == "DISABLE_FAILURE_PREDICTION") return 81; if (name == "ENABLE_PERFORMANCE_DATA") return 82; if (name == "DISABLE_PERFORMANCE_DATA") return 83; if (name == "SCHEDULE_HOSTGROUP_HOST_DOWNTIME") return 84; if (name == "SCHEDULE_HOSTGROUP_SVC_DOWNTIME") return 85; if (name == "SCHEDULE_HOST_SVC_DOWNTIME") return 86; if (name == "PROCESS_HOST_CHECK_RESULT") return 87; if (name == "START_EXECUTING_HOST_CHECKS") return 88; if (name == "STOP_EXECUTING_HOST_CHECKS") return 89; if (name == "START_ACCEPTING_PASSIVE_HOST_CHECKS") return 90; if (name == "STOP_ACCEPTING_PASSIVE_HOST_CHECKS") return 91; if (name == "ENABLE_PASSIVE_HOST_CHECKS") return 92; if (name == "DISABLE_PASSIVE_HOST_CHECKS") return 93; if (name == "START_OBSESSING_OVER_HOST_CHECKS") return 94; if (name == "STOP_OBSESSING_OVER_HOST_CHECKS") return 95; if (name == "SCHEDULE_HOST_CHECK") return 96; if (name == "SCHEDULE_FORCED_HOST_CHECK") return 98; if (name == "START_OBSESSING_OVER_SVC") return 99; if (name == "STOP_OBSESSING_OVER_SVC") return 100; if (name == "START_OBSESSING_OVER_HOST") return 101; if (name == "STOP_OBSESSING_OVER_HOST") return 102; if (name == "ENABLE_HOSTGROUP_HOST_CHECKS") return 103; if (name == "DISABLE_HOSTGROUP_HOST_CHECKS") return 104; if (name == "ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS") return 105; if (name == "DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS") return 106; if (name == "ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS") return 107; if (name == "DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS") return 108; if (name == "ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS") return 109; if (name == "DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS") return 110; if (name == "ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS") return 111; if (name == "DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS") return 112; if (name == "ENABLE_SERVICEGROUP_SVC_CHECKS") return 113; if (name == "DISABLE_SERVICEGROUP_SVC_CHECKS") return 114; if (name == "ENABLE_SERVICEGROUP_HOST_CHECKS") return 115; if (name == "DISABLE_SERVICEGROUP_HOST_CHECKS") return 116; if (name == "ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS") return 117; if (name == "DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS") return 118; if (name == "ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS") return 119; if (name == "DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS") return 120; if (name == "SCHEDULE_SERVICEGROUP_HOST_DOWNTIME") return 121; if (name == "SCHEDULE_SERVICEGROUP_SVC_DOWNTIME") return 122; if (name == "CHANGE_GLOBAL_HOST_EVENT_HANDLER") return 123; if (name == "CHANGE_GLOBAL_SVC_EVENT_HANDLER") return 124; if (name == "CHANGE_HOST_EVENT_HANDLER") return 125; if (name == "CHANGE_SVC_EVENT_HANDLER") return 126; if (name == "CHANGE_HOST_CHECK_COMMAND") return 127; if (name == "CHANGE_SVC_CHECK_COMMAND") return 128; if (name == "CHANGE_NORMAL_HOST_CHECK_INTERVAL") return 129; if (name == "CHANGE_NORMAL_SVC_CHECK_INTERVAL") return 130; if (name == "CHANGE_RETRY_SVC_CHECK_INTERVAL") return 131; if (name == "CHANGE_MAX_HOST_CHECK_ATTEMPTS") return 132; if (name == "CHANGE_MAX_SVC_CHECK_ATTEMPTS") return 133; if (name == "SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME") return 134; if (name == "ENABLE_HOST_AND_CHILD_NOTIFICATIONS") return 135; if (name == "DISABLE_HOST_AND_CHILD_NOTIFICATIONS") return 136; if (name == "SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME") return 137; if (name == "ENABLE_SERVICE_FRESHNESS_CHECKS") return 138; if (name == "DISABLE_SERVICE_FRESHNESS_CHECKS") return 139; if (name == "ENABLE_HOST_FRESHNESS_CHECKS") return 140; if (name == "DISABLE_HOST_FRESHNESS_CHECKS") return 141; if (name == "SET_HOST_NOTIFICATION_NUMBER") return 142; if (name == "SET_SVC_NOTIFICATION_NUMBER") return 143; if (name == "CHANGE_HOST_CHECK_TIMEPERIOD") return 144; if (name == "CHANGE_SVC_CHECK_TIMEPERIOD") return 145; if (name == "PROCESS_FILE") return 146; if (name == "CHANGE_CUSTOM_HOST_VAR") return 147; if (name == "CHANGE_CUSTOM_SVC_VAR") return 148; if (name == "CHANGE_CUSTOM_CONTACT_VAR") return 149; if (name == "ENABLE_CONTACT_HOST_NOTIFICATIONS") return 150; if (name == "DISABLE_CONTACT_HOST_NOTIFICATIONS") return 151; if (name == "ENABLE_CONTACT_SVC_NOTIFICATIONS") return 152; if (name == "DISABLE_CONTACT_SVC_NOTIFICATIONS") return 153; if (name == "ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS") return 154; if (name == "DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS") return 155; if (name == "ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS") return 156; if (name == "DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS") return 157; if (name == "CHANGE_RETRY_HOST_CHECK_INTERVAL") return 158; if (name == "SEND_CUSTOM_HOST_NOTIFICATION") return 159; if (name == "SEND_CUSTOM_SVC_NOTIFICATION") return 160; if (name == "CHANGE_HOST_NOTIFICATION_TIMEPERIOD") return 161; if (name == "CHANGE_SVC_NOTIFICATION_TIMEPERIOD") return 162; if (name == "CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD") return 163; if (name == "CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD") return 164; if (name == "CHANGE_HOST_MODATTR") return 165; if (name == "CHANGE_SVC_MODATTR") return 166; if (name == "CHANGE_CONTACT_MODATTR") return 167; if (name == "CHANGE_CONTACT_MODHATTR") return 168; if (name == "CHANGE_CONTACT_MODSATTR") return 169; if (name == "SYNC_STATE_INFORMATION") return 170; if (name == "DEL_DOWNTIME_BY_HOST_NAME") return 171; if (name == "DEL_DOWNTIME_BY_HOSTGROUP_NAME") return 172; if (name == "DEL_DOWNTIME_BY_START_TIME_COMMENT") return 173; if (name == "ACKNOWLEDGE_HOST_PROBLEM_EXPIRE") return 174; if (name == "ACKNOWLEDGE_SVC_PROBLEM_EXPIRE") return 175; if (name == "DISABLE_NOTIFICATIONS_EXPIRE_TIME") return 176; if (name == "CUSTOM_COMMAND") return 999; return 0; } icinga2-2.8.1/lib/icinga/compatutility.hpp000066400000000000000000000147371322762156600205040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMPATUTILITY_H #define COMPATUTILITY_H #include "icinga/i2-icinga.hpp" #include "icinga/customvarobject.hpp" #include "icinga/host.hpp" #include "icinga/command.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include namespace icinga { /** * Compatibility utility functions. * * @ingroup icinga */ class I2_ICINGA_API CompatUtility { public: /* command */ static String GetCommandLine(const Command::Ptr& command); static String GetCommandName(const Command::Ptr command); /* host */ static int GetHostCurrentState(const Host::Ptr& host); static String GetHostStateString(const Host::Ptr& host); static String GetHostAlias(const Host::Ptr& host); static int GetHostNotifyOnDown(const Host::Ptr& host); static int GetHostNotifyOnUnreachable(const Host::Ptr& host); /* service */ static String GetCheckableCommandArgs(const Checkable::Ptr& checkable); static int GetCheckableCheckType(const Checkable::Ptr& checkable); static double GetCheckableCheckInterval(const Checkable::Ptr& checkable); static double GetCheckableRetryInterval(const Checkable::Ptr& checkable); static String GetCheckableCheckPeriod(const Checkable::Ptr& checkable); static int GetCheckableHasBeenChecked(const Checkable::Ptr& checkable); static int GetCheckableProblemHasBeenAcknowledged(const Checkable::Ptr& checkable); static int GetCheckableAcknowledgementType(const Checkable::Ptr& checkable); static int GetCheckablePassiveChecksEnabled(const Checkable::Ptr& checkable); static int GetCheckableActiveChecksEnabled(const Checkable::Ptr& checkable); static int GetCheckableEventHandlerEnabled(const Checkable::Ptr& checkable); static int GetCheckableFlapDetectionEnabled(const Checkable::Ptr& checkable); static int GetCheckableIsFlapping(const Checkable::Ptr& checkable); static int GetCheckableIsReachable(const Checkable::Ptr& checkable); static double GetCheckablePercentStateChange(const Checkable::Ptr& checkable); static int GetCheckableProcessPerformanceData(const Checkable::Ptr& checkable); static String GetCheckableEventHandler(const Checkable::Ptr& checkable); static String GetCheckableCheckCommand(const Checkable::Ptr& checkable); static int GetCheckableIsVolatile(const Checkable::Ptr& checkable); static double GetCheckableLowFlapThreshold(const Checkable::Ptr& checkable); static double GetCheckableHighFlapThreshold(const Checkable::Ptr& checkable); static int GetCheckableFreshnessChecksEnabled(const Checkable::Ptr& checkable); static int GetCheckableFreshnessThreshold(const Checkable::Ptr& checkable); static double GetCheckableStaleness(const Checkable::Ptr& checkable); static int GetCheckableIsAcknowledged(const Checkable::Ptr& checkable); static int GetCheckableNoMoreNotifications(const Checkable::Ptr& checkable); static int GetCheckableInCheckPeriod(const Checkable::Ptr& checkable); static int GetCheckableInNotificationPeriod(const Checkable::Ptr& checkable); /* notification */ static int GetCheckableNotificationsEnabled(const Checkable::Ptr& checkable); static int GetCheckableNotificationLastNotification(const Checkable::Ptr& checkable); static int GetCheckableNotificationNextNotification(const Checkable::Ptr& checkable); static int GetCheckableNotificationNotificationNumber(const Checkable::Ptr& checkable); static double GetCheckableNotificationNotificationInterval(const Checkable::Ptr& checkable); static String GetCheckableNotificationNotificationOptions(const Checkable::Ptr& checkable); static int GetCheckableNotificationTypeFilter(const Checkable::Ptr& checkable); static int GetCheckableNotificationStateFilter(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnWarning(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnCritical(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnUnknown(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnRecovery(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnFlapping(const Checkable::Ptr& checkable); static int GetCheckableNotifyOnDowntime(const Checkable::Ptr& checkable); static std::set GetCheckableNotificationUsers(const Checkable::Ptr& checkable); static std::set GetCheckableNotificationUserGroups(const Checkable::Ptr& checkable); /* custom attribute */ static String GetCustomAttributeConfig(const CustomVarObject::Ptr& object, const String& name); static Dictionary::Ptr GetCustomAttributeConfig(const CustomVarObject::Ptr& object); /* check result */ static String GetCheckResultOutput(const CheckResult::Ptr& cr); static String GetCheckResultLongOutput(const CheckResult::Ptr& cr); static String GetCheckResultPerfdata(const CheckResult::Ptr& cr); /* misc */ static std::pair ConvertTimestamp(double time); static int MapNotificationReasonType(NotificationType type); static int MapExternalCommandType(const String& name); static String EscapeString(const String& str); static String UnEscapeString(const String& str); private: CompatUtility(void); static String GetCommandNamePrefix(const Command::Ptr command); }; } #endif /* COMPATUTILITY_H */ icinga2-2.8.1/lib/icinga/customvarobject.cpp000066400000000000000000000046711322762156600207760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #include "icinga/customvarobject.tcpp" #include "icinga/macroprocessor.hpp" #include "base/logger.hpp" #include "base/function.hpp" #include "base/exception.hpp" #include "base/objectlock.hpp" using namespace icinga; REGISTER_TYPE(CustomVarObject); void CustomVarObject::ValidateVars(const Dictionary::Ptr& value, const ValidationUtils& utils) { MacroProcessor::ValidateCustomVars(this, value); } int icinga::FilterArrayToInt(const Array::Ptr& typeFilters, const std::map& filterMap, int defaultValue) { int resultTypeFilter; if (!typeFilters) return defaultValue; resultTypeFilter = 0; ObjectLock olock(typeFilters); for (const Value& typeFilter : typeFilters) { if (typeFilter.IsNumber()) { resultTypeFilter = resultTypeFilter | typeFilter; continue; } if (!typeFilter.IsString()) return -1; auto it = filterMap.find(typeFilter); if (it == filterMap.end()) return -1; resultTypeFilter = resultTypeFilter | it->second; } return resultTypeFilter; } icinga2-2.8.1/lib/icinga/customvarobject.hpp000066400000000000000000000040761322762156600210020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CUSTOMVAROBJECT_H #define CUSTOMVAROBJECT_H #include "icinga/i2-icinga.hpp" #include "icinga/customvarobject.thpp" #include "base/configobject.hpp" #include "remote/messageorigin.hpp" namespace icinga { /** * An object with custom variable attribute. * * @ingroup icinga */ class I2_ICINGA_API CustomVarObject : public ObjectImpl { public: DECLARE_OBJECT(CustomVarObject); virtual void ValidateVars(const Dictionary::Ptr& value, const ValidationUtils& utils) override; }; I2_ICINGA_API int FilterArrayToInt(const Array::Ptr& typeFilters, const std::map& filterMap, int defaultValue); } #endif /* CUSTOMVAROBJECT_H */ icinga2-2.8.1/lib/icinga/customvarobject.ti000066400000000000000000000030771322762156600206270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library icinga; namespace icinga { abstract class CustomVarObject : ConfigObject { [config] Dictionary::Ptr vars; }; } icinga2-2.8.1/lib/icinga/dependency-apply.cpp000066400000000000000000000137671322762156600210330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/dependency.hpp" #include "icinga/service.hpp" #include "config/configitembuilder.hpp" #include "config/applyrule.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" #include "base/exception.hpp" using namespace icinga; INITIALIZE_ONCE([]() { std::vector targets; targets.push_back("Host"); targets.push_back("Service"); ApplyRule::RegisterType("Dependency", targets); }); bool Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule) { if (!rule.EvaluateFilter(frame)) return false; DebugInfo di = rule.GetDebugInfo(); #ifdef _DEBUG Log(LogDebug, "Dependency") << "Applying dependency '" << name << "' to object '" << checkable->GetName() << "' for rule " << di; #endif /* _DEBUG */ ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(di); builder->SetType(Dependency::TypeInstance); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "parent_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "child_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di)); if (service) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "child_service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di)); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "zone"), OpSetLiteral, MakeLiteral(zone), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "package"), OpSetLiteral, MakeLiteral(rule.GetPackage()), di)); builder->AddExpression(new ImportDefaultTemplatesExpression()); builder->AddExpression(new OwnedExpression(rule.GetExpression())); ConfigItem::Ptr dependencyItem = builder->Compile(); dependencyItem->Register(); return true; } bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule) { DebugInfo di = rule.GetDebugInfo(); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); ScriptFrame frame; if (rule.GetScope()) rule.GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); if (service) frame.Locals->Set("service", service); Value vinstances; if (rule.GetFTerm()) { try { vinstances = rule.GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } } else { Array::Ptr instances = new Array(); instances->Add(""); vinstances = instances; } bool match = false; if (vinstances.IsObjectType()) { if (!rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { String name = rule.GetName(); if (!rule.GetFKVar().IsEmpty()) { frame.Locals->Set(rule.GetFKVar(), instance); name += instance; } if (EvaluateApplyRuleInstance(checkable, name, frame, rule)) match = true; } } else if (vinstances.IsObjectType()) { if (rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; for (const String& key : dict->GetKeys()) { frame.Locals->Set(rule.GetFKVar(), key); frame.Locals->Set(rule.GetFVVar(), dict->Get(key)); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule)) match = true; } } return match; } void Dependency::EvaluateApplyRules(const Host::Ptr& host) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("Dependency")) { if (rule.GetTargetType() != "Host") continue; if (EvaluateApplyRule(host, rule)) rule.AddMatch(); } } void Dependency::EvaluateApplyRules(const Service::Ptr& service) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("Dependency")) { if (rule.GetTargetType() != "Service") continue; if (EvaluateApplyRule(service, rule)) rule.AddMatch(); } } icinga2-2.8.1/lib/icinga/dependency.cpp000066400000000000000000000170111322762156600176720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/dependency.hpp" #include "icinga/dependency.tcpp" #include "icinga/service.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include #include using namespace icinga; REGISTER_TYPE(Dependency); String DependencyNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Dependency::Ptr dependency = dynamic_pointer_cast(context); if (!dependency) return ""; String name = dependency->GetChildHostName(); if (!dependency->GetChildServiceName().IsEmpty()) name += "!" + dependency->GetChildServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr DependencyNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Dependency name.")); Dictionary::Ptr result = new Dictionary(); result->Set("child_host_name", tokens[0]); if (tokens.size() > 2) { result->Set("child_service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void Dependency::OnConfigLoaded(void) { Value defaultFilter; if (GetParentServiceName().IsEmpty()) defaultFilter = StateFilterUp; else defaultFilter = StateFilterOK | StateFilterWarning; SetStateFilter(FilterArrayToInt(GetStates(), Notification::GetStateFilterMap(), defaultFilter)); } void Dependency::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); Host::Ptr childHost = Host::GetByName(GetChildHostName()); if (childHost) { if (GetChildServiceName().IsEmpty()) m_Child = childHost; else m_Child = childHost->GetServiceByShortName(GetChildServiceName()); } if (!m_Child) BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a child host/service which doesn't exist.", GetDebugInfo())); m_Child->AddDependency(this); Host::Ptr parentHost = Host::GetByName(GetParentHostName()); if (parentHost) { if (GetParentServiceName().IsEmpty()) m_Parent = parentHost; else m_Parent = parentHost->GetServiceByShortName(GetParentServiceName()); } if (!m_Parent) BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist.", GetDebugInfo())); m_Parent->AddReverseDependency(this); } void Dependency::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); GetChild()->RemoveDependency(this); GetParent()->RemoveReverseDependency(this); } bool Dependency::IsAvailable(DependencyType dt) const { Checkable::Ptr parent = GetParent(); Host::Ptr parentHost; Service::Ptr parentService; tie(parentHost, parentService) = GetHostService(parent); /* ignore if it's the same checkable object */ if (parent == GetChild()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent and child " << (parentService ? "service" : "host") << " are identical."; return true; } /* ignore pending */ if (!parent->GetLastCheckResult()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' hasn't been checked yet."; return true; } if (GetIgnoreSoftStates()) { /* ignore soft states */ if (parent->GetStateType() == StateTypeSoft) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state."; return true; } } else { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' failed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is in a soft state."; } int state; if (parentService) state = ServiceStateToFilter(parentService->GetState()); else state = HostStateToFilter(parentHost->GetState()); /* check state */ if (state & GetStateFilter()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' matches state filter."; return true; } /* ignore if not in time period */ TimePeriod::Ptr tp = GetPeriod(); if (tp && !tp->IsInside(Utility::GetTime())) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Outside time period."; return true; } if (dt == DependencyCheckExecution && !GetDisableChecks()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Checks are not disabled."; return true; } else if (dt == DependencyNotification && !GetDisableNotifications()) { Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' passed: Notifications are not disabled"; return true; } Log(LogNotice, "Dependency") << "Dependency '" << GetName() << "' failed. Parent " << (parentService ? "service" : "host") << " '" << parent->GetName() << "' is " << (parentService ? Service::StateToString(parentService->GetState()) : Host::StateToString(parentHost->GetState())); return false; } Checkable::Ptr Dependency::GetChild(void) const { return m_Child; } Checkable::Ptr Dependency::GetParent(void) const { return m_Parent; } TimePeriod::Ptr Dependency::GetPeriod(void) const { return TimePeriod::GetByName(GetPeriodRaw()); } void Dependency::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateStates(value, utils); int sfilter = FilterArrayToInt(value, Notification::GetStateFilterMap(), 0); if (GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for host dependency.")); if (!GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for service dependency.")); } icinga2-2.8.1/lib/icinga/dependency.hpp000066400000000000000000000052401322762156600177000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DEPENDENCY_H #define DEPENDENCY_H #include "icinga/i2-icinga.hpp" #include "icinga/dependency.thpp" namespace icinga { class ApplyRule; struct ScriptFrame; class Host; class Service; /** * A service dependency.. * * @ingroup icinga */ class I2_ICINGA_API Dependency : public ObjectImpl { public: DECLARE_OBJECT(Dependency); DECLARE_OBJECTNAME(Dependency); intrusive_ptr GetParent(void) const; intrusive_ptr GetChild(void) const; TimePeriod::Ptr GetPeriod(void) const; bool IsAvailable(DependencyType dt) const; virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override; static void EvaluateApplyRules(const intrusive_ptr& host); static void EvaluateApplyRules(const intrusive_ptr& service); protected: virtual void OnConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override; virtual void Stop(bool runtimeRemoved) override; private: Checkable::Ptr m_Parent; Checkable::Ptr m_Child; static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule); static bool EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule); }; } #endif /* DEPENDENCY_H */ icinga2-2.8.1/lib/icinga/dependency.ti000066400000000000000000000075451322762156600175370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #include "icinga/checkable.hpp" #impl_include "icinga/service.hpp" library icinga; namespace icinga { code {{{ class I2_ICINGA_API DependencyNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class Dependency : CustomVarObject < DependencyNameComposer { load_after Host; load_after Service; [config, required, navigation(child_host)] name(Host) child_host_name { navigate {{{ return Host::GetByName(GetChildHostName()); }}} }; [config, navigation(child_service)] String child_service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetParentHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetParentHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetChildServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetChildHostName()); return host->GetServiceByShortName(GetChildServiceName()); }}} }; [config, required, navigation(parent_host)] name(Host) parent_host_name { navigate {{{ return Host::GetByName(GetParentHostName()); }}} }; [config, navigation(parent_service)] String parent_service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetParentHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetParentHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetParentServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetParentHostName()); return host->GetServiceByShortName(GetParentServiceName()); }}} }; [config, navigation] name(TimePeriod) period (PeriodRaw) { navigate {{{ return TimePeriod::GetByName(GetPeriodRaw()); }}} }; [config] array(Value) states; [no_user_view, no_user_modify] int state_filter_real (StateFilter); [config] bool ignore_soft_states { default {{{ return true; }}} }; [config] bool disable_checks; [config] bool disable_notifications { default {{{ return true; }}} }; }; } icinga2-2.8.1/lib/icinga/downtime.cpp000066400000000000000000000276171322762156600174170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/downtime.hpp" #include "icinga/downtime.tcpp" #include "icinga/host.hpp" #include "icinga/scheduleddowntime.hpp" #include "remote/configobjectutility.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/timer.hpp" #include #include using namespace icinga; static int l_NextDowntimeID = 1; static boost::mutex l_DowntimeMutex; static std::map l_LegacyDowntimesCache; static Timer::Ptr l_DowntimesExpireTimer; static Timer::Ptr l_DowntimesStartTimer; boost::signals2::signal Downtime::OnDowntimeAdded; boost::signals2::signal Downtime::OnDowntimeRemoved; boost::signals2::signal Downtime::OnDowntimeStarted; boost::signals2::signal Downtime::OnDowntimeTriggered; INITIALIZE_ONCE(&Downtime::StaticInitialize); REGISTER_TYPE(Downtime); void Downtime::StaticInitialize(void) { l_DowntimesStartTimer = new Timer(); l_DowntimesStartTimer->SetInterval(5); l_DowntimesStartTimer->OnTimerExpired.connect(boost::bind(&Downtime::DowntimesStartTimerHandler)); l_DowntimesStartTimer->Start(); l_DowntimesExpireTimer = new Timer(); l_DowntimesExpireTimer->SetInterval(60); l_DowntimesExpireTimer->OnTimerExpired.connect(boost::bind(&Downtime::DowntimesExpireTimerHandler)); l_DowntimesExpireTimer->Start(); } String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Downtime::Ptr downtime = dynamic_pointer_cast(context); if (!downtime) return ""; String name = downtime->GetHostName(); if (!downtime->GetServiceName().IsEmpty()) name += "!" + downtime->GetServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr DowntimeNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Downtime name.")); Dictionary::Ptr result = new Dictionary(); result->Set("host_name", tokens[0]); if (tokens.size() > 2) { result->Set("service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void Downtime::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); Host::Ptr host = Host::GetByName(GetHostName()); if (GetServiceName().IsEmpty()) m_Checkable = host; else m_Checkable = host->GetServiceByShortName(GetServiceName()); if (!m_Checkable) BOOST_THROW_EXCEPTION(ScriptError("Downtime '" + GetName() + "' references a host/service which doesn't exist.", GetDebugInfo())); } void Downtime::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); { boost::mutex::scoped_lock lock(l_DowntimeMutex); SetLegacyId(l_NextDowntimeID); l_LegacyDowntimesCache[l_NextDowntimeID] = GetName(); l_NextDowntimeID++; } Checkable::Ptr checkable = GetCheckable(); checkable->RegisterDowntime(this); if (runtimeCreated) OnDowntimeAdded(this); /* if this object is already in a NOT-OK state trigger * this downtime now *after* it has been added (important * for DB IDO, etc.) */ if (!checkable->IsStateOK(checkable->GetStateRaw())) { Log(LogNotice, "Downtime") << "Checkable '" << checkable->GetName() << "' already in a NOT-OK state." << " Triggering downtime now."; TriggerDowntime(); } } void Downtime::Stop(bool runtimeRemoved) { GetCheckable()->UnregisterDowntime(this); if (runtimeRemoved) OnDowntimeRemoved(this); ObjectImpl::Stop(runtimeRemoved); } Checkable::Ptr Downtime::GetCheckable(void) const { return static_pointer_cast(m_Checkable); } bool Downtime::IsInEffect(void) const { double now = Utility::GetTime(); if (now < GetStartTime() || now > GetEndTime()) return false; if (GetFixed()) return true; double triggerTime = GetTriggerTime(); if (triggerTime == 0) return false; return (now < triggerTime + GetDuration()); } bool Downtime::IsTriggered(void) const { double now = Utility::GetTime(); double triggerTime = GetTriggerTime(); return (triggerTime > 0 && triggerTime <= now); } bool Downtime::IsExpired(void) const { double now = Utility::GetTime(); if (GetFixed()) return (GetEndTime() < now); else { /* triggered flexible downtime not in effect anymore */ if (IsTriggered() && !IsInEffect()) return true; /* flexible downtime never triggered */ else if (!IsTriggered() && (GetEndTime() < now)) return true; else return false; } } bool Downtime::HasValidConfigOwner(void) const { String configOwner = GetConfigOwner(); return configOwner.IsEmpty() || GetObject(configOwner); } int Downtime::GetNextDowntimeID(void) { boost::mutex::scoped_lock lock(l_DowntimeMutex); return l_NextDowntimeID; } String Downtime::AddDowntime(const Checkable::Ptr& checkable, const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledDowntime, const String& scheduledBy, const String& id, const MessageOrigin::Ptr& origin) { String fullName; if (id.IsEmpty()) fullName = checkable->GetName() + "!" + Utility::NewUniqueID(); else fullName = id; Dictionary::Ptr attrs = new Dictionary(); attrs->Set("author", author); attrs->Set("comment", comment); attrs->Set("start_time", startTime); attrs->Set("end_time", endTime); attrs->Set("fixed", fixed); attrs->Set("duration", duration); attrs->Set("triggered_by", triggeredBy); attrs->Set("scheduled_by", scheduledBy); attrs->Set("config_owner", scheduledDowntime); attrs->Set("entry_time", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); attrs->Set("host_name", host->GetName()); if (service) attrs->Set("service_name", service->GetShortName()); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) attrs->Set("zone", zone); String config = ConfigObjectUtility::CreateObjectConfig(Downtime::TypeInstance, fullName, true, Array::Ptr(), attrs); Array::Ptr errors = new Array(); if (!ConfigObjectUtility::CreateObject(Downtime::TypeInstance, fullName, config, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Downtime", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not create downtime.")); } if (!triggeredBy.IsEmpty()) { Downtime::Ptr parentDowntime = Downtime::GetByName(triggeredBy); Array::Ptr triggers = parentDowntime->GetTriggers(); ObjectLock olock(triggers); if (!triggers->Contains(fullName)) triggers->Add(fullName); } Downtime::Ptr downtime = Downtime::GetByName(fullName); if (!downtime) BOOST_THROW_EXCEPTION(std::runtime_error("Could not create downtime object.")); Log(LogNotice, "Downtime") << "Added downtime '" << downtime->GetName() << "' between '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime) << "' and '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "'."; return fullName; } void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, const MessageOrigin::Ptr& origin) { Downtime::Ptr downtime = Downtime::GetByName(id); if (!downtime || downtime->GetPackage() != "_api") return; String config_owner = downtime->GetConfigOwner(); if (!config_owner.IsEmpty() && !expired) { Log(LogWarning, "Downtime") << "Cannot remove downtime '" << downtime->GetName() << "'. It is owned by scheduled downtime object '" << config_owner << "'"; return; } downtime->SetWasCancelled(cancelled); Log(LogNotice, "Downtime") << "Removed downtime '" << downtime->GetName() << "' from object '" << downtime->GetCheckable()->GetName() << "'."; Array::Ptr errors = new Array(); if (!ConfigObjectUtility::DeleteObject(downtime, false, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Downtime", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not remove downtime.")); } } bool Downtime::CanBeTriggered(void) { if (IsInEffect() && IsTriggered()) return false; if (IsExpired()) return false; double now = Utility::GetTime(); if (now < GetStartTime() || now > GetEndTime()) return false; return true; } void Downtime::TriggerDowntime(void) { if (!CanBeTriggered()) return; Log(LogNotice, "Downtime") << "Triggering downtime '" << GetName() << "'."; if (GetTriggerTime() == 0) SetTriggerTime(Utility::GetTime()); Array::Ptr triggers = GetTriggers(); { ObjectLock olock(triggers); for (const String& triggerName : triggers) { Downtime::Ptr downtime = Downtime::GetByName(triggerName); if (!downtime) continue; downtime->TriggerDowntime(); } } OnDowntimeTriggered(this); } String Downtime::GetDowntimeIDFromLegacyID(int id) { boost::mutex::scoped_lock lock(l_DowntimeMutex); auto it = l_LegacyDowntimesCache.find(id); if (it == l_LegacyDowntimesCache.end()) return Empty; return it->second; } void Downtime::DowntimesStartTimerHandler(void) { /* Start fixed downtimes. Flexible downtimes will be triggered on-demand. */ for (const Downtime::Ptr& downtime : ConfigType::GetObjectsByType()) { if (downtime->IsActive() && downtime->CanBeTriggered() && downtime->GetFixed()) { /* Send notifications. */ OnDowntimeStarted(downtime); /* Trigger fixed downtime immediately. */ downtime->TriggerDowntime(); } } } void Downtime::DowntimesExpireTimerHandler(void) { std::vector downtimes; for (const Downtime::Ptr& downtime : ConfigType::GetObjectsByType()) { downtimes.push_back(downtime); } for (const Downtime::Ptr& downtime : downtimes) { /* Only remove downtimes which are activated after daemon start. */ if (downtime->IsActive() && (downtime->IsExpired() || !downtime->HasValidConfigOwner())) RemoveDowntime(downtime->GetName(), false, true); } } void Downtime::ValidateStartTime(const Timestamp& value, const ValidationUtils& utils) { ObjectImpl::ValidateStartTime(value, utils); if (value <= 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("start_time"), "Start time must be greater than 0.")); } void Downtime::ValidateEndTime(const Timestamp& value, const ValidationUtils& utils) { ObjectImpl::ValidateEndTime(value, utils); if (value <= 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("end_time"), "End time must be greater than 0.")); } icinga2-2.8.1/lib/icinga/downtime.hpp000066400000000000000000000067551322762156600174240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DOWNTIME_H #define DOWNTIME_H #include "icinga/i2-icinga.hpp" #include "icinga/downtime.thpp" #include "icinga/checkable.thpp" #include "remote/messageorigin.hpp" namespace icinga { /** * A downtime. * * @ingroup icinga */ class I2_ICINGA_API Downtime : public ObjectImpl { public: DECLARE_OBJECT(Downtime); DECLARE_OBJECTNAME(Downtime); static boost::signals2::signal OnDowntimeAdded; static boost::signals2::signal OnDowntimeRemoved; static boost::signals2::signal OnDowntimeStarted; static boost::signals2::signal OnDowntimeTriggered; intrusive_ptr GetCheckable(void) const; bool IsInEffect(void) const; bool IsTriggered(void) const; bool IsExpired(void) const; bool HasValidConfigOwner(void) const; static int GetNextDowntimeID(void); static String AddDowntime(const intrusive_ptr& checkable, const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledDowntime = String(), const String& scheduledBy = String(), const String& id = String(), const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); static void RemoveDowntime(const String& id, bool cancelled, bool expired = false, const MessageOrigin::Ptr& origin = MessageOrigin::Ptr()); void TriggerDowntime(void); static String GetDowntimeIDFromLegacyID(int id); static void StaticInitialize(void); protected: virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; virtual void ValidateStartTime(const Timestamp& value, const ValidationUtils& utils) override; virtual void ValidateEndTime(const Timestamp& value, const ValidationUtils& utils) override; private: ObjectImpl::Ptr m_Checkable; bool CanBeTriggered(void); static void DowntimesStartTimerHandler(void); static void DowntimesExpireTimerHandler(void); }; } #endif /* DOWNTIME_H */ icinga2-2.8.1/lib/icinga/downtime.ti000066400000000000000000000061701322762156600172400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/utility.hpp" #impl_include "icinga/service.hpp" library icinga; namespace icinga { code {{{ class I2_ICINGA_API DowntimeNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class Downtime : ConfigObject < DowntimeNameComposer { load_after Host; load_after Service; [config, protected, required, navigation(host)] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; [config, protected, navigation(service)] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetHostName()); return host->GetServiceByShortName(GetServiceName()); }}} }; [config] Timestamp entry_time { default {{{ return Utility::GetTime(); }}} }; [config, required] String author; [config, required] String comment; [config] Timestamp start_time; [config] Timestamp end_time; [state] Timestamp trigger_time; [config] bool fixed; [config] Timestamp duration; [config] String triggered_by; [config] String scheduled_by; [state] Array::Ptr triggers { default {{{ return new Array(); }}} }; [state] int legacy_id; [state] bool was_cancelled; [config] String config_owner; }; } icinga2-2.8.1/lib/icinga/eventcommand.cpp000066400000000000000000000035251322762156600202410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/eventcommand.hpp" #include "icinga/eventcommand.tcpp" using namespace icinga; REGISTER_TYPE(EventCommand); void EventCommand::Execute(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { std::vector arguments; arguments.push_back(checkable); arguments.push_back(resolvedMacros); arguments.push_back(useResolvedMacros); GetExecute()->Invoke(arguments); } icinga2-2.8.1/lib/icinga/eventcommand.hpp000066400000000000000000000036651322762156600202530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EVENTCOMMAND_H #define EVENTCOMMAND_H #include "icinga/eventcommand.thpp" #include "icinga/checkable.hpp" namespace icinga { /** * An event handler command. * * @ingroup icinga */ class I2_ICINGA_API EventCommand : public ObjectImpl { public: DECLARE_OBJECT(EventCommand); DECLARE_OBJECTNAME(EventCommand); virtual void Execute(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), bool useResolvedMacros = false); }; } #endif /* EVENTCOMMAND_H */ icinga2-2.8.1/lib/icinga/eventcommand.ti000066400000000000000000000030141322762156600200640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/command.hpp" library icinga; namespace icinga { class EventCommand : Command { }; } icinga2-2.8.1/lib/icinga/externalcommandprocessor.cpp000066400000000000000000002642571322762156600227150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/externalcommandprocessor.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/user.hpp" #include "icinga/hostgroup.hpp" #include "icinga/servicegroup.hpp" #include "icinga/pluginutility.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/compatutility.hpp" #include "remote/apifunction.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/application.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include #include #include using namespace icinga; INITIALIZE_ONCE(&ExternalCommandProcessor::StaticInitialize); typedef boost::function& arguments)> ExternalCommandCallback; struct ExternalCommandInfo { ExternalCommandCallback Callback; size_t MinArgs; size_t MaxArgs; }; static boost::mutex& GetMutex(void) { static boost::mutex mtx; return mtx; } static std::map& GetCommands(void) { static std::map commands; return commands; } boost::signals2::signal&)> ExternalCommandProcessor::OnNewExternalCommand; static void RegisterCommand(const String& command, const ExternalCommandCallback& callback, size_t minArgs = 0, size_t maxArgs = UINT_MAX) { boost::mutex::scoped_lock lock(GetMutex()); ExternalCommandInfo eci; eci.Callback = callback; eci.MinArgs = minArgs; eci.MaxArgs = (maxArgs == UINT_MAX) ? minArgs : maxArgs; GetCommands()[command] = eci; } void ExternalCommandProcessor::Execute(const String& line) { if (line.IsEmpty()) return; if (line[0] != '[') BOOST_THROW_EXCEPTION(std::invalid_argument("Missing timestamp in command: " + line)); size_t pos = line.FindFirstOf("]"); if (pos == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Missing timestamp in command: " + line)); String timestamp = line.SubStr(1, pos - 1); String args = line.SubStr(pos + 2, String::NPos); double ts = Convert::ToDouble(timestamp); if (ts == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid timestamp in command: " + line)); std::vector argv; boost::algorithm::split(argv, args, boost::is_any_of(";")); if (argv.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Missing arguments in command: " + line)); std::vector argvExtra(argv.begin() + 1, argv.end()); Execute(ts, argv[0], argvExtra); } void ExternalCommandProcessor::Execute(double time, const String& command, const std::vector& arguments) { ExternalCommandInfo eci; { boost::mutex::scoped_lock lock(GetMutex()); auto it = GetCommands().find(command); if (it == GetCommands().end()) BOOST_THROW_EXCEPTION(std::invalid_argument("The external command '" + command + "' does not exist.")); eci = it->second; } if (arguments.size() < eci.MinArgs) BOOST_THROW_EXCEPTION(std::invalid_argument("Expected " + Convert::ToString(eci.MinArgs) + " arguments")); size_t argnum = std::min(arguments.size(), eci.MaxArgs); std::vector realArguments; realArguments.resize(argnum); if (argnum > 0) { std::copy(arguments.begin(), arguments.begin() + argnum - 1, realArguments.begin()); String last_argument; for (std::vector::size_type i = argnum - 1; i < arguments.size(); i++) { if (!last_argument.IsEmpty()) last_argument += ";"; last_argument += arguments[i]; } realArguments[argnum - 1] = last_argument; } OnNewExternalCommand(time, command, realArguments); eci.Callback(time, realArguments); } void ExternalCommandProcessor::StaticInitialize(void) { RegisterCommand("PROCESS_HOST_CHECK_RESULT", &ExternalCommandProcessor::ProcessHostCheckResult, 3); RegisterCommand("PROCESS_SERVICE_CHECK_RESULT", &ExternalCommandProcessor::ProcessServiceCheckResult, 4); RegisterCommand("SCHEDULE_HOST_CHECK", &ExternalCommandProcessor::ScheduleHostCheck, 2); RegisterCommand("SCHEDULE_FORCED_HOST_CHECK", &ExternalCommandProcessor::ScheduleForcedHostCheck, 2); RegisterCommand("SCHEDULE_SVC_CHECK", &ExternalCommandProcessor::ScheduleSvcCheck, 3); RegisterCommand("SCHEDULE_FORCED_SVC_CHECK", &ExternalCommandProcessor::ScheduleForcedSvcCheck, 3); RegisterCommand("ENABLE_HOST_CHECK", &ExternalCommandProcessor::EnableHostCheck, 1); RegisterCommand("DISABLE_HOST_CHECK", &ExternalCommandProcessor::DisableHostCheck, 1); RegisterCommand("ENABLE_SVC_CHECK", &ExternalCommandProcessor::EnableSvcCheck, 2); RegisterCommand("DISABLE_SVC_CHECK", &ExternalCommandProcessor::DisableSvcCheck, 2); RegisterCommand("SHUTDOWN_PROCESS", &ExternalCommandProcessor::ShutdownProcess); RegisterCommand("RESTART_PROCESS", &ExternalCommandProcessor::RestartProcess); RegisterCommand("SCHEDULE_FORCED_HOST_SVC_CHECKS", &ExternalCommandProcessor::ScheduleForcedHostSvcChecks, 2); RegisterCommand("SCHEDULE_HOST_SVC_CHECKS", &ExternalCommandProcessor::ScheduleHostSvcChecks, 2); RegisterCommand("ENABLE_HOST_SVC_CHECKS", &ExternalCommandProcessor::EnableHostSvcChecks, 1); RegisterCommand("DISABLE_HOST_SVC_CHECKS", &ExternalCommandProcessor::DisableHostSvcChecks, 1); RegisterCommand("ACKNOWLEDGE_SVC_PROBLEM", &ExternalCommandProcessor::AcknowledgeSvcProblem, 7); RegisterCommand("ACKNOWLEDGE_SVC_PROBLEM_EXPIRE", &ExternalCommandProcessor::AcknowledgeSvcProblemExpire, 8); RegisterCommand("REMOVE_SVC_ACKNOWLEDGEMENT", &ExternalCommandProcessor::RemoveSvcAcknowledgement, 2); RegisterCommand("ACKNOWLEDGE_HOST_PROBLEM", &ExternalCommandProcessor::AcknowledgeHostProblem, 6); RegisterCommand("ACKNOWLEDGE_HOST_PROBLEM_EXPIRE", &ExternalCommandProcessor::AcknowledgeHostProblemExpire, 7); RegisterCommand("REMOVE_HOST_ACKNOWLEDGEMENT", &ExternalCommandProcessor::RemoveHostAcknowledgement, 1); RegisterCommand("DISABLE_HOST_FLAP_DETECTION", &ExternalCommandProcessor::DisableHostFlapping, 1); RegisterCommand("ENABLE_HOST_FLAP_DETECTION", &ExternalCommandProcessor::EnableHostFlapping, 1); RegisterCommand("DISABLE_SVC_FLAP_DETECTION", &ExternalCommandProcessor::DisableSvcFlapping, 2); RegisterCommand("ENABLE_SVC_FLAP_DETECTION", &ExternalCommandProcessor::EnableSvcFlapping, 2); RegisterCommand("ENABLE_HOSTGROUP_SVC_CHECKS", &ExternalCommandProcessor::EnableHostgroupSvcChecks, 1); RegisterCommand("DISABLE_HOSTGROUP_SVC_CHECKS", &ExternalCommandProcessor::DisableHostgroupSvcChecks, 1); RegisterCommand("ENABLE_SERVICEGROUP_SVC_CHECKS", &ExternalCommandProcessor::EnableServicegroupSvcChecks, 1); RegisterCommand("DISABLE_SERVICEGROUP_SVC_CHECKS", &ExternalCommandProcessor::DisableServicegroupSvcChecks, 1); RegisterCommand("ENABLE_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::EnablePassiveHostChecks, 1); RegisterCommand("DISABLE_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::DisablePassiveHostChecks, 1); RegisterCommand("ENABLE_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::EnablePassiveSvcChecks, 2); RegisterCommand("DISABLE_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::DisablePassiveSvcChecks, 2); RegisterCommand("ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::EnableServicegroupPassiveSvcChecks, 1); RegisterCommand("DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::DisableServicegroupPassiveSvcChecks, 1); RegisterCommand("ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::EnableHostgroupPassiveSvcChecks, 1); RegisterCommand("DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS", &ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks, 1); RegisterCommand("PROCESS_FILE", &ExternalCommandProcessor::ProcessFile, 2); RegisterCommand("SCHEDULE_SVC_DOWNTIME", &ExternalCommandProcessor::ScheduleSvcDowntime, 9); RegisterCommand("DEL_SVC_DOWNTIME", &ExternalCommandProcessor::DelSvcDowntime, 1); RegisterCommand("SCHEDULE_HOST_DOWNTIME", &ExternalCommandProcessor::ScheduleHostDowntime, 8); RegisterCommand("SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME", &ExternalCommandProcessor::ScheduleAndPropagateHostDowntime, 8); RegisterCommand("SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME", &ExternalCommandProcessor::ScheduleAndPropagateTriggeredHostDowntime, 8); RegisterCommand("DEL_HOST_DOWNTIME", &ExternalCommandProcessor::DelHostDowntime, 1); RegisterCommand("DEL_DOWNTIME_BY_HOST_NAME", &ExternalCommandProcessor::DelDowntimeByHostName, 1, 4); RegisterCommand("SCHEDULE_HOST_SVC_DOWNTIME", &ExternalCommandProcessor::ScheduleHostSvcDowntime, 8); RegisterCommand("SCHEDULE_HOSTGROUP_HOST_DOWNTIME", &ExternalCommandProcessor::ScheduleHostgroupHostDowntime, 8); RegisterCommand("SCHEDULE_HOSTGROUP_SVC_DOWNTIME", &ExternalCommandProcessor::ScheduleHostgroupSvcDowntime, 8); RegisterCommand("SCHEDULE_SERVICEGROUP_HOST_DOWNTIME", &ExternalCommandProcessor::ScheduleServicegroupHostDowntime, 8); RegisterCommand("SCHEDULE_SERVICEGROUP_SVC_DOWNTIME", &ExternalCommandProcessor::ScheduleServicegroupSvcDowntime, 8); RegisterCommand("ADD_HOST_COMMENT", &ExternalCommandProcessor::AddHostComment, 4); RegisterCommand("DEL_HOST_COMMENT", &ExternalCommandProcessor::DelHostComment, 1); RegisterCommand("ADD_SVC_COMMENT", &ExternalCommandProcessor::AddSvcComment, 5); RegisterCommand("DEL_SVC_COMMENT", &ExternalCommandProcessor::DelSvcComment, 1); RegisterCommand("DEL_ALL_HOST_COMMENTS", &ExternalCommandProcessor::DelAllHostComments, 1); RegisterCommand("DEL_ALL_SVC_COMMENTS", &ExternalCommandProcessor::DelAllSvcComments, 2); RegisterCommand("SEND_CUSTOM_HOST_NOTIFICATION", &ExternalCommandProcessor::SendCustomHostNotification, 4); RegisterCommand("SEND_CUSTOM_SVC_NOTIFICATION", &ExternalCommandProcessor::SendCustomSvcNotification, 5); RegisterCommand("DELAY_HOST_NOTIFICATION", &ExternalCommandProcessor::DelayHostNotification, 2); RegisterCommand("DELAY_SVC_NOTIFICATION", &ExternalCommandProcessor::DelaySvcNotification, 3); RegisterCommand("ENABLE_HOST_NOTIFICATIONS", &ExternalCommandProcessor::EnableHostNotifications, 1); RegisterCommand("DISABLE_HOST_NOTIFICATIONS", &ExternalCommandProcessor::DisableHostNotifications, 1); RegisterCommand("ENABLE_SVC_NOTIFICATIONS", &ExternalCommandProcessor::EnableSvcNotifications, 2); RegisterCommand("DISABLE_SVC_NOTIFICATIONS", &ExternalCommandProcessor::DisableSvcNotifications, 2); RegisterCommand("ENABLE_HOST_SVC_NOTIFICATIONS", &ExternalCommandProcessor::EnableHostSvcNotifications, 1); RegisterCommand("DISABLE_HOST_SVC_NOTIFICATIONS", &ExternalCommandProcessor::DisableHostSvcNotifications, 1); RegisterCommand("DISABLE_HOSTGROUP_HOST_CHECKS", &ExternalCommandProcessor::DisableHostgroupHostChecks, 1); RegisterCommand("DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::DisableHostgroupPassiveHostChecks, 1); RegisterCommand("DISABLE_SERVICEGROUP_HOST_CHECKS", &ExternalCommandProcessor::DisableServicegroupHostChecks, 1); RegisterCommand("DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::DisableServicegroupPassiveHostChecks, 1); RegisterCommand("ENABLE_HOSTGROUP_HOST_CHECKS", &ExternalCommandProcessor::EnableHostgroupHostChecks, 1); RegisterCommand("ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::EnableHostgroupPassiveHostChecks, 1); RegisterCommand("ENABLE_SERVICEGROUP_HOST_CHECKS", &ExternalCommandProcessor::EnableServicegroupHostChecks, 1); RegisterCommand("ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS", &ExternalCommandProcessor::EnableServicegroupPassiveHostChecks, 1); RegisterCommand("ENABLE_NOTIFICATIONS", &ExternalCommandProcessor::EnableNotifications); RegisterCommand("DISABLE_NOTIFICATIONS", &ExternalCommandProcessor::DisableNotifications); RegisterCommand("ENABLE_FLAP_DETECTION", &ExternalCommandProcessor::EnableFlapDetection); RegisterCommand("DISABLE_FLAP_DETECTION", &ExternalCommandProcessor::DisableFlapDetection); RegisterCommand("ENABLE_EVENT_HANDLERS", &ExternalCommandProcessor::EnableEventHandlers); RegisterCommand("DISABLE_EVENT_HANDLERS", &ExternalCommandProcessor::DisableEventHandlers); RegisterCommand("ENABLE_PERFORMANCE_DATA", &ExternalCommandProcessor::EnablePerformanceData); RegisterCommand("DISABLE_PERFORMANCE_DATA", &ExternalCommandProcessor::DisablePerformanceData); RegisterCommand("START_EXECUTING_SVC_CHECKS", &ExternalCommandProcessor::StartExecutingSvcChecks); RegisterCommand("STOP_EXECUTING_SVC_CHECKS", &ExternalCommandProcessor::StopExecutingSvcChecks); RegisterCommand("START_EXECUTING_HOST_CHECKS", &ExternalCommandProcessor::StartExecutingHostChecks); RegisterCommand("STOP_EXECUTING_HOST_CHECKS", &ExternalCommandProcessor::StopExecutingHostChecks); RegisterCommand("CHANGE_NORMAL_SVC_CHECK_INTERVAL", &ExternalCommandProcessor::ChangeNormalSvcCheckInterval, 3); RegisterCommand("CHANGE_NORMAL_HOST_CHECK_INTERVAL", &ExternalCommandProcessor::ChangeNormalHostCheckInterval, 2); RegisterCommand("CHANGE_RETRY_SVC_CHECK_INTERVAL", &ExternalCommandProcessor::ChangeRetrySvcCheckInterval, 3); RegisterCommand("CHANGE_RETRY_HOST_CHECK_INTERVAL", &ExternalCommandProcessor::ChangeRetryHostCheckInterval, 2); RegisterCommand("ENABLE_HOST_EVENT_HANDLER", &ExternalCommandProcessor::EnableHostEventHandler, 1); RegisterCommand("DISABLE_HOST_EVENT_HANDLER", &ExternalCommandProcessor::DisableHostEventHandler, 1); RegisterCommand("ENABLE_SVC_EVENT_HANDLER", &ExternalCommandProcessor::EnableSvcEventHandler, 2); RegisterCommand("DISABLE_SVC_EVENT_HANDLER", &ExternalCommandProcessor::DisableSvcEventHandler, 2); RegisterCommand("CHANGE_HOST_EVENT_HANDLER", &ExternalCommandProcessor::ChangeHostEventHandler, 2); RegisterCommand("CHANGE_SVC_EVENT_HANDLER", &ExternalCommandProcessor::ChangeSvcEventHandler, 3); RegisterCommand("CHANGE_HOST_CHECK_COMMAND", &ExternalCommandProcessor::ChangeHostCheckCommand, 2); RegisterCommand("CHANGE_SVC_CHECK_COMMAND", &ExternalCommandProcessor::ChangeSvcCheckCommand, 3); RegisterCommand("CHANGE_MAX_HOST_CHECK_ATTEMPTS", &ExternalCommandProcessor::ChangeMaxHostCheckAttempts, 2); RegisterCommand("CHANGE_MAX_SVC_CHECK_ATTEMPTS", &ExternalCommandProcessor::ChangeMaxSvcCheckAttempts, 3); RegisterCommand("CHANGE_HOST_CHECK_TIMEPERIOD", &ExternalCommandProcessor::ChangeHostCheckTimeperiod, 2); RegisterCommand("CHANGE_SVC_CHECK_TIMEPERIOD", &ExternalCommandProcessor::ChangeSvcCheckTimeperiod, 3); RegisterCommand("CHANGE_CUSTOM_HOST_VAR", &ExternalCommandProcessor::ChangeCustomHostVar, 3); RegisterCommand("CHANGE_CUSTOM_SVC_VAR", &ExternalCommandProcessor::ChangeCustomSvcVar, 4); RegisterCommand("CHANGE_CUSTOM_USER_VAR", &ExternalCommandProcessor::ChangeCustomUserVar, 3); RegisterCommand("CHANGE_CUSTOM_CHECKCOMMAND_VAR", &ExternalCommandProcessor::ChangeCustomCheckcommandVar, 3); RegisterCommand("CHANGE_CUSTOM_EVENTCOMMAND_VAR", &ExternalCommandProcessor::ChangeCustomEventcommandVar, 3); RegisterCommand("CHANGE_CUSTOM_NOTIFICATIONCOMMAND_VAR", &ExternalCommandProcessor::ChangeCustomNotificationcommandVar, 3); RegisterCommand("ENABLE_HOSTGROUP_HOST_NOTIFICATIONS", &ExternalCommandProcessor::EnableHostgroupHostNotifications, 1); RegisterCommand("ENABLE_HOSTGROUP_SVC_NOTIFICATIONS", &ExternalCommandProcessor::EnableHostgroupSvcNotifications, 1); RegisterCommand("DISABLE_HOSTGROUP_HOST_NOTIFICATIONS", &ExternalCommandProcessor::DisableHostgroupHostNotifications, 1); RegisterCommand("DISABLE_HOSTGROUP_SVC_NOTIFICATIONS", &ExternalCommandProcessor::DisableHostgroupSvcNotifications, 1); RegisterCommand("ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS", &ExternalCommandProcessor::EnableServicegroupHostNotifications, 1); RegisterCommand("DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS", &ExternalCommandProcessor::DisableServicegroupHostNotifications, 1); RegisterCommand("ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS", &ExternalCommandProcessor::EnableServicegroupSvcNotifications, 1); RegisterCommand("DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS", &ExternalCommandProcessor::DisableServicegroupSvcNotifications, 1); } void ExternalCommandProcessor::ExecuteFromFile(const String& line, std::deque< std::vector >& file_queue) { if (line.IsEmpty()) return; if (line[0] != '[') BOOST_THROW_EXCEPTION(std::invalid_argument("Missing timestamp in command: " + line)); size_t pos = line.FindFirstOf("]"); if (pos == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Missing timestamp in command: " + line)); String timestamp = line.SubStr(1, pos - 1); String args = line.SubStr(pos + 2, String::NPos); double ts = Convert::ToDouble(timestamp); if (ts == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid timestamp in command: " + line)); std::vector argv; boost::algorithm::split(argv, args, boost::is_any_of(";")); if (argv.empty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Missing arguments in command: " + line)); std::vector argvExtra(argv.begin() + 1, argv.end()); if (argv[0] == "PROCESS_FILE") { Log(LogDebug, "ExternalCommandProcessor") << "Enqueing external command file " << argvExtra[0]; file_queue.push_back(argvExtra); } else { Execute(ts, argv[0], argvExtra); } } void ExternalCommandProcessor::ProcessHostCheckResult(double time, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot process passive host check result for non-existent host '" + arguments[0] + "'")); if (!host->GetEnablePassiveChecks()) BOOST_THROW_EXCEPTION(std::invalid_argument("Got passive check result for host '" + arguments[0] + "' which has passive checks disabled.")); int exitStatus = Convert::ToDouble(arguments[1]); CheckResult::Ptr result = new CheckResult(); std::pair co = PluginUtility::ParseCheckOutput(arguments[2]); result->SetOutput(co.first); result->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); ServiceState state; if (exitStatus == 0) state = ServiceOK; else if (exitStatus == 1) state = ServiceCritical; else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status code: " + arguments[1])); result->SetState(state); result->SetScheduleStart(time); result->SetScheduleEnd(time); result->SetExecutionStart(time); result->SetExecutionEnd(time); /* Mark this check result as passive. */ result->SetActive(false); Log(LogNotice, "ExternalCommandProcessor") << "Processing passive check result for host '" << arguments[0] << "'"; host->ProcessCheckResult(result); } void ExternalCommandProcessor::ProcessServiceCheckResult(double time, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot process passive service check result for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); if (!service->GetEnablePassiveChecks()) BOOST_THROW_EXCEPTION(std::invalid_argument("Got passive check result for service '" + arguments[1] + "' which has passive checks disabled.")); int exitStatus = Convert::ToDouble(arguments[2]); CheckResult::Ptr result = new CheckResult(); String output = CompatUtility::UnEscapeString(arguments[3]); std::pair co = PluginUtility::ParseCheckOutput(output); result->SetOutput(co.first); result->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); result->SetState(PluginUtility::ExitStatusToState(exitStatus)); result->SetScheduleStart(time); result->SetScheduleEnd(time); result->SetExecutionStart(time); result->SetExecutionEnd(time); /* Mark this check result as passive. */ result->SetActive(false); Log(LogNotice, "ExternalCommandProcessor") << "Processing passive check result for service '" << arguments[1] << "'"; service->ProcessCheckResult(result); } void ExternalCommandProcessor::ScheduleHostCheck(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule host check for non-existent host '" + arguments[0] + "'")); double planned_check = Convert::ToDouble(arguments[1]); if (planned_check > host->GetNextCheck()) { Log(LogNotice, "ExternalCommandProcessor") << "Ignoring reschedule request for host '" << arguments[0] << "' (next check is already sooner than requested check time)"; return; } Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for host '" << arguments[0] << "'"; if (planned_check < Utility::GetTime()) planned_check = Utility::GetTime(); host->SetNextCheck(planned_check); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(host); } void ExternalCommandProcessor::ScheduleForcedHostCheck(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule forced host check for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for host '" << arguments[0] << "'"; host->SetForceNextCheck(true); host->SetNextCheck(Convert::ToDouble(arguments[1])); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(host); } void ExternalCommandProcessor::ScheduleSvcCheck(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule service check for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); double planned_check = Convert::ToDouble(arguments[2]); if (planned_check > service->GetNextCheck()) { Log(LogNotice, "ExternalCommandProcessor") << "Ignoring reschedule request for service '" << arguments[1] << "' (next check is already sooner than requested check time)"; return; } Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for service '" << arguments[1] << "'"; if (planned_check < Utility::GetTime()) planned_check = Utility::GetTime(); service->SetNextCheck(planned_check); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(service); } void ExternalCommandProcessor::ScheduleForcedSvcCheck(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule forced service check for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for service '" << arguments[1] << "'"; service->SetForceNextCheck(true); service->SetNextCheck(Convert::ToDouble(arguments[2])); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(service); } void ExternalCommandProcessor::EnableHostCheck(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host checks for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_active_checks", true); } void ExternalCommandProcessor::DisableHostCheck(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host check non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_active_checks", false); } void ExternalCommandProcessor::EnableSvcCheck(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service check for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_active_checks", true); } void ExternalCommandProcessor::DisableSvcCheck(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service check for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_active_checks", false); } void ExternalCommandProcessor::ShutdownProcess(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Shutting down Icinga via external command."); Application::RequestShutdown(); } void ExternalCommandProcessor::RestartProcess(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Restarting Icinga via external command."); Application::RequestRestart(); } void ExternalCommandProcessor::ScheduleForcedHostSvcChecks(double, const std::vector& arguments) { double planned_check = Convert::ToDouble(arguments[1]); Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule forced host service checks for non-existent host '" + arguments[0] + "'")); for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for service '" << service->GetName() << "'"; service->SetNextCheck(planned_check); service->SetForceNextCheck(true); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(service); } } void ExternalCommandProcessor::ScheduleHostSvcChecks(double, const std::vector& arguments) { double planned_check = Convert::ToDouble(arguments[1]); Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot reschedule host service checks for non-existent host '" + arguments[0] + "'")); if (planned_check < Utility::GetTime()) planned_check = Utility::GetTime(); for (const Service::Ptr& service : host->GetServices()) { if (planned_check > service->GetNextCheck()) { Log(LogNotice, "ExternalCommandProcessor") << "Ignoring reschedule request for service '" << service->GetName() << "' (next check is already sooner than requested check time)"; continue; } Log(LogNotice, "ExternalCommandProcessor") << "Rescheduling next check for service '" << service->GetName() << "'"; service->SetNextCheck(planned_check); /* trigger update event for DB IDO */ Checkable::OnNextCheckUpdated(service); } } void ExternalCommandProcessor::EnableHostSvcChecks(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host service checks for non-existent host '" + arguments[0] + "'")); for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", true); } } void ExternalCommandProcessor::DisableHostSvcChecks(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host service checks for non-existent host '" + arguments[0] + "'")); for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", false); } } void ExternalCommandProcessor::AcknowledgeSvcProblem(double, const std::vector& arguments) { bool sticky = (Convert::ToLong(arguments[2]) == 2 ? true : false); bool notify = (Convert::ToLong(arguments[3]) > 0 ? true : false); bool persistent = (Convert::ToLong(arguments[4]) > 0 ? true : false); Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot acknowledge service problem for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); if (service->GetState() == ServiceOK) BOOST_THROW_EXCEPTION(std::invalid_argument("The service '" + arguments[1] + "' is OK.")); Log(LogNotice, "ExternalCommandProcessor") << "Setting acknowledgement for service '" << service->GetName() << "'" << (notify ? "" : ". Disabled notification"); Comment::AddComment(service, CommentAcknowledgement, arguments[5], arguments[6], persistent, 0); service->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent); } void ExternalCommandProcessor::AcknowledgeSvcProblemExpire(double, const std::vector& arguments) { bool sticky = (Convert::ToLong(arguments[2]) == 2 ? true : false); bool notify = (Convert::ToLong(arguments[3]) > 0 ? true : false); bool persistent = (Convert::ToLong(arguments[4]) > 0 ? true : false); double timestamp = Convert::ToDouble(arguments[5]); Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot acknowledge service problem with expire time for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); if (service->GetState() == ServiceOK) BOOST_THROW_EXCEPTION(std::invalid_argument("The service '" + arguments[1] + "' is OK.")); if (timestamp != 0 && timestamp <= Utility::GetTime()) BOOST_THROW_EXCEPTION(std::invalid_argument("Acknowledgement expire time must be in the future for service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Setting timed acknowledgement for service '" << service->GetName() << "'" << (notify ? "" : ". Disabled notification"); Comment::AddComment(service, CommentAcknowledgement, arguments[6], arguments[7], persistent, timestamp); service->AcknowledgeProblem(arguments[6], arguments[7], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent, timestamp); } void ExternalCommandProcessor::RemoveSvcAcknowledgement(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot remove service acknowledgement for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Removing acknowledgement for service '" << service->GetName() << "'"; { ObjectLock olock(service); service->ClearAcknowledgement(); } service->RemoveCommentsByType(CommentAcknowledgement); } void ExternalCommandProcessor::AcknowledgeHostProblem(double, const std::vector& arguments) { bool sticky = (Convert::ToLong(arguments[1]) == 2 ? true : false); bool notify = (Convert::ToLong(arguments[2]) > 0 ? true : false); bool persistent = (Convert::ToLong(arguments[3]) > 0 ? true : false); Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot acknowledge host problem for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Setting acknowledgement for host '" << host->GetName() << "'" << (notify ? "" : ". Disabled notification"); if (host->GetState() == HostUp) BOOST_THROW_EXCEPTION(std::invalid_argument("The host '" + arguments[0] + "' is OK.")); Comment::AddComment(host, CommentAcknowledgement, arguments[4], arguments[5], persistent, 0); host->AcknowledgeProblem(arguments[4], arguments[5], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent); } void ExternalCommandProcessor::AcknowledgeHostProblemExpire(double, const std::vector& arguments) { bool sticky = (Convert::ToLong(arguments[1]) == 2 ? true : false); bool notify = (Convert::ToLong(arguments[2]) > 0 ? true : false); bool persistent = (Convert::ToLong(arguments[3]) > 0 ? true : false); double timestamp = Convert::ToDouble(arguments[4]); Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot acknowledge host problem with expire time for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Setting timed acknowledgement for host '" << host->GetName() << "'" << (notify ? "" : ". Disabled notification"); if (host->GetState() == HostUp) BOOST_THROW_EXCEPTION(std::invalid_argument("The host '" + arguments[0] + "' is OK.")); if (timestamp != 0 && timestamp <= Utility::GetTime()) BOOST_THROW_EXCEPTION(std::invalid_argument("Acknowledgement expire time must be in the future for host '" + arguments[0] + "'")); Comment::AddComment(host, CommentAcknowledgement, arguments[5], arguments[6], persistent, timestamp); host->AcknowledgeProblem(arguments[5], arguments[6], sticky ? AcknowledgementSticky : AcknowledgementNormal, notify, persistent, timestamp); } void ExternalCommandProcessor::RemoveHostAcknowledgement(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot remove acknowledgement for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Removing acknowledgement for host '" << host->GetName() << "'"; { ObjectLock olock(host); host->ClearAcknowledgement(); } host->RemoveCommentsByType(CommentAcknowledgement); } void ExternalCommandProcessor::EnableHostgroupSvcChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable hostgroup service checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", true); } } } void ExternalCommandProcessor::DisableHostgroupSvcChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable hostgroup service checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", false); } } } void ExternalCommandProcessor::EnableServicegroupSvcChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable servicegroup service checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", true); } } void ExternalCommandProcessor::DisableServicegroupSvcChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable servicegroup service checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_active_checks", false); } } void ExternalCommandProcessor::EnablePassiveHostChecks(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable passive host checks for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_passive_checks", true); } void ExternalCommandProcessor::DisablePassiveHostChecks(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable passive host checks for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_passive_checks", false); } void ExternalCommandProcessor::EnablePassiveSvcChecks(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service checks for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_passive_checks", true); } void ExternalCommandProcessor::DisablePassiveSvcChecks(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service checks for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_passive_checks", false); } void ExternalCommandProcessor::EnableServicegroupPassiveSvcChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable servicegroup passive service checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_passive_checks", true); } } void ExternalCommandProcessor::DisableServicegroupPassiveSvcChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable servicegroup passive service checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_passive_checks", false); } } void ExternalCommandProcessor::EnableHostgroupPassiveSvcChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable hostgroup passive service checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_passive_checks", true); } } } void ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable hostgroup passive service checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_passive_checks", false); } } } void ExternalCommandProcessor::ProcessFile(double, const std::vector& arguments) { std::deque< std::vector > file_queue; file_queue.push_back(arguments); while (!file_queue.empty()) { std::vector argument = file_queue.front(); file_queue.pop_front(); String file = argument[0]; int to_delete = Convert::ToLong(argument[1]); std::ifstream ifp; ifp.exceptions(std::ifstream::badbit); ifp.open(file.CStr(), std::ifstream::in); while (ifp.good()) { std::string line; std::getline(ifp, line); try { Log(LogNotice, "compat") << "Executing external command: " << line; ExecuteFromFile(line, file_queue); } catch (const std::exception& ex) { Log(LogWarning, "ExternalCommandProcessor") << "External command failed: " << DiagnosticInformation(ex); } } ifp.close(); if (to_delete > 0) (void) unlink(file.CStr()); } } void ExternalCommandProcessor::ScheduleSvcDowntime(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule service downtime for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[5]); int is_fixed = Convert::ToLong(arguments[4]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for service " << service->GetName(); (void) Downtime::AddDowntime(service, arguments[7], arguments[8], Convert::ToDouble(arguments[2]), Convert::ToDouble(arguments[3]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[6])); } void ExternalCommandProcessor::DelSvcDowntime(double, const std::vector& arguments) { int id = Convert::ToLong(arguments[0]); Log(LogNotice, "ExternalCommandProcessor") << "Removing downtime ID " << arguments[0]; String rid = Downtime::GetDowntimeIDFromLegacyID(id); Downtime::RemoveDowntime(rid, true); } void ExternalCommandProcessor::ScheduleHostDowntime(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule host downtime for non-existent host '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); (void) Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } void ExternalCommandProcessor::ScheduleAndPropagateHostDowntime(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule and propagate host downtime for non-existent host '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); (void) Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); /* Schedule downtime for all child hosts */ for (const Checkable::Ptr& child : host->GetAllChildren()) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(child); /* ignore all service children */ if (service) continue; (void) Downtime::AddDowntime(child, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::ScheduleAndPropagateTriggeredHostDowntime(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule and propagate triggered host downtime for non-existent host '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); String parentDowntime = Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); /* Schedule downtime for all child hosts and explicitely trigger them through the parent host's downtime */ for (const Checkable::Ptr& child : host->GetAllChildren()) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(child); /* ignore all service children */ if (service) continue; (void) Downtime::AddDowntime(child, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), parentDowntime, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::DelHostDowntime(double, const std::vector& arguments) { int id = Convert::ToLong(arguments[0]); Log(LogNotice, "ExternalCommandProcessor") << "Removing downtime ID " << arguments[0]; String rid = Downtime::GetDowntimeIDFromLegacyID(id); Downtime::RemoveDowntime(rid, true); } void ExternalCommandProcessor::DelDowntimeByHostName(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule host services downtime for non-existent host '" + arguments[0] + "'")); String serviceName; if (arguments.size() >= 2) serviceName = arguments[1]; String startTime; if (arguments.size() >= 3) startTime = arguments[2]; String commentString; if (arguments.size() >= 4) commentString = arguments[3]; if (arguments.size() > 5) Log(LogWarning, "ExternalCommandProcessor") << ("Ignoring additional parameters for host '" + arguments[0] + "' downtime deletion."); for (const Downtime::Ptr& downtime : host->GetDowntimes()) { Log(LogNotice, "ExternalCommandProcessor") << "Removing downtime '" << downtime->GetName() << "'."; Downtime::RemoveDowntime(downtime->GetName(), true); } for (const Service::Ptr& service : host->GetServices()) { if (!serviceName.IsEmpty() && serviceName != service->GetName()) continue; for (const Downtime::Ptr& downtime : service->GetDowntimes()) { if (!startTime.IsEmpty() && downtime->GetStartTime() != Convert::ToDouble(startTime)) continue; if (!commentString.IsEmpty() && downtime->GetComment() != commentString) continue; Log(LogNotice, "ExternalCommandProcessor") << "Removing downtime '" << downtime->GetName() << "'."; Downtime::RemoveDowntime(downtime->GetName(), true); } } } void ExternalCommandProcessor::ScheduleHostSvcDowntime(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule host services downtime for non-existent host '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); (void) Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for service " << service->GetName(); (void) Downtime::AddDowntime(service, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::ScheduleHostgroupHostDowntime(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule hostgroup host downtime for non-existent hostgroup '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); (void) Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::ScheduleHostgroupSvcDowntime(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule hostgroup service downtime for non-existent hostgroup '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); /* Note: we can't just directly create downtimes for all the services by iterating * over all hosts in the host group - otherwise we might end up creating multiple * downtimes for some services. */ std::set services; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { services.insert(service); } } for (const Service::Ptr& service : services) { Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for service " << service->GetName(); (void) Downtime::AddDowntime(service, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::ScheduleServicegroupHostDowntime(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule servicegroup host downtime for non-existent servicegroup '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); /* Note: we can't just directly create downtimes for all the hosts by iterating * over all services in the service group - otherwise we might end up creating multiple * downtimes for some hosts. */ std::set hosts; for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); hosts.insert(host); } for (const Host::Ptr& host : hosts) { Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for host " << host->GetName(); (void) Downtime::AddDowntime(host, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::ScheduleServicegroupSvcDowntime(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot schedule servicegroup service downtime for non-existent servicegroup '" + arguments[0] + "'")); String triggeredBy; int triggeredByLegacy = Convert::ToLong(arguments[4]); int is_fixed = Convert::ToLong(arguments[3]); if (triggeredByLegacy != 0) triggeredBy = Downtime::GetDowntimeIDFromLegacyID(triggeredByLegacy); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Creating downtime for service " << service->GetName(); (void) Downtime::AddDowntime(service, arguments[6], arguments[7], Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToBool(is_fixed), triggeredBy, Convert::ToDouble(arguments[5])); } } void ExternalCommandProcessor::AddHostComment(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot add host comment for non-existent host '" + arguments[0] + "'")); if (arguments[2].IsEmpty() || arguments[3].IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Author and comment must not be empty")); Log(LogNotice, "ExternalCommandProcessor") << "Creating comment for host " << host->GetName(); (void) Comment::AddComment(host, CommentUser, arguments[2], arguments[3], false, 0); } void ExternalCommandProcessor::DelHostComment(double, const std::vector& arguments) { int id = Convert::ToLong(arguments[0]); Log(LogNotice, "ExternalCommandProcessor") << "Removing comment ID " << arguments[0]; String rid = Comment::GetCommentIDFromLegacyID(id); Comment::RemoveComment(rid); } void ExternalCommandProcessor::AddSvcComment(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot add service comment for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); if (arguments[3].IsEmpty() || arguments[4].IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Author and comment must not be empty")); Log(LogNotice, "ExternalCommandProcessor") << "Creating comment for service " << service->GetName(); (void) Comment::AddComment(service, CommentUser, arguments[3], arguments[4], false, 0); } void ExternalCommandProcessor::DelSvcComment(double, const std::vector& arguments) { int id = Convert::ToLong(arguments[0]); Log(LogNotice, "ExternalCommandProcessor") << "Removing comment ID " << arguments[0]; String rid = Comment::GetCommentIDFromLegacyID(id); Comment::RemoveComment(rid); } void ExternalCommandProcessor::DelAllHostComments(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot delete all host comments for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Removing all comments for host " << host->GetName(); host->RemoveAllComments(); } void ExternalCommandProcessor::DelAllSvcComments(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot delete all service comments for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Removing all comments for service " << service->GetName(); service->RemoveAllComments(); } void ExternalCommandProcessor::SendCustomHostNotification(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot send custom host notification for non-existent host '" + arguments[0] + "'")); int options = Convert::ToLong(arguments[1]); Log(LogNotice, "ExternalCommandProcessor") << "Sending custom notification for host " << host->GetName(); if (options & 2) { host->SetForceNextNotification(true); } Checkable::OnNotificationsRequested(host, NotificationCustom, host->GetLastCheckResult(), arguments[2], arguments[3], MessageOrigin::Ptr()); } void ExternalCommandProcessor::SendCustomSvcNotification(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot send custom service notification for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); int options = Convert::ToLong(arguments[2]); Log(LogNotice, "ExternalCommandProcessor") << "Sending custom notification for service " << service->GetName(); if (options & 2) { service->SetForceNextNotification(true); } Service::OnNotificationsRequested(service, NotificationCustom, service->GetLastCheckResult(), arguments[3], arguments[4], MessageOrigin::Ptr()); } void ExternalCommandProcessor::DelayHostNotification(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot delay host notification for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Delaying notifications for host '" << host->GetName() << "'"; for (const Notification::Ptr& notification : host->GetNotifications()) { notification->SetNextNotification(Convert::ToDouble(arguments[1])); } } void ExternalCommandProcessor::DelaySvcNotification(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot delay service notification for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Delaying notifications for service " << service->GetName(); for (const Notification::Ptr& notification : service->GetNotifications()) { notification->SetNextNotification(Convert::ToDouble(arguments[2])); } } void ExternalCommandProcessor::EnableHostNotifications(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host notifications for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_notifications", true); } void ExternalCommandProcessor::DisableHostNotifications(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host notifications for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_notifications", false); } void ExternalCommandProcessor::EnableSvcNotifications(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service notifications for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_notifications", true); } void ExternalCommandProcessor::DisableSvcNotifications(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service notifications for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_notifications", false); } void ExternalCommandProcessor::EnableHostSvcNotifications(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable notifications for all services for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for all services on host '" << arguments[0] << "'"; for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", true); } } void ExternalCommandProcessor::DisableHostSvcNotifications(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable notifications for all services for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for all services on host '" << arguments[0] << "'"; for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", false); } } void ExternalCommandProcessor::DisableHostgroupHostChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable hostgroup host checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_active_checks", false); } } void ExternalCommandProcessor::DisableHostgroupPassiveHostChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable hostgroup passive host checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_passive_checks", false); } } void ExternalCommandProcessor::DisableServicegroupHostChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable servicegroup host checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Disabling active checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_active_checks", false); } } void ExternalCommandProcessor::DisableServicegroupPassiveHostChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable servicegroup passive host checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Disabling passive checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_passive_checks", false); } } void ExternalCommandProcessor::EnableHostgroupHostChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable hostgroup host checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_active_checks", true); } } void ExternalCommandProcessor::EnableHostgroupPassiveHostChecks(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable hostgroup passive host checks for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_passive_checks", true); } } void ExternalCommandProcessor::EnableServicegroupHostChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable servicegroup host checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Enabling active checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_active_checks", true); } } void ExternalCommandProcessor::EnableServicegroupPassiveHostChecks(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable servicegroup passive host checks for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Enabling passive checks for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_passive_checks", true); } } void ExternalCommandProcessor::EnableHostFlapping(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host flapping for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling flapping detection for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_flapping", true); } void ExternalCommandProcessor::DisableHostFlapping(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host flapping for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling flapping detection for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_flapping", false); } void ExternalCommandProcessor::EnableSvcFlapping(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service flapping for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling flapping detection for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_flapping", true); } void ExternalCommandProcessor::DisableSvcFlapping(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service flapping for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling flapping detection for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_flapping", false); } void ExternalCommandProcessor::EnableNotifications(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling notifications."); IcingaApplication::GetInstance()->ModifyAttribute("enable_notifications", true); } void ExternalCommandProcessor::DisableNotifications(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling notifications."); IcingaApplication::GetInstance()->ModifyAttribute("enable_notifications", false); } void ExternalCommandProcessor::EnableFlapDetection(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling flap detection."); IcingaApplication::GetInstance()->ModifyAttribute("enable_flapping", true); } void ExternalCommandProcessor::DisableFlapDetection(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling flap detection."); IcingaApplication::GetInstance()->ModifyAttribute("enable_flapping", false); } void ExternalCommandProcessor::EnableEventHandlers(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling event handlers."); IcingaApplication::GetInstance()->ModifyAttribute("enable_event_handlers", true); } void ExternalCommandProcessor::DisableEventHandlers(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling event handlers."); IcingaApplication::GetInstance()->ModifyAttribute("enable_event_handlers", false); } void ExternalCommandProcessor::EnablePerformanceData(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling performance data processing."); IcingaApplication::GetInstance()->ModifyAttribute("enable_perfdata", true); } void ExternalCommandProcessor::DisablePerformanceData(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling performance data processing."); IcingaApplication::GetInstance()->ModifyAttribute("enable_perfdata", false); } void ExternalCommandProcessor::StartExecutingSvcChecks(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling service checks."); IcingaApplication::GetInstance()->ModifyAttribute("enable_service_checks", true); } void ExternalCommandProcessor::StopExecutingSvcChecks(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling service checks."); IcingaApplication::GetInstance()->ModifyAttribute("enable_service_checks", false); } void ExternalCommandProcessor::StartExecutingHostChecks(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally enabling host checks."); IcingaApplication::GetInstance()->ModifyAttribute("enable_host_checks", true); } void ExternalCommandProcessor::StopExecutingHostChecks(double, const std::vector&) { Log(LogNotice, "ExternalCommandProcessor", "Globally disabling host checks."); IcingaApplication::GetInstance()->ModifyAttribute("enable_host_checks", false); } void ExternalCommandProcessor::ChangeNormalSvcCheckInterval(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot update check interval for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); double interval = Convert::ToDouble(arguments[2]); Log(LogNotice, "ExternalCommandProcessor") << "Updating check interval for service '" << arguments[1] << "'"; service->ModifyAttribute("check_interval", interval * 60); } void ExternalCommandProcessor::ChangeNormalHostCheckInterval(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot update check interval for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Updating check interval for host '" << arguments[0] << "'"; double interval = Convert::ToDouble(arguments[1]); host->ModifyAttribute("check_interval", interval * 60); } void ExternalCommandProcessor::ChangeRetrySvcCheckInterval(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot update retry interval for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); double interval = Convert::ToDouble(arguments[2]); Log(LogNotice, "ExternalCommandProcessor") << "Updating retry interval for service '" << arguments[1] << "'"; service->ModifyAttribute("retry_interval", interval * 60); } void ExternalCommandProcessor::ChangeRetryHostCheckInterval(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot update retry interval for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Updating retry interval for host '" << arguments[0] << "'"; double interval = Convert::ToDouble(arguments[1]); host->ModifyAttribute("retry_interval", interval * 60); } void ExternalCommandProcessor::EnableHostEventHandler(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable event handler for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling event handler for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_event_handler", true); } void ExternalCommandProcessor::DisableHostEventHandler(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable event handler for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling event handler for host '" << arguments[0] << "'"; host->ModifyAttribute("enable_event_handler", false); } void ExternalCommandProcessor::EnableSvcEventHandler(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable event handler for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Enabling event handler for service '" << arguments[1] << "'"; service->ModifyAttribute("enable_event_handler", true); } void ExternalCommandProcessor::DisableSvcEventHandler(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable event handler for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Disabling event handler for service '" << arguments[1] + "'"; service->ModifyAttribute("enable_event_handler", false); } void ExternalCommandProcessor::ChangeHostEventHandler(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change event handler for non-existent host '" + arguments[0] + "'")); if (arguments[1].IsEmpty()) { Log(LogNotice, "ExternalCommandProcessor") << "Unsetting event handler for host '" << arguments[0] << "'"; host->ModifyAttribute("event_command", ""); } else { EventCommand::Ptr command = EventCommand::GetByName(arguments[1]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Event command '" + arguments[1] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing event handler for host '" << arguments[0] << "' to '" << arguments[1] << "'"; host->ModifyAttribute("event_command", command->GetName()); } } void ExternalCommandProcessor::ChangeSvcEventHandler(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change event handler for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); if (arguments[2].IsEmpty()) { Log(LogNotice, "ExternalCommandProcessor") << "Unsetting event handler for service '" << arguments[1] << "'"; service->ModifyAttribute("event_command", ""); } else { EventCommand::Ptr command = EventCommand::GetByName(arguments[2]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Event command '" + arguments[2] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing event handler for service '" << arguments[1] << "' to '" << arguments[2] << "'"; service->ModifyAttribute("event_command", command->GetName()); } } void ExternalCommandProcessor::ChangeHostCheckCommand(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change check command for non-existent host '" + arguments[0] + "'")); CheckCommand::Ptr command = CheckCommand::GetByName(arguments[1]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Check command '" + arguments[1] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing check command for host '" << arguments[0] << "' to '" << arguments[1] << "'"; host->ModifyAttribute("check_command", command->GetName()); } void ExternalCommandProcessor::ChangeSvcCheckCommand(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change check command for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); CheckCommand::Ptr command = CheckCommand::GetByName(arguments[2]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Check command '" + arguments[2] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing check command for service '" << arguments[1] << "' to '" << arguments[2] << "'"; service->ModifyAttribute("check_command", command->GetName()); } void ExternalCommandProcessor::ChangeMaxHostCheckAttempts(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change max check attempts for non-existent host '" + arguments[0] + "'")); int attempts = Convert::ToLong(arguments[1]); Log(LogNotice, "ExternalCommandProcessor") << "Changing max check attempts for host '" << arguments[0] << "' to '" << arguments[1] << "'"; host->ModifyAttribute("max_check_attempts", attempts); } void ExternalCommandProcessor::ChangeMaxSvcCheckAttempts(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change max check attempts for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); int attempts = Convert::ToLong(arguments[2]); Log(LogNotice, "ExternalCommandProcessor") << "Changing max check attempts for service '" << arguments[1] << "' to '" << arguments[2] << "'"; service->ModifyAttribute("max_check_attempts", attempts); } void ExternalCommandProcessor::ChangeHostCheckTimeperiod(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change check period for non-existent host '" + arguments[0] + "'")); TimePeriod::Ptr tp = TimePeriod::GetByName(arguments[1]); if (!tp) BOOST_THROW_EXCEPTION(std::invalid_argument("Time period '" + arguments[1] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing check period for host '" << arguments[0] << "' to '" << arguments[1] << "'"; host->ModifyAttribute("check_period", tp->GetName()); } void ExternalCommandProcessor::ChangeSvcCheckTimeperiod(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change check period for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); TimePeriod::Ptr tp = TimePeriod::GetByName(arguments[2]); if (!tp) BOOST_THROW_EXCEPTION(std::invalid_argument("Time period '" + arguments[2] + "' does not exist.")); Log(LogNotice, "ExternalCommandProcessor") << "Changing check period for service '" << arguments[1] << "' to '" << arguments[2] << "'"; service->ModifyAttribute("check_period", tp->GetName()); } void ExternalCommandProcessor::ChangeCustomHostVar(double, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); if (!host) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Changing custom var '" << arguments[1] << "' for host '" << arguments[0] << "' to value '" << arguments[2] << "'"; host->ModifyAttribute("vars." + arguments[1], arguments[2]); } void ExternalCommandProcessor::ChangeCustomSvcVar(double, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); if (!service) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent service '" + arguments[1] + "' on host '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Changing custom var '" << arguments[2] << "' for service '" << arguments[1] << "' on host '" << arguments[0] << "' to value '" << arguments[3] << "'"; service->ModifyAttribute("vars." + arguments[2], arguments[3]); } void ExternalCommandProcessor::ChangeCustomUserVar(double, const std::vector& arguments) { User::Ptr user = User::GetByName(arguments[0]); if (!user) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent user '" + arguments[0] + "'")); Log(LogNotice, "ExternalCommandProcessor") << "Changing custom var '" << arguments[1] << "' for user '" << arguments[0] << "' to value '" << arguments[2] << "'"; user->ModifyAttribute("vars." + arguments[1], arguments[2]); } void ExternalCommandProcessor::ChangeCustomCheckcommandVar(double, const std::vector& arguments) { CheckCommand::Ptr command = CheckCommand::GetByName(arguments[0]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent command '" + arguments[0] + "'")); ChangeCustomCommandVarInternal(command, arguments[1], arguments[2]); } void ExternalCommandProcessor::ChangeCustomEventcommandVar(double, const std::vector& arguments) { EventCommand::Ptr command = EventCommand::GetByName(arguments[0]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent command '" + arguments[0] + "'")); ChangeCustomCommandVarInternal(command, arguments[1], arguments[2]); } void ExternalCommandProcessor::ChangeCustomNotificationcommandVar(double, const std::vector& arguments) { NotificationCommand::Ptr command = NotificationCommand::GetByName(arguments[0]); if (!command) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot change custom var for non-existent command '" + arguments[0] + "'")); ChangeCustomCommandVarInternal(command, arguments[1], arguments[2]); } void ExternalCommandProcessor::ChangeCustomCommandVarInternal(const Command::Ptr& command, const String& name, const Value& value) { Log(LogNotice, "ExternalCommandProcessor") << "Changing custom var '" << name << "' for command '" << command->GetName() << "' to value '" << value << "'"; command->ModifyAttribute("vars." + name, value); } void ExternalCommandProcessor::EnableHostgroupHostNotifications(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host notifications for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_notifications", true); } } void ExternalCommandProcessor::EnableHostgroupSvcNotifications(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service notifications for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", true); } } } void ExternalCommandProcessor::DisableHostgroupHostNotifications(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host notifications for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_notifications", false); } } void ExternalCommandProcessor::DisableHostgroupSvcNotifications(double, const std::vector& arguments) { HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); if (!hg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service notifications for non-existent hostgroup '" + arguments[0] + "'")); for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", false); } } } void ExternalCommandProcessor::EnableServicegroupHostNotifications(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable host notifications for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_notifications", true); } } void ExternalCommandProcessor::EnableServicegroupSvcNotifications(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot enable service notifications for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Enabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", true); } } void ExternalCommandProcessor::DisableServicegroupHostNotifications(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable host notifications for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Host::Ptr host = service->GetHost(); Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for host '" << host->GetName() << "'"; host->ModifyAttribute("enable_notifications", false); } } void ExternalCommandProcessor::DisableServicegroupSvcNotifications(double, const std::vector& arguments) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); if (!sg) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot disable service notifications for non-existent servicegroup '" + arguments[0] + "'")); for (const Service::Ptr& service : sg->GetMembers()) { Log(LogNotice, "ExternalCommandProcessor") << "Disabling notifications for service '" << service->GetName() << "'"; service->ModifyAttribute("enable_notifications", false); } } icinga2-2.8.1/lib/icinga/externalcommandprocessor.hpp000066400000000000000000000310001322762156600226740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXTERNALCOMMANDPROCESSOR_H #define EXTERNALCOMMANDPROCESSOR_H #include "icinga/i2-icinga.hpp" #include "icinga/command.hpp" #include "base/string.hpp" #include #include #include namespace icinga { class I2_ICINGA_API ExternalCommandProcessor { public: static void Execute(const String& line); static void Execute(double time, const String& command, const std::vector& arguments); static void StaticInitialize(void); static boost::signals2::signal&)> OnNewExternalCommand; private: ExternalCommandProcessor(void); static void ExecuteFromFile(const String& line, std::deque< std::vector >& file_queue); static void ProcessHostCheckResult(double time, const std::vector& arguments); static void ProcessServiceCheckResult(double time, const std::vector& arguments); static void ScheduleHostCheck(double time, const std::vector& arguments); static void ScheduleForcedHostCheck(double time, const std::vector& arguments); static void ScheduleSvcCheck(double time, const std::vector& arguments); static void ScheduleForcedSvcCheck(double time, const std::vector& arguments); static void EnableHostCheck(double time, const std::vector& arguments); static void DisableHostCheck(double time, const std::vector& arguments); static void EnableSvcCheck(double time, const std::vector& arguments); static void DisableSvcCheck(double time, const std::vector& arguments); static void ShutdownProcess(double time, const std::vector& arguments); static void RestartProcess(double time, const std::vector& arguments); static void ScheduleForcedHostSvcChecks(double time, const std::vector& arguments); static void ScheduleHostSvcChecks(double time, const std::vector& arguments); static void EnableHostSvcChecks(double time, const std::vector& arguments); static void DisableHostSvcChecks(double time, const std::vector& arguments); static void AcknowledgeSvcProblem(double time, const std::vector& arguments); static void AcknowledgeSvcProblemExpire(double time, const std::vector& arguments); static void RemoveSvcAcknowledgement(double time, const std::vector& arguments); static void AcknowledgeHostProblem(double time, const std::vector& arguments); static void AcknowledgeHostProblemExpire(double time, const std::vector& arguments); static void RemoveHostAcknowledgement(double time, const std::vector& arguments); static void EnableHostgroupSvcChecks(double time, const std::vector& arguments); static void DisableHostgroupSvcChecks(double time, const std::vector& arguments); static void EnableServicegroupSvcChecks(double time, const std::vector& arguments); static void DisableServicegroupSvcChecks(double time, const std::vector& arguments); static void EnablePassiveHostChecks(double time, const std::vector& arguments); static void DisablePassiveHostChecks(double time, const std::vector& arguments); static void EnablePassiveSvcChecks(double time, const std::vector& arguments); static void DisablePassiveSvcChecks(double time, const std::vector& arguments); static void EnableServicegroupPassiveSvcChecks(double time, const std::vector& arguments); static void DisableServicegroupPassiveSvcChecks(double time, const std::vector& arguments); static void EnableHostgroupPassiveSvcChecks(double time, const std::vector& arguments); static void DisableHostgroupPassiveSvcChecks(double time, const std::vector& arguments); static void ProcessFile(double time, const std::vector& arguments); static void ScheduleSvcDowntime(double time, const std::vector& arguments); static void DelSvcDowntime(double time, const std::vector& arguments); static void ScheduleHostDowntime(double time, const std::vector& arguments); static void ScheduleAndPropagateHostDowntime(double, const std::vector& arguments); static void ScheduleAndPropagateTriggeredHostDowntime(double, const std::vector& arguments); static void DelHostDowntime(double time, const std::vector& arguments); static void DelDowntimeByHostName(double, const std::vector& arguments); static void ScheduleHostSvcDowntime(double time, const std::vector& arguments); static void ScheduleHostgroupHostDowntime(double time, const std::vector& arguments); static void ScheduleHostgroupSvcDowntime(double time, const std::vector& arguments); static void ScheduleServicegroupHostDowntime(double time, const std::vector& arguments); static void ScheduleServicegroupSvcDowntime(double time, const std::vector& arguments); static void AddHostComment(double time, const std::vector& arguments); static void DelHostComment(double time, const std::vector& arguments); static void AddSvcComment(double time, const std::vector& arguments); static void DelSvcComment(double time, const std::vector& arguments); static void DelAllHostComments(double time, const std::vector& arguments); static void DelAllSvcComments(double time, const std::vector& arguments); static void SendCustomHostNotification(double time, const std::vector& arguments); static void SendCustomSvcNotification(double time, const std::vector& arguments); static void DelayHostNotification(double time, const std::vector& arguments); static void DelaySvcNotification(double time, const std::vector& arguments); static void EnableHostNotifications(double time, const std::vector& arguments); static void DisableHostNotifications(double time, const std::vector& arguments); static void EnableSvcNotifications(double time, const std::vector& arguments); static void DisableSvcNotifications(double time, const std::vector& arguments); static void EnableHostSvcNotifications(double, const std::vector& arguments); static void DisableHostSvcNotifications(double, const std::vector& arguments); static void DisableHostgroupHostChecks(double, const std::vector& arguments); static void DisableHostgroupPassiveHostChecks(double, const std::vector& arguments); static void DisableServicegroupHostChecks(double, const std::vector& arguments); static void DisableServicegroupPassiveHostChecks(double, const std::vector& arguments); static void EnableHostgroupHostChecks(double, const std::vector& arguments); static void EnableHostgroupPassiveHostChecks(double, const std::vector& arguments); static void EnableServicegroupHostChecks(double, const std::vector& arguments); static void EnableServicegroupPassiveHostChecks(double, const std::vector& arguments); static void EnableSvcFlapping(double time, const std::vector& arguments); static void DisableSvcFlapping(double time, const std::vector& arguments); static void EnableHostFlapping(double time, const std::vector& arguments); static void DisableHostFlapping(double time, const std::vector& arguments); static void EnableNotifications(double time, const std::vector& arguments); static void DisableNotifications(double time, const std::vector& arguments); static void EnableFlapDetection(double time, const std::vector& arguments); static void DisableFlapDetection(double time, const std::vector& arguments); static void EnableEventHandlers(double time, const std::vector& arguments); static void DisableEventHandlers(double time, const std::vector& arguments); static void EnablePerformanceData(double time, const std::vector& arguments); static void DisablePerformanceData(double time, const std::vector& arguments); static void StartExecutingSvcChecks(double time, const std::vector& arguments); static void StopExecutingSvcChecks(double time, const std::vector& arguments); static void StartExecutingHostChecks(double time, const std::vector& arguments); static void StopExecutingHostChecks(double time, const std::vector& arguments); static void ChangeNormalSvcCheckInterval(double time, const std::vector& arguments); static void ChangeNormalHostCheckInterval(double time, const std::vector& arguments); static void ChangeRetrySvcCheckInterval(double time, const std::vector& arguments); static void ChangeRetryHostCheckInterval(double time, const std::vector& arguments); static void EnableHostEventHandler(double time, const std::vector& arguments); static void DisableHostEventHandler(double time, const std::vector& arguments); static void EnableSvcEventHandler(double time, const std::vector& arguments); static void DisableSvcEventHandler(double time, const std::vector& arguments); static void ChangeHostEventHandler(double time, const std::vector& arguments); static void ChangeSvcEventHandler(double time, const std::vector& arguments); static void ChangeHostCheckCommand(double time, const std::vector& arguments); static void ChangeSvcCheckCommand(double time, const std::vector& arguments); static void ChangeMaxHostCheckAttempts(double time, const std::vector& arguments); static void ChangeMaxSvcCheckAttempts(double time, const std::vector& arguments); static void ChangeHostCheckTimeperiod(double time, const std::vector& arguments); static void ChangeSvcCheckTimeperiod(double time, const std::vector& arguments); static void ChangeCustomHostVar(double time, const std::vector& arguments); static void ChangeCustomSvcVar(double time, const std::vector& arguments); static void ChangeCustomUserVar(double time, const std::vector& arguments); static void ChangeCustomCheckcommandVar(double time, const std::vector& arguments); static void ChangeCustomEventcommandVar(double time, const std::vector& arguments); static void ChangeCustomNotificationcommandVar(double time, const std::vector& arguments); static void EnableHostgroupHostNotifications(double time, const std::vector& arguments); static void EnableHostgroupSvcNotifications(double time, const std::vector& arguments); static void DisableHostgroupHostNotifications(double time, const std::vector& arguments); static void DisableHostgroupSvcNotifications(double time, const std::vector& arguments); static void EnableServicegroupHostNotifications(double time, const std::vector& arguments); static void EnableServicegroupSvcNotifications(double time, const std::vector& arguments); static void DisableServicegroupHostNotifications(double time, const std::vector& arguments); static void DisableServicegroupSvcNotifications(double time, const std::vector& arguments); private: static void ChangeCustomCommandVarInternal(const Command::Ptr& command, const String& name, const Value& value); }; } #endif /* EXTERNALCOMMANDPROCESSOR_H */ icinga2-2.8.1/lib/icinga/host.cpp000066400000000000000000000207211322762156600165330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/host.hpp" #include "icinga/host.tcpp" #include "icinga/service.hpp" #include "icinga/hostgroup.hpp" #include "icinga/pluginutility.hpp" #include "icinga/scheduleddowntime.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/debug.hpp" #include "base/json.hpp" using namespace icinga; REGISTER_TYPE(Host); void Host::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); String zoneName = GetZoneName(); if (!zoneName.IsEmpty()) { Zone::Ptr zone = Zone::GetByName(zoneName); if (zone && zone->IsGlobal()) BOOST_THROW_EXCEPTION(std::invalid_argument("Host '" + GetName() + "' cannot be put into global zone '" + zone->GetName() + "'.")); } HostGroup::EvaluateObjectRules(this); Array::Ptr groups = GetGroups(); if (groups) { groups = groups->ShallowClone(); ObjectLock olock(groups); for (const String& name : groups) { HostGroup::Ptr hg = HostGroup::GetByName(name); if (hg) hg->ResolveGroupMembership(this, true); } } } void Host::CreateChildObjects(const Type::Ptr& childType) { if (childType == ScheduledDowntime::TypeInstance) ScheduledDowntime::EvaluateApplyRules(this); if (childType == Notification::TypeInstance) Notification::EvaluateApplyRules(this); if (childType == Dependency::TypeInstance) Dependency::EvaluateApplyRules(this); if (childType == Service::TypeInstance) Service::EvaluateApplyRules(this); } void Host::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); Array::Ptr groups = GetGroups(); if (groups) { ObjectLock olock(groups); for (const String& name : groups) { HostGroup::Ptr hg = HostGroup::GetByName(name); if (hg) hg->ResolveGroupMembership(this, false); } } // TODO: unregister slave services/notifications? } std::vector Host::GetServices(void) const { boost::mutex::scoped_lock lock(m_ServicesMutex); std::vector services; services.reserve(m_Services.size()); typedef std::pair ServicePair; for (const ServicePair& kv : m_Services) { services.push_back(kv.second); } return services; } void Host::AddService(const Service::Ptr& service) { boost::mutex::scoped_lock lock(m_ServicesMutex); m_Services[service->GetShortName()] = service; } void Host::RemoveService(const Service::Ptr& service) { boost::mutex::scoped_lock lock(m_ServicesMutex); m_Services.erase(service->GetShortName()); } int Host::GetTotalServices(void) const { return GetServices().size(); } Service::Ptr Host::GetServiceByShortName(const Value& name) { if (name.IsScalar()) { { boost::mutex::scoped_lock lock(m_ServicesMutex); auto it = m_Services.find(name); if (it != m_Services.end()) return it->second; } return Service::Ptr(); } else if (name.IsObjectType()) { Dictionary::Ptr dict = name; String short_name; return Service::GetByNamePair(dict->Get("host"), dict->Get("service")); } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + JsonEncode(name))); } } HostState Host::CalculateState(ServiceState state) { switch (state) { case ServiceOK: case ServiceWarning: return HostUp; default: return HostDown; } } HostState Host::GetState(void) const { return CalculateState(GetStateRaw()); } HostState Host::GetLastState(void) const { return CalculateState(GetLastStateRaw()); } HostState Host::GetLastHardState(void) const { return CalculateState(GetLastHardStateRaw()); } /* keep in sync with Service::GetSeverity() */ int Host::GetSeverity(void) const { int severity = 0; ObjectLock olock(this); ServiceState state = GetStateRaw(); /* OK/Warning = Up, Critical/Unknownb = Down */ if (!HasBeenChecked()) severity |= SeverityFlagPending; else if (state == ServiceUnknown) severity |= SeverityFlagCritical; else if (state == ServiceCritical) severity |= SeverityFlagCritical; if (IsInDowntime()) severity |= SeverityFlagDowntime; else if (IsAcknowledged()) severity |= SeverityFlagAcknowledgement; else severity |= SeverityFlagUnhandled; olock.Unlock(); return severity; } bool Host::IsStateOK(ServiceState state) { return Host::CalculateState(state) == HostUp; } void Host::SaveLastState(ServiceState state, double timestamp) { if (state == ServiceOK || state == ServiceWarning) SetLastStateUp(timestamp); else if (state == ServiceCritical) SetLastStateDown(timestamp); } HostState Host::StateFromString(const String& state) { if (state == "UP") return HostUp; else return HostDown; } String Host::StateToString(HostState state) { switch (state) { case HostUp: return "UP"; case HostDown: return "DOWN"; default: return "INVALID"; } } StateType Host::StateTypeFromString(const String& type) { if (type == "SOFT") return StateTypeSoft; else return StateTypeHard; } String Host::StateTypeToString(StateType type) { if (type == StateTypeSoft) return "SOFT"; else return "HARD"; } bool Host::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *result) const { if (macro == "state") { *result = StateToString(GetState()); return true; } else if (macro == "state_id") { *result = GetState(); return true; } else if (macro == "state_type") { *result = StateTypeToString(GetStateType()); return true; } else if (macro == "last_state") { *result = StateToString(GetLastState()); return true; } else if (macro == "last_state_id") { *result = GetLastState(); return true; } else if (macro == "last_state_type") { *result = StateTypeToString(GetLastStateType()); return true; } else if (macro == "last_state_change") { *result = static_cast(GetLastStateChange()); return true; } else if (macro == "downtime_depth") { *result = GetDowntimeDepth(); return true; } else if (macro == "duration_sec") { *result = Utility::GetTime() - GetLastStateChange(); return true; } else if (macro == "num_services" || macro == "num_services_ok" || macro == "num_services_warning" || macro == "num_services_unknown" || macro == "num_services_critical") { int filter = -1; int count = 0; if (macro == "num_services_ok") filter = ServiceOK; else if (macro == "num_services_warning") filter = ServiceWarning; else if (macro == "num_services_unknown") filter = ServiceUnknown; else if (macro == "num_services_critical") filter = ServiceCritical; for (const Service::Ptr& service : GetServices()) { if (filter != -1 && service->GetState() != filter) continue; count++; } *result = count; return true; } CheckResult::Ptr cr = GetLastCheckResult(); if (cr) { if (macro == "latency") { *result = cr->CalculateLatency(); return true; } else if (macro == "execution_time") { *result = cr->CalculateExecutionTime(); return true; } else if (macro == "output") { *result = cr->GetOutput(); return true; } else if (macro == "perfdata") { *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData()); return true; } else if (macro == "check_source") { *result = cr->GetCheckSource(); return true; } } return false; } icinga2-2.8.1/lib/icinga/host.hpp000066400000000000000000000062141322762156600165410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOST_H #define HOST_H #include "icinga/i2-icinga.hpp" #include "icinga/host.thpp" #include "icinga/macroresolver.hpp" #include "icinga/checkresult.hpp" namespace icinga { class Service; /** * An Icinga host. * * @ingroup icinga */ class I2_ICINGA_API Host : public ObjectImpl, public MacroResolver { public: DECLARE_OBJECT(Host); DECLARE_OBJECTNAME(Host); intrusive_ptr GetServiceByShortName(const Value& name); std::vector > GetServices(void) const; void AddService(const intrusive_ptr& service); void RemoveService(const intrusive_ptr& service); int GetTotalServices(void) const; static HostState CalculateState(ServiceState state); virtual HostState GetState(void) const override; virtual HostState GetLastState(void) const override; virtual HostState GetLastHardState(void) const override; virtual int GetSeverity(void) const override; virtual bool IsStateOK(ServiceState state) override; virtual void SaveLastState(ServiceState state, double timestamp) override; static HostState StateFromString(const String& state); static String StateToString(HostState state); static StateType StateTypeFromString(const String& state); static String StateTypeToString(StateType state); virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, Value *result) const override; protected: virtual void Stop(bool runtimeRemoved) override; virtual void OnAllConfigLoaded(void) override; virtual void CreateChildObjects(const Type::Ptr& childType) override; private: mutable boost::mutex m_ServicesMutex; std::map > m_Services; static void RefreshServicesCache(void); }; } #endif /* HOST_H */ #include "icinga/service.hpp" icinga2-2.8.1/lib/icinga/host.ti000066400000000000000000000042601322762156600163650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/customvarobject.hpp" #impl_include "icinga/hostgroup.hpp" library icinga; namespace icinga { class Host : Checkable { load_after ApiListener; load_after Endpoint; load_after Zone; [config, no_user_modify, required] array(name(HostGroup)) groups { default {{{ return new Array(); }}} }; [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config] String address; [config] String address6; [enum, no_storage] HostState "state" { get; }; [enum, no_storage] HostState last_state { get; }; [enum, no_storage] HostState last_hard_state { get; }; [state] Timestamp last_state_up; [state] Timestamp last_state_down; }; } icinga2-2.8.1/lib/icinga/hostgroup.cpp000066400000000000000000000074111322762156600176110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/hostgroup.hpp" #include "icinga/hostgroup.tcpp" #include "config/objectrule.hpp" #include "config/configitem.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" using namespace icinga; REGISTER_TYPE(HostGroup); INITIALIZE_ONCE([]() { ObjectRule::RegisterType("HostGroup"); }); bool HostGroup::EvaluateObjectRule(const Host::Ptr& host, const ConfigItem::Ptr& group) { String group_name = group->GetName(); CONTEXT("Evaluating rule for group '" + group_name + "'"); ScriptFrame frame; if (group->GetScope()) group->GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "HostGroup") << "Assigning membership for group '" << group_name << "' to host '" << host->GetName() << "'"; Array::Ptr groups = host->GetGroups(); groups->Add(group_name); return true; } void HostGroup::EvaluateObjectRules(const Host::Ptr& host) { CONTEXT("Evaluating group memberships for host '" + host->GetName() + "'"); for (const ConfigItem::Ptr& group : ConfigItem::GetItems(HostGroup::TypeInstance)) { if (!group->GetFilter()) continue; EvaluateObjectRule(host, group); } } std::set HostGroup::GetMembers(void) const { boost::mutex::scoped_lock lock(m_HostGroupMutex); return m_Members; } void HostGroup::AddMember(const Host::Ptr& host) { host->AddGroup(GetName()); boost::mutex::scoped_lock lock(m_HostGroupMutex); m_Members.insert(host); } void HostGroup::RemoveMember(const Host::Ptr& host) { boost::mutex::scoped_lock lock(m_HostGroupMutex); m_Members.erase(host); } bool HostGroup::ResolveGroupMembership(const Host::Ptr& host, bool add, int rstack) { if (add && rstack > 20) { Log(LogWarning, "HostGroup") << "Too many nested groups for group '" << GetName() << "': Host '" << host->GetName() << "' membership assignment failed."; return false; } Array::Ptr groups = GetGroups(); if (groups && groups->GetLength() > 0) { ObjectLock olock(groups); for (const String& name : groups) { HostGroup::Ptr group = HostGroup::GetByName(name); if (group && !group->ResolveGroupMembership(host, add, rstack + 1)) return false; } } if (add) AddMember(host); else RemoveMember(host); return true; } icinga2-2.8.1/lib/icinga/hostgroup.hpp000066400000000000000000000043551322762156600176220ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOSTGROUP_H #define HOSTGROUP_H #include "icinga/i2-icinga.hpp" #include "icinga/hostgroup.thpp" #include "icinga/host.hpp" namespace icinga { class ConfigItem; /** * An Icinga host group. * * @ingroup icinga */ class I2_ICINGA_API HostGroup : public ObjectImpl { public: DECLARE_OBJECT(HostGroup); DECLARE_OBJECTNAME(HostGroup); std::set GetMembers(void) const; void AddMember(const Host::Ptr& host); void RemoveMember(const Host::Ptr& host); bool ResolveGroupMembership(const Host::Ptr& host, bool add = true, int rstack = 0); static void EvaluateObjectRules(const Host::Ptr& host); private: mutable boost::mutex m_HostGroupMutex; std::set m_Members; static bool EvaluateObjectRule(const Host::Ptr& host, const intrusive_ptr& item); }; } #endif /* HOSTGROUP_H */ icinga2-2.8.1/lib/icinga/hostgroup.ti000066400000000000000000000034571322762156600174510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" library icinga; namespace icinga { class HostGroup : CustomVarObject { [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config, no_user_modify] array(name(HostGroup)) groups; [config] String notes; [config] String notes_url; [config] String action_url; }; } icinga2-2.8.1/lib/icinga/i2-icinga.hpp000066400000000000000000000035051322762156600173260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2ICINGA_H #define I2ICINGA_H /** * @defgroup icinga Icinga library * * The Icinga library implements all Icinga-specific functionality that is * common to all components (e.g. hosts, services, etc.). */ #include "base/i2-base.hpp" #ifdef I2_ICINGA_BUILD # define I2_ICINGA_API I2_EXPORT #else /* I2_ICINGA_BUILD */ # define I2_ICINGA_API I2_IMPORT #endif /* I2_ICINGA_BUILD */ #endif /* I2ICINGA_H */ icinga2-2.8.1/lib/icinga/icinga-itl.conf000066400000000000000000000033221322762156600177370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ System.assert(Internal.run_with_activation_context(function() { var _Internal = Internal.clone() template TimePeriod "legacy-timeperiod" use (_Internal) default { update = _Internal.LegacyTimePeriod } })) var methods = [ "LegacyTimePeriod" ] for (method in methods) { Internal.remove(method) } icinga2-2.8.1/lib/icinga/icingaapplication.cpp000066400000000000000000000224461322762156600212420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/icingaapplication.hpp" #include "icinga/icingaapplication.tcpp" #include "icinga/cib.hpp" #include "icinga/macroprocessor.hpp" #include "config/configcompiler.hpp" #include "base/configwriter.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/debug.hpp" #include "base/utility.hpp" #include "base/timer.hpp" #include "base/scriptglobal.hpp" #include "base/initialize.hpp" #include "base/statsfunction.hpp" #include "base/loader.hpp" using namespace icinga; static Timer::Ptr l_RetentionTimer; REGISTER_TYPE(IcingaApplication); INITIALIZE_ONCE(&IcingaApplication::StaticInitialize); void IcingaApplication::StaticInitialize(void) { Loader::LoadExtensionLibrary("methods"); String node_name = Utility::GetFQDN(); if (node_name.IsEmpty()) { Log(LogNotice, "IcingaApplication", "No FQDN available. Trying Hostname."); node_name = Utility::GetHostName(); if (node_name.IsEmpty()) { Log(LogWarning, "IcingaApplication", "No FQDN nor Hostname available. Setting Nodename to 'localhost'."); node_name = "localhost"; } } ScriptGlobal::Set("NodeName", node_name); ScriptGlobal::Set("ApplicationType", "IcingaApplication"); } REGISTER_STATSFUNCTION(IcingaApplication, &IcingaApplication::StatsFunc); void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const IcingaApplication::Ptr& icingaapplication : ConfigType::GetObjectsByType()) { Dictionary::Ptr stats = new Dictionary(); stats->Set("node_name", icingaapplication->GetNodeName()); stats->Set("enable_notifications", icingaapplication->GetEnableNotifications()); stats->Set("enable_event_handlers", icingaapplication->GetEnableEventHandlers()); stats->Set("enable_flapping", icingaapplication->GetEnableFlapping()); stats->Set("enable_host_checks", icingaapplication->GetEnableHostChecks()); stats->Set("enable_service_checks", icingaapplication->GetEnableServiceChecks()); stats->Set("enable_perfdata", icingaapplication->GetEnablePerfdata()); stats->Set("pid", Utility::GetPid()); stats->Set("program_start", Application::GetStartTime()); stats->Set("version", Application::GetAppVersion()); nodes->Set(icingaapplication->GetName(), stats); } status->Set("icingaapplication", nodes); } /** * The entry point for the Icinga application. * * @returns An exit status. */ int IcingaApplication::Main(void) { Log(LogDebug, "IcingaApplication", "In IcingaApplication::Main()"); /* periodically dump the program state */ l_RetentionTimer = new Timer(); l_RetentionTimer->SetInterval(300); l_RetentionTimer->OnTimerExpired.connect(boost::bind(&IcingaApplication::DumpProgramState, this)); l_RetentionTimer->Start(); RunEventLoop(); Log(LogInformation, "IcingaApplication", "Icinga has shut down."); return EXIT_SUCCESS; } void IcingaApplication::OnShutdown(void) { { ObjectLock olock(this); l_RetentionTimer->Stop(); } DumpProgramState(); } static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value) { if (object != previousObject) { if (previousObject) { ConfigWriter::EmitRaw(fp, "\tobj.version = "); ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion()); ConfigWriter::EmitRaw(fp, "\n}\n\n"); } ConfigWriter::EmitRaw(fp, "var obj = "); Array::Ptr args1 = new Array(); args1->Add(object->GetReflectionType()->GetName()); args1->Add(object->GetName()); ConfigWriter::EmitFunctionCall(fp, "get_object", args1); ConfigWriter::EmitRaw(fp, "\nif (obj) {\n"); } ConfigWriter::EmitRaw(fp, "\tobj."); Array::Ptr args2 = new Array(); args2->Add(attr); args2->Add(value); ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2); ConfigWriter::EmitRaw(fp, "\n"); previousObject = object; } void IcingaApplication::DumpProgramState(void) { ConfigObject::DumpObjects(GetStatePath()); DumpModifiedAttributes(); } void IcingaApplication::DumpModifiedAttributes(void) { String path = GetModAttrPath(); std::fstream fp; String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", 0644, fp); fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); ConfigObject::Ptr previousObject; ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3)); if (previousObject) { ConfigWriter::EmitRaw(fp, "\tobj.version = "); ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion()); ConfigWriter::EmitRaw(fp, "\n}\n"); } fp.close(); #ifdef _WIN32 _unlink(path.CStr()); #endif /* _WIN32 */ if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempFilename)); } } IcingaApplication::Ptr IcingaApplication::GetInstance(void) { return static_pointer_cast(Application::GetInstance()); } bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *result) const { double now = Utility::GetTime(); if (macro == "timet") { *result = static_cast(now); return true; } else if (macro == "long_date_time") { *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now); return true; } else if (macro == "short_date_time") { *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now); return true; } else if (macro == "date") { *result = Utility::FormatDateTime("%Y-%m-%d", now); return true; } else if (macro == "time") { *result = Utility::FormatDateTime("%H:%M:%S %z", now); return true; } else if (macro == "uptime") { *result = Utility::FormatDuration(Utility::GetTime() - Application::GetStartTime()); return true; } Dictionary::Ptr vars = GetVars(); if (vars && vars->Contains(macro)) { *result = vars->Get(macro); return true; } if (macro.Contains("num_services")) { ServiceStatistics ss = CIB::CalculateServiceStats(); if (macro == "num_services_ok") { *result = ss.services_ok; return true; } else if (macro == "num_services_warning") { *result = ss.services_warning; return true; } else if (macro == "num_services_critical") { *result = ss.services_critical; return true; } else if (macro == "num_services_unknown") { *result = ss.services_unknown; return true; } else if (macro == "num_services_pending") { *result = ss.services_pending; return true; } else if (macro == "num_services_unreachable") { *result = ss.services_unreachable; return true; } else if (macro == "num_services_flapping") { *result = ss.services_flapping; return true; } else if (macro == "num_services_in_downtime") { *result = ss.services_in_downtime; return true; } else if (macro == "num_services_acknowledged") { *result = ss.services_acknowledged; return true; } } else if (macro.Contains("num_hosts")) { HostStatistics hs = CIB::CalculateHostStats(); if (macro == "num_hosts_up") { *result = hs.hosts_up; return true; } else if (macro == "num_hosts_down") { *result = hs.hosts_down; return true; } else if (macro == "num_hosts_pending") { *result = hs.hosts_pending; return true; } else if (macro == "num_hosts_unreachable") { *result = hs.hosts_unreachable; return true; } else if (macro == "num_hosts_flapping") { *result = hs.hosts_flapping; return true; } else if (macro == "num_hosts_in_downtime") { *result = hs.hosts_in_downtime; return true; } else if (macro == "num_hosts_acknowledged") { *result = hs.hosts_acknowledged; return true; } } return false; } String IcingaApplication::GetNodeName(void) const { return ScriptGlobal::Get("NodeName"); } void IcingaApplication::ValidateVars(const Dictionary::Ptr& value, const ValidationUtils& utils) { MacroProcessor::ValidateCustomVars(this, value); } icinga2-2.8.1/lib/icinga/icingaapplication.hpp000066400000000000000000000047161322762156600212470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ICINGAAPPLICATION_H #define ICINGAAPPLICATION_H #include "icinga/i2-icinga.hpp" #include "icinga/icingaapplication.thpp" #include "icinga/macroresolver.hpp" namespace icinga { /** * The Icinga application. * * @ingroup icinga */ class I2_ICINGA_API IcingaApplication : public ObjectImpl, public MacroResolver { public: DECLARE_OBJECT(IcingaApplication); DECLARE_OBJECTNAME(IcingaApplication); static void StaticInitialize(void); virtual int Main(void) override; static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); static IcingaApplication::Ptr GetInstance(void); String GetPidPath(void) const; virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, Value *result) const override; String GetNodeName(void) const; virtual void ValidateVars(const Dictionary::Ptr& value, const ValidationUtils& utils) override; private: void DumpProgramState(void); void DumpModifiedAttributes(void); virtual void OnShutdown(void) override; }; } #endif /* ICINGAAPPLICATION_H */ icinga2-2.8.1/lib/icinga/icingaapplication.ti000066400000000000000000000037421322762156600210720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/application.hpp" library icinga; namespace icinga { class IcingaApplication : Application { [config] bool enable_notifications { default {{{ return true; }}} }; [config] bool enable_event_handlers { default {{{ return true; }}} }; [config] bool enable_flapping { default {{{ return true; }}} }; [config] bool enable_host_checks { default {{{ return true; }}} }; [config] bool enable_service_checks { default {{{ return true; }}} }; [config] bool enable_perfdata { default {{{ return true; }}} }; [config] Dictionary::Ptr vars; }; } icinga2-2.8.1/lib/icinga/legacytimeperiod.cpp000066400000000000000000000303771322762156600211140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/legacytimeperiod.hpp" #include "base/function.hpp" #include "base/convert.hpp" #include "base/exception.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/debug.hpp" #include "base/utility.hpp" #include #include using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, LegacyTimePeriod, &LegacyTimePeriod::ScriptFunc, "tp:begin:end"); bool LegacyTimePeriod::IsInTimeRange(tm *begin, tm *end, int stride, tm *reference) { time_t tsbegin, tsend, tsref; tsbegin = mktime(begin); tsend = mktime(end); tsref = mktime(reference); if (tsref < tsbegin || tsref > tsend) return false; int daynumber = (tsref - tsbegin) / (24 * 60 * 60); if (stride > 1 && daynumber % stride == 0) return false; return true; } void LegacyTimePeriod::FindNthWeekday(int wday, int n, tm *reference) { int dir, seen = 0; if (n > 0) { dir = 1; } else { n *= -1; dir = -1; /* Negative days are relative to the next month. */ reference->tm_mon++; } ASSERT(n > 0); reference->tm_mday = 1; for (;;) { mktime(reference); if (reference->tm_wday == wday) { seen++; if (seen == n) return; } reference->tm_mday += dir; } } int LegacyTimePeriod::WeekdayFromString(const String& daydef) { if (daydef == "sunday") return 0; else if (daydef == "monday") return 1; else if (daydef == "tuesday") return 2; else if (daydef == "wednesday") return 3; else if (daydef == "thursday") return 4; else if (daydef == "friday") return 5; else if (daydef == "saturday") return 6; else return -1; } int LegacyTimePeriod::MonthFromString(const String& monthdef) { if (monthdef == "january") return 0; else if (monthdef == "february") return 1; else if (monthdef == "march") return 2; else if (monthdef == "april") return 3; else if (monthdef == "may") return 4; else if (monthdef == "june") return 5; else if (monthdef == "july") return 6; else if (monthdef == "august") return 7; else if (monthdef == "september") return 8; else if (monthdef == "october") return 9; else if (monthdef == "november") return 10; else if (monthdef == "december") return 11; else return -1; } void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference) { /* Let mktime() figure out whether we're in DST or not. */ reference->tm_isdst = -1; /* YYYY-MM-DD */ if (timespec.GetLength() == 10 && timespec[4] == '-' && timespec[7] == '-') { int year = Convert::ToLong(timespec.SubStr(0, 4)); int month = Convert::ToLong(timespec.SubStr(5, 2)); int day = Convert::ToLong(timespec.SubStr(8, 2)); if (month < 1 || month > 12) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid month in time specification: " + timespec)); if (day < 1 || day > 31) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid day in time specification: " + timespec)); if (begin) { *begin = *reference; begin->tm_year = year - 1900; begin->tm_mon = month - 1; begin->tm_mday = day; begin->tm_hour = 0; begin->tm_min = 0; begin->tm_sec = 0; } if (end) { *end = *reference; end->tm_year = year - 1900; end->tm_mon = month - 1; end->tm_mday = day; end->tm_hour = 24; end->tm_min = 0; end->tm_sec = 0; } return; } std::vector tokens; boost::algorithm::split(tokens, timespec, boost::is_any_of(" ")); int mon = -1; if (tokens.size() > 1 && (tokens[0] == "day" || (mon = MonthFromString(tokens[0])) != -1)) { if (mon == -1) mon = reference->tm_mon; int mday = Convert::ToLong(tokens[1]); if (begin) { *begin = *reference; begin->tm_mon = mon; begin->tm_mday = mday; begin->tm_hour = 0; begin->tm_min = 0; begin->tm_sec = 0; /* Negative days are relative to the next month. */ if (mday < 0) { begin->tm_mday = mday * -1 - 1; begin->tm_mon++; } } if (end) { *end = *reference; end->tm_mon = mon; end->tm_mday = mday; end->tm_hour = 24; end->tm_min = 0; end->tm_sec = 0; /* Negative days are relative to the next month. */ if (mday < 0) { end->tm_mday = mday * -1 - 1; end->tm_mon++; } } return; } int wday; if (tokens.size() >= 1 && (wday = WeekdayFromString(tokens[0])) != -1) { tm myref = *reference; if (tokens.size() > 2) { mon = MonthFromString(tokens[2]); if (mon == -1) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid month in time specification: " + timespec)); myref.tm_mon = mon; } int n = 0; if (tokens.size() > 1) n = Convert::ToLong(tokens[1]); if (begin) { *begin = myref; if (tokens.size() > 1) FindNthWeekday(wday, n, begin); else begin->tm_mday += (7 - begin->tm_wday + wday) % 7; begin->tm_hour = 0; begin->tm_min = 0; begin->tm_sec = 0; } if (end) { *end = myref; if (tokens.size() > 1) FindNthWeekday(wday, n, end); else end->tm_mday += (7 - end->tm_wday + wday) % 7; end->tm_hour = 0; end->tm_min = 0; end->tm_sec = 0; end->tm_mday++; } return; } BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid time specification: " + timespec)); } void LegacyTimePeriod::ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference) { String def = timerange; /* Figure out the stride. */ size_t pos = def.FindFirstOf('/'); if (pos != String::NPos) { String strStride = def.SubStr(pos + 1).Trim(); *stride = Convert::ToLong(strStride); /* Remove the stride parameter from the definition. */ def = def.SubStr(0, pos); } else { *stride = 1; /* User didn't specify anything, assume default. */ } /* Figure out whether the user has specified two dates. */ pos = def.Find("- "); if (pos != String::NPos) { String first = def.SubStr(0, pos).Trim(); String second = def.SubStr(pos + 1).Trim(); ParseTimeSpec(first, begin, NULL, reference); /* If the second definition starts with a number we need * to add the first word from the first definition, e.g.: * day 1 - 15 --> "day 15" */ bool is_number = true; size_t xpos = second.FindFirstOf(' '); String fword = second.SubStr(0, xpos); try { Convert::ToLong(fword); } catch (...) { is_number = false; } if (is_number) { xpos = first.FindFirstOf(' '); ASSERT(xpos != String::NPos); second = first.SubStr(0, xpos + 1) + second; } ParseTimeSpec(second, NULL, end, reference); } else { ParseTimeSpec(def, begin, end, reference); } } bool LegacyTimePeriod::IsInDayDefinition(const String& daydef, tm *reference) { tm begin, end; int stride; ParseTimeRange(daydef, &begin, &end, &stride, reference); Log(LogDebug, "LegacyTimePeriod") << "ParseTimeRange: '" << daydef << "' => " << mktime(&begin) << " -> " << mktime(&end) << ", stride: " << stride; return IsInTimeRange(&begin, &end, stride, reference); } void LegacyTimePeriod::ProcessTimeRangeRaw(const String& timerange, tm *reference, tm *begin, tm *end) { std::vector times; boost::algorithm::split(times, timerange, boost::is_any_of("-")); if (times.size() != 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid timerange: " + timerange)); std::vector hd1, hd2; boost::algorithm::split(hd1, times[0], boost::is_any_of(":")); if (hd1.size() != 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid time specification: " + times[0])); boost::algorithm::split(hd2, times[1], boost::is_any_of(":")); if (hd2.size() != 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid time specification: " + times[1])); *begin = *reference; begin->tm_sec = 0; begin->tm_min = Convert::ToLong(hd1[1]); begin->tm_hour = Convert::ToLong(hd1[0]); *end = *reference; end->tm_sec = 0; end->tm_min = Convert::ToLong(hd2[1]); end->tm_hour = Convert::ToLong(hd2[0]); if (begin->tm_hour * 3600 + begin->tm_min * 60 + begin->tm_sec >= end->tm_hour * 3600 + end->tm_min * 60 + end->tm_sec) BOOST_THROW_EXCEPTION(std::invalid_argument("Time period segment ends before it begins")); } Dictionary::Ptr LegacyTimePeriod::ProcessTimeRange(const String& timestamp, tm *reference) { tm begin, end; ProcessTimeRangeRaw(timestamp, reference, &begin, &end); Dictionary::Ptr segment = new Dictionary(); segment->Set("begin", (long)mktime(&begin)); segment->Set("end", (long)mktime(&end)); return segment; } void LegacyTimePeriod::ProcessTimeRanges(const String& timeranges, tm *reference, const Array::Ptr& result) { std::vector ranges; boost::algorithm::split(ranges, timeranges, boost::is_any_of(",")); for (const String& range : ranges) { Dictionary::Ptr segment = ProcessTimeRange(range, reference); if (segment->Get("begin") >= segment->Get("end")) continue; result->Add(segment); } } Dictionary::Ptr LegacyTimePeriod::FindNextSegment(const String& daydef, const String& timeranges, tm *reference) { tm begin, end, iter, ref; time_t tsend, tsiter, tsref; int stride; for (int pass = 1; pass <= 2; pass++) { if (pass == 1) { ref = *reference; } else { ref = end; ref.tm_mday++; } tsref = mktime(&ref); ParseTimeRange(daydef, &begin, &end, &stride, &ref); iter = begin; tsend = mktime(&end); do { if (IsInTimeRange(&begin, &end, stride, &iter)) { Array::Ptr segments = new Array(); ProcessTimeRanges(timeranges, &iter, segments); Dictionary::Ptr bestSegment; double bestBegin; ObjectLock olock(segments); for (const Dictionary::Ptr& segment : segments) { double begin = segment->Get("begin"); if (begin < tsref) continue; if (!bestSegment || begin < bestBegin) { bestSegment = segment; bestBegin = begin; } } if (bestSegment) return bestSegment; } iter.tm_mday++; iter.tm_hour = 0; iter.tm_min = 0; iter.tm_sec = 0; tsiter = mktime(&iter); } while (tsiter < tsend); } return Dictionary::Ptr(); } Array::Ptr LegacyTimePeriod::ScriptFunc(const TimePeriod::Ptr& tp, double begin, double end) { Array::Ptr segments = new Array(); Dictionary::Ptr ranges = tp->GetRanges(); if (ranges) { for (int i = 0; i <= (end - begin) / (24 * 60 * 60); i++) { time_t refts = begin + i * 24 * 60 * 60; tm reference = Utility::LocalTime(refts); #ifdef I2_DEBUG Log(LogDebug, "LegacyTimePeriod") << "Checking reference time " << refts; #endif /* I2_DEBUG */ ObjectLock olock(ranges); for (const Dictionary::Pair& kv : ranges) { if (!IsInDayDefinition(kv.first, &reference)) { #ifdef I2_DEBUG Log(LogDebug, "LegacyTimePeriod") << "Not in day definition '" << kv.first << "'."; #endif /* I2_DEBUG */ continue; } #ifdef I2_DEBUG Log(LogDebug, "LegacyTimePeriod") << "In day definition '" << kv.first << "'."; #endif /* I2_DEBUG */ ProcessTimeRanges(kv.second, &reference, segments); } } } Log(LogDebug, "LegacyTimePeriod") << "Legacy timeperiod update returned " << segments->GetLength() << " segments."; return segments; } icinga2-2.8.1/lib/icinga/legacytimeperiod.hpp000066400000000000000000000053201322762156600211070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LEGACYTIMEPERIOD_H #define LEGACYTIMEPERIOD_H #include "icinga/i2-icinga.hpp" #include "icinga/timeperiod.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Implements Icinga 1.x time periods. * * @ingroup icinga */ class I2_ICINGA_API LegacyTimePeriod { public: static Array::Ptr ScriptFunc(const TimePeriod::Ptr& tp, double start, double end); static bool IsInTimeRange(tm *begin, tm *end, int stride, tm *reference); static void FindNthWeekday(int wday, int n, tm *reference); static int WeekdayFromString(const String& daydef); static int MonthFromString(const String& monthdef); static void ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference); static void ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference); static bool IsInDayDefinition(const String& daydef, tm *reference); static void ProcessTimeRangeRaw(const String& timerange, tm *reference, tm *begin, tm *end); static Dictionary::Ptr ProcessTimeRange(const String& timerange, tm *reference); static void ProcessTimeRanges(const String& timeranges, tm *reference, const Array::Ptr& result); static Dictionary::Ptr FindNextSegment(const String& daydef, const String& timeranges, tm *reference); private: LegacyTimePeriod(void); }; } #endif /* LEGACYTIMEPERIOD_H */ icinga2-2.8.1/lib/icinga/macroprocessor.cpp000066400000000000000000000424301322762156600206200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/macroprocessor.hpp" #include "icinga/macroresolver.hpp" #include "icinga/customvarobject.hpp" #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/configobject.hpp" #include "base/scriptframe.hpp" #include "base/convert.hpp" #include "base/exception.hpp" #include #include #include #include using namespace icinga; Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { Value result; if (str.IsEmpty()) return Empty; if (str.IsScalar()) { result = InternalResolveMacros(str, resolvers, cr, missingMacro, escapeFn, resolvedMacros, useResolvedMacros, recursionLevel + 1); } else if (str.IsObjectType()) { Array::Ptr resultArr = new Array(); Array::Ptr arr = str; ObjectLock olock(arr); for (const Value& arg : arr) { /* Note: don't escape macros here. */ Value value = InternalResolveMacros(arg, resolvers, cr, missingMacro, EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1); if (value.IsObjectType()) resultArr->Add(Utility::Join(value, ';')); else resultArr->Add(value); } result = resultArr; } else if (str.IsObjectType()) { Dictionary::Ptr resultDict = new Dictionary(); Dictionary::Ptr dict = str; ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { /* Note: don't escape macros here. */ resultDict->Set(kv.first, InternalResolveMacros(kv.second, resolvers, cr, missingMacro, EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1)); } result = resultDict; } else if (str.IsObjectType()) { result = EvaluateFunction(str, resolvers, cr, escapeFn, resolvedMacros, useResolvedMacros, 0); } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Macro is not a string or array.")); } return result; } bool MacroProcessor::ResolveMacro(const String& macro, const ResolverList& resolvers, const CheckResult::Ptr& cr, Value *result, bool *recursive_macro) { CONTEXT("Resolving macro '" + macro + "'"); *recursive_macro = false; std::vector tokens; boost::algorithm::split(tokens, macro, boost::is_any_of(".")); String objName; if (tokens.size() > 1) { objName = tokens[0]; tokens.erase(tokens.begin()); } for (const ResolverSpec& resolver : resolvers) { if (!objName.IsEmpty() && objName != resolver.first) continue; if (objName.IsEmpty()) { CustomVarObject::Ptr dobj = dynamic_pointer_cast(resolver.second); if (dobj) { Dictionary::Ptr vars = dobj->GetVars(); if (vars && vars->Contains(macro)) { *result = vars->Get(macro); *recursive_macro = true; return true; } } } MacroResolver *mresolver = dynamic_cast(resolver.second.get()); if (mresolver && mresolver->ResolveMacro(boost::algorithm::join(tokens, "."), cr, result)) return true; Value ref = resolver.second; bool valid = true; for (const String& token : tokens) { if (ref.IsObjectType()) { Dictionary::Ptr dict = ref; if (dict->Contains(token)) { ref = dict->Get(token); continue; } else { valid = false; break; } } else if (ref.IsObject()) { Object::Ptr object = ref; Type::Ptr type = object->GetReflectionType(); if (!type) { valid = false; break; } int field = type->GetFieldId(token); if (field == -1) { valid = false; break; } ref = object->GetField(field); Field fieldInfo = type->GetFieldInfo(field); if (strcmp(fieldInfo.TypeName, "Timestamp") == 0) ref = static_cast(ref); } } if (valid) { if (tokens[0] == "vars" || tokens[0] == "action_url" || tokens[0] == "notes_url" || tokens[0] == "notes") *recursive_macro = true; *result = ref; return true; } } return false; } Value MacroProcessor::InternalResolveMacrosShim(const std::vector& args, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { if (args.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); String missingMacro; return MacroProcessor::InternalResolveMacros(args[0], resolvers, cr, &missingMacro, escapeFn, resolvedMacros, useResolvedMacros, recursionLevel); } Value MacroProcessor::InternalResolveArgumentsShim(const std::vector& args, const ResolverList& resolvers, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { if (args.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); return MacroProcessor::ResolveArguments(args[0], args[1], resolvers, cr, resolvedMacros, useResolvedMacros, recursionLevel); } Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { Dictionary::Ptr resolvers_this = new Dictionary(); for (const ResolverSpec& resolver : resolvers) { resolvers_this->Set(resolver.first, resolver.second); } resolvers_this->Set("macro", new Function("macro (temporary)", boost::bind(&MacroProcessor::InternalResolveMacrosShim, _1, boost::cref(resolvers), cr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1), { "str" })); resolvers_this->Set("resolve_arguments", new Function("resolve_arguments (temporary)", boost::bind(&MacroProcessor::InternalResolveArgumentsShim, _1, boost::cref(resolvers), cr, resolvedMacros, useResolvedMacros, recursionLevel + 1))); std::vector args; return func->Invoke(resolvers_this, args); } Value MacroProcessor::InternalResolveMacros(const String& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { CONTEXT("Resolving macros for string '" + str + "'"); if (recursionLevel > 15) BOOST_THROW_EXCEPTION(std::runtime_error("Infinite recursion detected while resolving macros")); size_t offset, pos_first, pos_second; offset = 0; Dictionary::Ptr resolvers_this; String result = str; while ((pos_first = result.FindFirstOf("$", offset)) != String::NPos) { pos_second = result.FindFirstOf("$", pos_first + 1); if (pos_second == String::NPos) BOOST_THROW_EXCEPTION(std::runtime_error("Closing $ not found in macro format string.")); String name = result.SubStr(pos_first + 1, pos_second - pos_first - 1); Value resolved_macro; bool recursive_macro; bool found; if (useResolvedMacros) { recursive_macro = false; found = resolvedMacros->Contains(name); if (found) resolved_macro = resolvedMacros->Get(name); } else found = ResolveMacro(name, resolvers, cr, &resolved_macro, &recursive_macro); /* $$ is an escape sequence for $. */ if (name.IsEmpty()) { resolved_macro = "$"; found = true; } if (resolved_macro.IsObjectType()) { resolved_macro = EvaluateFunction(resolved_macro, resolvers, cr, escapeFn, resolvedMacros, useResolvedMacros, recursionLevel + 1); } if (!found) { if (!missingMacro) Log(LogWarning, "MacroProcessor") << "Macro '" << name << "' is not defined."; else *missingMacro = name; } /* recursively resolve macros in the macro if it was a user macro */ if (recursive_macro) { if (resolved_macro.IsObjectType()) { Array::Ptr arr = resolved_macro; Array::Ptr resolved_arr = new Array(); ObjectLock olock(arr); for (const Value& value : arr) { if (value.IsScalar()) { resolved_arr->Add(InternalResolveMacros(value, resolvers, cr, missingMacro, EscapeCallback(), Dictionary::Ptr(), false, recursionLevel + 1)); } else resolved_arr->Add(value); } resolved_macro = resolved_arr; } else if (resolved_macro.IsString()) { resolved_macro = InternalResolveMacros(resolved_macro, resolvers, cr, missingMacro, EscapeCallback(), Dictionary::Ptr(), false, recursionLevel + 1); } } if (!useResolvedMacros && found && resolvedMacros) resolvedMacros->Set(name, resolved_macro); if (escapeFn) resolved_macro = escapeFn(resolved_macro); /* we're done if this is the only macro and there are no other non-macro parts in the string */ if (pos_first == 0 && pos_second == str.GetLength() - 1) return resolved_macro; else if (resolved_macro.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Mixing both strings and non-strings in macros is not allowed.")); if (resolved_macro.IsObjectType()) { /* don't allow mixing strings and arrays in macro strings */ if (pos_first != 0 || pos_second != str.GetLength() - 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Mixing both strings and non-strings in macros is not allowed.")); return resolved_macro; } String resolved_macro_str = resolved_macro; result.Replace(pos_first, pos_second - pos_first + 1, resolved_macro_str); offset = pos_first + resolved_macro_str.GetLength(); } return result; } bool MacroProcessor::ValidateMacroString(const String& macro) { if (macro.IsEmpty()) return true; size_t pos_first, pos_second, offset; offset = 0; while ((pos_first = macro.FindFirstOf("$", offset)) != String::NPos) { pos_second = macro.FindFirstOf("$", pos_first + 1); if (pos_second == String::NPos) return false; offset = pos_second + 1; } return true; } void MacroProcessor::ValidateCustomVars(const ConfigObject::Ptr& object, const Dictionary::Ptr& value) { if (!value) return; /* string, array, dictionary */ ObjectLock olock(value); for (const Dictionary::Pair& kv : value) { const Value& varval = kv.second; if (varval.IsObjectType()) { /* only one dictonary level */ Dictionary::Ptr varval_dict = varval; ObjectLock xlock(varval_dict); for (const Dictionary::Pair& kv_var : varval_dict) { if (!kv_var.second.IsString()) continue; if (!ValidateMacroString(kv_var.second)) BOOST_THROW_EXCEPTION(ValidationError(object.get(), boost::assign::list_of("vars")(kv.first)(kv_var.first), "Closing $ not found in macro format string '" + kv_var.second + "'.")); } } else if (varval.IsObjectType()) { /* check all array entries */ Array::Ptr varval_arr = varval; ObjectLock ylock (varval_arr); for (const Value& arrval : varval_arr) { if (!arrval.IsString()) continue; if (!ValidateMacroString(arrval)) { BOOST_THROW_EXCEPTION(ValidationError(object.get(), boost::assign::list_of("vars")(kv.first), "Closing $ not found in macro format string '" + arrval + "'.")); } } } else { if (!varval.IsString()) continue; if (!ValidateMacroString(varval)) BOOST_THROW_EXCEPTION(ValidationError(object.get(), boost::assign::list_of("vars")(kv.first), "Closing $ not found in macro format string '" + varval + "'.")); } } } void MacroProcessor::AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value, bool add_key, bool add_value) { if (add_key) args->Add(key); if (add_value) args->Add(value); } Value MacroProcessor::EscapeMacroShellArg(const Value& value) { String result; if (value.IsObjectType()) { Array::Ptr arr = value; ObjectLock olock(arr); for (const Value& arg : arr) { if (result.GetLength() > 0) result += " "; result += Utility::EscapeShellArg(arg); } } else result = Utility::EscapeShellArg(value); return result; } struct CommandArgument { int Order; bool SkipKey; bool RepeatKey; bool SkipValue; String Key; Value AValue; CommandArgument(void) : Order(0), SkipKey(false), RepeatKey(true), SkipValue(false) { } bool operator<(const CommandArgument& rhs) const { return Order < rhs.Order; } }; Value MacroProcessor::ResolveArguments(const Value& command, const Dictionary::Ptr& arguments, const MacroProcessor::ResolverList& resolvers, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) { Value resolvedCommand; if (!arguments || command.IsObjectType() || command.IsObjectType()) resolvedCommand = MacroProcessor::ResolveMacros(command, resolvers, cr, NULL, EscapeMacroShellArg, resolvedMacros, useResolvedMacros, recursionLevel + 1); else { Array::Ptr arr = new Array(); arr->Add(command); resolvedCommand = arr; } if (arguments) { std::vector args; ObjectLock olock(arguments); for (const Dictionary::Pair& kv : arguments) { const Value& arginfo = kv.second; CommandArgument arg; arg.Key = kv.first; bool required = false; Value argval; if (arginfo.IsObjectType()) { Dictionary::Ptr argdict = arginfo; if (argdict->Contains("key")) arg.Key = argdict->Get("key"); argval = argdict->Get("value"); if (argdict->Contains("required")) required = argdict->Get("required"); arg.SkipKey = argdict->Get("skip_key"); if (argdict->Contains("repeat_key")) arg.RepeatKey = argdict->Get("repeat_key"); arg.Order = argdict->Get("order"); Value set_if = argdict->Get("set_if"); if (!set_if.IsEmpty()) { String missingMacro; Value set_if_resolved = MacroProcessor::ResolveMacros(set_if, resolvers, cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1); if (!missingMacro.IsEmpty()) continue; int value; if (set_if_resolved == "true") value = 1; else if (set_if_resolved == "false") value = 0; else { try { value = Convert::ToLong(set_if_resolved); } catch (const std::exception& ex) { /* tried to convert a string */ Log(LogWarning, "PluginUtility") << "Error evaluating set_if value '" << set_if_resolved << "' used in argument '" << arg.Key << "': " << ex.what(); continue; } } if (!value) continue; } } else argval = arginfo; if (argval.IsEmpty()) arg.SkipValue = true; String missingMacro; arg.AValue = MacroProcessor::ResolveMacros(argval, resolvers, cr, &missingMacro, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros, recursionLevel + 1); if (!missingMacro.IsEmpty()) { if (required) { BOOST_THROW_EXCEPTION(ScriptError("Non-optional macro '" + missingMacro + "' used in argument '" + arg.Key + "' is missing.")); } continue; } args.push_back(arg); } std::sort(args.begin(), args.end()); Array::Ptr command_arr = resolvedCommand; for (const CommandArgument& arg : args) { if (arg.AValue.IsObjectType()) { Log(LogWarning, "PluginUtility") << "Tried to use dictionary in argument '" << arg.Key << "'."; continue; } else if (arg.AValue.IsObjectType()) { bool first = true; Array::Ptr arr = static_cast(arg.AValue); ObjectLock olock(arr); for (const Value& value : arr) { bool add_key; if (first) { first = false; add_key = !arg.SkipKey; } else add_key = !arg.SkipKey && arg.RepeatKey; AddArgumentHelper(command_arr, arg.Key, value, add_key, !arg.SkipValue); } } else AddArgumentHelper(command_arr, arg.Key, arg.AValue, !arg.SkipKey, !arg.SkipValue); } } return resolvedCommand; } icinga2-2.8.1/lib/icinga/macroprocessor.hpp000066400000000000000000000100261322762156600206210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MACROPROCESSOR_H #define MACROPROCESSOR_H #include "icinga/i2-icinga.hpp" #include "icinga/checkable.hpp" #include "base/value.hpp" #include #include namespace icinga { /** * Resolves macros. * * @ingroup icinga */ class I2_ICINGA_API MacroProcessor { public: typedef boost::function EscapeCallback; typedef std::pair ResolverSpec; typedef std::vector ResolverList; static Value ResolveMacros(const Value& str, const ResolverList& resolvers, const CheckResult::Ptr& cr = CheckResult::Ptr(), String *missingMacro = NULL, const EscapeCallback& escapeFn = EscapeCallback(), const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), bool useResolvedMacros = false, int recursionLevel = 0); static Value ResolveArguments(const Value& command, const Dictionary::Ptr& arguments, const MacroProcessor::ResolverList& resolvers, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel = 0); static bool ValidateMacroString(const String& macro); static void ValidateCustomVars(const ConfigObject::Ptr& object, const Dictionary::Ptr& value); private: MacroProcessor(void); static bool ResolveMacro(const String& macro, const ResolverList& resolvers, const CheckResult::Ptr& cr, Value *result, bool *recursive_macro); static Value InternalResolveMacros(const String& str, const ResolverList& resolvers, const CheckResult::Ptr& cr, String *missingMacro, const EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel = 0); static Value InternalResolveMacrosShim(const std::vector& args, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel); static Value InternalResolveArgumentsShim(const std::vector& args, const ResolverList& resolvers, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel); static Value EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel); static void AddArgumentHelper(const Array::Ptr& args, const String& key, const String& value, bool add_key, bool add_value); static Value EscapeMacroShellArg(const Value& value); }; } #endif /* MACROPROCESSOR_H */ icinga2-2.8.1/lib/icinga/macroresolver.hpp000066400000000000000000000035631322762156600204530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MACRORESOLVER_H #define MACRORESOLVER_H #include "icinga/i2-icinga.hpp" #include "icinga/checkresult.hpp" #include "base/dictionary.hpp" #include "base/string.hpp" namespace icinga { /** * Resolves macros. * * @ingroup icinga */ class I2_ICINGA_API MacroResolver { public: DECLARE_PTR_TYPEDEFS(MacroResolver); virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, Value *result) const = 0; }; } #endif /* MACRORESOLVER_H */ icinga2-2.8.1/lib/icinga/notification-apply.cpp000066400000000000000000000136011322762156600213660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/notification.hpp" #include "icinga/service.hpp" #include "config/configitembuilder.hpp" #include "config/applyrule.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" #include "base/exception.hpp" using namespace icinga; INITIALIZE_ONCE([]() { std::vector targets; targets.push_back("Host"); targets.push_back("Service"); ApplyRule::RegisterType("Notification", targets); }); bool Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule) { if (!rule.EvaluateFilter(frame)) return false; DebugInfo di = rule.GetDebugInfo(); #ifdef _DEBUG Log(LogDebug, "Notification") << "Applying notification '" << name << "' to object '" << checkable->GetName() << "' for rule " << di; #endif /* _DEBUG */ ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(di); builder->SetType(Notification::TypeInstance); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di)); if (service) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di)); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "zone"), OpSetLiteral, MakeLiteral(zone), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "package"), OpSetLiteral, MakeLiteral(rule.GetPackage()), di)); builder->AddExpression(new OwnedExpression(rule.GetExpression())); builder->AddExpression(new ImportDefaultTemplatesExpression()); ConfigItem::Ptr notificationItem = builder->Compile(); notificationItem->Register(); return true; } bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule) { DebugInfo di = rule.GetDebugInfo(); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); ScriptFrame frame; if (rule.GetScope()) rule.GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); if (service) frame.Locals->Set("service", service); Value vinstances; if (rule.GetFTerm()) { try { vinstances = rule.GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } } else { Array::Ptr instances = new Array(); instances->Add(""); vinstances = instances; } bool match = false; if (vinstances.IsObjectType()) { if (!rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { String name = rule.GetName(); if (!rule.GetFKVar().IsEmpty()) { frame.Locals->Set(rule.GetFKVar(), instance); name += instance; } if (EvaluateApplyRuleInstance(checkable, name, frame, rule)) match = true; } } else if (vinstances.IsObjectType()) { if (rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; for (const String& key : dict->GetKeys()) { frame.Locals->Set(rule.GetFKVar(), key); frame.Locals->Set(rule.GetFVVar(), dict->Get(key)); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule)) match = true; } } return match; } void Notification::EvaluateApplyRules(const Host::Ptr& host) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("Notification")) { if (rule.GetTargetType() != "Host") continue; if (EvaluateApplyRule(host, rule)) rule.AddMatch(); } } void Notification::EvaluateApplyRules(const Service::Ptr& service) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("Notification")) { if (rule.GetTargetType() != "Service") continue; if (EvaluateApplyRule(service, rule)) rule.AddMatch(); } } icinga2-2.8.1/lib/icinga/notification.cpp000066400000000000000000000536361322762156600202570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/notification.hpp" #include "icinga/notification.tcpp" #include "icinga/notificationcommand.hpp" #include "icinga/service.hpp" #include "remote/apilistener.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include "base/exception.hpp" #include "base/initialize.hpp" #include "base/scriptglobal.hpp" #include #include using namespace icinga; REGISTER_TYPE(Notification); INITIALIZE_ONCE(&Notification::StaticInitialize); std::map Notification::m_StateFilterMap; std::map Notification::m_TypeFilterMap; boost::signals2::signal Notification::OnNextNotificationChanged; String NotificationNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Notification::Ptr notification = dynamic_pointer_cast(context); if (!notification) return ""; String name = notification->GetHostName(); if (!notification->GetServiceName().IsEmpty()) name += "!" + notification->GetServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr NotificationNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Notification name.")); Dictionary::Ptr result = new Dictionary(); result->Set("host_name", tokens[0]); if (tokens.size() > 2) { result->Set("service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void Notification::StaticInitialize(void) { ScriptGlobal::Set("OK", "OK"); ScriptGlobal::Set("Warning", "Warning"); ScriptGlobal::Set("Critical", "Critical"); ScriptGlobal::Set("Unknown", "Unknown"); ScriptGlobal::Set("Up", "Up"); ScriptGlobal::Set("Down", "Down"); ScriptGlobal::Set("DowntimeStart", "DowntimeStart"); ScriptGlobal::Set("DowntimeEnd", "DowntimeEnd"); ScriptGlobal::Set("DowntimeRemoved", "DowntimeRemoved"); ScriptGlobal::Set("Custom", "Custom"); ScriptGlobal::Set("Acknowledgement", "Acknowledgement"); ScriptGlobal::Set("Problem", "Problem"); ScriptGlobal::Set("Recovery", "Recovery"); ScriptGlobal::Set("FlappingStart", "FlappingStart"); ScriptGlobal::Set("FlappingEnd", "FlappingEnd"); m_StateFilterMap["OK"] = StateFilterOK; m_StateFilterMap["Warning"] = StateFilterWarning; m_StateFilterMap["Critical"] = StateFilterCritical; m_StateFilterMap["Unknown"] = StateFilterUnknown; m_StateFilterMap["Up"] = StateFilterUp; m_StateFilterMap["Down"] = StateFilterDown; m_TypeFilterMap["DowntimeStart"] = NotificationDowntimeStart; m_TypeFilterMap["DowntimeEnd"] = NotificationDowntimeEnd; m_TypeFilterMap["DowntimeRemoved"] = NotificationDowntimeRemoved; m_TypeFilterMap["Custom"] = NotificationCustom; m_TypeFilterMap["Acknowledgement"] = NotificationAcknowledgement; m_TypeFilterMap["Problem"] = NotificationProblem; m_TypeFilterMap["Recovery"] = NotificationRecovery; m_TypeFilterMap["FlappingStart"] = NotificationFlappingStart; m_TypeFilterMap["FlappingEnd"] = NotificationFlappingEnd; } void Notification::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); SetTypeFilter(FilterArrayToInt(GetTypes(), GetTypeFilterMap(), ~0)); SetStateFilter(FilterArrayToInt(GetStates(), GetStateFilterMap(), ~0)); } void Notification::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); Host::Ptr host = Host::GetByName(GetHostName()); if (GetServiceName().IsEmpty()) m_Checkable = host; else m_Checkable = host->GetServiceByShortName(GetServiceName()); if (!m_Checkable) BOOST_THROW_EXCEPTION(ScriptError("Notification object refers to a host/service which doesn't exist.", GetDebugInfo())); GetCheckable()->RegisterNotification(this); } void Notification::Start(bool runtimeCreated) { Checkable::Ptr obj = GetCheckable(); if (obj) obj->RegisterNotification(this); if (ApiListener::IsHACluster() && GetNextNotification() < Utility::GetTime() + 60) SetNextNotification(Utility::GetTime() + 60, true); ObjectImpl::Start(runtimeCreated); } void Notification::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); Checkable::Ptr obj = GetCheckable(); if (obj) obj->UnregisterNotification(this); } Checkable::Ptr Notification::GetCheckable(void) const { return static_pointer_cast(m_Checkable); } NotificationCommand::Ptr Notification::GetCommand(void) const { return NotificationCommand::GetByName(GetCommandRaw()); } std::set Notification::GetUsers(void) const { std::set result; Array::Ptr users = GetUsersRaw(); if (users) { ObjectLock olock(users); for (const String& name : users) { User::Ptr user = User::GetByName(name); if (!user) continue; result.insert(user); } } return result; } std::set Notification::GetUserGroups(void) const { std::set result; Array::Ptr groups = GetUserGroupsRaw(); if (groups) { ObjectLock olock(groups); for (const String& name : groups) { UserGroup::Ptr ug = UserGroup::GetByName(name); if (!ug) continue; result.insert(ug); } } return result; } TimePeriod::Ptr Notification::GetPeriod(void) const { return TimePeriod::GetByName(GetPeriodRaw()); } void Notification::UpdateNotificationNumber(void) { SetNotificationNumber(GetNotificationNumber() + 1); } void Notification::ResetNotificationNumber(void) { SetNotificationNumber(0); } /* the upper case string used in all interfaces */ String Notification::NotificationTypeToString(NotificationType type) { switch (type) { case NotificationDowntimeStart: return "DOWNTIMESTART"; case NotificationDowntimeEnd: return "DOWNTIMEEND"; case NotificationDowntimeRemoved: return "DOWNTIMECANCELLED"; case NotificationCustom: return "CUSTOM"; case NotificationAcknowledgement: return "ACKNOWLEDGEMENT"; case NotificationProblem: return "PROBLEM"; case NotificationRecovery: return "RECOVERY"; case NotificationFlappingStart: return "FLAPPINGSTART"; case NotificationFlappingEnd: return "FLAPPINGEND"; default: return "UNKNOWN_NOTIFICATION"; } } void Notification::BeginExecuteNotification(NotificationType type, const CheckResult::Ptr& cr, bool force, bool reminder, const String& author, const String& text) { Log(LogNotice, "Notification") << "Attempting to send " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "'."; Checkable::Ptr checkable = GetCheckable(); if (!force) { TimePeriod::Ptr tp = GetPeriod(); if (tp && !tp->IsInside(Utility::GetTime())) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "': not in timeperiod '" << tp->GetName() << "'"; return; } double now = Utility::GetTime(); Dictionary::Ptr times = GetTimes(); if (times && type == NotificationProblem) { Value timesBegin = times->Get("begin"); Value timesEnd = times->Get("end"); if (timesBegin != Empty && timesBegin >= 0 && now < checkable->GetLastHardStateChange() + timesBegin) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "': before specified begin time (" << Utility::FormatDuration(timesBegin) << ")"; /* we need to adjust the next notification time * to now + begin delaying the first notification */ double nextProposedNotification = now + timesBegin + 1.0; if (GetNextNotification() > nextProposedNotification) SetNextNotification(nextProposedNotification); return; } if (timesEnd != Empty && timesEnd >= 0 && now > checkable->GetLastHardStateChange() + timesEnd) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "': after specified end time (" << Utility::FormatDuration(timesEnd) << ")"; return; } } unsigned long ftype = type; Log(LogDebug, "Notification") << "Type '" << NotificationTypeToStringInternal(type) << "', TypeFilter: " << NotificationFilterToString(GetTypeFilter(), GetTypeFilterMap()) << " (FType=" << ftype << ", TypeFilter=" << GetTypeFilter() << ")"; if (!(ftype & GetTypeFilter())) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "': type '" << NotificationTypeToStringInternal(type) << "' does not match type filter: " << NotificationFilterToString(GetTypeFilter(), GetTypeFilterMap()) << "."; return; } /* ensure that recovery notifications are always sent, no state filter checks necessary */ if (type != NotificationRecovery) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); unsigned long fstate; String stateStr; if (service) { fstate = ServiceStateToFilter(service->GetState()); stateStr = NotificationServiceStateToString(service->GetState()); } else { fstate = HostStateToFilter(host->GetState()); stateStr = NotificationHostStateToString(host->GetState()); } Log(LogDebug, "Notification") << "State '" << stateStr << "', StateFilter: " << NotificationFilterToString(GetStateFilter(), GetStateFilterMap()) << " (FState=" << fstate << ", StateFilter=" << GetStateFilter() << ")"; if (!(fstate & GetStateFilter())) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << "': state '" << stateStr << "' does not match state filter: " << NotificationFilterToString(GetStateFilter(), GetStateFilterMap()) << "."; return; } } } else { Log(LogNotice, "Notification") << "Not checking " << (reminder ? "reminder " : " ") << "notification filters for notification object '" << GetName() << "': Notification was forced."; } { ObjectLock olock(this); UpdateNotificationNumber(); double now = Utility::GetTime(); SetLastNotification(now); if (type == NotificationProblem && GetInterval() <= 0) SetNoMoreNotifications(true); else SetNoMoreNotifications(false); if (type == NotificationProblem && GetInterval() > 0) SetNextNotification(now + GetInterval()); if (type == NotificationProblem) SetLastProblemNotification(now); } std::set allUsers; std::set users = GetUsers(); std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin())); for (const UserGroup::Ptr& ug : GetUserGroups()) { std::set members = ug->GetMembers(); std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin())); } std::set allNotifiedUsers; Array::Ptr notifiedProblemUsers = GetNotifiedProblemUsers(); for (const User::Ptr& user : allUsers) { String userName = user->GetName(); if (!user->GetEnableNotifications()) { Log(LogNotice, "Notification") << "Disabled notifications for user '" << userName << "'. Not sending notification."; continue; } if (!CheckNotificationUserFilters(type, user, force, reminder)) { Log(LogNotice, "Notification") << "Notification filters for user '" << userName << "' not matched. Not sending notification."; continue; } /* on recovery, check if user was notified before */ if (type == NotificationRecovery) { if (!notifiedProblemUsers->Contains(userName)) { Log(LogNotice, "Notification") << "We did not notify user '" << userName << "' for a problem before. Not sending recovery notification."; continue; } } Log(LogInformation, "Notification") << "Sending " << (reminder ? "reminder " : "") << "'" << NotificationTypeToStringInternal(type) << "' notification '" << GetName() << "' for user '" << userName << "'"; Utility::QueueAsyncCallback(boost::bind(&Notification::ExecuteNotificationHelper, this, type, user, cr, force, author, text)); /* collect all notified users */ allNotifiedUsers.insert(user); /* store all notified users for later recovery checks */ if (type == NotificationProblem && !notifiedProblemUsers->Contains(userName)) notifiedProblemUsers->Add(userName); } /* if this was a recovery notification, reset all notified users */ if (type == NotificationRecovery) notifiedProblemUsers->Clear(); /* used in db_ido for notification history */ Service::OnNotificationSentToAllUsers(this, checkable, allNotifiedUsers, type, cr, author, text, MessageOrigin::Ptr()); } bool Notification::CheckNotificationUserFilters(NotificationType type, const User::Ptr& user, bool force, bool reminder) { if (!force) { TimePeriod::Ptr tp = user->GetPeriod(); if (tp && !tp->IsInside(Utility::GetTime())) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << " and user '" << user->GetName() << "': user period not in timeperiod '" << tp->GetName() << "'"; return false; } unsigned long ftype = type; Log(LogDebug, "Notification") << "User notification, Type '" << NotificationTypeToStringInternal(type) << "', TypeFilter: " << NotificationFilterToString(user->GetTypeFilter(), GetTypeFilterMap()) << " (FType=" << ftype << ", TypeFilter=" << GetTypeFilter() << ")"; if (!(ftype & user->GetTypeFilter())) { Log(LogNotice, "Notification") << "Not sending " << (reminder ? "reminder " : " ") << "notifications for notification object '" << GetName() << " and user '" << user->GetName() << "': type '" << NotificationTypeToStringInternal(type) << "' does not match type filter: " << NotificationFilterToString(user->GetTypeFilter(), GetTypeFilterMap()) << "."; return false; } /* check state filters it this is not a recovery notification */ if (type != NotificationRecovery) { Checkable::Ptr checkable = GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); unsigned long fstate; String stateStr; if (service) { fstate = ServiceStateToFilter(service->GetState()); stateStr = NotificationServiceStateToString(service->GetState()); } else { fstate = HostStateToFilter(host->GetState()); stateStr = NotificationHostStateToString(host->GetState()); } Log(LogDebug, "Notification") << "User notification, State '" << stateStr << "', StateFilter: " << NotificationFilterToString(user->GetStateFilter(), GetStateFilterMap()) << " (FState=" << fstate << ", StateFilter=" << user->GetStateFilter() << ")"; if (!(fstate & user->GetStateFilter())) { Log(LogNotice, "Notification") << "Not " << (reminder ? "reminder " : " ") << "sending notifications for notification object '" << GetName() << " and user '" << user->GetName() << "': state '" << stateStr << "' does not match state filter: " << NotificationFilterToString(user->GetStateFilter(), GetStateFilterMap()) << "."; return false; } } } else { Log(LogNotice, "Notification") << "Not checking " << (reminder ? "reminder " : " ") << "notification filters for notification object '" << GetName() << "' and user '" << user->GetName() << "': Notification was forced."; } return true; } void Notification::ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const CheckResult::Ptr& cr, bool force, const String& author, const String& text) { try { NotificationCommand::Ptr command = GetCommand(); if (!command) { Log(LogDebug, "Notification") << "No command found for notification '" << GetName() << "'. Skipping execution."; return; } command->Execute(this, user, cr, type, author, text); /* required by compatlogger */ Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, command->GetName(), MessageOrigin::Ptr()); Log(LogInformation, "Notification") << "Completed sending '" << NotificationTypeToStringInternal(type) << "' notification '" << GetName() << "' for checkable '" << GetCheckable()->GetName() << "' and user '" << user->GetName() << "'."; } catch (const std::exception& ex) { Log(LogWarning, "Notification") << "Exception occured during notification for checkable '" << GetCheckable()->GetName() << "': " << DiagnosticInformation(ex); } } int icinga::ServiceStateToFilter(ServiceState state) { switch (state) { case ServiceOK: return StateFilterOK; case ServiceWarning: return StateFilterWarning; case ServiceCritical: return StateFilterCritical; case ServiceUnknown: return StateFilterUnknown; default: VERIFY(!"Invalid state type."); } } int icinga::HostStateToFilter(HostState state) { switch (state) { case HostUp: return StateFilterUp; case HostDown: return StateFilterDown; default: VERIFY(!"Invalid state type."); } } String Notification::NotificationFilterToString(int filter, const std::map& filterMap) { std::vector sFilters; typedef std::pair kv_pair; for (const kv_pair& kv : filterMap) { if (filter & kv.second) sFilters.push_back(kv.first); } return Utility::NaturalJoin(sFilters); } /* internal for logging */ String Notification::NotificationTypeToStringInternal(NotificationType type) { switch (type) { case NotificationDowntimeStart: return "DowntimeStart"; case NotificationDowntimeEnd: return "DowntimeEnd"; case NotificationDowntimeRemoved: return "DowntimeRemoved"; case NotificationCustom: return "Custom"; case NotificationAcknowledgement: return "Acknowledgement"; case NotificationProblem: return "Problem"; case NotificationRecovery: return "Recovery"; case NotificationFlappingStart: return "FlappingStart"; case NotificationFlappingEnd: return "FlappingEnd"; default: return Empty; } } String Notification::NotificationServiceStateToString(ServiceState state) { switch (state) { case ServiceOK: return "OK"; case ServiceWarning: return "Warning"; case ServiceCritical: return "Critical"; case ServiceUnknown: return "Unknown"; default: VERIFY(!"Invalid state type."); } } String Notification::NotificationHostStateToString(HostState state) { switch (state) { case HostUp: return "Up"; case HostDown: return "Down"; default: VERIFY(!"Invalid state type."); } } void Notification::Validate(int types, const ValidationUtils& utils) { ObjectImpl::Validate(types, utils); if (!(types & FAConfig)) return; Array::Ptr users = GetUsersRaw(); Array::Ptr groups = GetUserGroupsRaw(); if ((!users || users->GetLength() == 0) && (!groups || groups->GetLength() == 0)) BOOST_THROW_EXCEPTION(ValidationError(this, std::vector(), "Validation failed: No users/user_groups specified.")); } void Notification::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateStates(value, utils); int filter = FilterArrayToInt(value, GetStateFilterMap(), 0); if (GetServiceName().IsEmpty() && (filter == -1 || (filter & ~(StateFilterUp | StateFilterDown)) != 0)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid.")); if (!GetServiceName().IsEmpty() && (filter == -1 || (filter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid.")); } void Notification::ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateTypes(value, utils); int filter = FilterArrayToInt(value, GetTypeFilterMap(), 0); if (filter == -1 || (filter & ~(NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved | NotificationCustom | NotificationAcknowledgement | NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("types"), "Type filter is invalid.")); } Endpoint::Ptr Notification::GetCommandEndpoint(void) const { return Endpoint::GetByName(GetCommandEndpointRaw()); } const std::map& Notification::GetStateFilterMap(void) { return m_StateFilterMap; } const std::map& Notification::GetTypeFilterMap(void) { return m_TypeFilterMap; } icinga2-2.8.1/lib/icinga/notification.hpp000066400000000000000000000123111322762156600202450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NOTIFICATION_H #define NOTIFICATION_H #include "icinga/i2-icinga.hpp" #include "icinga/notification.thpp" #include "icinga/checkable.thpp" #include "icinga/user.hpp" #include "icinga/usergroup.hpp" #include "icinga/timeperiod.hpp" #include "icinga/checkresult.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include "base/array.hpp" namespace icinga { /** * @ingroup icinga */ enum NotificationFilter { StateFilterOK = 1, StateFilterWarning = 2, StateFilterCritical = 4, StateFilterUnknown = 8, StateFilterUp = 16, StateFilterDown = 32 }; /** * The notification type. * * @ingroup icinga */ enum NotificationType { NotificationDowntimeStart = 1, NotificationDowntimeEnd = 2, NotificationDowntimeRemoved = 4, NotificationCustom = 8, NotificationAcknowledgement = 16, NotificationProblem = 32, NotificationRecovery = 64, NotificationFlappingStart = 128, NotificationFlappingEnd = 256 }; class NotificationCommand; class ApplyRule; struct ScriptFrame; class Host; class Service; /** * An Icinga notification specification. * * @ingroup icinga */ class I2_ICINGA_API Notification : public ObjectImpl { public: DECLARE_OBJECT(Notification); DECLARE_OBJECTNAME(Notification); static void StaticInitialize(void); intrusive_ptr GetCheckable(void) const; intrusive_ptr GetCommand(void) const; TimePeriod::Ptr GetPeriod(void) const; std::set GetUsers(void) const; std::set GetUserGroups(void) const; void UpdateNotificationNumber(void); void ResetNotificationNumber(void); void BeginExecuteNotification(NotificationType type, const CheckResult::Ptr& cr, bool force, bool reminder = false, const String& author = "", const String& text = ""); Endpoint::Ptr GetCommandEndpoint(void) const; static String NotificationTypeToString(NotificationType type); static String NotificationFilterToString(int filter, const std::map& filterMap); static boost::signals2::signal OnNextNotificationChanged; virtual void Validate(int types, const ValidationUtils& utils) override; virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override; virtual void ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) override; static void EvaluateApplyRules(const intrusive_ptr& host); static void EvaluateApplyRules(const intrusive_ptr& service); static const std::map& GetStateFilterMap(void); static const std::map& GetTypeFilterMap(void); protected: virtual void OnConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: ObjectImpl::Ptr m_Checkable; bool CheckNotificationUserFilters(NotificationType type, const User::Ptr& user, bool force, bool reminder); void ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const CheckResult::Ptr& cr, bool force, const String& author = "", const String& text = ""); static bool EvaluateApplyRuleInstance(const intrusive_ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule); static bool EvaluateApplyRule(const intrusive_ptr& checkable, const ApplyRule& rule); static String NotificationTypeToStringInternal(NotificationType type); static String NotificationServiceStateToString(ServiceState state); static String NotificationHostStateToString(HostState state); static std::map m_StateFilterMap; static std::map m_TypeFilterMap; }; I2_ICINGA_API int ServiceStateToFilter(ServiceState state); I2_ICINGA_API int HostStateToFilter(HostState state); } #endif /* NOTIFICATION_H */ icinga2-2.8.1/lib/icinga/notification.ti000066400000000000000000000077061322762156600201060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #impl_include "icinga/notificationcommand.hpp" #impl_include "icinga/service.hpp" library icinga; namespace icinga { code {{{ class I2_ICINGA_API NotificationNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class Notification : CustomVarObject < NotificationNameComposer { load_after Host; load_after Service; [config, protected, required, navigation] name(NotificationCommand) command (CommandRaw) { navigate {{{ return NotificationCommand::GetByName(GetCommandRaw()); }}} }; [config] double interval { default {{{ return 1800; }}} }; [config, navigation] name(TimePeriod) period (PeriodRaw) { navigate {{{ return TimePeriod::GetByName(GetPeriodRaw()); }}} }; [config, protected] array(name(User)) users (UsersRaw); [config, protected] array(name(UserGroup)) user_groups (UserGroupsRaw); [config] Dictionary::Ptr times; [config] array(Value) types; [no_user_view, no_user_modify] int type_filter_real (TypeFilter); [config] array(Value) states; [no_user_view, no_user_modify] int state_filter_real (StateFilter); [config, protected, required, navigation(host)] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; [config, protected, navigation(service)] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetHostName()); return host->GetServiceByShortName(GetServiceName()); }}} }; [state, no_user_modify] Array::Ptr notified_problem_users { default {{{ return new Array(); }}} }; [state, no_user_modify] bool no_more_notifications { default {{{ return false; }}} }; [state] Timestamp last_notification; [state] Timestamp next_notification; [state] int notification_number; [state] Timestamp last_problem_notification; [config, navigation] name(Endpoint) command_endpoint (CommandEndpointRaw) { navigate {{{ return Endpoint::GetByName(GetCommandEndpointRaw()); }}} }; }; validator Notification { Dictionary times { Number begin; Number end; }; }; } icinga2-2.8.1/lib/icinga/notificationcommand.cpp000066400000000000000000000042411322762156600216020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/notificationcommand.hpp" #include "icinga/notificationcommand.tcpp" using namespace icinga; REGISTER_TYPE(NotificationCommand); Dictionary::Ptr NotificationCommand::Execute(const Notification::Ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type, const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { std::vector arguments; arguments.push_back(notification); arguments.push_back(user); arguments.push_back(cr); arguments.push_back(type); arguments.push_back(author); arguments.push_back(comment); arguments.push_back(resolvedMacros); arguments.push_back(useResolvedMacros); return GetExecute()->Invoke(arguments); } icinga2-2.8.1/lib/icinga/notificationcommand.hpp000066400000000000000000000042431322762156600216110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NOTIFICATIONCOMMAND_H #define NOTIFICATIONCOMMAND_H #include "icinga/notificationcommand.thpp" #include "icinga/notification.hpp" namespace icinga { class Notification; /** * A notification command. * * @ingroup icinga */ class I2_ICINGA_API NotificationCommand : public ObjectImpl { public: DECLARE_OBJECT(NotificationCommand); DECLARE_OBJECTNAME(NotificationCommand); virtual Dictionary::Ptr Execute(const intrusive_ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type, const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), bool useResolvedMacros = false); }; } #endif /* NOTIFICATIONCOMMAND_H */ icinga2-2.8.1/lib/icinga/notificationcommand.ti000066400000000000000000000030221322762156600214300ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/command.hpp" library icinga; namespace icinga { class NotificationCommand : Command { }; } icinga2-2.8.1/lib/icinga/objectutils.cpp000066400000000000000000000062611322762156600201100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/objectutils.hpp" #include "icinga/host.hpp" #include "icinga/user.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/hostgroup.hpp" #include "icinga/servicegroup.hpp" #include "icinga/usergroup.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(System, get_host, &Host::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_service, &ObjectUtils::GetService, "host:name"); REGISTER_SCRIPTFUNCTION_NS(System, get_services, &ObjectUtils::GetServices, "host"); REGISTER_SCRIPTFUNCTION_NS(System, get_user, &User::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_check_command, &CheckCommand::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_event_command, &EventCommand::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_notification_command, &NotificationCommand::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_host_group, &HostGroup::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_service_group, &ServiceGroup::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_user_group, &UserGroup::GetByName, "name"); REGISTER_SCRIPTFUNCTION_NS(System, get_time_period, &TimePeriod::GetByName, "name"); Service::Ptr ObjectUtils::GetService(const Value& host, const String& name) { Host::Ptr hostObj; if (host.IsObjectType()) hostObj = host; else hostObj = Host::GetByName(host); if (!hostObj) return Service::Ptr(); return hostObj->GetServiceByShortName(name); } Array::Ptr ObjectUtils::GetServices(const Value& host) { Host::Ptr hostObj; if (host.IsObjectType()) hostObj = host; else hostObj = Host::GetByName(host); if (!hostObj) return Array::Ptr(); return Array::FromVector(hostObj->GetServices()); } icinga2-2.8.1/lib/icinga/objectutils.hpp000066400000000000000000000035231322762156600201130ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTUTILS_H #define OBJECTUTILS_H #include "base/i2-base.hpp" #include "base/string.hpp" #include "base/array.hpp" #include "icinga/service.hpp" namespace icinga { /** * @ingroup icinga */ class I2_ICINGA_API ObjectUtils { public: static Service::Ptr GetService(const Value& host, const String& name); static Array::Ptr GetServices(const Value& host); private: ObjectUtils(void); }; } #endif /* OBJECTUTILS_H */ icinga2-2.8.1/lib/icinga/pluginutility.cpp000066400000000000000000000137001322762156600204770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/pluginutility.hpp" #include "icinga/macroprocessor.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/convert.hpp" #include "base/process.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" #include #include #include using namespace icinga; void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, const boost::function& callback) { Value raw_command = commandObj->GetCommandLine(); Dictionary::Ptr raw_arguments = commandObj->GetArguments(); Value command; try { command = MacroProcessor::ResolveArguments(raw_command, raw_arguments, macroResolvers, cr, resolvedMacros, useResolvedMacros); } catch (const std::exception& ex) { String message = DiagnosticInformation(ex); Log(LogWarning, "PluginUtility", message); if (callback) { ProcessResult pr; pr.PID = -1; pr.ExecutionStart = Utility::GetTime(); pr.ExecutionEnd = pr.ExecutionStart; pr.ExitStatus = 3; /* Unknown */ pr.Output = message; callback(Empty, pr); } return; } Dictionary::Ptr envMacros = new Dictionary(); Dictionary::Ptr env = commandObj->GetEnv(); if (env) { ObjectLock olock(env); for (const Dictionary::Pair& kv : env) { String name = kv.second; Value value = MacroProcessor::ResolveMacros(name, macroResolvers, cr, NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); if (value.IsObjectType()) value = Utility::Join(value, ';'); envMacros->Set(kv.first, value); } } if (resolvedMacros && !useResolvedMacros) return; Process::Ptr process = new Process(Process::PrepareCommand(command), envMacros); if (checkable->GetCheckTimeout().IsEmpty()) process->SetTimeout(commandObj->GetTimeout()); else process->SetTimeout(checkable->GetCheckTimeout()); process->SetAdjustPriority(true); process->Run(boost::bind(callback, command, _1)); } ServiceState PluginUtility::ExitStatusToState(int exitStatus) { switch (exitStatus) { case 0: return ServiceOK; case 1: return ServiceWarning; case 2: return ServiceCritical; default: return ServiceUnknown; } } std::pair PluginUtility::ParseCheckOutput(const String& output) { String text; String perfdata; std::vector lines; boost::algorithm::split(lines, output, boost::is_any_of("\r\n")); for (const String& line : lines) { size_t delim = line.FindFirstOf("|"); if (!text.IsEmpty()) text += "\n"; if (delim != String::NPos) { text += line.SubStr(0, delim); if (!perfdata.IsEmpty()) perfdata += " "; perfdata += line.SubStr(delim + 1, line.GetLength()); } else { text += line; } } boost::algorithm::trim(perfdata); return std::make_pair(text, perfdata); } Array::Ptr PluginUtility::SplitPerfdata(const String& perfdata) { Array::Ptr result = new Array(); size_t begin = 0; String multi_prefix; for (;;) { size_t eqp = perfdata.FindFirstOf('=', begin); if (eqp == String::NPos) break; String label = perfdata.SubStr(begin, eqp - begin); if (label.GetLength() > 2 && label[0] == '\'' && label[label.GetLength() - 1] == '\'') label = label.SubStr(1, label.GetLength() - 2); size_t multi_index = label.RFind("::"); if (multi_index != String::NPos) multi_prefix = ""; size_t spq = perfdata.FindFirstOf(' ', eqp); if (spq == String::NPos) spq = perfdata.GetLength(); String value = perfdata.SubStr(eqp + 1, spq - eqp - 1); if (!multi_prefix.IsEmpty()) label = multi_prefix + "::" + label; String pdv; if (label.FindFirstOf(" ") != String::NPos) pdv = "'" + label + "'=" + value; else pdv = label + "=" + value; result->Add(pdv); if (multi_index != String::NPos) multi_prefix = label.SubStr(0, multi_index); begin = spq + 1; } return result; } String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata) { if (!perfdata) return ""; std::ostringstream result; ObjectLock olock(perfdata); bool first = true; for (const Value& pdv : perfdata) { if (!first) result << " "; else first = false; if (pdv.IsObjectType()) result << static_cast(pdv)->Format(); else result << pdv; } return result.str(); } icinga2-2.8.1/lib/icinga/pluginutility.hpp000066400000000000000000000047531322762156600205140ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PLUGINUTILITY_H #define PLUGINUTILITY_H #include "icinga/i2-icinga.hpp" #include "icinga/checkable.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include namespace icinga { struct ProcessResult; /** * Utility functions for plugin-based checks. * * @ingroup icinga */ class I2_ICINGA_API PluginUtility { public: static void ExecuteCommand(const Command::Ptr& commandObj, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, const boost::function& callback = boost::function()); static ServiceState ExitStatusToState(int exitStatus); static std::pair ParseCheckOutput(const String& output); static Array::Ptr SplitPerfdata(const String& perfdata); static String FormatPerfdata(const Array::Ptr& perfdata); private: PluginUtility(void); }; } #endif /* PLUGINUTILITY_H */ icinga2-2.8.1/lib/icinga/scheduleddowntime-apply.cpp000066400000000000000000000136311322762156600224120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/scheduleddowntime.hpp" #include "icinga/service.hpp" #include "config/configitembuilder.hpp" #include "config/applyrule.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/exception.hpp" using namespace icinga; INITIALIZE_ONCE([]() { std::vector targets; targets.push_back("Host"); targets.push_back("Service"); ApplyRule::RegisterType("ScheduledDowntime", targets); }); bool ScheduledDowntime::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule) { if (!rule.EvaluateFilter(frame)) return false; DebugInfo di = rule.GetDebugInfo(); #ifdef _DEBUG Log(LogDebug, "ScheduledDowntime") << "Applying scheduled downtime '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di; #endif /* _DEBUG */ ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(di); builder->SetType(ScheduledDowntime::TypeInstance); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di)); if (service) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di)); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "zone"), OpSetLiteral, MakeLiteral(zone), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "package"), OpSetLiteral, MakeLiteral(rule.GetPackage()), di)); builder->AddExpression(new OwnedExpression(rule.GetExpression())); builder->AddExpression(new ImportDefaultTemplatesExpression()); ConfigItem::Ptr downtimeItem = builder->Compile(); downtimeItem->Register(); return true; } bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule) { DebugInfo di = rule.GetDebugInfo(); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); ScriptFrame frame; if (rule.GetScope()) rule.GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); if (service) frame.Locals->Set("service", service); Value vinstances; if (rule.GetFTerm()) { try { vinstances = rule.GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } } else { Array::Ptr instances = new Array(); instances->Add(""); vinstances = instances; } bool match = false; if (vinstances.IsObjectType()) { if (!rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { String name = rule.GetName(); if (!rule.GetFKVar().IsEmpty()) { frame.Locals->Set(rule.GetFKVar(), instance); name += instance; } if (EvaluateApplyRuleInstance(checkable, name, frame, rule)) match = true; } } else if (vinstances.IsObjectType()) { if (rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; for (const String& key : dict->GetKeys()) { frame.Locals->Set(rule.GetFKVar(), key); frame.Locals->Set(rule.GetFVVar(), dict->Get(key)); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule)) match = true; } } return match; } void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("ScheduledDowntime")) { if (rule.GetTargetType() != "Host") continue; if (EvaluateApplyRule(host, rule)) rule.AddMatch(); } } void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (ApplyRule& rule : ApplyRule::GetRules("ScheduledDowntime")) { if (rule.GetTargetType() != "Service") continue; if (EvaluateApplyRule(service, rule)) rule.AddMatch(); } } icinga2-2.8.1/lib/icinga/scheduleddowntime.cpp000066400000000000000000000161031322762156600212640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/scheduleddowntime.hpp" #include "icinga/scheduleddowntime.tcpp" #include "icinga/legacytimeperiod.hpp" #include "icinga/downtime.hpp" #include "icinga/service.hpp" #include "base/timer.hpp" #include "base/configtype.hpp" #include "base/initialize.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include #include using namespace icinga; REGISTER_TYPE(ScheduledDowntime); INITIALIZE_ONCE(&ScheduledDowntime::StaticInitialize); static Timer::Ptr l_Timer; String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { ScheduledDowntime::Ptr downtime = dynamic_pointer_cast(context); if (!downtime) return ""; String name = downtime->GetHostName(); if (!downtime->GetServiceName().IsEmpty()) name += "!" + downtime->GetServiceName(); name += "!" + shortName; return name; } Dictionary::Ptr ScheduledDowntimeNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid ScheduledDowntime name.")); Dictionary::Ptr result = new Dictionary(); result->Set("host_name", tokens[0]); if (tokens.size() > 2) { result->Set("service_name", tokens[1]); result->Set("name", tokens[2]); } else { result->Set("name", tokens[1]); } return result; } void ScheduledDowntime::StaticInitialize(void) { l_Timer = new Timer(); l_Timer->SetInterval(60); l_Timer->OnTimerExpired.connect(boost::bind(&ScheduledDowntime::TimerProc)); l_Timer->Start(); } void ScheduledDowntime::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); if (!GetCheckable()) BOOST_THROW_EXCEPTION(ScriptError("ScheduledDowntime '" + GetName() + "' references a host/service which doesn't exist.", GetDebugInfo())); } void ScheduledDowntime::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Utility::QueueAsyncCallback(boost::bind(&ScheduledDowntime::CreateNextDowntime, this)); } void ScheduledDowntime::TimerProc(void) { for (const ScheduledDowntime::Ptr& sd : ConfigType::GetObjectsByType()) { if (sd->IsActive()) sd->CreateNextDowntime(); } } Checkable::Ptr ScheduledDowntime::GetCheckable(void) const { Host::Ptr host = Host::GetByName(GetHostName()); if (GetServiceName().IsEmpty()) return host; else return host->GetServiceByShortName(GetServiceName()); } std::pair ScheduledDowntime::FindNextSegment(void) { time_t refts = Utility::GetTime(); tm reference = Utility::LocalTime(refts); Log(LogDebug, "ScheduledDowntime") << "Finding next scheduled downtime segment for time " << refts; Dictionary::Ptr ranges = GetRanges(); if (!ranges) return std::make_pair(0, 0); Array::Ptr segments = new Array(); Dictionary::Ptr bestSegment; double bestBegin; double now = Utility::GetTime(); ObjectLock olock(ranges); for (const Dictionary::Pair& kv : ranges) { Log(LogDebug, "ScheduledDowntime") << "Evaluating segment: " << kv.first << ": " << kv.second << " at "; Dictionary::Ptr segment = LegacyTimePeriod::FindNextSegment(kv.first, kv.second, &reference); if (!segment) continue; Log(LogDebug, "ScheduledDowntime") << "Considering segment: " << Utility::FormatDateTime("%c", segment->Get("begin")) << " -> " << Utility::FormatDateTime("%c", segment->Get("end")); double begin = segment->Get("begin"); if (begin < now) continue; if (!bestSegment || begin < bestBegin) { bestSegment = segment; bestBegin = begin; } } if (bestSegment) return std::make_pair(bestSegment->Get("begin"), bestSegment->Get("end")); else return std::make_pair(0, 0); } void ScheduledDowntime::CreateNextDowntime(void) { for (const Downtime::Ptr& downtime : GetCheckable()->GetDowntimes()) { if (downtime->GetScheduledBy() != GetName() || downtime->GetStartTime() < Utility::GetTime()) continue; /* We've found a downtime that is owned by us and that hasn't started yet - we're done. */ return; } std::pair segment = FindNextSegment(); if (segment.first == 0 && segment.second == 0) { tm reference = Utility::LocalTime(Utility::GetTime()); reference.tm_mday++; reference.tm_hour = 0; reference.tm_min = 0; reference.tm_sec = 0; return; } Downtime::AddDowntime(GetCheckable(), GetAuthor(), GetComment(), segment.first, segment.second, GetFixed(), String(), GetDuration(), GetName(), GetName()); } void ScheduledDowntime::ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateRanges(value, utils); if (!value) return; /* create a fake time environment to validate the definitions */ time_t refts = Utility::GetTime(); tm reference = Utility::LocalTime(refts); Array::Ptr segments = new Array(); ObjectLock olock(value); for (const Dictionary::Pair& kv : value) { try { tm begin_tm, end_tm; int stride; LegacyTimePeriod::ParseTimeRange(kv.first, &begin_tm, &end_tm, &stride, &reference); } catch (const std::exception& ex) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time specification '" + kv.first + "': " + ex.what())); } try { LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments); } catch (const std::exception& ex) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time range definition '" + kv.second + "': " + ex.what())); } } } icinga2-2.8.1/lib/icinga/scheduleddowntime.hpp000066400000000000000000000053201322762156600212700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SCHEDULEDDOWNTIME_H #define SCHEDULEDDOWNTIME_H #include "icinga/i2-icinga.hpp" #include "icinga/scheduleddowntime.thpp" #include "icinga/checkable.hpp" #include namespace icinga { class ApplyRule; struct ScriptFrame; class Host; class Service; /** * An Icinga scheduled downtime specification. * * @ingroup icinga */ class I2_ICINGA_API ScheduledDowntime : public ObjectImpl { public: DECLARE_OBJECT(ScheduledDowntime); DECLARE_OBJECTNAME(ScheduledDowntime); static void StaticInitialize(void); Checkable::Ptr GetCheckable(void) const; static void EvaluateApplyRules(const intrusive_ptr& host); static void EvaluateApplyRules(const intrusive_ptr& service); virtual void ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) override; protected: virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; private: static void TimerProc(void); std::pair FindNextSegment(void); void CreateNextDowntime(void); static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule); static bool EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule); }; } #endif /* SCHEDULEDDOWNTIME_H */ icinga2-2.8.1/lib/icinga/scheduleddowntime.ti000066400000000000000000000056131322762156600211220ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #impl_include "icinga/service.hpp" library icinga; namespace icinga { code {{{ class I2_ICINGA_API ScheduledDowntimeNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class ScheduledDowntime : CustomVarObject < ScheduledDowntimeNameComposer { load_after Host; load_after Service; [config, protected, required, navigation(host)] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; [config, protected, navigation(service)] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); DependencyGraph::RemoveDependency(this, service.get()); } if (!newValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue); DependencyGraph::AddDependency(this, service.get()); } }}} navigate {{{ if (GetServiceName().IsEmpty()) return Service::Ptr(); Host::Ptr host = Host::GetByName(GetHostName()); return host->GetServiceByShortName(GetServiceName()); }}} }; [config, required] String author; [config, required] String comment; [config] double duration; [config] bool fixed { default {{{ return true; }}} }; [config, required] Dictionary::Ptr ranges; }; validator ScheduledDowntime { Dictionary ranges { String "*"; }; }; } icinga2-2.8.1/lib/icinga/service-apply.cpp000066400000000000000000000121151322762156600203370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/service.hpp" #include "config/configitembuilder.hpp" #include "config/applyrule.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" #include "base/exception.hpp" using namespace icinga; INITIALIZE_ONCE([]() { std::vector targets; targets.push_back("Host"); ApplyRule::RegisterType("Service", targets); }); bool Service::EvaluateApplyRuleInstance(const Host::Ptr& host, const String& name, ScriptFrame& frame, const ApplyRule& rule) { if (!rule.EvaluateFilter(frame)) return false; DebugInfo di = rule.GetDebugInfo(); #ifdef _DEBUG Log(LogDebug, "Service") << "Applying service '" << name << "' to host '" << host->GetName() << "' for rule " << di; #endif /* _DEBUG */ ConfigItemBuilder::Ptr builder = new ConfigItemBuilder(di); builder->SetType(Service::TypeInstance); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); builder->SetIgnoreOnError(rule.GetIgnoreOnError()); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "name"), OpSetLiteral, MakeLiteral(name), di)); String zone = host->GetZoneName(); if (!zone.IsEmpty()) builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "zone"), OpSetLiteral, MakeLiteral(zone), di)); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "package"), OpSetLiteral, MakeLiteral(rule.GetPackage()), di)); builder->AddExpression(new OwnedExpression(rule.GetExpression())); builder->AddExpression(new ImportDefaultTemplatesExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); serviceItem->Register(); return true; } bool Service::EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule) { DebugInfo di = rule.GetDebugInfo(); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); ScriptFrame frame; if (rule.GetScope()) rule.GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); Value vinstances; if (rule.GetFTerm()) { try { vinstances = rule.GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } } else { Array::Ptr instances = new Array(); instances->Add(""); vinstances = instances; } bool match = false; if (vinstances.IsObjectType()) { if (!rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { String name = rule.GetName(); if (!rule.GetFKVar().IsEmpty()) { frame.Locals->Set(rule.GetFKVar(), instance); name += instance; } if (EvaluateApplyRuleInstance(host, name, frame, rule)) match = true; } } else if (vinstances.IsObjectType()) { if (rule.GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; for (const String& key : dict->GetKeys()) { frame.Locals->Set(rule.GetFKVar(), key); frame.Locals->Set(rule.GetFVVar(), dict->Get(key)); if (EvaluateApplyRuleInstance(host, rule.GetName() + key, frame, rule)) match = true; } } return match; } void Service::EvaluateApplyRules(const Host::Ptr& host) { for (ApplyRule& rule : ApplyRule::GetRules("Service")) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); if (EvaluateApplyRule(host, rule)) rule.AddMatch(); } } icinga2-2.8.1/lib/icinga/service.cpp000066400000000000000000000167241322762156600172260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/service.hpp" #include "icinga/service.tcpp" #include "icinga/servicegroup.hpp" #include "icinga/scheduleddowntime.hpp" #include "icinga/pluginutility.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include #include using namespace icinga; REGISTER_TYPE(Service); String ServiceNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Service::Ptr service = dynamic_pointer_cast(context); if (!service) return ""; return service->GetHostName() + "!" + shortName; } Dictionary::Ptr ServiceNameComposer::ParseName(const String& name) const { std::vector tokens; boost::algorithm::split(tokens, name, boost::is_any_of("!")); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Service name.")); Dictionary::Ptr result = new Dictionary(); result->Set("host_name", tokens[0]); result->Set("name", tokens[1]); return result; } void Service::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); String zoneName = GetZoneName(); if (!zoneName.IsEmpty()) { Zone::Ptr zone = Zone::GetByName(zoneName); if (zone && zone->IsGlobal()) BOOST_THROW_EXCEPTION(std::invalid_argument("Service '" + GetName() + "' cannot be put into global zone '" + zone->GetName() + "'.")); } m_Host = Host::GetByName(GetHostName()); if (m_Host) m_Host->AddService(this); ServiceGroup::EvaluateObjectRules(this); Array::Ptr groups = GetGroups(); if (groups) { groups = groups->ShallowClone(); ObjectLock olock(groups); for (const String& name : groups) { ServiceGroup::Ptr sg = ServiceGroup::GetByName(name); if (sg) sg->ResolveGroupMembership(this, true); } } } void Service::CreateChildObjects(const Type::Ptr& childType) { if (childType == ScheduledDowntime::TypeInstance) ScheduledDowntime::EvaluateApplyRules(this); if (childType == Notification::TypeInstance) Notification::EvaluateApplyRules(this); if (childType == Dependency::TypeInstance) Dependency::EvaluateApplyRules(this); } Service::Ptr Service::GetByNamePair(const String& hostName, const String& serviceName) { if (!hostName.IsEmpty()) { Host::Ptr host = Host::GetByName(hostName); if (!host) return Service::Ptr(); return host->GetServiceByShortName(serviceName); } else { return Service::GetByName(serviceName); } } Host::Ptr Service::GetHost(void) const { return m_Host; } /* keep in sync with Host::GetSeverity() */ int Service::GetSeverity(void) const { int severity = 0; ObjectLock olock(this); ServiceState state = GetStateRaw(); if (!HasBeenChecked()) severity |= SeverityFlagPending; else if (state == ServiceWarning) severity |= SeverityFlagWarning; else if (state == ServiceUnknown) severity |= SeverityFlagUnknown; else if (state == ServiceCritical) severity |= SeverityFlagCritical; /* TODO: Add host reachability and handled */ if (IsInDowntime()) severity |= SeverityFlagDowntime; else if (IsAcknowledged()) severity |= SeverityFlagAcknowledgement; else severity |= SeverityFlagUnhandled; olock.Unlock(); return severity; } bool Service::IsStateOK(ServiceState state) { return state == ServiceOK; } void Service::SaveLastState(ServiceState state, double timestamp) { if (state == ServiceOK) SetLastStateOK(timestamp); else if (state == ServiceWarning) SetLastStateWarning(timestamp); else if (state == ServiceCritical) SetLastStateCritical(timestamp); else if (state == ServiceUnknown) SetLastStateUnknown(timestamp); } ServiceState Service::StateFromString(const String& state) { if (state == "OK") return ServiceOK; else if (state == "WARNING") return ServiceWarning; else if (state == "CRITICAL") return ServiceCritical; else return ServiceUnknown; } String Service::StateToString(ServiceState state) { switch (state) { case ServiceOK: return "OK"; case ServiceWarning: return "WARNING"; case ServiceCritical: return "CRITICAL"; case ServiceUnknown: default: return "UNKNOWN"; } } StateType Service::StateTypeFromString(const String& type) { if (type == "SOFT") return StateTypeSoft; else return StateTypeHard; } String Service::StateTypeToString(StateType type) { if (type == StateTypeSoft) return "SOFT"; else return "HARD"; } bool Service::ResolveMacro(const String& macro, const CheckResult::Ptr& cr, Value *result) const { if (macro == "state") { *result = StateToString(GetState()); return true; } else if (macro == "state_id") { *result = GetState(); return true; } else if (macro == "state_type") { *result = StateTypeToString(GetStateType()); return true; } else if (macro == "last_state") { *result = StateToString(GetLastState()); return true; } else if (macro == "last_state_id") { *result = GetLastState(); return true; } else if (macro == "last_state_type") { *result = StateTypeToString(GetLastStateType()); return true; } else if (macro == "last_state_change") { *result = static_cast(GetLastStateChange()); return true; } else if (macro == "downtime_depth") { *result = GetDowntimeDepth(); return true; } else if (macro == "duration_sec") { *result = Utility::GetTime() - GetLastStateChange(); return true; } if (cr) { if (macro == "latency") { *result = cr->CalculateLatency(); return true; } else if (macro == "execution_time") { *result = cr->CalculateExecutionTime(); return true; } else if (macro == "output") { *result = cr->GetOutput(); return true; } else if (macro == "perfdata") { *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData()); return true; } else if (macro == "check_source") { *result = cr->GetCheckSource(); return true; } } return false; } boost::tuple icinga::GetHostService(const Checkable::Ptr& checkable) { Service::Ptr service = dynamic_pointer_cast(checkable); if (service) return boost::make_tuple(service->GetHost(), service); else return boost::make_tuple(static_pointer_cast(checkable), Service::Ptr()); } icinga2-2.8.1/lib/icinga/service.hpp000066400000000000000000000057171322762156600172330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICE_H #define SERVICE_H #include "icinga/i2-icinga.hpp" #include "icinga/service.thpp" #include "icinga/macroresolver.hpp" #include "icinga/host.hpp" namespace icinga { /** * An Icinga service. * * @ingroup icinga */ class I2_ICINGA_API Service : public ObjectImpl, public MacroResolver { public: DECLARE_OBJECT(Service); DECLARE_OBJECTNAME(Service); static Service::Ptr GetByNamePair(const String& hostName, const String& serviceName); virtual Host::Ptr GetHost(void) const override; virtual int GetSeverity(void) const override; virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, Value *result) const override; virtual bool IsStateOK(ServiceState state) override; virtual void SaveLastState(ServiceState state, double timestamp) override; static ServiceState StateFromString(const String& state); static String StateToString(ServiceState state); static StateType StateTypeFromString(const String& state); static String StateTypeToString(StateType state); static void EvaluateApplyRules(const Host::Ptr& host); protected: virtual void OnAllConfigLoaded(void) override; virtual void CreateChildObjects(const Type::Ptr& childType) override; private: Host::Ptr m_Host; static bool EvaluateApplyRuleInstance(const Host::Ptr& host, const String& name, ScriptFrame& frame, const ApplyRule& rule); static bool EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule); }; I2_ICINGA_API boost::tuple GetHostService(const Checkable::Ptr& checkable); } #endif /* SERVICE_H */ icinga2-2.8.1/lib/icinga/service.ti000066400000000000000000000055031322762156600170510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/checkable.hpp" #include "icinga/host.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/customvarobject.hpp" #impl_include "icinga/servicegroup.hpp" library icinga; namespace icinga { code {{{ class I2_ICINGA_API ServiceNameComposer : public NameComposer { public: virtual String MakeName(const String& shortName, const Object::Ptr& context) const; virtual Dictionary::Ptr ParseName(const String& name) const; }; }}} class Service : Checkable < ServiceNameComposer { load_after ApiListener; load_after Endpoint; load_after Host; load_after Zone; [config, no_user_modify, required] array(name(ServiceGroup)) groups { default {{{ return new Array(); }}} }; [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetShortName(); else return m_DisplayName; }}} }; [config, required] name(Host) host_name; [no_storage, navigation] Host::Ptr host { get; navigate {{{ return GetHost(); }}} }; [enum, no_storage] ServiceState "state" { get {{{ return GetStateRaw(); }}} }; [enum, no_storage] ServiceState last_state { get {{{ return GetLastStateRaw(); }}} }; [enum, no_storage] ServiceState last_hard_state { get {{{ return GetLastHardStateRaw(); }}} }; [state] Timestamp last_state_ok (LastStateOK); [state] Timestamp last_state_warning; [state] Timestamp last_state_critical; [state] Timestamp last_state_unknown; }; } icinga2-2.8.1/lib/icinga/servicegroup.cpp000066400000000000000000000077301322762156600203000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/servicegroup.hpp" #include "icinga/servicegroup.tcpp" #include "config/objectrule.hpp" #include "config/configitem.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" using namespace icinga; REGISTER_TYPE(ServiceGroup); INITIALIZE_ONCE([]() { ObjectRule::RegisterType("ServiceGroup"); }); bool ServiceGroup::EvaluateObjectRule(const Service::Ptr& service, const ConfigItem::Ptr& group) { String group_name = group->GetName(); CONTEXT("Evaluating rule for group '" + group_name + "'"); Host::Ptr host = service->GetHost(); ScriptFrame frame; if (group->GetScope()) group->GetScope()->CopyTo(frame.Locals); frame.Locals->Set("host", host); frame.Locals->Set("service", service); if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "ServiceGroup") << "Assigning membership for group '" << group_name << "' to service '" << service->GetName() << "'"; Array::Ptr groups = service->GetGroups(); groups->Add(group_name); return true; } void ServiceGroup::EvaluateObjectRules(const Service::Ptr& service) { CONTEXT("Evaluating group membership for service '" + service->GetName() + "'"); for (const ConfigItem::Ptr& group : ConfigItem::GetItems(ServiceGroup::TypeInstance)) { if (!group->GetFilter()) continue; EvaluateObjectRule(service, group); } } std::set ServiceGroup::GetMembers(void) const { boost::mutex::scoped_lock lock(m_ServiceGroupMutex); return m_Members; } void ServiceGroup::AddMember(const Service::Ptr& service) { service->AddGroup(GetName()); boost::mutex::scoped_lock lock(m_ServiceGroupMutex); m_Members.insert(service); } void ServiceGroup::RemoveMember(const Service::Ptr& service) { boost::mutex::scoped_lock lock(m_ServiceGroupMutex); m_Members.erase(service); } bool ServiceGroup::ResolveGroupMembership(const Service::Ptr& service, bool add, int rstack) { if (add && rstack > 20) { Log(LogWarning, "ServiceGroup") << "Too many nested groups for group '" << GetName() << "': Service '" << service->GetName() << "' membership assignment failed."; return false; } Array::Ptr groups = GetGroups(); if (groups && groups->GetLength() > 0) { ObjectLock olock(groups); for (const String& name : groups) { ServiceGroup::Ptr group = ServiceGroup::GetByName(name); if (group && !group->ResolveGroupMembership(service, add, rstack + 1)) return false; } } if (add) AddMember(service); else RemoveMember(service); return true; } icinga2-2.8.1/lib/icinga/servicegroup.hpp000066400000000000000000000044631322762156600203050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICEGROUP_H #define SERVICEGROUP_H #include "icinga/i2-icinga.hpp" #include "icinga/servicegroup.thpp" #include "icinga/service.hpp" namespace icinga { class ConfigItem; /** * An Icinga service group. * * @ingroup icinga */ class I2_ICINGA_API ServiceGroup : public ObjectImpl { public: DECLARE_OBJECT(ServiceGroup); DECLARE_OBJECTNAME(ServiceGroup); std::set GetMembers(void) const; void AddMember(const Service::Ptr& service); void RemoveMember(const Service::Ptr& service); bool ResolveGroupMembership(const Service::Ptr& service, bool add = true, int rstack = 0); static void EvaluateObjectRules(const Service::Ptr& service); private: mutable boost::mutex m_ServiceGroupMutex; std::set m_Members; static bool EvaluateObjectRule(const Service::Ptr& service, const intrusive_ptr& group); }; } #endif /* SERVICEGROUP_H */ icinga2-2.8.1/lib/icinga/servicegroup.ti000066400000000000000000000034651322762156600201330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" library icinga; namespace icinga { class ServiceGroup : CustomVarObject { [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config, no_user_modify] array(name(ServiceGroup)) groups; [config] String notes; [config] String notes_url; [config] String action_url; }; } icinga2-2.8.1/lib/icinga/timeperiod.cpp000066400000000000000000000266201322762156600177230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/timeperiod.hpp" #include "icinga/timeperiod.tcpp" #include "icinga/legacytimeperiod.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" #include "base/logger.hpp" #include "base/timer.hpp" #include "base/utility.hpp" using namespace icinga; REGISTER_TYPE(TimePeriod); static Timer::Ptr l_UpdateTimer; INITIALIZE_ONCE(&TimePeriod::StaticInitialize); void TimePeriod::StaticInitialize(void) { l_UpdateTimer = new Timer(); l_UpdateTimer->SetInterval(300); l_UpdateTimer->OnTimerExpired.connect(boost::bind(&TimePeriod::UpdateTimerHandler)); l_UpdateTimer->Start(); } void TimePeriod::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); /* Pre-fill the time period for the next 24 hours. */ double now = Utility::GetTime(); UpdateRegion(now, now + 24 * 3600, true); #ifdef _DEBUG Dump(); #endif /* _DEBUG */ } void TimePeriod::AddSegment(double begin, double end) { ASSERT(OwnsLock()); Log(LogDebug, "TimePeriod") << "Adding segment '" << Utility::FormatDateTime("%c", begin) << "' <-> '" << Utility::FormatDateTime("%c", end) << "' to TimePeriod '" << GetName() << "'"; if (GetValidBegin().IsEmpty() || begin < GetValidBegin()) SetValidBegin(begin); if (GetValidEnd().IsEmpty() || end > GetValidEnd()) SetValidEnd(end); Array::Ptr segments = GetSegments(); if (segments) { /* Try to merge the new segment into an existing segment. */ ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { if (segment->Get("begin") <= begin && segment->Get("end") >= end) return; /* New segment is fully contained in this segment. */ if (segment->Get("begin") >= begin && segment->Get("end") <= end) { segment->Set("begin", begin); segment->Set("end", end); /* Extend an existing segment to both sides */ return; } if (segment->Get("end") >= begin && segment->Get("end") <= end) { segment->Set("end", end); /* Extend an existing segment to right. */ return; } if (segment->Get("begin") >= begin && segment->Get("begin") <= end) { segment->Set("begin", begin); /* Extend an existing segment to left. */ return; } } } /* Create new segment if we weren't able to merge this into an existing segment. */ Dictionary::Ptr segment = new Dictionary(); segment->Set("begin", begin); segment->Set("end", end); if (!segments) { segments = new Array(); SetSegments(segments); } segments->Add(segment); } void TimePeriod::AddSegment(const Dictionary::Ptr& segment) { AddSegment(segment->Get("begin"), segment->Get("end")); } void TimePeriod::RemoveSegment(double begin, double end) { ASSERT(OwnsLock()); Log(LogDebug, "TimePeriod") << "Removing segment '" << Utility::FormatDateTime("%c", begin) << "' <-> '" << Utility::FormatDateTime("%c", end) << "' from TimePeriod '" << GetName() << "'"; if (GetValidBegin().IsEmpty() || begin < GetValidBegin()) SetValidBegin(begin); if (GetValidEnd().IsEmpty() || end > GetValidEnd()) SetValidEnd(end); Array::Ptr segments = GetSegments(); if (!segments) return; Array::Ptr newSegments = new Array(); /* Try to split or adjust an existing segment. */ ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { /* Fully contained in the specified range? */ if (segment->Get("begin") >= begin && segment->Get("end") <= end) continue; /* Not overlapping at all? */ if (segment->Get("end") < begin || segment->Get("begin") > end) { newSegments->Add(segment); continue; } /* Cut between */ if (segment->Get("begin") < begin && segment->Get("end") > end) { Dictionary::Ptr firstsegment = new Dictionary(); firstsegment->Set("begin", segment->Get("begin")); firstsegment->Set("end", begin); Dictionary::Ptr secondsegment = new Dictionary(); secondsegment->Set("begin", end); secondsegment->Set("end", segment->Get("end")); newSegments->Add(firstsegment); newSegments->Add(secondsegment); continue; } /* Adjust the begin/end timestamps so as to not overlap with the specified range. */ if (segment->Get("begin") > begin && segment->Get("begin") < end) segment->Set("begin", end); if (segment->Get("end") > begin && segment->Get("end") < end) segment->Set("end", begin); newSegments->Add(segment); } SetSegments(newSegments); #ifdef _DEBUG Dump(); #endif /* _DEBUG */ } void TimePeriod::RemoveSegment(const Dictionary::Ptr& segment) { RemoveSegment(segment->Get("begin"), segment->Get("end")); } void TimePeriod::PurgeSegments(double end) { ASSERT(OwnsLock()); Log(LogDebug, "TimePeriod") << "Purging segments older than '" << Utility::FormatDateTime("%c", end) << "' from TimePeriod '" << GetName() << "'"; if (GetValidBegin().IsEmpty() || end < GetValidBegin()) return; SetValidBegin(end); Array::Ptr segments = GetSegments(); if (!segments) return; Array::Ptr newSegments = new Array(); /* Remove old segments. */ ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { if (segment->Get("end") >= end) newSegments->Add(segment); } SetSegments(newSegments); } void TimePeriod::Merge(const TimePeriod::Ptr& timeperiod, bool include) { Log(LogDebug, "TimePeriod") << "Merge TimePeriod '" << GetName() << "' with '" << timeperiod->GetName() << "' " << "Method: " << (include ? "include" : "exclude"); Array::Ptr segments = timeperiod->GetSegments(); if (segments) { ObjectLock dlock(segments); ObjectLock ilock(this); for (const Dictionary::Ptr& segment : segments) { include ? AddSegment(segment) : RemoveSegment(segment); } } } void TimePeriod::UpdateRegion(double begin, double end, bool clearExisting) { if (!clearExisting) { if (begin < GetValidEnd()) begin = GetValidEnd(); if (end < GetValidEnd()) return; } std::vector arguments; arguments.push_back(this); arguments.push_back(begin); arguments.push_back(end); Array::Ptr segments = GetUpdate()->Invoke(arguments); { ObjectLock olock(this); RemoveSegment(begin, end); if (segments) { ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { AddSegment(segment); } } } bool preferInclude = GetPreferIncludes(); /* First handle the non preferred timeranges */ Array::Ptr timeranges = preferInclude ? GetExcludes() : GetIncludes(); if (timeranges) { ObjectLock olock(timeranges); for (const String& name : timeranges) { const TimePeriod::Ptr timeperiod = TimePeriod::GetByName(name); if (timeperiod) Merge(timeperiod, !preferInclude); } } /* Preferred timeranges must be handled at the end */ timeranges = preferInclude ? GetIncludes() : GetExcludes(); if (timeranges) { ObjectLock olock(timeranges); for (const String& name : timeranges) { const TimePeriod::Ptr timeperiod = TimePeriod::GetByName(name); if (timeperiod) Merge(timeperiod, preferInclude); } } } bool TimePeriod::GetIsInside(void) const { return IsInside(Utility::GetTime()); } bool TimePeriod::IsInside(double ts) const { ObjectLock olock(this); if (GetValidBegin().IsEmpty() || ts < GetValidBegin() || GetValidEnd().IsEmpty() || ts > GetValidEnd()) return true; /* Assume that all invalid regions are "inside". */ Array::Ptr segments = GetSegments(); if (segments) { ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { if (ts > segment->Get("begin") && ts < segment->Get("end")) return true; } } return false; } double TimePeriod::FindNextTransition(double begin) { ObjectLock olock(this); Array::Ptr segments = GetSegments(); double closestTransition = -1; if (segments) { ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { if (segment->Get("begin") > begin && (segment->Get("begin") < closestTransition || closestTransition == -1)) closestTransition = segment->Get("begin"); if (segment->Get("end") > begin && (segment->Get("end") < closestTransition || closestTransition == -1)) closestTransition = segment->Get("end"); } } return closestTransition; } void TimePeriod::UpdateTimerHandler(void) { double now = Utility::GetTime(); for (const TimePeriod::Ptr& tp : ConfigType::GetObjectsByType()) { if (!tp->IsActive()) continue; double valid_end; { ObjectLock olock(tp); tp->PurgeSegments(now - 3600); valid_end = tp->GetValidEnd(); } tp->UpdateRegion(valid_end, now + 24 * 3600, false); #ifdef _DEBUG tp->Dump(); #endif /* _DEBUG */ } } void TimePeriod::Dump(void) { Array::Ptr segments = GetSegments(); Log(LogDebug, "TimePeriod") << "Dumping TimePeriod '" << GetName() << "'"; Log(LogDebug, "TimePeriod") << "Valid from '" << Utility::FormatDateTime("%c", GetValidBegin()) << "' until '" << Utility::FormatDateTime("%c", GetValidEnd()); if (segments) { ObjectLock dlock(segments); for (const Dictionary::Ptr& segment : segments) { Log(LogDebug, "TimePeriod") << "Segment: " << Utility::FormatDateTime("%c", segment->Get("begin")) << " <-> " << Utility::FormatDateTime("%c", segment->Get("end")); } } Log(LogDebug, "TimePeriod", "---"); } void TimePeriod::ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) { if (!value) return; /* create a fake time environment to validate the definitions */ time_t refts = Utility::GetTime(); tm reference = Utility::LocalTime(refts); Array::Ptr segments = new Array(); ObjectLock olock(value); for (const Dictionary::Pair& kv : value) { try { tm begin_tm, end_tm; int stride; LegacyTimePeriod::ParseTimeRange(kv.first, &begin_tm, &end_tm, &stride, &reference); } catch (const std::exception& ex) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time specification '" + kv.first + "': " + ex.what())); } try { LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments); } catch (const std::exception& ex) { BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time range definition '" + kv.second + "': " + ex.what())); } } } icinga2-2.8.1/lib/icinga/timeperiod.hpp000066400000000000000000000047441322762156600177330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TIMEPERIOD_H #define TIMEPERIOD_H #include "icinga/i2-icinga.hpp" #include "icinga/timeperiod.thpp" namespace icinga { /** * A time period. * * @ingroup icinga */ class I2_ICINGA_API TimePeriod : public ObjectImpl { public: DECLARE_OBJECT(TimePeriod); DECLARE_OBJECTNAME(TimePeriod); static void StaticInitialize(void); virtual void Start(bool runtimeCreated) override; void UpdateRegion(double begin, double end, bool clearExisting); virtual bool GetIsInside(void) const override; bool IsInside(double ts) const; double FindNextTransition(double begin); virtual void ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) override; private: void AddSegment(double s, double end); void AddSegment(const Dictionary::Ptr& segment); void RemoveSegment(double begin, double end); void RemoveSegment(const Dictionary::Ptr& segment); void PurgeSegments(double end); void Merge(const TimePeriod::Ptr& timeperiod, bool include = true); void Dump(void); static void UpdateTimerHandler(void); }; } #endif /* TIMEPERIOD_H */ icinga2-2.8.1/lib/icinga/timeperiod.ti000066400000000000000000000044041322762156600175510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #include "base/function.hpp" library icinga; namespace icinga { class TimePeriod : CustomVarObject { [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config] Dictionary::Ptr ranges; [config, required] Function::Ptr update; [config] bool prefer_includes { default {{{ return true; }}} }; [config, required] array(name(TimePeriod)) excludes { default {{{ return new Array(); }}} }; [config, required] array(name(TimePeriod)) includes { default {{{ return new Array(); }}} }; [state, no_user_modify] Value valid_begin; [state, no_user_modify] Value valid_end; [state, no_user_modify] Array::Ptr segments; [no_storage] bool is_inside { get; }; }; validator TimePeriod { Dictionary ranges { String "*"; }; }; } icinga2-2.8.1/lib/icinga/user.cpp000066400000000000000000000077411322762156600165430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/user.hpp" #include "icinga/user.tcpp" #include "icinga/usergroup.hpp" #include "icinga/notification.hpp" #include "icinga/usergroup.hpp" #include "base/objectlock.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_TYPE(User); void User::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); SetTypeFilter(FilterArrayToInt(GetTypes(), Notification::GetTypeFilterMap(), ~0)); SetStateFilter(FilterArrayToInt(GetStates(), Notification::GetStateFilterMap(), ~0)); } void User::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); UserGroup::EvaluateObjectRules(this); Array::Ptr groups = GetGroups(); if (groups) { groups = groups->ShallowClone(); ObjectLock olock(groups); for (const String& name : groups) { UserGroup::Ptr ug = UserGroup::GetByName(name); if (ug) ug->ResolveGroupMembership(this, true); } } } void User::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); Array::Ptr groups = GetGroups(); if (groups) { ObjectLock olock(groups); for (const String& name : groups) { UserGroup::Ptr ug = UserGroup::GetByName(name); if (ug) ug->ResolveGroupMembership(this, false); } } } void User::AddGroup(const String& name) { boost::mutex::scoped_lock lock(m_UserMutex); Array::Ptr groups = GetGroups(); if (groups && groups->Contains(name)) return; if (!groups) groups = new Array(); groups->Add(name); } TimePeriod::Ptr User::GetPeriod(void) const { return TimePeriod::GetByName(GetPeriodRaw()); } void User::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateStates(value, utils); int filter = FilterArrayToInt(value, Notification::GetStateFilterMap(), 0); if (filter == -1 || (filter & ~(StateFilterUp | StateFilterDown | StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid.")); } void User::ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateTypes(value, utils); int filter = FilterArrayToInt(value, Notification::GetTypeFilterMap(), 0); if (filter == -1 || (filter & ~(NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved | NotificationCustom | NotificationAcknowledgement | NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd)) != 0) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("types"), "Type filter is invalid.")); } icinga2-2.8.1/lib/icinga/user.hpp000066400000000000000000000043611322762156600165430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef USER_H #define USER_H #include "icinga/i2-icinga.hpp" #include "icinga/user.thpp" #include "icinga/timeperiod.hpp" #include "remote/messageorigin.hpp" namespace icinga { /** * A User. * * @ingroup icinga */ class I2_ICINGA_API User : public ObjectImpl { public: DECLARE_OBJECT(User); DECLARE_OBJECTNAME(User); void AddGroup(const String& name); /* Notifications */ TimePeriod::Ptr GetPeriod(void) const; virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override; virtual void ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) override; protected: virtual void Stop(bool runtimeRemoved) override; virtual void OnConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override; private: mutable boost::mutex m_UserMutex; }; } #endif /* USER_H */ icinga2-2.8.1/lib/icinga/user.ti000066400000000000000000000044721322762156600163730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" #include "base/array.hpp" #impl_include "icinga/usergroup.hpp" library icinga; namespace icinga { class User : CustomVarObject { [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config, no_user_modify, required] array(name(UserGroup)) groups { default {{{ return new Array(); }}} }; [config, navigation] name(TimePeriod) period (PeriodRaw) { navigate {{{ return TimePeriod::GetByName(GetPeriodRaw()); }}} }; [config] array(Value) types; [no_user_view, no_user_modify] int type_filter_real (TypeFilter); [config] array(Value) states; [no_user_view, no_user_modify] int state_filter_real (StateFilter); [config] String email; [config] String pager; [config] bool enable_notifications { default {{{ return true; }}} }; [state] Timestamp last_notification; }; } icinga2-2.8.1/lib/icinga/usergroup.cpp000066400000000000000000000074111322762156600176120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/usergroup.hpp" #include "icinga/usergroup.tcpp" #include "config/objectrule.hpp" #include "config/configitem.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" using namespace icinga; REGISTER_TYPE(UserGroup); INITIALIZE_ONCE([]() { ObjectRule::RegisterType("UserGroup"); }); bool UserGroup::EvaluateObjectRule(const User::Ptr& user, const ConfigItem::Ptr& group) { String group_name = group->GetName(); CONTEXT("Evaluating rule for group '" + group_name + "'"); ScriptFrame frame; if (group->GetScope()) group->GetScope()->CopyTo(frame.Locals); frame.Locals->Set("user", user); if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool()) return false; Log(LogDebug, "UserGroup") << "Assigning membership for group '" << group_name << "' to user '" << user->GetName() << "'"; Array::Ptr groups = user->GetGroups(); groups->Add(group_name); return true; } void UserGroup::EvaluateObjectRules(const User::Ptr& user) { CONTEXT("Evaluating group membership for user '" + user->GetName() + "'"); for (const ConfigItem::Ptr& group : ConfigItem::GetItems(UserGroup::TypeInstance)) { if (!group->GetFilter()) continue; EvaluateObjectRule(user, group); } } std::set UserGroup::GetMembers(void) const { boost::mutex::scoped_lock lock(m_UserGroupMutex); return m_Members; } void UserGroup::AddMember(const User::Ptr& user) { user->AddGroup(GetName()); boost::mutex::scoped_lock lock(m_UserGroupMutex); m_Members.insert(user); } void UserGroup::RemoveMember(const User::Ptr& user) { boost::mutex::scoped_lock lock(m_UserGroupMutex); m_Members.erase(user); } bool UserGroup::ResolveGroupMembership(const User::Ptr& user, bool add, int rstack) { if (add && rstack > 20) { Log(LogWarning, "UserGroup") << "Too many nested groups for group '" << GetName() << "': User '" << user->GetName() << "' membership assignment failed."; return false; } Array::Ptr groups = GetGroups(); if (groups && groups->GetLength() > 0) { ObjectLock olock(groups); for (const String& name : groups) { UserGroup::Ptr group = UserGroup::GetByName(name); if (group && !group->ResolveGroupMembership(user, add, rstack + 1)) return false; } } if (add) AddMember(user); else RemoveMember(user); return true; } icinga2-2.8.1/lib/icinga/usergroup.hpp000066400000000000000000000043561322762156600176240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef USERGROUP_H #define USERGROUP_H #include "icinga/i2-icinga.hpp" #include "icinga/usergroup.thpp" #include "icinga/user.hpp" namespace icinga { class ConfigItem; /** * An Icinga user group. * * @ingroup icinga */ class I2_ICINGA_API UserGroup : public ObjectImpl { public: DECLARE_OBJECT(UserGroup); DECLARE_OBJECTNAME(UserGroup); std::set GetMembers(void) const; void AddMember(const User::Ptr& user); void RemoveMember(const User::Ptr& user); bool ResolveGroupMembership(const User::Ptr& user, bool add = true, int rstack = 0); static void EvaluateObjectRules(const User::Ptr& user); private: mutable boost::mutex m_UserGroupMutex; std::set m_Members; static bool EvaluateObjectRule(const User::Ptr& user, const intrusive_ptr& group); }; } #endif /* USERGROUP_H */ icinga2-2.8.1/lib/icinga/usergroup.ti000066400000000000000000000033361322762156600174460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/customvarobject.hpp" library icinga; namespace icinga { class UserGroup : CustomVarObject { [config] String display_name { get {{{ if (m_DisplayName.IsEmpty()) return GetName(); else return m_DisplayName; }}} }; [config, no_user_modify] array(name(UserGroup)) groups; }; } icinga2-2.8.1/lib/livestatus/000077500000000000000000000000001322762156600160215ustar00rootroot00000000000000icinga2-2.8.1/lib/livestatus/CMakeLists.txt000066400000000000000000000046351322762156600205710ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(livestatuslistener.ti livestatuslistener.tcpp livestatuslistener.thpp) set(livestatus_SOURCES aggregator.cpp andfilter.cpp attributefilter.cpp avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp commentstable.cpp contactgroupstable.cpp contactstable.cpp countaggregator.cpp downtimestable.cpp endpointstable.cpp filter.cpp historytable.cpp hostgroupstable.cpp hoststable.cpp invavgaggregator.cpp invsumaggregator.cpp livestatuslistener.cpp livestatuslistener.thpp livestatusquery.cpp livestatuslogutility.cpp logtable.cpp maxaggregator.cpp minaggregator.cpp negatefilter.cpp orfilter.cpp servicegroupstable.cpp servicestable.cpp statehisttable.cpp statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp timeperiodstable.cpp zonestable.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(livestatus livestatus livestatus_SOURCES) endif() add_library(livestatus SHARED ${livestatus_SOURCES}) target_link_libraries(livestatus ${Boost_LIBRARIES} base config icinga remote) set_target_properties ( livestatus PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_LIVESTATUS_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/livestatus.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ICINGA2_RUNDIR}/icinga2/cmd\")") install(TARGETS livestatus RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2) set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/livestatus/aggregator.cpp000066400000000000000000000033031322762156600206460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/aggregator.hpp" using namespace icinga; Aggregator::Aggregator(void) { } void Aggregator::SetFilter(const Filter::Ptr& filter) { m_Filter = filter; } Filter::Ptr Aggregator::GetFilter(void) const { return m_Filter; } AggregatorState::~AggregatorState(void) { } icinga2-2.8.1/lib/livestatus/aggregator.hpp000066400000000000000000000042241322762156600206560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef AGGREGATOR_H #define AGGREGATOR_H #include "livestatus/i2-livestatus.hpp" #include "livestatus/table.hpp" #include "livestatus/filter.hpp" namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API AggregatorState { virtual ~AggregatorState(void); }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API Aggregator : public Object { public: DECLARE_PTR_TYPEDEFS(Aggregator); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) = 0; virtual double GetResultAndFreeState(AggregatorState *state) const = 0; void SetFilter(const Filter::Ptr& filter); protected: Aggregator(void); Filter::Ptr GetFilter(void) const; private: Filter::Ptr m_Filter; }; } #endif /* AGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/andfilter.cpp000066400000000000000000000032711322762156600205000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/andfilter.hpp" using namespace icinga; AndFilter::AndFilter(void) { } bool AndFilter::Apply(const Table::Ptr& table, const Value& row) { for (const Filter::Ptr& filter : m_Filters) { if (!filter->Apply(table, row)) return false; } return true; } icinga2-2.8.1/lib/livestatus/andfilter.hpp000066400000000000000000000034441322762156600205070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ANDFILTER_H #define ANDFILTER_H #include "livestatus/combinerfilter.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API AndFilter : public CombinerFilter { public: DECLARE_PTR_TYPEDEFS(AndFilter); AndFilter(void); virtual bool Apply(const Table::Ptr& table, const Value& row) override; }; } #endif /* ANDFILTER_H */ icinga2-2.8.1/lib/livestatus/attributefilter.cpp000066400000000000000000000124611322762156600217420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/attributefilter.hpp" #include "base/convert.hpp" #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include #include using namespace icinga; AttributeFilter::AttributeFilter(const String& column, const String& op, const String& operand) : m_Column(column), m_Operator(op), m_Operand(operand) { } bool AttributeFilter::Apply(const Table::Ptr& table, const Value& row) { Column column = table->GetColumn(m_Column); Value value = column.ExtractValue(row); if (value.IsObjectType()) { Array::Ptr array = value; if (m_Operator == ">=" || m_Operator == "<") { bool negate = (m_Operator == "<"); ObjectLock olock(array); for (const String& item : array) { if (item == m_Operand) return !negate; /* Item found in list. */ } return negate; /* Item not found in list. */ } else if (m_Operator == "=") { return (array->GetLength() == 0); } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid operator for column '" + m_Column + "': " + m_Operator + " (expected '>=' or '=').")); } } else { if (m_Operator == "=") { if (value.GetType() == ValueNumber || value.GetType() == ValueBoolean) return (static_cast(value) == Convert::ToDouble(m_Operand)); else return (static_cast(value) == m_Operand); } else if (m_Operator == "~") { bool ret; try { boost::regex expr(m_Operand.GetData()); String operand = value; boost::smatch what; ret = boost::regex_search(operand.GetData(), what, expr); } catch (boost::exception&) { Log(LogWarning, "AttributeFilter") << "Regex '" << m_Operand << " " << m_Operator << " " << value << "' error."; ret = false; } //Log(LogDebug, "LivestatusListener/AttributeFilter") // << "Attribute filter '" << m_Operand + " " << m_Operator << " " // << value << "' " << (ret ? "matches" : "doesn't match") << "."; return ret; } else if (m_Operator == "=~") { bool ret; try { String operand = value; ret = boost::iequals(operand, m_Operand.GetData()); } catch (boost::exception&) { Log(LogWarning, "AttributeFilter") << "Case-insensitive equality '" << m_Operand << " " << m_Operator << " " << value << "' error."; ret = false; } return ret; } else if (m_Operator == "~~") { bool ret; try { boost::regex expr(m_Operand.GetData(), boost::regex::icase); String operand = value; boost::smatch what; ret = boost::regex_search(operand.GetData(), what, expr); } catch (boost::exception&) { Log(LogWarning, "AttributeFilter") << "Regex '" << m_Operand << " " << m_Operator << " " << value << "' error."; ret = false; } //Log(LogDebug, "LivestatusListener/AttributeFilter") // << "Attribute filter '" << m_Operand << " " << m_Operator << " " // << value << "' " << (ret ? "matches" : "doesn't match") << "."; return ret; } else if (m_Operator == "<") { if (value.GetType() == ValueNumber) return (static_cast(value) < Convert::ToDouble(m_Operand)); else return (static_cast(value) < m_Operand); } else if (m_Operator == ">") { if (value.GetType() == ValueNumber) return (static_cast(value) > Convert::ToDouble(m_Operand)); else return (static_cast(value) > m_Operand); } else if (m_Operator == "<=") { if (value.GetType() == ValueNumber) return (static_cast(value) <= Convert::ToDouble(m_Operand)); else return (static_cast(value) <= m_Operand); } else if (m_Operator == ">=") { if (value.GetType() == ValueNumber) return (static_cast(value) >= Convert::ToDouble(m_Operand)); else return (static_cast(value) >= m_Operand); } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Unknown operator for column '" + m_Column + "': " + m_Operator)); } } return false; } icinga2-2.8.1/lib/livestatus/attributefilter.hpp000066400000000000000000000036551322762156600217540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ATTRIBUTEFILTER_H #define ATTRIBUTEFILTER_H #include "livestatus/filter.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API AttributeFilter : public Filter { public: DECLARE_PTR_TYPEDEFS(AttributeFilter); AttributeFilter(const String& column, const String& op, const String& operand); virtual bool Apply(const Table::Ptr& table, const Value& row) override; protected: String m_Column; String m_Operator; String m_Operand; }; } #endif /* FILTER_H */ icinga2-2.8.1/lib/livestatus/avgaggregator.cpp000066400000000000000000000043221322762156600213460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/avgaggregator.hpp" using namespace icinga; AvgAggregator::AvgAggregator(const String& attr) : m_AvgAttr(attr) { } AvgAggregatorState *AvgAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new AvgAggregatorState(); return static_cast(*state); } void AvgAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_AvgAttr); Value value = column.ExtractValue(row); AvgAggregatorState *pstate = EnsureState(state); pstate->Avg += value; pstate->AvgCount++; } double AvgAggregator::GetResultAndFreeState(AggregatorState *state) const { AvgAggregatorState *pstate = EnsureState(&state); double result = pstate->Avg / pstate->AvgCount; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/avgaggregator.hpp000066400000000000000000000043021322762156600213510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef AVGAGGREGATOR_H #define AVGAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct AvgAggregatorState : public AggregatorState { AvgAggregatorState(void) : Avg(0), AvgCount(0) { } double Avg; double AvgCount; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API AvgAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(AvgAggregator); AvgAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_AvgAttr; static AvgAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* AVGAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/column.cpp000066400000000000000000000036301322762156600200240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/column.hpp" using namespace icinga; Column::Column(const ValueAccessor& valueAccessor, const ObjectAccessor& objectAccessor) : m_ValueAccessor(valueAccessor), m_ObjectAccessor(objectAccessor) { } Value Column::ExtractValue(const Value& urow, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) const { Value row; if (!m_ObjectAccessor.empty()) row = m_ObjectAccessor(urow, groupByType, groupByObject); else row = urow; return m_ValueAccessor(row); } icinga2-2.8.1/lib/livestatus/column.hpp000066400000000000000000000043521322762156600200330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COLUMN_H #define COLUMN_H #include "livestatus/i2-livestatus.hpp" #include "base/value.hpp" #include using namespace icinga; namespace icinga { enum LivestatusGroupByType { LivestatusGroupByNone, LivestatusGroupByHostGroup, LivestatusGroupByServiceGroup }; class I2_LIVESTATUS_API Column { public: typedef boost::function ValueAccessor; typedef boost::function ObjectAccessor; Column(const ValueAccessor& valueAccessor, const ObjectAccessor& objectAccessor); Value ExtractValue(const Value& urow, LivestatusGroupByType groupByType = LivestatusGroupByNone, const Object::Ptr& groupByObject = Empty) const; private: ValueAccessor m_ValueAccessor; ObjectAccessor m_ObjectAccessor; }; } #endif /* COLUMN_H */ icinga2-2.8.1/lib/livestatus/combinerfilter.cpp000066400000000000000000000031561322762156600215360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/combinerfilter.hpp" using namespace icinga; CombinerFilter::CombinerFilter(void) { } void CombinerFilter::AddSubFilter(const Filter::Ptr& filter) { m_Filters.push_back(filter); } icinga2-2.8.1/lib/livestatus/combinerfilter.hpp000066400000000000000000000035111322762156600215360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMBINERFILTER_H #define COMBINERFILTER_H #include "livestatus/filter.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API CombinerFilter : public Filter { public: DECLARE_PTR_TYPEDEFS(CombinerFilter); CombinerFilter(void); void AddSubFilter(const Filter::Ptr& filter); protected: std::vector m_Filters; }; } #endif /* COMBINERFILTER_H */ icinga2-2.8.1/lib/livestatus/commandstable.cpp000066400000000000000000000121151322762156600213360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/commandstable.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/compatutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include using namespace icinga; CommandsTable::CommandsTable(void) { AddColumns(this); } void CommandsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&CommandsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "line", Column(&CommandsTable::LineAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_names", Column(&CommandsTable::CustomVariableNamesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_values", Column(&CommandsTable::CustomVariableValuesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variables", Column(&CommandsTable::CustomVariablesAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes_list", Column(&Table::ZeroAccessor, objectAccessor)); } String CommandsTable::GetName(void) const { return "commands"; } String CommandsTable::GetPrefix(void) const { return "command"; } void CommandsTable::FetchRows(const AddRowFunction& addRowFn) { for (const ConfigObject::Ptr& object : ConfigType::GetObjectsByType()) { if (!addRowFn(object, LivestatusGroupByNone, Empty)) return; } for (const ConfigObject::Ptr& object : ConfigType::GetObjectsByType()) { if (!addRowFn(object, LivestatusGroupByNone, Empty)) return; } for (const ConfigObject::Ptr& object : ConfigType::GetObjectsByType()) { if (!addRowFn(object, LivestatusGroupByNone, Empty)) return; } } Value CommandsTable::NameAccessor(const Value& row) { Command::Ptr command = static_cast(row); return CompatUtility::GetCommandName(command); } Value CommandsTable::LineAccessor(const Value& row) { Command::Ptr command = static_cast(row); if (!command) return Empty; return CompatUtility::GetCommandLine(command); } Value CommandsTable::CustomVariableNamesAccessor(const Value& row) { Command::Ptr command = static_cast(row); if (!command) return Empty; Dictionary::Ptr vars; { ObjectLock olock(command); vars = CompatUtility::GetCustomAttributeConfig(command); } Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock xlock(vars); for (const auto& kv : vars) { cv->Add(kv.first); } } return cv; } Value CommandsTable::CustomVariableValuesAccessor(const Value& row) { Command::Ptr command = static_cast(row); if (!command) return Empty; Dictionary::Ptr vars; { ObjectLock olock(command); vars = CompatUtility::GetCustomAttributeConfig(command); } Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock xlock(vars); for (const auto& kv : vars) { cv->Add(kv.second); } } return cv; } Value CommandsTable::CustomVariablesAccessor(const Value& row) { Command::Ptr command = static_cast(row); if (!command) return Empty; Dictionary::Ptr vars; { ObjectLock olock(command); vars = CompatUtility::GetCustomAttributeConfig(command); } Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock xlock(vars); for (const auto& kv : vars) { Array::Ptr key_val = new Array(); key_val->Add(kv.first); key_val->Add(kv.second); cv->Add(key_val); } } return cv; } icinga2-2.8.1/lib/livestatus/commandstable.hpp000066400000000000000000000044651322762156600213540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMMANDSTABLE_H #define COMMANDSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API CommandsTable : public Table { public: DECLARE_PTR_TYPEDEFS(CommandsTable); CommandsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value LineAccessor(const Value& row); static Value CustomVariableNamesAccessor(const Value& row); static Value CustomVariableValuesAccessor(const Value& row); static Value CustomVariablesAccessor(const Value& row); }; } #endif /* COMMANDSTABLE_H */ icinga2-2.8.1/lib/livestatus/commentstable.cpp000066400000000000000000000136201322762156600213640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/commentstable.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicestable.hpp" #include "icinga/service.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include using namespace icinga; CommentsTable::CommentsTable(void) { AddColumns(this); } void CommentsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "author", Column(&CommentsTable::AuthorAccessor, objectAccessor)); table->AddColumn(prefix + "comment", Column(&CommentsTable::CommentAccessor, objectAccessor)); table->AddColumn(prefix + "id", Column(&CommentsTable::IdAccessor, objectAccessor)); table->AddColumn(prefix + "entry_time", Column(&CommentsTable::EntryTimeAccessor, objectAccessor)); table->AddColumn(prefix + "type", Column(&CommentsTable::TypeAccessor, objectAccessor)); table->AddColumn(prefix + "is_service", Column(&CommentsTable::IsServiceAccessor, objectAccessor)); table->AddColumn(prefix + "persistent", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "source", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "entry_type", Column(&CommentsTable::EntryTypeAccessor, objectAccessor)); table->AddColumn(prefix + "expires", Column(&CommentsTable::ExpiresAccessor, objectAccessor)); table->AddColumn(prefix + "expire_time", Column(&CommentsTable::ExpireTimeAccessor, objectAccessor)); /* order is important - host w/o services must not be empty */ ServicesTable::AddColumns(table, "service_", boost::bind(&CommentsTable::ServiceAccessor, _1, objectAccessor)); HostsTable::AddColumns(table, "host_", boost::bind(&CommentsTable::HostAccessor, _1, objectAccessor)); } String CommentsTable::GetName(void) const { return "comments"; } String CommentsTable::GetPrefix(void) const { return "comment"; } void CommentsTable::FetchRows(const AddRowFunction& addRowFn) { for (const Comment::Ptr& comment : ConfigType::GetObjectsByType()) { if (!addRowFn(comment, LivestatusGroupByNone, Empty)) return; } } Object::Ptr CommentsTable::HostAccessor(const Value& row, const Column::ObjectAccessor&) { Comment::Ptr comment = static_cast(row); Checkable::Ptr checkable = comment->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); return host; } Object::Ptr CommentsTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor&) { Comment::Ptr comment = static_cast(row); Checkable::Ptr checkable = comment->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); return service; } Value CommentsTable::AuthorAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return comment->GetAuthor(); } Value CommentsTable::CommentAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return comment->GetText(); } Value CommentsTable::IdAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return comment->GetLegacyId(); } Value CommentsTable::EntryTimeAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return static_cast(comment->GetEntryTime()); } Value CommentsTable::TypeAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); Checkable::Ptr checkable = comment->GetCheckable(); if (!checkable) return Empty; if (dynamic_pointer_cast(checkable)) return 1; else return 2; } Value CommentsTable::IsServiceAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); Checkable::Ptr checkable = comment->GetCheckable(); if (!checkable) return Empty; return (dynamic_pointer_cast(checkable) ? 0 : 1); } Value CommentsTable::EntryTypeAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return comment->GetEntryType(); } Value CommentsTable::ExpiresAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return comment->GetExpireTime() != 0; } Value CommentsTable::ExpireTimeAccessor(const Value& row) { Comment::Ptr comment = static_cast(row); if (!comment) return Empty; return static_cast(comment->GetExpireTime()); } icinga2-2.8.1/lib/livestatus/commentstable.hpp000066400000000000000000000052731322762156600213760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COMMENTSTABLE_H #define COMMENTSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API CommentsTable : public Table { public: DECLARE_PTR_TYPEDEFS(CommentsTable); CommentsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; private: static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Value AuthorAccessor(const Value& row); static Value CommentAccessor(const Value& row); static Value IdAccessor(const Value& row); static Value EntryTimeAccessor(const Value& row); static Value TypeAccessor(const Value& row); static Value IsServiceAccessor(const Value& row); static Value EntryTypeAccessor(const Value& row); static Value ExpiresAccessor(const Value& row); static Value ExpireTimeAccessor(const Value& row); }; } #endif /* COMMENTSTABLE_H */ icinga2-2.8.1/lib/livestatus/contactgroupstable.cpp000066400000000000000000000060731322762156600224360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/contactgroupstable.hpp" #include "icinga/usergroup.hpp" #include "base/configtype.hpp" using namespace icinga; ContactGroupsTable::ContactGroupsTable(void) { AddColumns(this); } void ContactGroupsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&ContactGroupsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&ContactGroupsTable::AliasAccessor, objectAccessor)); table->AddColumn(prefix + "members", Column(&ContactGroupsTable::MembersAccessor, objectAccessor)); } String ContactGroupsTable::GetName(void) const { return "contactgroups"; } String ContactGroupsTable::GetPrefix(void) const { return "contactgroup"; } void ContactGroupsTable::FetchRows(const AddRowFunction& addRowFn) { for (const UserGroup::Ptr& ug : ConfigType::GetObjectsByType()) { if (!addRowFn(ug, LivestatusGroupByNone, Empty)) return; } } Value ContactGroupsTable::NameAccessor(const Value& row) { UserGroup::Ptr user_group = static_cast(row); if (!user_group) return Empty; return user_group->GetName(); } Value ContactGroupsTable::AliasAccessor(const Value& row) { UserGroup::Ptr user_group = static_cast(row); if (!user_group) return Empty; return user_group->GetName(); } Value ContactGroupsTable::MembersAccessor(const Value& row) { UserGroup::Ptr user_group = static_cast(row); if (!user_group) return Empty; Array::Ptr members = new Array(); for (const User::Ptr& user : user_group->GetMembers()) { members->Add(user->GetName()); } return members; } icinga2-2.8.1/lib/livestatus/contactgroupstable.hpp000066400000000000000000000043211322762156600224350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONTACTGROUPSTABLE_H #define CONTACTGROUPSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API ContactGroupsTable : public Table { public: DECLARE_PTR_TYPEDEFS(ContactGroupsTable); ContactGroupsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value AliasAccessor(const Value& row); static Value MembersAccessor(const Value& row); }; } #endif /* CONTACTGROUPSTABLE_H */ icinga2-2.8.1/lib/livestatus/contactstable.cpp000066400000000000000000000205051322762156600213550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/contactstable.hpp" #include "icinga/user.hpp" #include "icinga/timeperiod.hpp" #include "icinga/compatutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include "base/utility.hpp" #include using namespace icinga; ContactsTable::ContactsTable(void) { AddColumns(this); } void ContactsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&ContactsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&ContactsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "email", Column(&ContactsTable::EmailAccessor, objectAccessor)); table->AddColumn(prefix + "pager", Column(&ContactsTable::PagerAccessor, objectAccessor)); table->AddColumn(prefix + "host_notification_period", Column(&ContactsTable::HostNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "service_notification_period", Column(&ContactsTable::ServiceNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "can_submit_commands", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "host_notifications_enabled", Column(&ContactsTable::HostNotificationsEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "service_notifications_enabled", Column(&ContactsTable::ServiceNotificationsEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "in_host_notification_period", Column(&ContactsTable::InHostNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "in_service_notification_period", Column(&ContactsTable::InServiceNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "vars_variable_names", Column(&ContactsTable::CustomVariableNamesAccessor, objectAccessor)); table->AddColumn(prefix + "vars_variable_values", Column(&ContactsTable::CustomVariableValuesAccessor, objectAccessor)); table->AddColumn(prefix + "vars_variables", Column(&ContactsTable::CustomVariablesAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes_list", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "cv_is_json", Column(&ContactsTable::CVIsJsonAccessor, objectAccessor)); } String ContactsTable::GetName(void) const { return "contacts"; } String ContactsTable::GetPrefix(void) const { return "contact"; } void ContactsTable::FetchRows(const AddRowFunction& addRowFn) { for (const User::Ptr& user : ConfigType::GetObjectsByType()) { if (!addRowFn(user, LivestatusGroupByNone, Empty)) return; } } Value ContactsTable::NameAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return user->GetName(); } Value ContactsTable::AliasAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return user->GetDisplayName(); } Value ContactsTable::EmailAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return user->GetEmail(); } Value ContactsTable::PagerAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return user->GetPager(); } Value ContactsTable::HostNotificationPeriodAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; /* same as service */ TimePeriod::Ptr timeperiod = user->GetPeriod(); if (!timeperiod) return Empty; return timeperiod->GetName(); } Value ContactsTable::ServiceNotificationPeriodAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; TimePeriod::Ptr timeperiod = user->GetPeriod(); if (!timeperiod) return Empty; return timeperiod->GetName(); } Value ContactsTable::HostNotificationsEnabledAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return (user->GetEnableNotifications() ? 1 : 0); } Value ContactsTable::ServiceNotificationsEnabledAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; return (user->GetEnableNotifications() ? 1 : 0); } Value ContactsTable::InHostNotificationPeriodAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; TimePeriod::Ptr timeperiod = user->GetPeriod(); if (!timeperiod) return Empty; return (timeperiod->IsInside(Utility::GetTime()) ? 1 : 0); } Value ContactsTable::InServiceNotificationPeriodAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; TimePeriod::Ptr timeperiod = user->GetPeriod(); if (!timeperiod) return Empty; return (timeperiod->IsInside(Utility::GetTime()) ? 1 : 0); } Value ContactsTable::CustomVariableNamesAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; Dictionary::Ptr vars; { ObjectLock olock(user); vars = CompatUtility::GetCustomAttributeConfig(user); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { cv->Add(kv.first); } return cv; } Value ContactsTable::CustomVariableValuesAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; Dictionary::Ptr vars; { ObjectLock olock(user); vars = CompatUtility::GetCustomAttributeConfig(user); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv->Add(JsonEncode(kv.second)); else cv->Add(kv.second); } return cv; } Value ContactsTable::CustomVariablesAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; Dictionary::Ptr vars; { ObjectLock olock(user); vars = CompatUtility::GetCustomAttributeConfig(user); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { Array::Ptr key_val = new Array(); key_val->Add(kv.first); if (kv.second.IsObjectType() || kv.second.IsObjectType()) key_val->Add(JsonEncode(kv.second)); else key_val->Add(kv.second); cv->Add(key_val); } return cv; } Value ContactsTable::CVIsJsonAccessor(const Value& row) { User::Ptr user = static_cast(row); if (!user) return Empty; Dictionary::Ptr vars; { ObjectLock olock(user); vars = CompatUtility::GetCustomAttributeConfig(user); } if (!vars) return Empty; bool cv_is_json = false; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv_is_json = true; } return cv_is_json; } icinga2-2.8.1/lib/livestatus/contactstable.hpp000066400000000000000000000055271322762156600213710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONTACTSTABLE_H #define CONTACTSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API ContactsTable : public Table { public: DECLARE_PTR_TYPEDEFS(ContactsTable); ContactsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value AliasAccessor(const Value& row); static Value EmailAccessor(const Value& row); static Value PagerAccessor(const Value& row); static Value HostNotificationPeriodAccessor(const Value& row); static Value ServiceNotificationPeriodAccessor(const Value& row); static Value HostNotificationsEnabledAccessor(const Value& row); static Value ServiceNotificationsEnabledAccessor(const Value& row); static Value InHostNotificationPeriodAccessor(const Value& row); static Value InServiceNotificationPeriodAccessor(const Value& row); static Value CustomVariableNamesAccessor(const Value& row); static Value CustomVariableValuesAccessor(const Value& row); static Value CustomVariablesAccessor(const Value& row); static Value CVIsJsonAccessor(const Value& row); }; } #endif /* CONTACTSTABLE_H */ icinga2-2.8.1/lib/livestatus/countaggregator.cpp000066400000000000000000000040721322762156600217230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/countaggregator.hpp" using namespace icinga; CountAggregatorState *CountAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new CountAggregatorState(); return static_cast(*state); } void CountAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { CountAggregatorState *pstate = EnsureState(state); if (GetFilter()->Apply(table, row)) pstate->Count++; } double CountAggregator::GetResultAndFreeState(AggregatorState *state) const { CountAggregatorState *pstate = EnsureState(&state); double result = pstate->Count; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/countaggregator.hpp000066400000000000000000000041661322762156600217340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef COUNTAGGREGATOR_H #define COUNTAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct CountAggregatorState : public AggregatorState { CountAggregatorState(void) : Count(0) { } int Count; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API CountAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(CountAggregator); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: static CountAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* COUNTAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/downtimestable.cpp000066400000000000000000000142141322762156600215500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/downtimestable.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicestable.hpp" #include "icinga/service.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include using namespace icinga; DowntimesTable::DowntimesTable(void) { AddColumns(this); } void DowntimesTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "author", Column(&DowntimesTable::AuthorAccessor, objectAccessor)); table->AddColumn(prefix + "comment", Column(&DowntimesTable::CommentAccessor, objectAccessor)); table->AddColumn(prefix + "id", Column(&DowntimesTable::IdAccessor, objectAccessor)); table->AddColumn(prefix + "entry_time", Column(&DowntimesTable::EntryTimeAccessor, objectAccessor)); table->AddColumn(prefix + "type", Column(&DowntimesTable::TypeAccessor, objectAccessor)); table->AddColumn(prefix + "is_service", Column(&DowntimesTable::IsServiceAccessor, objectAccessor)); table->AddColumn(prefix + "start_time", Column(&DowntimesTable::StartTimeAccessor, objectAccessor)); table->AddColumn(prefix + "end_time", Column(&DowntimesTable::EndTimeAccessor, objectAccessor)); table->AddColumn(prefix + "fixed", Column(&DowntimesTable::FixedAccessor, objectAccessor)); table->AddColumn(prefix + "duration", Column(&DowntimesTable::DurationAccessor, objectAccessor)); table->AddColumn(prefix + "triggered_by", Column(&DowntimesTable::TriggeredByAccessor, objectAccessor)); /* order is important - host w/o services must not be empty */ ServicesTable::AddColumns(table, "service_", boost::bind(&DowntimesTable::ServiceAccessor, _1, objectAccessor)); HostsTable::AddColumns(table, "host_", boost::bind(&DowntimesTable::HostAccessor, _1, objectAccessor)); } String DowntimesTable::GetName(void) const { return "downtimes"; } String DowntimesTable::GetPrefix(void) const { return "downtime"; } void DowntimesTable::FetchRows(const AddRowFunction& addRowFn) { for (const Downtime::Ptr& downtime : ConfigType::GetObjectsByType()) { if (!addRowFn(downtime, LivestatusGroupByNone, Empty)) return; } } Object::Ptr DowntimesTable::HostAccessor(const Value& row, const Column::ObjectAccessor&) { Downtime::Ptr downtime = static_cast(row); Checkable::Ptr checkable = downtime->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); return host; } Object::Ptr DowntimesTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor&) { Downtime::Ptr downtime = static_cast(row); Checkable::Ptr checkable = downtime->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); return service; } Value DowntimesTable::AuthorAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return downtime->GetAuthor(); } Value DowntimesTable::CommentAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return downtime->GetComment(); } Value DowntimesTable::IdAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return downtime->GetLegacyId(); } Value DowntimesTable::EntryTimeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return static_cast(downtime->GetEntryTime()); } Value DowntimesTable::TypeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); // 1 .. active, 0 .. pending return (downtime->IsInEffect() ? 1 : 0); } Value DowntimesTable::IsServiceAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); Checkable::Ptr checkable = downtime->GetCheckable(); return (dynamic_pointer_cast(checkable) ? 0 : 1); } Value DowntimesTable::StartTimeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return static_cast(downtime->GetStartTime()); } Value DowntimesTable::EndTimeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return static_cast(downtime->GetEndTime()); } Value DowntimesTable::FixedAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return downtime->GetFixed(); } Value DowntimesTable::DurationAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); return downtime->GetDuration(); } Value DowntimesTable::TriggeredByAccessor(const Value& row) { Downtime::Ptr downtime = static_cast(row); String triggerDowntimeName = downtime->GetTriggeredBy(); Downtime::Ptr triggerDowntime = Downtime::GetByName(triggerDowntimeName); if (triggerDowntime) return triggerDowntime->GetLegacyId(); return Empty; } icinga2-2.8.1/lib/livestatus/downtimestable.hpp000066400000000000000000000054431322762156600215610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DOWNTIMESTABLE_H #define DOWNTIMESTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API DowntimesTable : public Table { public: DECLARE_PTR_TYPEDEFS(DowntimesTable); DowntimesTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; private: static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Value AuthorAccessor(const Value& row); static Value CommentAccessor(const Value& row); static Value IdAccessor(const Value& row); static Value EntryTimeAccessor(const Value& row); static Value TypeAccessor(const Value& row); static Value IsServiceAccessor(const Value& row); static Value StartTimeAccessor(const Value& row); static Value EndTimeAccessor(const Value& row); static Value FixedAccessor(const Value& row); static Value DurationAccessor(const Value& row); static Value TriggeredByAccessor(const Value& row); }; } #endif /* DOWNTIMESTABLE_H */ icinga2-2.8.1/lib/livestatus/endpointstable.cpp000066400000000000000000000101411322762156600215350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/endpointstable.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/icingaapplication.hpp" #include "remote/endpoint.hpp" #include "remote/zone.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include #include #include #include using namespace icinga; EndpointsTable::EndpointsTable(void) { AddColumns(this); } void EndpointsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&EndpointsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "identity", Column(&EndpointsTable::IdentityAccessor, objectAccessor)); table->AddColumn(prefix + "node", Column(&EndpointsTable::NodeAccessor, objectAccessor)); table->AddColumn(prefix + "is_connected", Column(&EndpointsTable::IsConnectedAccessor, objectAccessor)); table->AddColumn(prefix + "zone", Column(&EndpointsTable::ZoneAccessor, objectAccessor)); } String EndpointsTable::GetName(void) const { return "endpoints"; } String EndpointsTable::GetPrefix(void) const { return "endpoint"; } void EndpointsTable::FetchRows(const AddRowFunction& addRowFn) { for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { if (!addRowFn(endpoint, LivestatusGroupByNone, Empty)) return; } } Value EndpointsTable::NameAccessor(const Value& row) { Endpoint::Ptr endpoint = static_cast(row); if (!endpoint) return Empty; return endpoint->GetName(); } Value EndpointsTable::IdentityAccessor(const Value& row) { Endpoint::Ptr endpoint = static_cast(row); if (!endpoint) return Empty; return endpoint->GetName(); } Value EndpointsTable::NodeAccessor(const Value& row) { Endpoint::Ptr endpoint = static_cast(row); if (!endpoint) return Empty; return IcingaApplication::GetInstance()->GetNodeName(); } Value EndpointsTable::IsConnectedAccessor(const Value& row) { Endpoint::Ptr endpoint = static_cast(row); if (!endpoint) return Empty; unsigned int is_connected = endpoint->GetConnected() ? 1 : 0; /* if identity is equal to node, fake is_connected */ if (endpoint->GetName() == IcingaApplication::GetInstance()->GetNodeName()) is_connected = 1; return is_connected; } Value EndpointsTable::ZoneAccessor(const Value& row) { Endpoint::Ptr endpoint = static_cast(row); if (!endpoint) return Empty; Zone::Ptr zone = endpoint->GetZone(); if (!zone) return Empty; return zone->GetName(); } icinga2-2.8.1/lib/livestatus/endpointstable.hpp000066400000000000000000000044341322762156600215520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ENDPOINTSTABLE_H #define ENDPOINTSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API EndpointsTable : public Table { public: DECLARE_PTR_TYPEDEFS(EndpointsTable); EndpointsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value IdentityAccessor(const Value& row); static Value NodeAccessor(const Value& row); static Value IsConnectedAccessor(const Value& row); static Value ZoneAccessor(const Value& row); }; } #endif /* ENDPOINTSTABLE_H */ icinga2-2.8.1/lib/livestatus/filter.cpp000066400000000000000000000027661322762156600200250ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/filter.hpp" using namespace icinga; Filter::Filter(void) { } icinga2-2.8.1/lib/livestatus/filter.hpp000066400000000000000000000034261322762156600200240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FILTER_H #define FILTER_H #include "livestatus/i2-livestatus.hpp" #include "livestatus/table.hpp" namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API Filter : public Object { public: DECLARE_PTR_TYPEDEFS(Filter); virtual bool Apply(const Table::Ptr& table, const Value& row) = 0; protected: Filter(void); }; } #endif /* FILTER_H */ icinga2-2.8.1/lib/livestatus/historytable.cpp000066400000000000000000000031431322762156600212370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/historytable.hpp" using namespace icinga; void HistoryTable::UpdateLogEntries(const Dictionary::Ptr&, int, int, const AddRowFunction&) { /* does nothing by default */ } icinga2-2.8.1/lib/livestatus/historytable.hpp000066400000000000000000000034361322762156600212510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HISTORYTABLE_H #define HISTORYTABLE_H #include "livestatus/table.hpp" #include "base/dictionary.hpp" namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API HistoryTable : public Table { public: virtual void UpdateLogEntries(const Dictionary::Ptr& bag, int line_count, int lineno, const AddRowFunction& addRowFn); }; } #endif /* HISTORYTABLE_H */ icinga2-2.8.1/lib/livestatus/hostgroupstable.cpp000066400000000000000000000314501322762156600217550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/hostgroupstable.hpp" #include "icinga/hostgroup.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "base/configtype.hpp" using namespace icinga; HostGroupsTable::HostGroupsTable(void) { AddColumns(this); } void HostGroupsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&HostGroupsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&HostGroupsTable::AliasAccessor, objectAccessor)); table->AddColumn(prefix + "notes", Column(&HostGroupsTable::NotesAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url", Column(&HostGroupsTable::NotesUrlAccessor, objectAccessor)); table->AddColumn(prefix + "action_url", Column(&HostGroupsTable::ActionUrlAccessor, objectAccessor)); table->AddColumn(prefix + "members", Column(&HostGroupsTable::MembersAccessor, objectAccessor)); table->AddColumn(prefix + "members_with_state", Column(&HostGroupsTable::MembersWithStateAccessor, objectAccessor)); table->AddColumn(prefix + "worst_host_state", Column(&HostGroupsTable::WorstHostStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts", Column(&HostGroupsTable::NumHostsAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts_pending", Column(&HostGroupsTable::NumHostsPendingAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts_up", Column(&HostGroupsTable::NumHostsUpAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts_down", Column(&HostGroupsTable::NumHostsDownAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts_unreach", Column(&HostGroupsTable::NumHostsUnreachAccessor, objectAccessor)); table->AddColumn(prefix + "num_services", Column(&HostGroupsTable::NumServicesAccessor, objectAccessor)); table->AddColumn(prefix + "worst_service_state", Column(&HostGroupsTable::WorstServiceStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_pending", Column(&HostGroupsTable::NumServicesPendingAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_ok", Column(&HostGroupsTable::NumServicesOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_warn", Column(&HostGroupsTable::NumServicesWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_crit", Column(&HostGroupsTable::NumServicesCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_unknown", Column(&HostGroupsTable::NumServicesUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "worst_service_hard_state", Column(&HostGroupsTable::WorstServiceHardStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_ok", Column(&HostGroupsTable::NumServicesHardOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_warn", Column(&HostGroupsTable::NumServicesHardWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_crit", Column(&HostGroupsTable::NumServicesHardCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_unknown", Column(&HostGroupsTable::NumServicesHardUnknownAccessor, objectAccessor)); } String HostGroupsTable::GetName(void) const { return "hostgroups"; } String HostGroupsTable::GetPrefix(void) const { return "hostgroup"; } void HostGroupsTable::FetchRows(const AddRowFunction& addRowFn) { for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType()) { if (!addRowFn(hg, LivestatusGroupByNone, Empty)) return; } } Value HostGroupsTable::NameAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetName(); } Value HostGroupsTable::AliasAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetDisplayName(); } Value HostGroupsTable::NotesAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetNotes(); } Value HostGroupsTable::NotesUrlAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetNotesUrl(); } Value HostGroupsTable::ActionUrlAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetActionUrl(); } Value HostGroupsTable::MembersAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; Array::Ptr members = new Array(); for (const Host::Ptr& host : hg->GetMembers()) { members->Add(host->GetName()); } return members; } Value HostGroupsTable::MembersWithStateAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; Array::Ptr members = new Array(); for (const Host::Ptr& host : hg->GetMembers()) { Array::Ptr member_state = new Array(); member_state->Add(host->GetName()); member_state->Add(host->GetState()); members->Add(member_state); } return members; } Value HostGroupsTable::WorstHostStateAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int worst_host = HostUp; for (const Host::Ptr& host : hg->GetMembers()) { if (host->GetState() > worst_host) worst_host = host->GetState(); } return worst_host; } Value HostGroupsTable::NumHostsAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; return hg->GetMembers().size(); } Value HostGroupsTable::NumHostsPendingAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_hosts = 0; for (const Host::Ptr& host : hg->GetMembers()) { /* no checkresult */ if (!host->GetLastCheckResult()) num_hosts++; } return num_hosts; } Value HostGroupsTable::NumHostsUpAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_hosts = 0; for (const Host::Ptr& host : hg->GetMembers()) { if (host->GetState() == HostUp) num_hosts++; } return num_hosts; } Value HostGroupsTable::NumHostsDownAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_hosts = 0; for (const Host::Ptr& host : hg->GetMembers()) { if (host->GetState() == HostDown) num_hosts++; } return num_hosts; } Value HostGroupsTable::NumHostsUnreachAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_hosts = 0; for (const Host::Ptr& host : hg->GetMembers()) { if (!host->IsReachable()) num_hosts++; } return num_hosts; } Value HostGroupsTable::NumServicesAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; if (hg->GetMembers().size() == 0) return 0; for (const Host::Ptr& host : hg->GetMembers()) { num_services += host->GetServices().size(); } return num_services; } Value HostGroupsTable::WorstServiceStateAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; Value worst_service = ServiceOK; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() > worst_service) worst_service = service->GetState(); } } return worst_service; } Value HostGroupsTable::NumServicesPendingAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (!service->GetLastCheckResult()) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesOkAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceOK) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesWarnAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceWarning) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesCritAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceCritical) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesUnknownAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceUnknown) num_services++; } } return num_services; } Value HostGroupsTable::WorstServiceHardStateAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; Value worst_service = ServiceOK; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard) { if (service->GetState() > worst_service) worst_service = service->GetState(); } } } return worst_service; } Value HostGroupsTable::NumServicesHardOkAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceOK) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesHardWarnAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceWarning) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesHardCritAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceCritical) num_services++; } } return num_services; } Value HostGroupsTable::NumServicesHardUnknownAccessor(const Value& row) { HostGroup::Ptr hg = static_cast(row); if (!hg) return Empty; int num_services = 0; for (const Host::Ptr& host : hg->GetMembers()) { for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceUnknown) num_services++; } } return num_services; } icinga2-2.8.1/lib/livestatus/hostgroupstable.hpp000066400000000000000000000066301322762156600217640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOSTGROUPSTABLE_H #define HOSTGROUPSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API HostGroupsTable : public Table { public: DECLARE_PTR_TYPEDEFS(HostGroupsTable); HostGroupsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value AliasAccessor(const Value& row); static Value NotesAccessor(const Value& row); static Value NotesUrlAccessor(const Value& row); static Value ActionUrlAccessor(const Value& row); static Value MembersAccessor(const Value& row); static Value MembersWithStateAccessor(const Value& row); static Value WorstHostStateAccessor(const Value& row); static Value NumHostsAccessor(const Value& row); static Value NumHostsPendingAccessor(const Value& row); static Value NumHostsUpAccessor(const Value& row); static Value NumHostsDownAccessor(const Value& row); static Value NumHostsUnreachAccessor(const Value& row); static Value NumServicesAccessor(const Value& row); static Value WorstServiceStateAccessor(const Value& row); static Value NumServicesPendingAccessor(const Value& row); static Value NumServicesOkAccessor(const Value& row); static Value NumServicesWarnAccessor(const Value& row); static Value NumServicesCritAccessor(const Value& row); static Value NumServicesUnknownAccessor(const Value& row); static Value WorstServiceHardStateAccessor(const Value& row); static Value NumServicesHardOkAccessor(const Value& row); static Value NumServicesHardWarnAccessor(const Value& row); static Value NumServicesHardCritAccessor(const Value& row); static Value NumServicesHardUnknownAccessor(const Value& row); }; } #endif /* HOSTGROUPSTABLE_H */ icinga2-2.8.1/lib/livestatus/hoststable.cpp000066400000000000000000001221411322762156600206760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/hoststable.hpp" #include "livestatus/hostgroupstable.hpp" #include "livestatus/endpointstable.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "icinga/hostgroup.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/timeperiod.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/compatutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include #include using namespace icinga; HostsTable::HostsTable(LivestatusGroupByType type) :Table(type) { AddColumns(this); } void HostsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&HostsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "host_name", Column(&HostsTable::NameAccessor, objectAccessor)); //ugly compatibility hack table->AddColumn(prefix + "display_name", Column(&HostsTable::DisplayNameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&HostsTable::DisplayNameAccessor, objectAccessor)); table->AddColumn(prefix + "address", Column(&HostsTable::AddressAccessor, objectAccessor)); table->AddColumn(prefix + "address6", Column(&HostsTable::Address6Accessor, objectAccessor)); table->AddColumn(prefix + "check_command", Column(&HostsTable::CheckCommandAccessor, objectAccessor)); table->AddColumn(prefix + "check_command_expanded", Column(&HostsTable::CheckCommandExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "event_handler", Column(&HostsTable::EventHandlerAccessor, objectAccessor)); table->AddColumn(prefix + "notification_period", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "check_period", Column(&HostsTable::CheckPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "notes", Column(&HostsTable::NotesAccessor, objectAccessor)); table->AddColumn(prefix + "notes_expanded", Column(&HostsTable::NotesExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url", Column(&HostsTable::NotesUrlAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url_expanded", Column(&HostsTable::NotesUrlExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "action_url", Column(&HostsTable::ActionUrlAccessor, objectAccessor)); table->AddColumn(prefix + "action_url_expanded", Column(&HostsTable::ActionUrlExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "plugin_output", Column(&HostsTable::PluginOutputAccessor, objectAccessor)); table->AddColumn(prefix + "perf_data", Column(&HostsTable::PerfDataAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image", Column(&HostsTable::IconImageAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image_expanded", Column(&HostsTable::IconImageExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image_alt", Column(&HostsTable::IconImageAltAccessor, objectAccessor)); table->AddColumn(prefix + "statusmap_image", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "long_plugin_output", Column(&HostsTable::LongPluginOutputAccessor, objectAccessor)); table->AddColumn(prefix + "initial_state", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "max_check_attempts", Column(&HostsTable::MaxCheckAttemptsAccessor, objectAccessor)); table->AddColumn(prefix + "flap_detection_enabled", Column(&HostsTable::FlapDetectionEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "check_freshness", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "process_performance_data", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "accept_passive_checks", Column(&HostsTable::AcceptPassiveChecksAccessor, objectAccessor)); table->AddColumn(prefix + "event_handler_enabled", Column(&HostsTable::EventHandlerEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "acknowledgement_type", Column(&HostsTable::AcknowledgementTypeAccessor, objectAccessor)); table->AddColumn(prefix + "check_type", Column(&HostsTable::CheckTypeAccessor, objectAccessor)); table->AddColumn(prefix + "last_state", Column(&HostsTable::LastStateAccessor, objectAccessor)); table->AddColumn(prefix + "last_hard_state", Column(&HostsTable::LastHardStateAccessor, objectAccessor)); table->AddColumn(prefix + "current_attempt", Column(&HostsTable::CurrentAttemptAccessor, objectAccessor)); table->AddColumn(prefix + "last_notification", Column(&HostsTable::LastNotificationAccessor, objectAccessor)); table->AddColumn(prefix + "next_notification", Column(&HostsTable::NextNotificationAccessor, objectAccessor)); table->AddColumn(prefix + "next_check", Column(&HostsTable::NextCheckAccessor, objectAccessor)); table->AddColumn(prefix + "last_hard_state_change", Column(&HostsTable::LastHardStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "has_been_checked", Column(&HostsTable::HasBeenCheckedAccessor, objectAccessor)); table->AddColumn(prefix + "current_notification_number", Column(&HostsTable::CurrentNotificationNumberAccessor, objectAccessor)); table->AddColumn(prefix + "pending_flex_downtime", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "total_services", Column(&HostsTable::TotalServicesAccessor, objectAccessor)); table->AddColumn(prefix + "checks_enabled", Column(&HostsTable::ChecksEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "notifications_enabled", Column(&HostsTable::NotificationsEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "acknowledged", Column(&HostsTable::AcknowledgedAccessor, objectAccessor)); table->AddColumn(prefix + "state", Column(&HostsTable::StateAccessor, objectAccessor)); table->AddColumn(prefix + "state_type", Column(&HostsTable::StateTypeAccessor, objectAccessor)); table->AddColumn(prefix + "no_more_notifications", Column(&HostsTable::NoMoreNotificationsAccessor, objectAccessor)); table->AddColumn(prefix + "check_flapping_recovery_notification", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "last_check", Column(&HostsTable::LastCheckAccessor, objectAccessor)); table->AddColumn(prefix + "last_state_change", Column(&HostsTable::LastStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_up", Column(&HostsTable::LastTimeUpAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_down", Column(&HostsTable::LastTimeDownAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_unreachable", Column(&HostsTable::LastTimeUnreachableAccessor, objectAccessor)); table->AddColumn(prefix + "is_flapping", Column(&HostsTable::IsFlappingAccessor, objectAccessor)); table->AddColumn(prefix + "scheduled_downtime_depth", Column(&HostsTable::ScheduledDowntimeDepthAccessor, objectAccessor)); table->AddColumn(prefix + "is_executing", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "active_checks_enabled", Column(&HostsTable::ActiveChecksEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "check_options", Column(&HostsTable::CheckOptionsAccessor, objectAccessor)); table->AddColumn(prefix + "obsess_over_host", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes_list", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "check_interval", Column(&HostsTable::CheckIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "retry_interval", Column(&HostsTable::RetryIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "notification_interval", Column(&HostsTable::NotificationIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "first_notification_delay", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "low_flap_threshold", Column(&HostsTable::LowFlapThresholdAccessor, objectAccessor)); table->AddColumn(prefix + "high_flap_threshold", Column(&HostsTable::HighFlapThresholdAccessor, objectAccessor)); table->AddColumn(prefix + "x_3d", Column(&EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "y_3d", Column(&EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "z_3d", Column(&EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "x_2d", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "y_2d", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "latency", Column(&HostsTable::LatencyAccessor, objectAccessor)); table->AddColumn(prefix + "execution_time", Column(&HostsTable::ExecutionTimeAccessor, objectAccessor)); table->AddColumn(prefix + "percent_state_change", Column(&HostsTable::PercentStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "in_notification_period", Column(&HostsTable::InNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "in_check_period", Column(&HostsTable::InCheckPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "contacts", Column(&HostsTable::ContactsAccessor, objectAccessor)); table->AddColumn(prefix + "downtimes", Column(&HostsTable::DowntimesAccessor, objectAccessor)); table->AddColumn(prefix + "downtimes_with_info", Column(&HostsTable::DowntimesWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "comments", Column(&HostsTable::CommentsAccessor, objectAccessor)); table->AddColumn(prefix + "comments_with_info", Column(&HostsTable::CommentsWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "comments_with_extra_info", Column(&HostsTable::CommentsWithExtraInfoAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_names", Column(&HostsTable::CustomVariableNamesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_values", Column(&HostsTable::CustomVariableValuesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variables", Column(&HostsTable::CustomVariablesAccessor, objectAccessor)); table->AddColumn(prefix + "filename", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "parents", Column(&HostsTable::ParentsAccessor, objectAccessor)); table->AddColumn(prefix + "childs", Column(&HostsTable::ChildsAccessor, objectAccessor)); table->AddColumn(prefix + "num_services", Column(&HostsTable::NumServicesAccessor, objectAccessor)); table->AddColumn(prefix + "worst_service_state", Column(&HostsTable::WorstServiceStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_ok", Column(&HostsTable::NumServicesOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_warn", Column(&HostsTable::NumServicesWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_crit", Column(&HostsTable::NumServicesCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_unknown", Column(&HostsTable::NumServicesUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_pending", Column(&HostsTable::NumServicesPendingAccessor, objectAccessor)); table->AddColumn(prefix + "worst_service_hard_state", Column(&HostsTable::WorstServiceHardStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_ok", Column(&HostsTable::NumServicesHardOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_warn", Column(&HostsTable::NumServicesHardWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_crit", Column(&HostsTable::NumServicesHardCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_unknown", Column(&HostsTable::NumServicesHardUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "hard_state", Column(&HostsTable::HardStateAccessor, objectAccessor)); table->AddColumn(prefix + "pnpgraph_present", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "staleness", Column(&HostsTable::StalenessAccessor, objectAccessor)); table->AddColumn(prefix + "groups", Column(&HostsTable::GroupsAccessor, objectAccessor)); table->AddColumn(prefix + "contact_groups", Column(&HostsTable::ContactGroupsAccessor, objectAccessor)); table->AddColumn(prefix + "services", Column(&HostsTable::ServicesAccessor, objectAccessor)); table->AddColumn(prefix + "services_with_state", Column(&HostsTable::ServicesWithStateAccessor, objectAccessor)); table->AddColumn(prefix + "services_with_info", Column(&HostsTable::ServicesWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "check_source", Column(&HostsTable::CheckSourceAccessor, objectAccessor)); table->AddColumn(prefix + "is_reachable", Column(&HostsTable::IsReachableAccessor, objectAccessor)); table->AddColumn(prefix + "cv_is_json", Column(&HostsTable::CVIsJsonAccessor, objectAccessor)); table->AddColumn(prefix + "original_attributes", Column(&HostsTable::OriginalAttributesAccessor, objectAccessor)); /* add additional group by values received through the object accessor */ if (table->GetGroupByType() == LivestatusGroupByHostGroup) { /* _1 = row, _2 = groupByType, _3 = groupByObject */ Log(LogDebug, "Livestatus") << "Processing hosts group by hostgroup table."; HostGroupsTable::AddColumns(table, "hostgroup_", boost::bind(&HostsTable::HostGroupAccessor, _1, _2, _3)); } } String HostsTable::GetName(void) const { return "hosts"; } String HostsTable::GetPrefix(void) const { return "host"; } void HostsTable::FetchRows(const AddRowFunction& addRowFn) { if (GetGroupByType() == LivestatusGroupByHostGroup) { for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType()) { for (const Host::Ptr& host : hg->GetMembers()) { /* the caller must know which groupby type and value are set for this row */ if (!addRowFn(host, LivestatusGroupByHostGroup, hg)) return; } } } else { for (const Host::Ptr& host : ConfigType::GetObjectsByType()) { if (!addRowFn(host, LivestatusGroupByNone, Empty)) return; } } } Object::Ptr HostsTable::HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) { /* return the current group by value set from within FetchRows() * this is the hostgrouo object used for the table join inside * in AddColumns() */ if (groupByType == LivestatusGroupByHostGroup) return groupByObject; return Object::Ptr(); } Value HostsTable::NameAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetName(); } Value HostsTable::DisplayNameAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetDisplayName(); } Value HostsTable::AddressAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetAddress(); } Value HostsTable::Address6Accessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetAddress6(); } Value HostsTable::CheckCommandAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; CheckCommand::Ptr checkcommand = host->GetCheckCommand(); if (checkcommand) return CompatUtility::GetCommandName(checkcommand) + "!" + CompatUtility::GetCheckableCommandArgs(host); return Empty; } Value HostsTable::CheckCommandExpandedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; CheckCommand::Ptr checkcommand = host->GetCheckCommand(); if (checkcommand) return CompatUtility::GetCommandName(checkcommand) + "!" + CompatUtility::GetCheckableCommandArgs(host); return Empty; } Value HostsTable::EventHandlerAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; EventCommand::Ptr eventcommand = host->GetEventCommand(); if (eventcommand) return CompatUtility::GetCommandName(eventcommand); return Empty; } Value HostsTable::CheckPeriodAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableCheckPeriod(host); } Value HostsTable::NotesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetNotes(); } Value HostsTable::NotesExpandedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(host->GetNotes(), resolvers, CheckResult::Ptr()); } Value HostsTable::NotesUrlAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetNotesUrl(); } Value HostsTable::NotesUrlExpandedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(host->GetNotesUrl(), resolvers); } Value HostsTable::ActionUrlAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetActionUrl(); } Value HostsTable::ActionUrlExpandedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(host->GetActionUrl(), resolvers); } Value HostsTable::PluginOutputAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; String output; CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) output = CompatUtility::GetCheckResultOutput(cr); return output; } Value HostsTable::PerfDataAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; String perfdata; CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) perfdata = CompatUtility::GetCheckResultPerfdata(cr); return perfdata; } Value HostsTable::IconImageAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetIconImage(); } Value HostsTable::IconImageExpandedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(host->GetIconImage(), resolvers); } Value HostsTable::IconImageAltAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetIconImageAlt(); } Value HostsTable::LongPluginOutputAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; String long_output; CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) long_output = CompatUtility::GetCheckResultLongOutput(cr); return long_output; } Value HostsTable::MaxCheckAttemptsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetMaxCheckAttempts(); } Value HostsTable::FlapDetectionEnabledAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableFlapDetectionEnabled(host); } Value HostsTable::AcceptPassiveChecksAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckablePassiveChecksEnabled(host); } Value HostsTable::EventHandlerEnabledAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableEventHandlerEnabled(host); } Value HostsTable::AcknowledgementTypeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; ObjectLock olock(host); return CompatUtility::GetCheckableAcknowledgementType(host); } Value HostsTable::CheckTypeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableCheckType(host); } Value HostsTable::LastStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetLastState(); } Value HostsTable::LastHardStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetLastHardState(); } Value HostsTable::CurrentAttemptAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetCheckAttempt(); } Value HostsTable::LastNotificationAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNotificationLastNotification(host); } Value HostsTable::NextNotificationAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNotificationNextNotification(host); } Value HostsTable::NextCheckAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetNextCheck()); } Value HostsTable::LastHardStateChangeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastHardStateChange()); } Value HostsTable::HasBeenCheckedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableHasBeenChecked(host); } Value HostsTable::CurrentNotificationNumberAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNotificationNotificationNumber(host); } Value HostsTable::TotalServicesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetTotalServices(); } Value HostsTable::ChecksEnabledAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableActiveChecksEnabled(host); } Value HostsTable::NotificationsEnabledAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNotificationsEnabled(host); } Value HostsTable::AcknowledgedAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; ObjectLock olock(host); return CompatUtility::GetCheckableIsAcknowledged(host); } Value HostsTable::StateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->IsReachable() ? host->GetState() : 2; } Value HostsTable::StateTypeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetStateType(); } Value HostsTable::NoMoreNotificationsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNoMoreNotifications(host); } Value HostsTable::LastCheckAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastCheck()); } Value HostsTable::LastStateChangeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastStateChange()); } Value HostsTable::LastTimeUpAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastStateUp()); } Value HostsTable::LastTimeDownAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastStateDown()); } Value HostsTable::LastTimeUnreachableAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return static_cast(host->GetLastStateUnreachable()); } Value HostsTable::IsFlappingAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->IsFlapping(); } Value HostsTable::ScheduledDowntimeDepthAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetDowntimeDepth(); } Value HostsTable::ActiveChecksEnabledAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableActiveChecksEnabled(host); } Value HostsTable::CheckOptionsAccessor(const Value&) { /* TODO - forcexec, freshness, orphan, none */ return Empty; } Value HostsTable::CheckIntervalAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableCheckInterval(host); } Value HostsTable::RetryIntervalAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableRetryInterval(host); } Value HostsTable::NotificationIntervalAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableNotificationNotificationInterval(host); } Value HostsTable::LowFlapThresholdAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableLowFlapThreshold(host); } Value HostsTable::HighFlapThresholdAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableHighFlapThreshold(host); } Value HostsTable::LatencyAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; CheckResult::Ptr cr = host->GetLastCheckResult(); if (!cr) return Empty; return cr->CalculateLatency(); } Value HostsTable::ExecutionTimeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; CheckResult::Ptr cr = host->GetLastCheckResult(); if (!cr) return Empty; return cr->CalculateExecutionTime(); } Value HostsTable::PercentStateChangeAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckablePercentStateChange(host); } Value HostsTable::InNotificationPeriodAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableInNotificationPeriod(host); } Value HostsTable::InCheckPeriodAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableInCheckPeriod(host); } Value HostsTable::ContactsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr contact_names = new Array(); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(host)) { contact_names->Add(user->GetName()); } return contact_names; } Value HostsTable::DowntimesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr results = new Array(); for (const Downtime::Ptr& downtime : host->GetDowntimes()) { if (downtime->IsExpired()) continue; results->Add(downtime->GetLegacyId()); } return results; } Value HostsTable::DowntimesWithInfoAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr results = new Array(); for (const Downtime::Ptr& downtime : host->GetDowntimes()) { if (downtime->IsExpired()) continue; Array::Ptr downtime_info = new Array(); downtime_info->Add(downtime->GetLegacyId()); downtime_info->Add(downtime->GetAuthor()); downtime_info->Add(downtime->GetComment()); results->Add(downtime_info); } return results; } Value HostsTable::CommentsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : host->GetComments()) { if (comment->IsExpired()) continue; results->Add(comment->GetLegacyId()); } return results; } Value HostsTable::CommentsWithInfoAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : host->GetComments()) { if (comment->IsExpired()) continue; Array::Ptr comment_info = new Array(); comment_info->Add(comment->GetLegacyId()); comment_info->Add(comment->GetAuthor()); comment_info->Add(comment->GetText()); results->Add(comment_info); } return results; } Value HostsTable::CommentsWithExtraInfoAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : host->GetComments()) { if (comment->IsExpired()) continue; Array::Ptr comment_info = new Array(); comment_info->Add(comment->GetLegacyId()); comment_info->Add(comment->GetAuthor()); comment_info->Add(comment->GetText()); comment_info->Add(comment->GetEntryType()); comment_info->Add(static_cast(comment->GetEntryTime())); results->Add(comment_info); } return results; } Value HostsTable::CustomVariableNamesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Dictionary::Ptr vars; { ObjectLock olock(host); vars = CompatUtility::GetCustomAttributeConfig(host); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { cv->Add(kv.first); } return cv; } Value HostsTable::CustomVariableValuesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Dictionary::Ptr vars; { ObjectLock olock(host); vars = CompatUtility::GetCustomAttributeConfig(host); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv->Add(JsonEncode(kv.second)); else cv->Add(kv.second); } return cv; } Value HostsTable::CustomVariablesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Dictionary::Ptr vars; { ObjectLock olock(host); vars = CompatUtility::GetCustomAttributeConfig(host); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { Array::Ptr key_val = new Array(); key_val->Add(kv.first); if (kv.second.IsObjectType() || kv.second.IsObjectType()) key_val->Add(JsonEncode(kv.second)); else key_val->Add(kv.second); cv->Add(key_val); } return cv; } Value HostsTable::CVIsJsonAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Dictionary::Ptr vars; { ObjectLock olock(host); vars = CompatUtility::GetCustomAttributeConfig(host); } if (!vars) return Empty; bool cv_is_json = false; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv_is_json = true; } return cv_is_json; } Value HostsTable::ParentsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr parents = new Array(); for (const Checkable::Ptr& parent : host->GetParents()) { Host::Ptr parent_host = dynamic_pointer_cast(parent); if (!parent_host) continue; parents->Add(parent_host->GetName()); } return parents; } Value HostsTable::ChildsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr childs = new Array(); for (const Checkable::Ptr& child : host->GetChildren()) { Host::Ptr child_host = dynamic_pointer_cast(child); if (!child_host) continue; childs->Add(child_host->GetName()); } return childs; } Value HostsTable::NumServicesAccessor(const Value& row) { /* duplicate of TotalServices */ Host::Ptr host = static_cast(row); if (!host) return Empty; return host->GetTotalServices(); } Value HostsTable::WorstServiceStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Value worst_service = ServiceOK; for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() > worst_service) worst_service = service->GetState(); } return worst_service; } Value HostsTable::NumServicesOkAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceOK) num_services++; } return num_services; } Value HostsTable::NumServicesWarnAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceWarning) num_services++; } return num_services; } Value HostsTable::NumServicesCritAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceCritical) num_services++; } return num_services; } Value HostsTable::NumServicesUnknownAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetState() == ServiceUnknown) num_services++; } return num_services; } Value HostsTable::NumServicesPendingAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (!service->GetLastCheckResult()) num_services++; } return num_services; } Value HostsTable::WorstServiceHardStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Value worst_service = ServiceOK; for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard) { if (service->GetState() > worst_service) worst_service = service->GetState(); } } return worst_service; } Value HostsTable::NumServicesHardOkAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceOK) num_services++; } return num_services; } Value HostsTable::NumServicesHardWarnAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceWarning) num_services++; } return num_services; } Value HostsTable::NumServicesHardCritAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceCritical) num_services++; } return num_services; } Value HostsTable::NumServicesHardUnknownAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; int num_services = 0; for (const Service::Ptr& service : host->GetServices()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceUnknown) num_services++; } return num_services; } Value HostsTable::HardStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; if (host->GetState() == HostUp) return HostUp; else if (host->GetStateType() == StateTypeHard) return host->GetState(); return host->GetLastHardState(); } Value HostsTable::StalenessAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return CompatUtility::GetCheckableStaleness(host); } Value HostsTable::GroupsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr groups = host->GetGroups(); if (!groups) return Empty; return groups; } Value HostsTable::ContactGroupsAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; Array::Ptr contactgroup_names = new Array(); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(host)) { contactgroup_names->Add(usergroup->GetName()); } return contactgroup_names; } Value HostsTable::ServicesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; std::vector rservices = host->GetServices(); Array::Ptr services = new Array(); services->Reserve(rservices.size()); for (const Service::Ptr& service : rservices) { services->Add(service->GetShortName()); } return services; } Value HostsTable::ServicesWithStateAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; std::vector rservices = host->GetServices(); Array::Ptr services = new Array(); services->Reserve(rservices.size()); for (const Service::Ptr& service : rservices) { Array::Ptr svc_add = new Array(); svc_add->Add(service->GetShortName()); svc_add->Add(service->GetState()); svc_add->Add(service->HasBeenChecked() ? 1 : 0); services->Add(svc_add); } return services; } Value HostsTable::ServicesWithInfoAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; std::vector rservices = host->GetServices(); Array::Ptr services = new Array(); services->Reserve(rservices.size()); for (const Service::Ptr& service : rservices) { Array::Ptr svc_add = new Array(); svc_add->Add(service->GetShortName()); svc_add->Add(service->GetState()); svc_add->Add(service->HasBeenChecked() ? 1 : 0); String output; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) output = CompatUtility::GetCheckResultOutput(cr); svc_add->Add(output); services->Add(svc_add); } return services; } Value HostsTable::CheckSourceAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; CheckResult::Ptr cr = host->GetLastCheckResult(); if (cr) return cr->GetCheckSource(); return Empty; } Value HostsTable::IsReachableAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return host->IsReachable(); } Value HostsTable::OriginalAttributesAccessor(const Value& row) { Host::Ptr host = static_cast(row); if (!host) return Empty; return JsonEncode(host->GetOriginalAttributes()); } icinga2-2.8.1/lib/livestatus/hoststable.hpp000066400000000000000000000166641322762156600207170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HOSTSTABLE_H #define HOSTSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API HostsTable : public Table { public: DECLARE_PTR_TYPEDEFS(HostsTable); HostsTable(LivestatusGroupByType type = LivestatusGroupByNone); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Object::Ptr HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject); static Value NameAccessor(const Value& row); static Value DisplayNameAccessor(const Value& row); static Value AddressAccessor(const Value& row); static Value Address6Accessor(const Value& row); static Value CheckCommandAccessor(const Value& row); static Value CheckCommandExpandedAccessor(const Value& row); static Value EventHandlerAccessor(const Value& row); static Value CheckPeriodAccessor(const Value& row); static Value NotesAccessor(const Value& row); static Value NotesExpandedAccessor(const Value& row); static Value NotesUrlAccessor(const Value& row); static Value NotesUrlExpandedAccessor(const Value& row); static Value ActionUrlAccessor(const Value& row); static Value ActionUrlExpandedAccessor(const Value& row); static Value PluginOutputAccessor(const Value& row); static Value PerfDataAccessor(const Value& row); static Value IconImageAccessor(const Value& row); static Value IconImageExpandedAccessor(const Value& row); static Value IconImageAltAccessor(const Value& row); static Value LongPluginOutputAccessor(const Value& row); static Value MaxCheckAttemptsAccessor(const Value& row); static Value FlapDetectionEnabledAccessor(const Value& row); static Value ProcessPerformanceDataAccessor(const Value& row); static Value AcceptPassiveChecksAccessor(const Value& row); static Value EventHandlerEnabledAccessor(const Value& row); static Value AcknowledgementTypeAccessor(const Value& row); static Value CheckTypeAccessor(const Value& row); static Value LastStateAccessor(const Value& row); static Value LastHardStateAccessor(const Value& row); static Value CurrentAttemptAccessor(const Value& row); static Value LastNotificationAccessor(const Value& row); static Value NextNotificationAccessor(const Value& row); static Value NextCheckAccessor(const Value& row); static Value LastHardStateChangeAccessor(const Value& row); static Value HasBeenCheckedAccessor(const Value& row); static Value CurrentNotificationNumberAccessor(const Value& row); static Value TotalServicesAccessor(const Value& row); static Value ChecksEnabledAccessor(const Value& row); static Value NotificationsEnabledAccessor(const Value& row); static Value AcknowledgedAccessor(const Value& row); static Value StateAccessor(const Value& row); static Value StateTypeAccessor(const Value& row); static Value NoMoreNotificationsAccessor(const Value& row); static Value LastCheckAccessor(const Value& row); static Value LastStateChangeAccessor(const Value& row); static Value LastTimeUpAccessor(const Value& row); static Value LastTimeDownAccessor(const Value& row); static Value LastTimeUnreachableAccessor(const Value& row); static Value IsFlappingAccessor(const Value& row); static Value ScheduledDowntimeDepthAccessor(const Value& row); static Value ActiveChecksEnabledAccessor(const Value& row); static Value CheckOptionsAccessor(const Value& row); static Value CheckIntervalAccessor(const Value& row); static Value RetryIntervalAccessor(const Value& row); static Value NotificationIntervalAccessor(const Value& row); static Value LowFlapThresholdAccessor(const Value& row); static Value HighFlapThresholdAccessor(const Value& row); static Value LatencyAccessor(const Value& row); static Value ExecutionTimeAccessor(const Value& row); static Value PercentStateChangeAccessor(const Value& row); static Value InNotificationPeriodAccessor(const Value& row); static Value InCheckPeriodAccessor(const Value& row); static Value ContactsAccessor(const Value& row); static Value DowntimesAccessor(const Value& row); static Value DowntimesWithInfoAccessor(const Value& row); static Value CommentsAccessor(const Value& row); static Value CommentsWithInfoAccessor(const Value& row); static Value CommentsWithExtraInfoAccessor(const Value& row); static Value CustomVariableNamesAccessor(const Value& row); static Value CustomVariableValuesAccessor(const Value& row); static Value CustomVariablesAccessor(const Value& row); static Value ParentsAccessor(const Value& row); static Value ChildsAccessor(const Value& row); static Value NumServicesAccessor(const Value& row); static Value WorstServiceStateAccessor(const Value& row); static Value NumServicesOkAccessor(const Value& row); static Value NumServicesWarnAccessor(const Value& row); static Value NumServicesCritAccessor(const Value& row); static Value NumServicesUnknownAccessor(const Value& row); static Value NumServicesPendingAccessor(const Value& row); static Value WorstServiceHardStateAccessor(const Value& row); static Value NumServicesHardOkAccessor(const Value& row); static Value NumServicesHardWarnAccessor(const Value& row); static Value NumServicesHardCritAccessor(const Value& row); static Value NumServicesHardUnknownAccessor(const Value& row); static Value HardStateAccessor(const Value& row); static Value StalenessAccessor(const Value& row); static Value GroupsAccessor(const Value& row); static Value ContactGroupsAccessor(const Value& row); static Value ServicesAccessor(const Value& row); static Value ServicesWithStateAccessor(const Value& row); static Value ServicesWithInfoAccessor(const Value& row); static Value CheckSourceAccessor(const Value& row); static Value IsReachableAccessor(const Value& row); static Value CVIsJsonAccessor(const Value& row); static Value OriginalAttributesAccessor(const Value& row); }; } #endif /* HOSTSTABLE_H */ icinga2-2.8.1/lib/livestatus/i2-livestatus.hpp000066400000000000000000000034451322762156600212530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2LIVESTATUS_H #define I2LIVESTATUS_H /** * @defgroup icinga Livestatus * * The Livestatus library implements the Livestatus protocol for Icinga. */ #include "base/i2-base.hpp" #ifdef I2_LIVESTATUS_BUILD # define I2_LIVESTATUS_API I2_EXPORT #else /* I2_LIVESTATUS_BUILD */ # define I2_LIVESTATUS_API I2_IMPORT #endif /* I2_LIVESTATUS_BUILD */ #endif /* I2LIVESTATUS_H */ icinga2-2.8.1/lib/livestatus/invavgaggregator.cpp000066400000000000000000000044151322762156600220660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/invavgaggregator.hpp" using namespace icinga; InvAvgAggregator::InvAvgAggregator(const String& attr) : m_InvAvgAttr(attr) { } InvAvgAggregatorState *InvAvgAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new InvAvgAggregatorState(); return static_cast(*state); } void InvAvgAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_InvAvgAttr); Value value = column.ExtractValue(row); InvAvgAggregatorState *pstate = EnsureState(state); pstate->InvAvg += (1.0 / value); pstate->InvAvgCount++; } double InvAvgAggregator::GetResultAndFreeState(AggregatorState *state) const { InvAvgAggregatorState *pstate = EnsureState(&state); double result = pstate->InvAvg / pstate->InvAvgCount; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/invavgaggregator.hpp000066400000000000000000000043541322762156600220750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef INVAVGAGGREGATOR_H #define INVAVGAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct InvAvgAggregatorState : public AggregatorState { InvAvgAggregatorState(void) : InvAvg(0), InvAvgCount(0) { } double InvAvg; double InvAvgCount; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API InvAvgAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(InvAvgAggregator); InvAvgAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_InvAvgAttr; static InvAvgAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* INVAVGAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/invsumaggregator.cpp000066400000000000000000000043371322762156600221200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/invsumaggregator.hpp" using namespace icinga; InvSumAggregator::InvSumAggregator(const String& attr) : m_InvSumAttr(attr) { } InvSumAggregatorState *InvSumAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new InvSumAggregatorState(); return static_cast(*state); } void InvSumAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_InvSumAttr); Value value = column.ExtractValue(row); InvSumAggregatorState *pstate = EnsureState(state); pstate->InvSum += (1.0 / value); } double InvSumAggregator::GetResultAndFreeState(AggregatorState *state) const { InvSumAggregatorState *pstate = EnsureState(&state); double result = pstate->InvSum; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/invsumaggregator.hpp000066400000000000000000000043311322762156600221170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef INVSUMAGGREGATOR_H #define INVSUMAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API InvSumAggregatorState : public AggregatorState { InvSumAggregatorState(void) : InvSum(0) { } double InvSum; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API InvSumAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(InvSumAggregator); InvSumAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_InvSumAttr; static InvSumAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* INVSUMAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/livestatuslistener.cpp000066400000000000000000000152311322762156600225000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/livestatuslistener.hpp" #include "livestatus/livestatuslistener.tcpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/objectlock.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/tcpsocket.hpp" #include "base/unixsocket.hpp" #include "base/networkstream.hpp" #include "base/application.hpp" #include "base/function.hpp" #include "base/statsfunction.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_TYPE(LivestatusListener); static int l_ClientsConnected = 0; static int l_Connections = 0; static boost::mutex l_ComponentMutex; REGISTER_STATSFUNCTION(LivestatusListener, &LivestatusListener::StatsFunc); void LivestatusListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const LivestatusListener::Ptr& livestatuslistener : ConfigType::GetObjectsByType()) { Dictionary::Ptr stats = new Dictionary(); stats->Set("connections", l_Connections); nodes->Set(livestatuslistener->GetName(), stats); perfdata->Add(new PerfdataValue("livestatuslistener_" + livestatuslistener->GetName() + "_connections", l_Connections)); } status->Set("livestatuslistener", nodes); } /** * Starts the component. */ void LivestatusListener::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "LivestatusListener") << "'" << GetName() << "' started."; if (GetSocketType() == "tcp") { TcpSocket::Ptr socket = new TcpSocket(); try { socket->Bind(GetBindHost(), GetBindPort(), AF_UNSPEC); } catch (std::exception&) { Log(LogCritical, "LivestatusListener") << "Cannot bind TCP socket on host '" << GetBindHost() << "' port '" << GetBindPort() << "'."; return; } m_Listener = socket; m_Thread = boost::thread(boost::bind(&LivestatusListener::ServerThreadProc, this)); Log(LogInformation, "LivestatusListener") << "Created TCP socket listening on host '" << GetBindHost() << "' port '" << GetBindPort() << "'."; } else if (GetSocketType() == "unix") { #ifndef _WIN32 UnixSocket::Ptr socket = new UnixSocket(); try { socket->Bind(GetSocketPath()); } catch (std::exception&) { Log(LogCritical, "LivestatusListener") << "Cannot bind UNIX socket to '" << GetSocketPath() << "'."; return; } /* group must be able to write */ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if (chmod(GetSocketPath().CStr(), mode) < 0) { Log(LogCritical, "LivestatusListener") << "chmod() on unix socket '" << GetSocketPath() << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; return; } m_Listener = socket; m_Thread = boost::thread(boost::bind(&LivestatusListener::ServerThreadProc, this)); Log(LogInformation, "LivestatusListener") << "Created UNIX socket in '" << GetSocketPath() << "'."; #else /* no UNIX sockets on windows */ Log(LogCritical, "LivestatusListener", "Unix sockets are not supported on Windows."); return; #endif } } void LivestatusListener::Stop(bool runtimeRemoved) { ObjectImpl::Stop(runtimeRemoved); Log(LogInformation, "LivestatusListener") << "'" << GetName() << "' stopped."; m_Listener->Close(); if (m_Thread.joinable()) m_Thread.join(); } int LivestatusListener::GetClientsConnected(void) { boost::mutex::scoped_lock lock(l_ComponentMutex); return l_ClientsConnected; } int LivestatusListener::GetConnections(void) { boost::mutex::scoped_lock lock(l_ComponentMutex); return l_Connections; } void LivestatusListener::ServerThreadProc(void) { m_Listener->Listen(); try { for (;;) { timeval tv = { 0, 500000 }; if (m_Listener->Poll(true, false, &tv)) { Socket::Ptr client = m_Listener->Accept(); Log(LogNotice, "LivestatusListener", "Client connected"); Utility::QueueAsyncCallback(boost::bind(&LivestatusListener::ClientHandler, this, client), LowLatencyScheduler); } if (!IsActive()) break; } } catch (std::exception&) { Log(LogCritical, "LivestatusListener", "Cannot accept new connection."); } m_Listener->Close(); } void LivestatusListener::ClientHandler(const Socket::Ptr& client) { { boost::mutex::scoped_lock lock(l_ComponentMutex); l_ClientsConnected++; l_Connections++; } Stream::Ptr stream = new NetworkStream(client); StreamReadContext context; for (;;) { String line; std::vector lines; for (;;) { StreamReadStatus srs = stream->ReadLine(&line, context); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; if (line.GetLength() > 0) lines.push_back(line); else break; } if (lines.empty()) break; LivestatusQuery::Ptr query = new LivestatusQuery(lines, GetCompatLogPath()); if (!query->Execute(stream)) break; } { boost::mutex::scoped_lock lock(l_ComponentMutex); l_ClientsConnected--; } } void LivestatusListener::ValidateSocketType(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateSocketType(value, utils); if (value != "unix" && value != "tcp") BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("socket_type"), "Socket type '" + value + "' is invalid.")); } icinga2-2.8.1/lib/livestatus/livestatuslistener.hpp000066400000000000000000000046651322762156600225160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LIVESTATUSLISTENER_H #define LIVESTATUSLISTENER_H #include "livestatus/i2-livestatus.hpp" #include "livestatus/livestatuslistener.thpp" #include "livestatus/livestatusquery.hpp" #include "base/socket.hpp" #include using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API LivestatusListener : public ObjectImpl { public: DECLARE_OBJECT(LivestatusListener); DECLARE_OBJECTNAME(LivestatusListener); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); static int GetClientsConnected(void); static int GetConnections(void); virtual void ValidateSocketType(const String& value, const ValidationUtils& utils) override; protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: void ServerThreadProc(void); void ClientHandler(const Socket::Ptr& client); Socket::Ptr m_Listener; boost::thread m_Thread; }; } #endif /* LIVESTATUSLISTENER_H */ icinga2-2.8.1/lib/livestatus/livestatuslistener.ti000066400000000000000000000037651322762156600223430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library livestatus; namespace icinga { class LivestatusListener : ConfigObject { [config] String socket_type { default {{{ return "unix"; }}} }; [config] String socket_path { default {{{ return Application::GetRunDir() + "/icinga2/cmd/livestatus"; }}} }; [config] String bind_host { default {{{ return "127.0.0.1"; }}} }; [config] String bind_port { default {{{ return "6558"; }}} }; [config] String compat_log_path { default {{{ return Application::GetLocalStateDir() + "/log/icinga2/compat"; }}} }; }; } icinga2-2.8.1/lib/livestatus/livestatuslogutility.cpp000066400000000000000000000253431322762156600230650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/livestatuslogutility.hpp" #include "icinga/service.hpp" #include "icinga/host.hpp" #include "icinga/user.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include "base/logger.hpp" #include #include #include #include #include #include #include using namespace icinga; void LivestatusLogUtility::CreateLogIndex(const String& path, std::map& index) { Utility::Glob(path + "/icinga.log", boost::bind(&LivestatusLogUtility::CreateLogIndexFileHandler, _1, boost::ref(index)), GlobFile); Utility::Glob(path + "/archives/*.log", boost::bind(&LivestatusLogUtility::CreateLogIndexFileHandler, _1, boost::ref(index)), GlobFile); } void LivestatusLogUtility::CreateLogIndexFileHandler(const String& path, std::map& index) { std::ifstream stream; stream.open(path.CStr(), std::ifstream::in); if (!stream) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open log file: " + path)); /* read the first bytes to get the timestamp: [123456789] */ char buffer[12]; stream.read(buffer, 12); if (buffer[0] != '[' || buffer[11] != ']') { /* this can happen for directories too, silently ignore them */ return; } /* extract timestamp */ buffer[11] = 0; time_t ts_start = atoi(buffer+1); stream.close(); Log(LogDebug, "LivestatusLogUtility") << "Indexing log file: '" << path << "' with timestamp start: '" << ts_start << "'."; index[ts_start] = path; } void LivestatusLogUtility::CreateLogCache(std::map index, HistoryTable *table, time_t from, time_t until, const AddRowFunction& addRowFn) { ASSERT(table); /* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */ unsigned long line_count = 0; for (const auto& kv : index) { unsigned int ts = kv.first; /* skip log files not in range (performance optimization) */ if (ts < from || ts > until) continue; String log_file = index[ts]; int lineno = 0; std::ifstream fp; fp.exceptions(std::ifstream::badbit); fp.open(log_file.CStr(), std::ifstream::in); while (fp.good()) { std::string line; std::getline(fp, line); if (line.empty()) continue; /* Ignore empty lines */ Dictionary::Ptr log_entry_attrs = LivestatusLogUtility::GetAttributes(line); /* no attributes available - invalid log line */ if (!log_entry_attrs) { Log(LogDebug, "LivestatusLogUtility") << "Skipping invalid log line: '" << line << "'."; continue; } table->UpdateLogEntries(log_entry_attrs, line_count, lineno, addRowFn); line_count++; lineno++; } fp.close(); } } Dictionary::Ptr LivestatusLogUtility::GetAttributes(const String& text) { Dictionary::Ptr bag = new Dictionary(); /* * [1379025342] SERVICE NOTIFICATION: contactname;hostname;servicedesc;WARNING;true;foo output */ unsigned long time = atoi(text.SubStr(1, 11).CStr()); Log(LogDebug, "LivestatusLogUtility") << "Processing log line: '" << text << "'."; bag->Set("time", time); size_t colon = text.FindFirstOf(':'); size_t colon_offset = colon - 13; String type = String(text.SubStr(13, colon_offset)).Trim(); String options = String(text.SubStr(colon + 1)).Trim(); bag->Set("type", type); bag->Set("options", options); std::vector tokens; boost::algorithm::split(tokens, options, boost::is_any_of(";")); /* set default values */ bag->Set("class", LogEntryClassInfo); bag->Set("log_type", 0); bag->Set("state", 0); bag->Set("attempt", 0); bag->Set("message", text); /* used as 'message' in log table, and 'log_output' in statehist table */ if (type.Contains("INITIAL HOST STATE") || type.Contains("CURRENT HOST STATE") || type.Contains("HOST ALERT")) { if (tokens.size() < 5) return bag; bag->Set("host_name", tokens[0]); bag->Set("state", Host::StateFromString(tokens[1])); bag->Set("state_type", tokens[2]); bag->Set("attempt", atoi(tokens[3].CStr())); bag->Set("plugin_output", tokens[4]); if (type.Contains("INITIAL HOST STATE")) { bag->Set("class", LogEntryClassState); bag->Set("log_type", LogEntryTypeHostInitialState); } else if (type.Contains("CURRENT HOST STATE")) { bag->Set("class", LogEntryClassState); bag->Set("log_type", LogEntryTypeHostCurrentState); } else { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeHostAlert); } return bag; } else if (type.Contains("HOST DOWNTIME ALERT") || type.Contains("HOST FLAPPING ALERT")) { if (tokens.size() < 3) return bag; bag->Set("host_name", tokens[0]); bag->Set("state_type", tokens[1]); bag->Set("comment", tokens[2]); if (type.Contains("HOST FLAPPING ALERT")) { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeHostFlapping); } else { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeHostDowntimeAlert); } return bag; } else if (type.Contains("INITIAL SERVICE STATE") || type.Contains("CURRENT SERVICE STATE") || type.Contains("SERVICE ALERT")) { if (tokens.size() < 6) return bag; bag->Set("host_name", tokens[0]); bag->Set("service_description", tokens[1]); bag->Set("state", Service::StateFromString(tokens[2])); bag->Set("state_type", tokens[3]); bag->Set("attempt", atoi(tokens[4].CStr())); bag->Set("plugin_output", tokens[5]); if (type.Contains("INITIAL SERVICE STATE")) { bag->Set("class", LogEntryClassState); bag->Set("log_type", LogEntryTypeServiceInitialState); } else if (type.Contains("CURRENT SERVICE STATE")) { bag->Set("class", LogEntryClassState); bag->Set("log_type", LogEntryTypeServiceCurrentState); } else { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeServiceAlert); } return bag; } else if (type.Contains("SERVICE DOWNTIME ALERT") || type.Contains("SERVICE FLAPPING ALERT")) { if (tokens.size() < 4) return bag; bag->Set("host_name", tokens[0]); bag->Set("service_description", tokens[1]); bag->Set("state_type", tokens[2]); bag->Set("comment", tokens[3]); if (type.Contains("SERVICE FLAPPING ALERT")) { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeServiceFlapping); } else { bag->Set("class", LogEntryClassAlert); bag->Set("log_type", LogEntryTypeServiceDowntimeAlert); } return bag; } else if (type.Contains("TIMEPERIOD TRANSITION")) { if (tokens.size() < 4) return bag; bag->Set("class", LogEntryClassState); bag->Set("log_type", LogEntryTypeTimeperiodTransition); bag->Set("host_name", tokens[0]); bag->Set("service_description", tokens[1]); bag->Set("state_type", tokens[2]); bag->Set("comment", tokens[3]); } else if (type.Contains("HOST NOTIFICATION")) { if (tokens.size() < 6) return bag; bag->Set("contact_name", tokens[0]); bag->Set("host_name", tokens[1]); bag->Set("state_type", tokens[2].CStr()); bag->Set("state", Service::StateFromString(tokens[3])); bag->Set("command_name", tokens[4]); bag->Set("plugin_output", tokens[5]); bag->Set("class", LogEntryClassNotification); bag->Set("log_type", LogEntryTypeHostNotification); return bag; } else if (type.Contains("SERVICE NOTIFICATION")) { if (tokens.size() < 7) return bag; bag->Set("contact_name", tokens[0]); bag->Set("host_name", tokens[1]); bag->Set("service_description", tokens[2]); bag->Set("state_type", tokens[3].CStr()); bag->Set("state", Service::StateFromString(tokens[4])); bag->Set("command_name", tokens[5]); bag->Set("plugin_output", tokens[6]); bag->Set("class", LogEntryClassNotification); bag->Set("log_type", LogEntryTypeServiceNotification); return bag; } else if (type.Contains("PASSIVE HOST CHECK")) { if (tokens.size() < 3) return bag; bag->Set("host_name", tokens[0]); bag->Set("state", Host::StateFromString(tokens[1])); bag->Set("plugin_output", tokens[2]); bag->Set("class", LogEntryClassPassive); return bag; } else if (type.Contains("PASSIVE SERVICE CHECK")) { if (tokens.size() < 4) return bag; bag->Set("host_name", tokens[0]); bag->Set("service_description", tokens[1]); bag->Set("state", Host::StateFromString(tokens[2])); bag->Set("plugin_output", tokens[3]); bag->Set("class", LogEntryClassPassive); return bag; } else if (type.Contains("EXTERNAL COMMAND")) { bag->Set("class", LogEntryClassCommand); /* string processing not implemented in 1.x */ return bag; } else if (type.Contains("LOG VERSION")) { bag->Set("class", LogEntryClassProgram); bag->Set("log_type", LogEntryTypeVersion); return bag; } else if (type.Contains("logging initial states")) { bag->Set("class", LogEntryClassProgram); bag->Set("log_type", LogEntryTypeInitialStates); return bag; } else if (type.Contains("starting... (PID=")) { bag->Set("class", LogEntryClassProgram); bag->Set("log_type", LogEntryTypeProgramStarting); return bag; } /* program */ else if (type.Contains("restarting...") || type.Contains("shutting down...") || type.Contains("Bailing out") || type.Contains("active mode...") || type.Contains("standby mode...")) { bag->Set("class", LogEntryClassProgram); return bag; } return bag; } icinga2-2.8.1/lib/livestatus/livestatuslogutility.hpp000066400000000000000000000056041322762156600230700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LIVESTATUSLOGUTILITY_H #define LIVESTATUSLOGUTILITY_H #include "livestatus/historytable.hpp" using namespace icinga; namespace icinga { enum LogEntryType { LogEntryTypeHostAlert, LogEntryTypeHostDowntimeAlert, LogEntryTypeHostFlapping, LogEntryTypeHostNotification, LogEntryTypeHostInitialState, LogEntryTypeHostCurrentState, LogEntryTypeServiceAlert, LogEntryTypeServiceDowntimeAlert, LogEntryTypeServiceFlapping, LogEntryTypeServiceNotification, LogEntryTypeServiceInitialState, LogEntryTypeServiceCurrentState, LogEntryTypeTimeperiodTransition, LogEntryTypeVersion, LogEntryTypeInitialStates, LogEntryTypeProgramStarting }; enum LogEntryClass { LogEntryClassInfo = 0, LogEntryClassAlert = 1, LogEntryClassProgram = 2, LogEntryClassNotification = 3, LogEntryClassPassive = 4, LogEntryClassCommand = 5, LogEntryClassState = 6, LogEntryClassText = 7 }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API LivestatusLogUtility { public: static void CreateLogIndex(const String& path, std::map& index); static void CreateLogIndexFileHandler(const String& path, std::map& index); static void CreateLogCache(std::map index, HistoryTable *table, time_t from, time_t until, const AddRowFunction& addRowFn); static Dictionary::Ptr GetAttributes(const String& text); private: LivestatusLogUtility(void); }; } #endif /* LIVESTATUSLOGUTILITY_H */ icinga2-2.8.1/lib/livestatus/livestatusquery.cpp000066400000000000000000000444751322762156600220340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/livestatusquery.hpp" #include "livestatus/countaggregator.hpp" #include "livestatus/sumaggregator.hpp" #include "livestatus/minaggregator.hpp" #include "livestatus/maxaggregator.hpp" #include "livestatus/avgaggregator.hpp" #include "livestatus/stdaggregator.hpp" #include "livestatus/invsumaggregator.hpp" #include "livestatus/invavgaggregator.hpp" #include "livestatus/attributefilter.hpp" #include "livestatus/negatefilter.hpp" #include "livestatus/orfilter.hpp" #include "livestatus/andfilter.hpp" #include "icinga/externalcommandprocessor.hpp" #include "base/debug.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/utility.hpp" #include "base/json.hpp" #include "base/serializer.hpp" #include "base/timer.hpp" #include "base/initialize.hpp" #include #include #include #include using namespace icinga; static int l_ExternalCommands = 0; static boost::mutex l_QueryMutex; LivestatusQuery::LivestatusQuery(const std::vector& lines, const String& compat_log_path) : m_KeepAlive(false), m_OutputFormat("csv"), m_ColumnHeaders(true), m_Limit(-1), m_ErrorCode(0), m_LogTimeFrom(0), m_LogTimeUntil(static_cast(Utility::GetTime())) { if (lines.size() == 0) { m_Verb = "ERROR"; m_ErrorCode = LivestatusErrorQuery; m_ErrorMessage = "Empty Query. Aborting."; return; } String msg; for (const String& line : lines) { msg += line + "\n"; } Log(LogDebug, "LivestatusQuery", msg); m_CompatLogPath = compat_log_path; /* default separators */ m_Separators.push_back("\n"); m_Separators.push_back(";"); m_Separators.push_back(","); m_Separators.push_back("|"); String line = lines[0]; size_t sp_index = line.FindFirstOf(" "); if (sp_index == String::NPos) BOOST_THROW_EXCEPTION(std::runtime_error("Livestatus header must contain a verb.")); String verb = line.SubStr(0, sp_index); String target = line.SubStr(sp_index + 1); m_Verb = verb; if (m_Verb == "COMMAND") { m_KeepAlive = true; m_Command = target; } else if (m_Verb == "GET") { m_Table = target; } else { m_Verb = "ERROR"; m_ErrorCode = LivestatusErrorQuery; m_ErrorMessage = "Unknown livestatus verb: " + m_Verb; return; } std::deque filters, stats; std::deque aggregators; for (unsigned int i = 1; i < lines.size(); i++) { line = lines[i]; size_t col_index = line.FindFirstOf(":"); String header = line.SubStr(0, col_index); String params; //OutputFormat:json or OutputFormat: json if (line.GetLength() > col_index + 1) params = line.SubStr(col_index + 1).Trim(); if (header == "ResponseHeader") m_ResponseHeader = params; else if (header == "OutputFormat") m_OutputFormat = params; else if (header == "KeepAlive") m_KeepAlive = (params == "on"); else if (header == "Columns") { m_ColumnHeaders = false; // Might be explicitly re-enabled later on boost::algorithm::split(m_Columns, params, boost::is_any_of(" ")); } else if (header == "Separators") { std::vector separators; boost::algorithm::split(separators, params, boost::is_any_of(" ")); /* ugly ascii long to char conversion, but works */ if (separators.size() > 0) m_Separators[0] = String(1, static_cast(Convert::ToLong(separators[0]))); if (separators.size() > 1) m_Separators[1] = String(1, static_cast(Convert::ToLong(separators[1]))); if (separators.size() > 2) m_Separators[2] = String(1, static_cast(Convert::ToLong(separators[2]))); if (separators.size() > 3) m_Separators[3] = String(1, static_cast(Convert::ToLong(separators[3]))); } else if (header == "ColumnHeaders") m_ColumnHeaders = (params == "on"); else if (header == "Limit") m_Limit = Convert::ToLong(params); else if (header == "Filter") { Filter::Ptr filter = ParseFilter(params, m_LogTimeFrom, m_LogTimeUntil); if (!filter) { m_Verb = "ERROR"; m_ErrorCode = LivestatusErrorQuery; m_ErrorMessage = "Invalid filter specification: " + line; return; } filters.push_back(filter); } else if (header == "Stats") { m_ColumnHeaders = false; // Might be explicitly re-enabled later on std::vector tokens; boost::algorithm::split(tokens, params, boost::is_any_of(" ")); if (tokens.size() < 2) { m_Verb = "ERROR"; m_ErrorCode = LivestatusErrorQuery; m_ErrorMessage = "Missing aggregator column name: " + line; return; } String aggregate_arg = tokens[0]; String aggregate_attr = tokens[1]; Aggregator::Ptr aggregator; Filter::Ptr filter; if (aggregate_arg == "sum") { aggregator = new SumAggregator(aggregate_attr); } else if (aggregate_arg == "min") { aggregator = new MinAggregator(aggregate_attr); } else if (aggregate_arg == "max") { aggregator = new MaxAggregator(aggregate_attr); } else if (aggregate_arg == "avg") { aggregator = new AvgAggregator(aggregate_attr); } else if (aggregate_arg == "std") { aggregator = new StdAggregator(aggregate_attr); } else if (aggregate_arg == "suminv") { aggregator = new InvSumAggregator(aggregate_attr); } else if (aggregate_arg == "avginv") { aggregator = new InvAvgAggregator(aggregate_attr); } else { filter = ParseFilter(params, m_LogTimeFrom, m_LogTimeUntil); if (!filter) { m_Verb = "ERROR"; m_ErrorCode = LivestatusErrorQuery; m_ErrorMessage = "Invalid filter specification: " + line; return; } aggregator = new CountAggregator(); } aggregator->SetFilter(filter); aggregators.push_back(aggregator); stats.push_back(filter); } else if (header == "Or" || header == "And" || header == "StatsOr" || header == "StatsAnd") { std::deque& deq = (header == "Or" || header == "And") ? filters : stats; unsigned int num = Convert::ToLong(params); CombinerFilter::Ptr filter; if (header == "Or" || header == "StatsOr") { filter = new OrFilter(); Log(LogDebug, "LivestatusQuery") << "Add OR filter for " << params << " column(s). " << deq.size() << " filters available."; } else { filter = new AndFilter(); Log(LogDebug, "LivestatusQuery") << "Add AND filter for " << params << " column(s). " << deq.size() << " filters available."; } if (num > deq.size()) { m_Verb = "ERROR"; m_ErrorCode = 451; m_ErrorMessage = "Or/StatsOr is referencing " + Convert::ToString(num) + " filters; stack only contains " + Convert::ToString(static_cast(deq.size())) + " filters"; return; } while (num > 0 && num--) { filter->AddSubFilter(deq.back()); Log(LogDebug, "LivestatusQuery") << "Add " << num << " filter."; deq.pop_back(); if (&deq == &stats) aggregators.pop_back(); } deq.push_back(filter); if (&deq == &stats) { Aggregator::Ptr aggregator = new CountAggregator(); aggregator->SetFilter(filter); aggregators.push_back(aggregator); } } else if (header == "Negate" || header == "StatsNegate") { std::deque& deq = (header == "Negate") ? filters : stats; if (deq.empty()) { m_Verb = "ERROR"; m_ErrorCode = 451; m_ErrorMessage = "Negate/StatsNegate used, however the filter stack is empty"; return; } Filter::Ptr filter = deq.back(); deq.pop_back(); if (!filter) { m_Verb = "ERROR"; m_ErrorCode = 451; m_ErrorMessage = "Negate/StatsNegate used, however last stats doesn't have a filter"; return; } deq.push_back(new NegateFilter(filter)); if (deq == stats) { Aggregator::Ptr aggregator = aggregators.back(); aggregator->SetFilter(filter); } } } /* Combine all top-level filters into a single filter. */ AndFilter::Ptr top_filter = new AndFilter(); for (const Filter::Ptr& filter : filters) { top_filter->AddSubFilter(filter); } m_Filter = top_filter; m_Aggregators.swap(aggregators); } int LivestatusQuery::GetExternalCommands(void) { boost::mutex::scoped_lock lock(l_QueryMutex); return l_ExternalCommands; } Filter::Ptr LivestatusQuery::ParseFilter(const String& params, unsigned long& from, unsigned long& until) { /* * time >= 1382696656 * type = SERVICE FLAPPING ALERT */ std::vector tokens; size_t sp_index; String temp_buffer = params; /* extract attr and op */ for (int i = 0; i < 2; i++) { sp_index = temp_buffer.FindFirstOf(" "); /* check if this is the last argument */ if (sp_index == String::NPos) { /* 'attr op' or 'attr op val' is valid */ if (i < 1) BOOST_THROW_EXCEPTION(std::runtime_error("Livestatus filter '" + params + "' does not contain all required fields.")); break; } tokens.push_back(temp_buffer.SubStr(0, sp_index)); temp_buffer = temp_buffer.SubStr(sp_index + 1); } /* add the rest as value */ tokens.push_back(temp_buffer); if (tokens.size() == 2) tokens.push_back(""); if (tokens.size() < 3) return Filter::Ptr(); bool negate = false; String attr = tokens[0]; String op = tokens[1]; String val = tokens[2]; if (op == "!=") { op = "="; negate = true; } else if (op == "!~") { op = "~"; negate = true; } else if (op == "!=~") { op = "=~"; negate = true; } else if (op == "!~~") { op = "~~"; negate = true; } Filter::Ptr filter = new AttributeFilter(attr, op, val); if (negate) filter = new NegateFilter(filter); /* pre-filter log time duration */ if (attr == "time") { if (op == "<" || op == "<=") { until = Convert::ToLong(val); } else if (op == ">" || op == ">=") { from = Convert::ToLong(val); } } Log(LogDebug, "LivestatusQuery") << "Parsed filter with attr: '" << attr << "' op: '" << op << "' val: '" << val << "'."; return filter; } void LivestatusQuery::BeginResultSet(std::ostream& fp) const { if (m_OutputFormat == "json" || m_OutputFormat == "python") fp << "["; } void LivestatusQuery::EndResultSet(std::ostream& fp) const { if (m_OutputFormat == "json" || m_OutputFormat == "python") fp << "]"; } void LivestatusQuery::AppendResultRow(std::ostream& fp, const Array::Ptr& row, bool& first_row) const { if (m_OutputFormat == "csv") { bool first = true; ObjectLock rlock(row); for (const Value& value : row) { if (first) first = false; else fp << m_Separators[1]; if (value.IsObjectType()) PrintCsvArray(fp, value, 0); else fp << value; } fp << m_Separators[0]; } else if (m_OutputFormat == "json") { if (!first_row) fp << ", "; fp << JsonEncode(row); } else if (m_OutputFormat == "python") { if (!first_row) fp << ", "; PrintPythonArray(fp, row); } first_row = false; } void LivestatusQuery::PrintCsvArray(std::ostream& fp, const Array::Ptr& array, int level) const { bool first = true; ObjectLock olock(array); for (const Value& value : array) { if (first) first = false; else fp << ((level == 0) ? m_Separators[2] : m_Separators[3]); if (value.IsObjectType()) PrintCsvArray(fp, value, level + 1); else if (value.IsBoolean()) fp << Convert::ToLong(value); else fp << value; } } void LivestatusQuery::PrintPythonArray(std::ostream& fp, const Array::Ptr& rs) const { fp << "[ "; bool first = true; for (const Value& value : rs) { if (first) first = false; else fp << ", "; if (value.IsObjectType()) PrintPythonArray(fp, value); else if (value.IsNumber()) fp << value; else fp << QuoteStringPython(value); } fp << " ]"; } String LivestatusQuery::QuoteStringPython(const String& str) { String result = str; boost::algorithm::replace_all(result, "\"", "\\\""); return "r\"" + result + "\""; } void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream) { Log(LogNotice, "LivestatusQuery") << "Table: " << m_Table; Table::Ptr table = Table::GetByName(m_Table, m_CompatLogPath, m_LogTimeFrom, m_LogTimeUntil); if (!table) { SendResponse(stream, LivestatusErrorNotFound, "Table '" + m_Table + "' does not exist."); return; } std::vector objects = table->FilterRows(m_Filter, m_Limit); std::vector columns; if (m_Columns.size() > 0) columns = m_Columns; else columns = table->GetColumnNames(); std::ostringstream result; bool first_row = true; BeginResultSet(result); if (m_Aggregators.empty()) { Array::Ptr header = new Array(); typedef std::pair ColumnPair; std::vector column_objs; column_objs.reserve(columns.size()); for (const String& columnName : columns) column_objs.push_back(std::make_pair(columnName, table->GetColumn(columnName))); for (const LivestatusRowValue& object : objects) { Array::Ptr row = new Array(); row->Reserve(column_objs.size()); for (const ColumnPair& cv : column_objs) { if (m_ColumnHeaders) header->Add(cv.first); row->Add(cv.second.ExtractValue(object.Row, object.GroupByType, object.GroupByObject)); } if (m_ColumnHeaders) { AppendResultRow(result, header, first_row); m_ColumnHeaders = false; } AppendResultRow(result, row, first_row); } } else { std::map, std::vector > allStats; /* add aggregated stats */ for (const LivestatusRowValue& object : objects) { std::vector statsKey; for (const String& columnName : m_Columns) { Column column = table->GetColumn(columnName); statsKey.push_back(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject)); } auto it = allStats.find(statsKey); if (it == allStats.end()) { std::vector newStats(m_Aggregators.size(), NULL); it = allStats.insert(std::make_pair(statsKey, newStats)).first; } auto& stats = it->second; int index = 0; for (const Aggregator::Ptr aggregator : m_Aggregators) { aggregator->Apply(table, object.Row, &stats[index]); index++; } } /* add column headers both for raw and aggregated data */ if (m_ColumnHeaders) { Array::Ptr header = new Array(); for (const String& columnName : m_Columns) { header->Add(columnName); } for (size_t i = 1; i <= m_Aggregators.size(); i++) { header->Add("stats_" + Convert::ToString(i)); } AppendResultRow(result, header, first_row); } for (const auto& kv : allStats) { Array::Ptr row = new Array(); row->Reserve(m_Columns.size() + m_Aggregators.size()); for (const Value& keyPart : kv.first) { row->Add(keyPart); } auto& stats = kv.second; for (size_t i = 0; i < m_Aggregators.size(); i++) row->Add(m_Aggregators[i]->GetResultAndFreeState(stats[i])); AppendResultRow(result, row, first_row); } /* add a bogus zero value if aggregated is empty*/ if (allStats.empty()) { Array::Ptr row = new Array(); for (size_t i = 1; i <= m_Aggregators.size(); i++) { row->Add(0); } AppendResultRow(result, row, first_row); } } EndResultSet(result); SendResponse(stream, LivestatusErrorOK, result.str()); } void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream) { { boost::mutex::scoped_lock lock(l_QueryMutex); l_ExternalCommands++; } Log(LogNotice, "LivestatusQuery") << "Executing command: " << m_Command; ExternalCommandProcessor::Execute(m_Command); SendResponse(stream, LivestatusErrorOK, ""); } void LivestatusQuery::ExecuteErrorHelper(const Stream::Ptr& stream) { Log(LogDebug, "LivestatusQuery") << "ERROR: Code: '" << m_ErrorCode << "' Message: '" << m_ErrorMessage << "'."; SendResponse(stream, m_ErrorCode, m_ErrorMessage); } void LivestatusQuery::SendResponse(const Stream::Ptr& stream, int code, const String& data) { if (m_ResponseHeader == "fixed16") PrintFixed16(stream, code, data); if (m_ResponseHeader == "fixed16" || code == LivestatusErrorOK) { try { stream->Write(data.CStr(), data.GetLength()); } catch (const std::exception&) { Log(LogCritical, "LivestatusQuery", "Cannot write query response to socket."); } } } void LivestatusQuery::PrintFixed16(const Stream::Ptr& stream, int code, const String& data) { ASSERT(code >= 100 && code <= 999); String sCode = Convert::ToString(code); String sLength = Convert::ToString(static_cast(data.GetLength())); String header = sCode + String(16 - 3 - sLength.GetLength() - 1, ' ') + sLength + m_Separators[0]; try { stream->Write(header.CStr(), header.GetLength()); } catch (const std::exception&) { Log(LogCritical, "LivestatusQuery", "Cannot write to TCP socket."); } } bool LivestatusQuery::Execute(const Stream::Ptr& stream) { try { Log(LogNotice, "LivestatusQuery") << "Executing livestatus query: " << m_Verb; if (m_Verb == "GET") ExecuteGetHelper(stream); else if (m_Verb == "COMMAND") ExecuteCommandHelper(stream); else if (m_Verb == "ERROR") ExecuteErrorHelper(stream); else BOOST_THROW_EXCEPTION(std::runtime_error("Invalid livestatus query verb.")); } catch (const std::exception& ex) { SendResponse(stream, LivestatusErrorQuery, DiagnosticInformation(ex)); } if (!m_KeepAlive) { stream->Close(); return false; } return true; } icinga2-2.8.1/lib/livestatus/livestatusquery.hpp000066400000000000000000000067631322762156600220370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LIVESTATUSQUERY_H #define LIVESTATUSQUERY_H #include "livestatus/filter.hpp" #include "livestatus/aggregator.hpp" #include "base/object.hpp" #include "base/array.hpp" #include "base/stream.hpp" #include "base/scriptframe.hpp" #include using namespace icinga; namespace icinga { enum LivestatusError { LivestatusErrorOK = 200, LivestatusErrorNotFound = 404, LivestatusErrorQuery = 452 }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API LivestatusQuery : public Object { public: DECLARE_PTR_TYPEDEFS(LivestatusQuery); LivestatusQuery(const std::vector& lines, const String& compat_log_path); bool Execute(const Stream::Ptr& stream); static int GetExternalCommands(void); private: String m_Verb; bool m_KeepAlive; /* Parameters for GET queries. */ String m_Table; std::vector m_Columns; std::vector m_Separators; Filter::Ptr m_Filter; std::deque m_Aggregators; String m_OutputFormat; bool m_ColumnHeaders; int m_Limit; String m_ResponseHeader; /* Parameters for COMMAND/SCRIPT queries. */ String m_Command; String m_Session; /* Parameters for invalid queries. */ int m_ErrorCode; String m_ErrorMessage; unsigned long m_LogTimeFrom; unsigned long m_LogTimeUntil; String m_CompatLogPath; void BeginResultSet(std::ostream& fp) const; void EndResultSet(std::ostream& fp) const; void AppendResultRow(std::ostream& fp, const Array::Ptr& row, bool& first_row) const; void PrintCsvArray(std::ostream& fp, const Array::Ptr& array, int level) const; void PrintPythonArray(std::ostream& fp, const Array::Ptr& array) const; static String QuoteStringPython(const String& str); void ExecuteGetHelper(const Stream::Ptr& stream); void ExecuteCommandHelper(const Stream::Ptr& stream); void ExecuteErrorHelper(const Stream::Ptr& stream); void SendResponse(const Stream::Ptr& stream, int code, const String& data); void PrintFixed16(const Stream::Ptr& stream, int code, const String& data); static Filter::Ptr ParseFilter(const String& params, unsigned long& from, unsigned long& until); }; } #endif /* LIVESTATUSQUERY_H */ icinga2-2.8.1/lib/livestatus/logtable.cpp000066400000000000000000000211341322762156600203170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/logtable.hpp" #include "livestatus/livestatuslogutility.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicestable.hpp" #include "livestatus/contactstable.hpp" #include "livestatus/commandstable.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "icinga/service.hpp" #include "icinga/host.hpp" #include "icinga/user.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" #include #include #include #include #include #include #include using namespace icinga; LogTable::LogTable(const String& compat_log_path, time_t from, time_t until) { /* store attributes for FetchRows */ m_TimeFrom = from; m_TimeUntil = until; m_CompatLogPath = compat_log_path; AddColumns(this); } void LogTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "time", Column(&LogTable::TimeAccessor, objectAccessor)); table->AddColumn(prefix + "lineno", Column(&LogTable::LinenoAccessor, objectAccessor)); table->AddColumn(prefix + "class", Column(&LogTable::ClassAccessor, objectAccessor)); table->AddColumn(prefix + "message", Column(&LogTable::MessageAccessor, objectAccessor)); table->AddColumn(prefix + "type", Column(&LogTable::TypeAccessor, objectAccessor)); table->AddColumn(prefix + "options", Column(&LogTable::OptionsAccessor, objectAccessor)); table->AddColumn(prefix + "comment", Column(&LogTable::CommentAccessor, objectAccessor)); table->AddColumn(prefix + "plugin_output", Column(&LogTable::PluginOutputAccessor, objectAccessor)); table->AddColumn(prefix + "state", Column(&LogTable::StateAccessor, objectAccessor)); table->AddColumn(prefix + "state_type", Column(&LogTable::StateTypeAccessor, objectAccessor)); table->AddColumn(prefix + "attempt", Column(&LogTable::AttemptAccessor, objectAccessor)); table->AddColumn(prefix + "service_description", Column(&LogTable::ServiceDescriptionAccessor, objectAccessor)); table->AddColumn(prefix + "host_name", Column(&LogTable::HostNameAccessor, objectAccessor)); table->AddColumn(prefix + "contact_name", Column(&LogTable::ContactNameAccessor, objectAccessor)); table->AddColumn(prefix + "command_name", Column(&LogTable::CommandNameAccessor, objectAccessor)); HostsTable::AddColumns(table, "current_host_", boost::bind(&LogTable::HostAccessor, _1, objectAccessor)); ServicesTable::AddColumns(table, "current_service_", boost::bind(&LogTable::ServiceAccessor, _1, objectAccessor)); ContactsTable::AddColumns(table, "current_contact_", boost::bind(&LogTable::ContactAccessor, _1, objectAccessor)); CommandsTable::AddColumns(table, "current_command_", boost::bind(&LogTable::CommandAccessor, _1, objectAccessor)); } String LogTable::GetName(void) const { return "log"; } String LogTable::GetPrefix(void) const { return "log"; } void LogTable::FetchRows(const AddRowFunction& addRowFn) { Log(LogDebug, "LogTable") << "Pre-selecting log file from " << m_TimeFrom << " until " << m_TimeUntil; /* create log file index */ LivestatusLogUtility::CreateLogIndex(m_CompatLogPath, m_LogFileIndex); /* generate log cache */ LivestatusLogUtility::CreateLogCache(m_LogFileIndex, this, m_TimeFrom, m_TimeUntil, addRowFn); } /* gets called in LivestatusLogUtility::CreateLogCache */ void LogTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) { /* additional attributes only for log table */ log_entry_attrs->Set("lineno", lineno); addRowFn(log_entry_attrs, LivestatusGroupByNone, Empty); } Object::Ptr LogTable::HostAccessor(const Value& row, const Column::ObjectAccessor&) { String host_name = static_cast(row)->Get("host_name"); if (host_name.IsEmpty()) return Object::Ptr(); return Host::GetByName(host_name); } Object::Ptr LogTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor&) { String host_name = static_cast(row)->Get("host_name"); String service_description = static_cast(row)->Get("service_description"); if (service_description.IsEmpty() || host_name.IsEmpty()) return Object::Ptr(); return Service::GetByNamePair(host_name, service_description); } Object::Ptr LogTable::ContactAccessor(const Value& row, const Column::ObjectAccessor&) { String contact_name = static_cast(row)->Get("contact_name"); if (contact_name.IsEmpty()) return Object::Ptr(); return User::GetByName(contact_name); } Object::Ptr LogTable::CommandAccessor(const Value& row, const Column::ObjectAccessor&) { String command_name = static_cast(row)->Get("command_name"); if (command_name.IsEmpty()) return Object::Ptr(); CheckCommand::Ptr check_command = CheckCommand::GetByName(command_name); if (!check_command) { EventCommand::Ptr event_command = EventCommand::GetByName(command_name); if (!event_command) { NotificationCommand::Ptr notification_command = NotificationCommand::GetByName(command_name); if (!notification_command) return Object::Ptr(); else return notification_command; } else return event_command; } else return check_command; } Value LogTable::TimeAccessor(const Value& row) { return static_cast(row)->Get("time"); } Value LogTable::LinenoAccessor(const Value& row) { return static_cast(row)->Get("lineno"); } Value LogTable::ClassAccessor(const Value& row) { return static_cast(row)->Get("class"); } Value LogTable::MessageAccessor(const Value& row) { return static_cast(row)->Get("message"); } Value LogTable::TypeAccessor(const Value& row) { return static_cast(row)->Get("type"); } Value LogTable::OptionsAccessor(const Value& row) { return static_cast(row)->Get("options"); } Value LogTable::CommentAccessor(const Value& row) { return static_cast(row)->Get("comment"); } Value LogTable::PluginOutputAccessor(const Value& row) { return static_cast(row)->Get("plugin_output"); } Value LogTable::StateAccessor(const Value& row) { return static_cast(row)->Get("state"); } Value LogTable::StateTypeAccessor(const Value& row) { return static_cast(row)->Get("state_type"); } Value LogTable::AttemptAccessor(const Value& row) { return static_cast(row)->Get("attempt"); } Value LogTable::ServiceDescriptionAccessor(const Value& row) { return static_cast(row)->Get("service_description"); } Value LogTable::HostNameAccessor(const Value& row) { return static_cast(row)->Get("host_name"); } Value LogTable::ContactNameAccessor(const Value& row) { return static_cast(row)->Get("contact_name"); } Value LogTable::CommandNameAccessor(const Value& row) { return static_cast(row)->Get("command_name"); } icinga2-2.8.1/lib/livestatus/logtable.hpp000066400000000000000000000070601322762156600203260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef LOGTABLE_H #define LOGTABLE_H #include "livestatus/historytable.hpp" #include using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API LogTable : public HistoryTable { public: DECLARE_PTR_TYPEDEFS(LogTable); LogTable(const String& compat_log_path, time_t from, time_t until); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; void UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ContactAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr CommandAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Value TimeAccessor(const Value& row); static Value LinenoAccessor(const Value& row); static Value ClassAccessor(const Value& row); static Value MessageAccessor(const Value& row); static Value TypeAccessor(const Value& row); static Value OptionsAccessor(const Value& row); static Value CommentAccessor(const Value& row); static Value PluginOutputAccessor(const Value& row); static Value StateAccessor(const Value& row); static Value StateTypeAccessor(const Value& row); static Value AttemptAccessor(const Value& row); static Value ServiceDescriptionAccessor(const Value& row); static Value HostNameAccessor(const Value& row); static Value ContactNameAccessor(const Value& row); static Value CommandNameAccessor(const Value& row); private: std::map m_LogFileIndex; std::map m_RowsCache; time_t m_TimeFrom; time_t m_TimeUntil; String m_CompatLogPath; }; } #endif /* LOGTABLE_H */ icinga2-2.8.1/lib/livestatus/maxaggregator.cpp000066400000000000000000000043041322762156600213560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/maxaggregator.hpp" using namespace icinga; MaxAggregator::MaxAggregator(const String& attr) : m_MaxAttr(attr) { } MaxAggregatorState *MaxAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new MaxAggregatorState(); return static_cast(*state); } void MaxAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_MaxAttr); Value value = column.ExtractValue(row); MaxAggregatorState *pstate = EnsureState(state); if (value > pstate->Max) pstate->Max = value; } double MaxAggregator::GetResultAndFreeState(AggregatorState *state) const { MaxAggregatorState *pstate = EnsureState(&state); double result = pstate->Max; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/maxaggregator.hpp000066400000000000000000000042651322762156600213710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MAXAGGREGATOR_H #define MAXAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API MaxAggregatorState : public AggregatorState { MaxAggregatorState(void) : Max(0) { } double Max; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API MaxAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(MaxAggregator); MaxAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_MaxAttr; static MaxAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* MAXAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/minaggregator.cpp000066400000000000000000000044021322762156600213530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/minaggregator.hpp" using namespace icinga; MinAggregator::MinAggregator(const String& attr) : m_MinAttr(attr) { } MinAggregatorState *MinAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new MinAggregatorState(); return static_cast(*state); } void MinAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_MinAttr); Value value = column.ExtractValue(row); MinAggregatorState *pstate = EnsureState(state); if (value < pstate->Min) pstate->Min = value; } double MinAggregator::GetResultAndFreeState(AggregatorState *state) const { MinAggregatorState *pstate = EnsureState(&state); double result; if (pstate->Min == DBL_MAX) result = 0; else result = pstate->Min; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/minaggregator.hpp000066400000000000000000000043151322762156600213630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MINAGGREGATOR_H #define MINAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" #include namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API MinAggregatorState : public AggregatorState { MinAggregatorState(void) : Min(DBL_MAX) { } double Min; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API MinAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(MinAggregator); MinAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_MinAttr; static MinAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* MINAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/negatefilter.cpp000066400000000000000000000032341322762156600212000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/negatefilter.hpp" using namespace icinga; NegateFilter::NegateFilter(const Filter::Ptr& inner) : m_Inner(inner) { } bool NegateFilter::Apply(const Table::Ptr& table, const Value& row) { return !m_Inner->Apply(table, row); } icinga2-2.8.1/lib/livestatus/negatefilter.hpp000066400000000000000000000035321322762156600212060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NEGATEFILTER_H #define NEGATEFILTER_H #include "livestatus/filter.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API NegateFilter : public Filter { public: DECLARE_PTR_TYPEDEFS(NegateFilter); NegateFilter(const Filter::Ptr& inner); virtual bool Apply(const Table::Ptr& table, const Value& row) override; private: Filter::Ptr m_Inner; }; } #endif /* NEGATEFILTER_H */ icinga2-2.8.1/lib/livestatus/orfilter.cpp000066400000000000000000000033341322762156600203560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/orfilter.hpp" using namespace icinga; OrFilter::OrFilter(void) { } bool OrFilter::Apply(const Table::Ptr& table, const Value& row) { if (m_Filters.empty()) return true; for (const Filter::Ptr& filter : m_Filters) { if (filter->Apply(table, row)) return true; } return false; } icinga2-2.8.1/lib/livestatus/orfilter.hpp000066400000000000000000000034361322762156600203660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ORFILTER_H #define ORFILTER_H #include "livestatus/combinerfilter.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API OrFilter : public CombinerFilter { public: DECLARE_PTR_TYPEDEFS(OrFilter); OrFilter(void); virtual bool Apply(const Table::Ptr& table, const Value& row) override; }; } #endif /* ORFILTER_H */ icinga2-2.8.1/lib/livestatus/servicegroupstable.cpp000066400000000000000000000230651322762156600224430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/servicegroupstable.hpp" #include "icinga/servicegroup.hpp" #include "base/configtype.hpp" using namespace icinga; ServiceGroupsTable::ServiceGroupsTable(void) { AddColumns(this); } void ServiceGroupsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&ServiceGroupsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&ServiceGroupsTable::AliasAccessor, objectAccessor)); table->AddColumn(prefix + "notes", Column(&ServiceGroupsTable::NotesAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url", Column(&ServiceGroupsTable::NotesUrlAccessor, objectAccessor)); table->AddColumn(prefix + "action_url", Column(&ServiceGroupsTable::ActionUrlAccessor, objectAccessor)); table->AddColumn(prefix + "members", Column(&ServiceGroupsTable::MembersAccessor, objectAccessor)); table->AddColumn(prefix + "members_with_state", Column(&ServiceGroupsTable::MembersWithStateAccessor, objectAccessor)); table->AddColumn(prefix + "worst_service_state", Column(&ServiceGroupsTable::WorstServiceStateAccessor, objectAccessor)); table->AddColumn(prefix + "num_services", Column(&ServiceGroupsTable::NumServicesAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_ok", Column(&ServiceGroupsTable::NumServicesOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_warn", Column(&ServiceGroupsTable::NumServicesWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_crit", Column(&ServiceGroupsTable::NumServicesCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_unknown", Column(&ServiceGroupsTable::NumServicesUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_pending", Column(&ServiceGroupsTable::NumServicesPendingAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_ok", Column(&ServiceGroupsTable::NumServicesHardOkAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_warn", Column(&ServiceGroupsTable::NumServicesHardWarnAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_crit", Column(&ServiceGroupsTable::NumServicesHardCritAccessor, objectAccessor)); table->AddColumn(prefix + "num_services_hard_unknown", Column(&ServiceGroupsTable::NumServicesHardUnknownAccessor, objectAccessor)); } String ServiceGroupsTable::GetName(void) const { return "servicegroups"; } String ServiceGroupsTable::GetPrefix(void) const { return "servicegroup"; } void ServiceGroupsTable::FetchRows(const AddRowFunction& addRowFn) { for (const ServiceGroup::Ptr& sg : ConfigType::GetObjectsByType()) { if (!addRowFn(sg, LivestatusGroupByNone, Empty)) return; } } Value ServiceGroupsTable::NameAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetName(); } Value ServiceGroupsTable::AliasAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetDisplayName(); } Value ServiceGroupsTable::NotesAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetNotes(); } Value ServiceGroupsTable::NotesUrlAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetNotesUrl(); } Value ServiceGroupsTable::ActionUrlAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetActionUrl(); } Value ServiceGroupsTable::MembersAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; Array::Ptr members = new Array(); for (const Service::Ptr& service : sg->GetMembers()) { Array::Ptr host_svc = new Array(); host_svc->Add(service->GetHost()->GetName()); host_svc->Add(service->GetShortName()); members->Add(host_svc); } return members; } Value ServiceGroupsTable::MembersWithStateAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; Array::Ptr members = new Array(); for (const Service::Ptr& service : sg->GetMembers()) { Array::Ptr host_svc = new Array(); host_svc->Add(service->GetHost()->GetName()); host_svc->Add(service->GetShortName()); host_svc->Add(service->GetHost()->GetState()); host_svc->Add(service->GetState()); members->Add(host_svc); } return members; } Value ServiceGroupsTable::WorstServiceStateAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; Value worst_service = ServiceOK; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetState() > worst_service) worst_service = service->GetState(); } return worst_service; } Value ServiceGroupsTable::NumServicesAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; return sg->GetMembers().size(); } Value ServiceGroupsTable::NumServicesOkAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetState() == ServiceOK) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesWarnAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetState() == ServiceWarning) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesCritAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetState() == ServiceCritical) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesUnknownAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetState() == ServiceUnknown) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesPendingAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (!service->GetLastCheckResult()) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesHardOkAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceOK) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesHardWarnAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceWarning) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesHardCritAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceCritical) num_services++; } return num_services; } Value ServiceGroupsTable::NumServicesHardUnknownAccessor(const Value& row) { ServiceGroup::Ptr sg = static_cast(row); if (!sg) return Empty; int num_services = 0; for (const Service::Ptr& service : sg->GetMembers()) { if (service->GetStateType() == StateTypeHard && service->GetState() == ServiceUnknown) num_services++; } return num_services; } icinga2-2.8.1/lib/livestatus/servicegroupstable.hpp000066400000000000000000000060451322762156600224470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICEGROUPSTABLE_H #define SERVICEGROUPSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API ServiceGroupsTable : public Table { public: DECLARE_PTR_TYPEDEFS(ServiceGroupsTable); ServiceGroupsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value AliasAccessor(const Value& row); static Value NotesAccessor(const Value& row); static Value NotesUrlAccessor(const Value& row); static Value ActionUrlAccessor(const Value& row); static Value MembersAccessor(const Value& row); static Value MembersWithStateAccessor(const Value& row); static Value WorstServiceStateAccessor(const Value& row); static Value NumServicesAccessor(const Value& row); static Value NumServicesOkAccessor(const Value& row); static Value NumServicesWarnAccessor(const Value& row); static Value NumServicesCritAccessor(const Value& row); static Value NumServicesUnknownAccessor(const Value& row); static Value NumServicesPendingAccessor(const Value& row); static Value NumServicesHardOkAccessor(const Value& row); static Value NumServicesHardWarnAccessor(const Value& row); static Value NumServicesHardCritAccessor(const Value& row); static Value NumServicesHardUnknownAccessor(const Value& row); }; } #endif /* SERVICEGROUPSTABLE_H */ icinga2-2.8.1/lib/livestatus/servicestable.cpp000066400000000000000000001066161322762156600213720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/servicestable.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicegroupstable.hpp" #include "livestatus/hostgroupstable.hpp" #include "livestatus/endpointstable.hpp" #include "icinga/service.hpp" #include "icinga/servicegroup.hpp" #include "icinga/hostgroup.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/timeperiod.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/compatutility.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include #include using namespace icinga; ServicesTable::ServicesTable(LivestatusGroupByType type) : Table(type) { AddColumns(this); } void ServicesTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "description", Column(&ServicesTable::ShortNameAccessor, objectAccessor)); table->AddColumn(prefix + "service_description", Column(&ServicesTable::ShortNameAccessor, objectAccessor)); //ugly compatibility hack table->AddColumn(prefix + "display_name", Column(&ServicesTable::DisplayNameAccessor, objectAccessor)); table->AddColumn(prefix + "check_command", Column(&ServicesTable::CheckCommandAccessor, objectAccessor)); table->AddColumn(prefix + "check_command_expanded", Column(&ServicesTable::CheckCommandExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "event_handler", Column(&ServicesTable::EventHandlerAccessor, objectAccessor)); table->AddColumn(prefix + "plugin_output", Column(&ServicesTable::PluginOutputAccessor, objectAccessor)); table->AddColumn(prefix + "long_plugin_output", Column(&ServicesTable::LongPluginOutputAccessor, objectAccessor)); table->AddColumn(prefix + "perf_data", Column(&ServicesTable::PerfDataAccessor, objectAccessor)); table->AddColumn(prefix + "notification_period", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "check_period", Column(&ServicesTable::CheckPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "notes", Column(&ServicesTable::NotesAccessor, objectAccessor)); table->AddColumn(prefix + "notes_expanded", Column(&ServicesTable::NotesExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url", Column(&ServicesTable::NotesUrlAccessor, objectAccessor)); table->AddColumn(prefix + "notes_url_expanded", Column(&ServicesTable::NotesUrlExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "action_url", Column(&ServicesTable::ActionUrlAccessor, objectAccessor)); table->AddColumn(prefix + "action_url_expanded", Column(&ServicesTable::ActionUrlExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image", Column(&ServicesTable::IconImageAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image_expanded", Column(&ServicesTable::IconImageExpandedAccessor, objectAccessor)); table->AddColumn(prefix + "icon_image_alt", Column(&ServicesTable::IconImageAltAccessor, objectAccessor)); table->AddColumn(prefix + "initial_state", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "max_check_attempts", Column(&ServicesTable::MaxCheckAttemptsAccessor, objectAccessor)); table->AddColumn(prefix + "current_attempt", Column(&ServicesTable::CurrentAttemptAccessor, objectAccessor)); table->AddColumn(prefix + "state", Column(&ServicesTable::StateAccessor, objectAccessor)); table->AddColumn(prefix + "has_been_checked", Column(&ServicesTable::HasBeenCheckedAccessor, objectAccessor)); table->AddColumn(prefix + "last_state", Column(&ServicesTable::LastStateAccessor, objectAccessor)); table->AddColumn(prefix + "last_hard_state", Column(&ServicesTable::LastHardStateAccessor, objectAccessor)); table->AddColumn(prefix + "state_type", Column(&ServicesTable::StateTypeAccessor, objectAccessor)); table->AddColumn(prefix + "check_type", Column(&ServicesTable::CheckTypeAccessor, objectAccessor)); table->AddColumn(prefix + "acknowledged", Column(&ServicesTable::AcknowledgedAccessor, objectAccessor)); table->AddColumn(prefix + "acknowledgement_type", Column(&ServicesTable::AcknowledgementTypeAccessor, objectAccessor)); table->AddColumn(prefix + "no_more_notifications", Column(&ServicesTable::NoMoreNotificationsAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_ok", Column(&ServicesTable::LastTimeOkAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_warning", Column(&ServicesTable::LastTimeWarningAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_critical", Column(&ServicesTable::LastTimeCriticalAccessor, objectAccessor)); table->AddColumn(prefix + "last_time_unknown", Column(&ServicesTable::LastTimeUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "last_check", Column(&ServicesTable::LastCheckAccessor, objectAccessor)); table->AddColumn(prefix + "next_check", Column(&ServicesTable::NextCheckAccessor, objectAccessor)); table->AddColumn(prefix + "last_notification", Column(&ServicesTable::LastNotificationAccessor, objectAccessor)); table->AddColumn(prefix + "next_notification", Column(&ServicesTable::NextNotificationAccessor, objectAccessor)); table->AddColumn(prefix + "current_notification_number", Column(&ServicesTable::CurrentNotificationNumberAccessor, objectAccessor)); table->AddColumn(prefix + "last_state_change", Column(&ServicesTable::LastStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "last_hard_state_change", Column(&ServicesTable::LastHardStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "scheduled_downtime_depth", Column(&ServicesTable::ScheduledDowntimeDepthAccessor, objectAccessor)); table->AddColumn(prefix + "is_flapping", Column(&ServicesTable::IsFlappingAccessor, objectAccessor)); table->AddColumn(prefix + "checks_enabled", Column(&ServicesTable::ChecksEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "accept_passive_checks", Column(&ServicesTable::AcceptPassiveChecksAccessor, objectAccessor)); table->AddColumn(prefix + "event_handler_enabled", Column(&ServicesTable::EventHandlerEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "notifications_enabled", Column(&ServicesTable::NotificationsEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "process_performance_data", Column(&ServicesTable::ProcessPerformanceDataAccessor, objectAccessor)); table->AddColumn(prefix + "is_executing", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "active_checks_enabled", Column(&ServicesTable::ActiveChecksEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "check_options", Column(&ServicesTable::CheckOptionsAccessor, objectAccessor)); table->AddColumn(prefix + "flap_detection_enabled", Column(&ServicesTable::FlapDetectionEnabledAccessor, objectAccessor)); table->AddColumn(prefix + "check_freshness", Column(&ServicesTable::CheckFreshnessAccessor, objectAccessor)); table->AddColumn(prefix + "obsess_over_service", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes_list", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "pnpgraph_present", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "staleness", Column(&ServicesTable::StalenessAccessor, objectAccessor)); table->AddColumn(prefix + "check_interval", Column(&ServicesTable::CheckIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "retry_interval", Column(&ServicesTable::RetryIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "notification_interval", Column(&ServicesTable::NotificationIntervalAccessor, objectAccessor)); table->AddColumn(prefix + "first_notification_delay", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "low_flap_threshold", Column(&ServicesTable::LowFlapThresholdAccessor, objectAccessor)); table->AddColumn(prefix + "high_flap_threshold", Column(&ServicesTable::HighFlapThresholdAccessor, objectAccessor)); table->AddColumn(prefix + "latency", Column(&ServicesTable::LatencyAccessor, objectAccessor)); table->AddColumn(prefix + "execution_time", Column(&ServicesTable::ExecutionTimeAccessor, objectAccessor)); table->AddColumn(prefix + "percent_state_change", Column(&ServicesTable::PercentStateChangeAccessor, objectAccessor)); table->AddColumn(prefix + "in_check_period", Column(&ServicesTable::InCheckPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "in_notification_period", Column(&ServicesTable::InNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "contacts", Column(&ServicesTable::ContactsAccessor, objectAccessor)); table->AddColumn(prefix + "downtimes", Column(&ServicesTable::DowntimesAccessor, objectAccessor)); table->AddColumn(prefix + "downtimes_with_info", Column(&ServicesTable::DowntimesWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "comments", Column(&ServicesTable::CommentsAccessor, objectAccessor)); table->AddColumn(prefix + "comments_with_info", Column(&ServicesTable::CommentsWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "comments_with_extra_info", Column(&ServicesTable::CommentsWithExtraInfoAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_names", Column(&ServicesTable::CustomVariableNamesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_values", Column(&ServicesTable::CustomVariableValuesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variables", Column(&ServicesTable::CustomVariablesAccessor, objectAccessor)); table->AddColumn(prefix + "groups", Column(&ServicesTable::GroupsAccessor, objectAccessor)); table->AddColumn(prefix + "contact_groups", Column(&ServicesTable::ContactGroupsAccessor, objectAccessor)); table->AddColumn(prefix + "check_source", Column(&ServicesTable::CheckSourceAccessor, objectAccessor)); table->AddColumn(prefix + "is_reachable", Column(&ServicesTable::IsReachableAccessor, objectAccessor)); table->AddColumn(prefix + "cv_is_json", Column(&ServicesTable::CVIsJsonAccessor, objectAccessor)); table->AddColumn(prefix + "original_attributes", Column(&ServicesTable::OriginalAttributesAccessor, objectAccessor)); HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor)); /* add additional group by values received through the object accessor */ if (table->GetGroupByType() == LivestatusGroupByServiceGroup) { /* _1 = row, _2 = groupByType, _3 = groupByObject */ Log(LogDebug, "Livestatus") << "Processing services group by servicegroup table."; ServiceGroupsTable::AddColumns(table, "servicegroup_", boost::bind(&ServicesTable::ServiceGroupAccessor, _1, _2, _3)); } else if (table->GetGroupByType() == LivestatusGroupByHostGroup) { /* _1 = row, _2 = groupByType, _3 = groupByObject */ Log(LogDebug, "Livestatus") << "Processing services group by hostgroup table."; HostGroupsTable::AddColumns(table, "hostgroup_", boost::bind(&ServicesTable::HostGroupAccessor, _1, _2, _3)); } } String ServicesTable::GetName(void) const { return "services"; } String ServicesTable::GetPrefix(void) const { return "service"; } void ServicesTable::FetchRows(const AddRowFunction& addRowFn) { if (GetGroupByType() == LivestatusGroupByServiceGroup) { for (const ServiceGroup::Ptr& sg : ConfigType::GetObjectsByType()) { for (const Service::Ptr& service : sg->GetMembers()) { /* the caller must know which groupby type and value are set for this row */ if (!addRowFn(service, LivestatusGroupByServiceGroup, sg)) return; } } } else if (GetGroupByType() == LivestatusGroupByHostGroup) { for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType()) { ObjectLock ylock(hg); for (const Host::Ptr& host : hg->GetMembers()) { ObjectLock ylock(host); for (const Service::Ptr& service : host->GetServices()) { /* the caller must know which groupby type and value are set for this row */ if (!addRowFn(service, LivestatusGroupByHostGroup, hg)) return; } } } } else { for (const Service::Ptr& service : ConfigType::GetObjectsByType()) { if (!addRowFn(service, LivestatusGroupByNone, Empty)) return; } } } Object::Ptr ServicesTable::HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor) { Value service; if (parentObjectAccessor) service = parentObjectAccessor(row, LivestatusGroupByNone, Empty); else service = row; Service::Ptr svc = static_cast(service); if (!svc) return Object::Ptr(); return svc->GetHost(); } Object::Ptr ServicesTable::ServiceGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) { /* return the current group by value set from within FetchRows() * this is the servicegroup object used for the table join inside * in AddColumns() */ if (groupByType == LivestatusGroupByServiceGroup) return groupByObject; return Object::Ptr(); } Object::Ptr ServicesTable::HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) { /* return the current group by value set from within FetchRows() * this is the servicegroup object used for the table join inside * in AddColumns() */ if (groupByType == LivestatusGroupByHostGroup) return groupByObject; return Object::Ptr(); } Value ServicesTable::ShortNameAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetShortName(); } Value ServicesTable::DisplayNameAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetDisplayName(); } Value ServicesTable::CheckCommandAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; CheckCommand::Ptr checkcommand = service->GetCheckCommand(); if (checkcommand) return CompatUtility::GetCommandName(checkcommand) + "!" + CompatUtility::GetCheckableCommandArgs(service); return Empty; } Value ServicesTable::CheckCommandExpandedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; CheckCommand::Ptr checkcommand = service->GetCheckCommand(); if (checkcommand) return CompatUtility::GetCommandName(checkcommand) + "!" + CompatUtility::GetCheckableCommandArgs(service); return Empty; } Value ServicesTable::EventHandlerAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; EventCommand::Ptr eventcommand = service->GetEventCommand(); if (eventcommand) return CompatUtility::GetCommandName(eventcommand); return Empty; } Value ServicesTable::PluginOutputAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; String output; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) output = CompatUtility::GetCheckResultOutput(cr); return output; } Value ServicesTable::LongPluginOutputAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; String long_output; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) long_output = CompatUtility::GetCheckResultLongOutput(cr); return long_output; } Value ServicesTable::PerfDataAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; String perfdata; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) perfdata = CompatUtility::GetCheckResultPerfdata(cr); return perfdata; } Value ServicesTable::CheckPeriodAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableCheckPeriod(service); } Value ServicesTable::NotesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetNotes(); } Value ServicesTable::NotesExpandedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", service->GetHost())); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(service->GetNotes(), resolvers); } Value ServicesTable::NotesUrlAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetNotesUrl(); } Value ServicesTable::NotesUrlExpandedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", service->GetHost())); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(service->GetNotesUrl(), resolvers); } Value ServicesTable::ActionUrlAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetActionUrl(); } Value ServicesTable::ActionUrlExpandedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", service->GetHost())); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(service->GetActionUrl(), resolvers); } Value ServicesTable::IconImageAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetIconImage(); } Value ServicesTable::IconImageExpandedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", service->GetHost())); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); return MacroProcessor::ResolveMacros(service->GetIconImage(), resolvers); } Value ServicesTable::IconImageAltAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetIconImageAlt(); } Value ServicesTable::MaxCheckAttemptsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetMaxCheckAttempts(); } Value ServicesTable::CurrentAttemptAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetCheckAttempt(); } Value ServicesTable::StateAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetState(); } Value ServicesTable::HasBeenCheckedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableHasBeenChecked(service); } Value ServicesTable::LastStateAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetLastState(); } Value ServicesTable::LastHardStateAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetLastHardState(); } Value ServicesTable::StateTypeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetStateType(); } Value ServicesTable::CheckTypeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableCheckType(service); } Value ServicesTable::AcknowledgedAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; ObjectLock olock(service); return CompatUtility::GetCheckableIsAcknowledged(service); } Value ServicesTable::AcknowledgementTypeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; ObjectLock olock(service); return CompatUtility::GetCheckableAcknowledgementType(service); } Value ServicesTable::NoMoreNotificationsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNoMoreNotifications(service); } Value ServicesTable::LastTimeOkAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastStateOK()); } Value ServicesTable::LastTimeWarningAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastStateWarning()); } Value ServicesTable::LastTimeCriticalAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastStateCritical()); } Value ServicesTable::LastTimeUnknownAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastStateUnknown()); } Value ServicesTable::LastCheckAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastCheck()); } Value ServicesTable::NextCheckAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetNextCheck()); } Value ServicesTable::LastNotificationAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNotificationLastNotification(service); } Value ServicesTable::NextNotificationAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNotificationNextNotification(service); } Value ServicesTable::CurrentNotificationNumberAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNotificationNotificationNumber(service); } Value ServicesTable::LastStateChangeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastStateChange()); } Value ServicesTable::LastHardStateChangeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return static_cast(service->GetLastHardStateChange()); } Value ServicesTable::ScheduledDowntimeDepthAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->GetDowntimeDepth(); } Value ServicesTable::IsFlappingAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->IsFlapping(); } Value ServicesTable::ChecksEnabledAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableActiveChecksEnabled(service); } Value ServicesTable::AcceptPassiveChecksAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckablePassiveChecksEnabled(service); } Value ServicesTable::EventHandlerEnabledAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableEventHandlerEnabled(service); } Value ServicesTable::NotificationsEnabledAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNotificationsEnabled(service); } Value ServicesTable::ProcessPerformanceDataAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableProcessPerformanceData(service); } Value ServicesTable::ActiveChecksEnabledAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableActiveChecksEnabled(service); } Value ServicesTable::CheckOptionsAccessor(const Value& row) { /* TODO - forcexec, freshness, orphan, none */ return Empty; } Value ServicesTable::FlapDetectionEnabledAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableFlapDetectionEnabled(service); } Value ServicesTable::CheckFreshnessAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableFreshnessChecksEnabled(service); } Value ServicesTable::StalenessAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableStaleness(service); } Value ServicesTable::CheckIntervalAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableCheckInterval(service); } Value ServicesTable::RetryIntervalAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableRetryInterval(service); } Value ServicesTable::NotificationIntervalAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableNotificationNotificationInterval(service); } Value ServicesTable::LowFlapThresholdAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableLowFlapThreshold(service); } Value ServicesTable::HighFlapThresholdAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableHighFlapThreshold(service); } Value ServicesTable::LatencyAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; CheckResult::Ptr cr = service->GetLastCheckResult(); if (!cr) return Empty; return cr->CalculateLatency(); } Value ServicesTable::ExecutionTimeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; CheckResult::Ptr cr = service->GetLastCheckResult(); if (!cr) return Empty; return cr->CalculateExecutionTime(); } Value ServicesTable::PercentStateChangeAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckablePercentStateChange(service); } Value ServicesTable::InCheckPeriodAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableInCheckPeriod(service); } Value ServicesTable::InNotificationPeriodAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return CompatUtility::GetCheckableInNotificationPeriod(service); } Value ServicesTable::ContactsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr contact_names = new Array(); for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(service)) { contact_names->Add(user->GetName()); } return contact_names; } Value ServicesTable::DowntimesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr results = new Array(); for (const Downtime::Ptr& downtime : service->GetDowntimes()) { if (downtime->IsExpired()) continue; results->Add(downtime->GetLegacyId()); } return results; } Value ServicesTable::DowntimesWithInfoAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr results = new Array(); for (const Downtime::Ptr& downtime : service->GetDowntimes()) { if (downtime->IsExpired()) continue; Array::Ptr downtime_info = new Array(); downtime_info->Add(downtime->GetLegacyId()); downtime_info->Add(downtime->GetAuthor()); downtime_info->Add(downtime->GetComment()); results->Add(downtime_info); } return results; } Value ServicesTable::CommentsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : service->GetComments()) { if (comment->IsExpired()) continue; results->Add(comment->GetLegacyId()); } return results; } Value ServicesTable::CommentsWithInfoAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : service->GetComments()) { if (comment->IsExpired()) continue; Array::Ptr comment_info = new Array(); comment_info->Add(comment->GetLegacyId()); comment_info->Add(comment->GetAuthor()); comment_info->Add(comment->GetText()); results->Add(comment_info); } return results; } Value ServicesTable::CommentsWithExtraInfoAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr results = new Array(); for (const Comment::Ptr& comment : service->GetComments()) { if (comment->IsExpired()) continue; Array::Ptr comment_info = new Array(); comment_info->Add(comment->GetLegacyId()); comment_info->Add(comment->GetAuthor()); comment_info->Add(comment->GetText()); comment_info->Add(comment->GetEntryType()); comment_info->Add(static_cast(comment->GetEntryTime())); results->Add(comment_info); } return results; } Value ServicesTable::CustomVariableNamesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Dictionary::Ptr vars; { ObjectLock olock(service); vars = CompatUtility::GetCustomAttributeConfig(service); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { cv->Add(kv.first); } return cv; } Value ServicesTable::CustomVariableValuesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Dictionary::Ptr vars; { ObjectLock olock(service); vars = CompatUtility::GetCustomAttributeConfig(service); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv->Add(JsonEncode(kv.second)); else cv->Add(kv.second); } return cv; } Value ServicesTable::CustomVariablesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Dictionary::Ptr vars; { ObjectLock olock(service); vars = CompatUtility::GetCustomAttributeConfig(service); } Array::Ptr cv = new Array(); if (!vars) return cv; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { Array::Ptr key_val = new Array(); key_val->Add(kv.first); if (kv.second.IsObjectType() || kv.second.IsObjectType()) key_val->Add(JsonEncode(kv.second)); else key_val->Add(kv.second); cv->Add(key_val); } return cv; } Value ServicesTable::CVIsJsonAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Dictionary::Ptr vars; { ObjectLock olock(service); vars = CompatUtility::GetCustomAttributeConfig(service); } if (!vars) return Empty; bool cv_is_json = false; ObjectLock olock(vars); for (const Dictionary::Pair& kv : vars) { if (kv.second.IsObjectType() || kv.second.IsObjectType()) cv_is_json = true; } return cv_is_json; } Value ServicesTable::GroupsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr groups = service->GetGroups(); if (!groups) return Empty; return groups; } Value ServicesTable::ContactGroupsAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; Array::Ptr contactgroup_names = new Array(); for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(service)) { contactgroup_names->Add(usergroup->GetName()); } return contactgroup_names; } Value ServicesTable::CheckSourceAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; CheckResult::Ptr cr = service->GetLastCheckResult(); if (cr) return cr->GetCheckSource(); return Empty; } Value ServicesTable::IsReachableAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return service->IsReachable(); } Value ServicesTable::OriginalAttributesAccessor(const Value& row) { Service::Ptr service = static_cast(row); if (!service) return Empty; return JsonEncode(service->GetOriginalAttributes()); } icinga2-2.8.1/lib/livestatus/servicestable.hpp000066400000000000000000000152131322762156600213670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SERVICESTABLE_H #define SERVICESTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API ServicesTable : public Table { public: DECLARE_PTR_TYPEDEFS(ServicesTable); ServicesTable(LivestatusGroupByType type = LivestatusGroupByNone); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ServiceGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject); static Object::Ptr HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject); static Value ShortNameAccessor(const Value& row); static Value DisplayNameAccessor(const Value& row); static Value CheckCommandAccessor(const Value& row); static Value CheckCommandExpandedAccessor(const Value& row); static Value EventHandlerAccessor(const Value& row); static Value PluginOutputAccessor(const Value& row); static Value LongPluginOutputAccessor(const Value& row); static Value PerfDataAccessor(const Value& row); static Value CheckPeriodAccessor(const Value& row); static Value NotesAccessor(const Value& row); static Value NotesExpandedAccessor(const Value& row); static Value NotesUrlAccessor(const Value& row); static Value NotesUrlExpandedAccessor(const Value& row); static Value ActionUrlAccessor(const Value& row); static Value ActionUrlExpandedAccessor(const Value& row); static Value IconImageAccessor(const Value& row); static Value IconImageExpandedAccessor(const Value& row); static Value IconImageAltAccessor(const Value& row); static Value MaxCheckAttemptsAccessor(const Value& row); static Value CurrentAttemptAccessor(const Value& row); static Value StateAccessor(const Value& row); static Value HasBeenCheckedAccessor(const Value& row); static Value LastStateAccessor(const Value& row); static Value LastHardStateAccessor(const Value& row); static Value StateTypeAccessor(const Value& row); static Value CheckTypeAccessor(const Value& row); static Value AcknowledgedAccessor(const Value& row); static Value AcknowledgementTypeAccessor(const Value& row); static Value NoMoreNotificationsAccessor(const Value& row); static Value LastTimeOkAccessor(const Value& row); static Value LastTimeWarningAccessor(const Value& row); static Value LastTimeCriticalAccessor(const Value& row); static Value LastTimeUnknownAccessor(const Value& row); static Value LastCheckAccessor(const Value& row); static Value NextCheckAccessor(const Value& row); static Value LastNotificationAccessor(const Value& row); static Value NextNotificationAccessor(const Value& row); static Value CurrentNotificationNumberAccessor(const Value& row); static Value LastStateChangeAccessor(const Value& row); static Value LastHardStateChangeAccessor(const Value& row); static Value ScheduledDowntimeDepthAccessor(const Value& row); static Value IsFlappingAccessor(const Value& row); static Value ChecksEnabledAccessor(const Value& row); static Value AcceptPassiveChecksAccessor(const Value& row); static Value EventHandlerEnabledAccessor(const Value& row); static Value NotificationsEnabledAccessor(const Value& row); static Value ProcessPerformanceDataAccessor(const Value& row); static Value ActiveChecksEnabledAccessor(const Value& row); static Value CheckOptionsAccessor(const Value& row); static Value FlapDetectionEnabledAccessor(const Value& row); static Value CheckFreshnessAccessor(const Value& row); static Value StalenessAccessor(const Value& row); static Value CheckIntervalAccessor(const Value& row); static Value RetryIntervalAccessor(const Value& row); static Value NotificationIntervalAccessor(const Value& row); static Value LowFlapThresholdAccessor(const Value& row); static Value HighFlapThresholdAccessor(const Value& row); static Value LatencyAccessor(const Value& row); static Value ExecutionTimeAccessor(const Value& row); static Value PercentStateChangeAccessor(const Value& row); static Value InCheckPeriodAccessor(const Value& row); static Value InNotificationPeriodAccessor(const Value& row); static Value ContactsAccessor(const Value& row); static Value DowntimesAccessor(const Value& row); static Value DowntimesWithInfoAccessor(const Value& row); static Value CommentsAccessor(const Value& row); static Value CommentsWithInfoAccessor(const Value& row); static Value CommentsWithExtraInfoAccessor(const Value& row); static Value CustomVariableNamesAccessor(const Value& row); static Value CustomVariableValuesAccessor(const Value& row); static Value CustomVariablesAccessor(const Value& row); static Value GroupsAccessor(const Value& row); static Value ContactGroupsAccessor(const Value& row); static Value CheckSourceAccessor(const Value& row); static Value IsReachableAccessor(const Value& row); static Value CVIsJsonAccessor(const Value& row); static Value OriginalAttributesAccessor(const Value& row); }; } #endif /* SERVICESTABLE_H */ icinga2-2.8.1/lib/livestatus/statehisttable.cpp000066400000000000000000000444651322762156600215620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/statehisttable.hpp" #include "livestatus/livestatuslogutility.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicestable.hpp" #include "livestatus/contactstable.hpp" #include "livestatus/commandstable.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "icinga/service.hpp" #include "icinga/host.hpp" #include "icinga/user.hpp" #include "icinga/checkcommand.hpp" #include "icinga/eventcommand.hpp" #include "icinga/notificationcommand.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" #include #include #include #include #include #include #include using namespace icinga; StateHistTable::StateHistTable(const String& compat_log_path, time_t from, time_t until) { /* store attributes for FetchRows */ m_TimeFrom = from; m_TimeUntil = until; m_CompatLogPath = compat_log_path; AddColumns(this); } void StateHistTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) { unsigned int time = log_entry_attrs->Get("time"); String host_name = log_entry_attrs->Get("host_name"); String service_description = log_entry_attrs->Get("service_description"); unsigned long state = log_entry_attrs->Get("state"); int log_type = log_entry_attrs->Get("log_type"); String state_type = log_entry_attrs->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... String log_line = log_entry_attrs->Get("message"); /* use message from log table */ Checkable::Ptr checkable; if (service_description.IsEmpty()) checkable = Host::GetByName(host_name); else checkable = Service::GetByNamePair(host_name, service_description); /* invalid log line for state history */ if (!checkable) return; Array::Ptr state_hist_service_states; Dictionary::Ptr state_hist_bag; unsigned long query_part = m_TimeUntil - m_TimeFrom; /* insert new service states array with values if not existing */ if (m_CheckablesCache.find(checkable) == m_CheckablesCache.end()) { /* create new values */ state_hist_service_states = new Array(); state_hist_bag = new Dictionary(); Service::Ptr service = dynamic_pointer_cast(checkable); Host::Ptr host; if (service) host = service->GetHost(); else host = static_pointer_cast(checkable); state_hist_bag->Set("host_name", host->GetName()); if (service) state_hist_bag->Set("service_description", service->GetShortName()); state_hist_bag->Set("state", state); state_hist_bag->Set("in_downtime", 0); state_hist_bag->Set("in_host_downtime", 0); state_hist_bag->Set("in_notification_period", 1); // assume "always" state_hist_bag->Set("is_flapping", 0); state_hist_bag->Set("time", time); state_hist_bag->Set("lineno", lineno); state_hist_bag->Set("log_output", log_line); /* complete line */ state_hist_bag->Set("from", time); /* starting at current timestamp */ state_hist_bag->Set("until", time); /* will be updated later on state change */ state_hist_bag->Set("query_part", query_part); /* required for _part calculations */ state_hist_service_states->Add(state_hist_bag); Log(LogDebug, "StateHistTable") << "statehist: Adding new object '" << checkable->GetName() << "' to services cache."; } else { state_hist_service_states = m_CheckablesCache[checkable]; state_hist_bag = state_hist_service_states->Get(state_hist_service_states->GetLength()-1); /* fetch latest state from history */ /* state duration */ /* determine service notifications notification_period and compare against current timestamp */ bool in_notification_period = true; String notification_period_name; for (const Notification::Ptr& notification : checkable->GetNotifications()) { TimePeriod::Ptr notification_period = notification->GetPeriod(); if (notification_period) { if (notification_period->IsInside(static_cast(time))) in_notification_period = true; else in_notification_period = false; notification_period_name = notification_period->GetName(); // last one wins } else in_notification_period = true; // assume "always" } /* check for state changes, flapping & downtime start/end */ switch (log_type) { case LogEntryTypeHostAlert: case LogEntryTypeHostInitialState: case LogEntryTypeHostCurrentState: case LogEntryTypeServiceAlert: case LogEntryTypeServiceInitialState: case LogEntryTypeServiceCurrentState: if (state != state_hist_bag->Get("state")) { /* 1. seal old state_hist_bag */ state_hist_bag->Set("until", time); /* add until record for duration calculation */ /* 2. add new state_hist_bag */ Dictionary::Ptr state_hist_bag_new = new Dictionary(); state_hist_bag_new->Set("host_name", state_hist_bag->Get("host_name")); state_hist_bag_new->Set("service_description", state_hist_bag->Get("service_description")); state_hist_bag_new->Set("state", state); state_hist_bag_new->Set("in_downtime", state_hist_bag->Get("in_downtime")); // keep value from previous state! state_hist_bag_new->Set("in_host_downtime", state_hist_bag->Get("in_host_downtime")); // keep value from previous state! state_hist_bag_new->Set("in_notification_period", (in_notification_period ? 1 : 0)); state_hist_bag_new->Set("notification_period", notification_period_name); state_hist_bag_new->Set("is_flapping", state_hist_bag->Get("is_flapping")); // keep value from previous state! state_hist_bag_new->Set("time", time); state_hist_bag_new->Set("lineno", lineno); state_hist_bag_new->Set("log_output", log_line); /* complete line */ state_hist_bag_new->Set("from", time); /* starting at current timestamp */ state_hist_bag_new->Set("until", time + 1); /* will be updated later */ state_hist_bag_new->Set("query_part", query_part); state_hist_service_states->Add(state_hist_bag_new); Log(LogDebug, "StateHistTable") << "statehist: State change detected for object '" << checkable->GetName() << "' in '" << log_line << "'."; } break; case LogEntryTypeHostFlapping: case LogEntryTypeServiceFlapping: if (state_type == "STARTED") state_hist_bag->Set("is_flapping", 1); else if (state_type == "STOPPED" || state_type == "DISABLED") state_hist_bag->Set("is_flapping", 0); break; break; case LogEntryTypeHostDowntimeAlert: case LogEntryTypeServiceDowntimeAlert: if (state_type == "STARTED") { state_hist_bag->Set("in_downtime", 1); if (log_type == LogEntryTypeHostDowntimeAlert) state_hist_bag->Set("in_host_downtime", 1); } else if (state_type == "STOPPED" || state_type == "CANCELLED") { state_hist_bag->Set("in_downtime", 0); if (log_type == LogEntryTypeHostDowntimeAlert) state_hist_bag->Set("in_host_downtime", 0); } break; default: //nothing to update break; } } m_CheckablesCache[checkable] = state_hist_service_states; /* TODO find a way to directly call addRowFn() - right now m_ServicesCache depends on historical lines ("already seen service") */ } void StateHistTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "time", Column(&StateHistTable::TimeAccessor, objectAccessor)); table->AddColumn(prefix + "lineno", Column(&StateHistTable::LinenoAccessor, objectAccessor)); table->AddColumn(prefix + "from", Column(&StateHistTable::FromAccessor, objectAccessor)); table->AddColumn(prefix + "until", Column(&StateHistTable::UntilAccessor, objectAccessor)); table->AddColumn(prefix + "duration", Column(&StateHistTable::DurationAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part", Column(&StateHistTable::DurationPartAccessor, objectAccessor)); table->AddColumn(prefix + "state", Column(&StateHistTable::StateAccessor, objectAccessor)); table->AddColumn(prefix + "host_down", Column(&StateHistTable::HostDownAccessor, objectAccessor)); table->AddColumn(prefix + "in_downtime", Column(&StateHistTable::InDowntimeAccessor, objectAccessor)); table->AddColumn(prefix + "in_host_downtime", Column(&StateHistTable::InHostDowntimeAccessor, objectAccessor)); table->AddColumn(prefix + "is_flapping", Column(&StateHistTable::IsFlappingAccessor, objectAccessor)); table->AddColumn(prefix + "in_notification_period", Column(&StateHistTable::InNotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "notification_period", Column(&StateHistTable::NotificationPeriodAccessor, objectAccessor)); table->AddColumn(prefix + "debug_info", Column(&Table::EmptyStringAccessor, objectAccessor)); table->AddColumn(prefix + "host_name", Column(&StateHistTable::HostNameAccessor, objectAccessor)); table->AddColumn(prefix + "service_description", Column(&StateHistTable::ServiceDescriptionAccessor, objectAccessor)); table->AddColumn(prefix + "log_output", Column(&StateHistTable::LogOutputAccessor, objectAccessor)); table->AddColumn(prefix + "duration_ok", Column(&StateHistTable::DurationOkAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part_ok", Column(&StateHistTable::DurationPartOkAccessor, objectAccessor)); table->AddColumn(prefix + "duration_warning", Column(&StateHistTable::DurationWarningAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part_warning", Column(&StateHistTable::DurationPartWarningAccessor, objectAccessor)); table->AddColumn(prefix + "duration_critical", Column(&StateHistTable::DurationCriticalAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part_critical", Column(&StateHistTable::DurationPartCriticalAccessor, objectAccessor)); table->AddColumn(prefix + "duration_unknown", Column(&StateHistTable::DurationUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part_unknown", Column(&StateHistTable::DurationPartUnknownAccessor, objectAccessor)); table->AddColumn(prefix + "duration_unmonitored", Column(&StateHistTable::DurationUnmonitoredAccessor, objectAccessor)); table->AddColumn(prefix + "duration_part_unmonitored", Column(&StateHistTable::DurationPartUnmonitoredAccessor, objectAccessor)); HostsTable::AddColumns(table, "current_host_", boost::bind(&StateHistTable::HostAccessor, _1, objectAccessor)); ServicesTable::AddColumns(table, "current_service_", boost::bind(&StateHistTable::ServiceAccessor, _1, objectAccessor)); } String StateHistTable::GetName(void) const { return "log"; } String StateHistTable::GetPrefix(void) const { return "log"; } void StateHistTable::FetchRows(const AddRowFunction& addRowFn) { Log(LogDebug, "StateHistTable") << "Pre-selecting log file from " << m_TimeFrom << " until " << m_TimeUntil; /* create log file index */ LivestatusLogUtility::CreateLogIndex(m_CompatLogPath, m_LogFileIndex); /* generate log cache */ LivestatusLogUtility::CreateLogCache(m_LogFileIndex, this, m_TimeFrom, m_TimeUntil, addRowFn); Checkable::Ptr checkable; for (const auto& kv : m_CheckablesCache) { for (const Dictionary::Ptr& state_hist_bag : kv.second) { /* pass a dictionary from state history array */ if (!addRowFn(state_hist_bag, LivestatusGroupByNone, Empty)) return; } } } Object::Ptr StateHistTable::HostAccessor(const Value& row, const Column::ObjectAccessor&) { String host_name = static_cast(row)->Get("host_name"); if (host_name.IsEmpty()) return Object::Ptr(); return Host::GetByName(host_name); } Object::Ptr StateHistTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor&) { String host_name = static_cast(row)->Get("host_name"); String service_description = static_cast(row)->Get("service_description"); if (service_description.IsEmpty() || host_name.IsEmpty()) return Object::Ptr(); return Service::GetByNamePair(host_name, service_description); } Value StateHistTable::TimeAccessor(const Value& row) { return static_cast(row)->Get("time"); } Value StateHistTable::LinenoAccessor(const Value& row) { return static_cast(row)->Get("lineno"); } Value StateHistTable::FromAccessor(const Value& row) { return static_cast(row)->Get("from"); } Value StateHistTable::UntilAccessor(const Value& row) { return static_cast(row)->Get("until"); } Value StateHistTable::DurationAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); } Value StateHistTable::DurationPartAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); } Value StateHistTable::StateAccessor(const Value& row) { return static_cast(row)->Get("state"); } Value StateHistTable::HostDownAccessor(const Value& row) { return static_cast(row)->Get("host_down"); } Value StateHistTable::InDowntimeAccessor(const Value& row) { return static_cast(row)->Get("in_downtime"); } Value StateHistTable::InHostDowntimeAccessor(const Value& row) { return static_cast(row)->Get("in_host_downtime"); } Value StateHistTable::IsFlappingAccessor(const Value& row) { return static_cast(row)->Get("is_flapping"); } Value StateHistTable::InNotificationPeriodAccessor(const Value& row) { return static_cast(row)->Get("in_notification_period"); } Value StateHistTable::NotificationPeriodAccessor(const Value& row) { return static_cast(row)->Get("notification_period"); } Value StateHistTable::HostNameAccessor(const Value& row) { return static_cast(row)->Get("host_name"); } Value StateHistTable::ServiceDescriptionAccessor(const Value& row) { return static_cast(row)->Get("service_description"); } Value StateHistTable::LogOutputAccessor(const Value& row) { return static_cast(row)->Get("log_output"); } Value StateHistTable::DurationOkAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceOK) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); return 0; } Value StateHistTable::DurationPartOkAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceOK) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; } Value StateHistTable::DurationWarningAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceWarning) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); return 0; } Value StateHistTable::DurationPartWarningAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceWarning) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; } Value StateHistTable::DurationCriticalAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceCritical) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); return 0; } Value StateHistTable::DurationPartCriticalAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceCritical) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; } Value StateHistTable::DurationUnknownAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceUnknown) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); return 0; } Value StateHistTable::DurationPartUnknownAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == ServiceUnknown) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; } Value StateHistTable::DurationUnmonitoredAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == -1) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")); return 0; } Value StateHistTable::DurationPartUnmonitoredAccessor(const Value& row) { Dictionary::Ptr state_hist_bag = static_cast(row); if (state_hist_bag->Get("state") == -1) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; } icinga2-2.8.1/lib/livestatus/statehisttable.hpp000066400000000000000000000101031322762156600215450ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STATEHISTTABLE_H #define STATEHISTTABLE_H #include "icinga/service.hpp" #include "livestatus/historytable.hpp" #include using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API StateHistTable : public HistoryTable { public: DECLARE_PTR_TYPEDEFS(StateHistTable); StateHistTable(const String& compat_log_path, time_t from, time_t until); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; void UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Object::Ptr ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor); static Value TimeAccessor(const Value& row); static Value LinenoAccessor(const Value& row); static Value FromAccessor(const Value& row); static Value UntilAccessor(const Value& row); static Value DurationAccessor(const Value& row); static Value DurationPartAccessor(const Value& row); static Value StateAccessor(const Value& row); static Value HostDownAccessor(const Value& row); static Value InDowntimeAccessor(const Value& row); static Value InHostDowntimeAccessor(const Value& row); static Value IsFlappingAccessor(const Value& row); static Value InNotificationPeriodAccessor(const Value& row); static Value NotificationPeriodAccessor(const Value& row); static Value HostNameAccessor(const Value& row); static Value ServiceDescriptionAccessor(const Value& row); static Value LogOutputAccessor(const Value& row); static Value DurationOkAccessor(const Value& row); static Value DurationPartOkAccessor(const Value& row); static Value DurationWarningAccessor(const Value& row); static Value DurationPartWarningAccessor(const Value& row); static Value DurationCriticalAccessor(const Value& row); static Value DurationPartCriticalAccessor(const Value& row); static Value DurationUnknownAccessor(const Value& row); static Value DurationPartUnknownAccessor(const Value& row); static Value DurationUnmonitoredAccessor(const Value& row); static Value DurationPartUnmonitoredAccessor(const Value& row); private: std::map m_LogFileIndex; std::map m_CheckablesCache; time_t m_TimeFrom; time_t m_TimeUntil; String m_CompatLogPath; }; } #endif /* STATEHISTTABLE_H */ icinga2-2.8.1/lib/livestatus/statustable.cpp000066400000000000000000000266421322762156600210720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/statustable.hpp" #include "livestatus/livestatuslistener.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/cib.hpp" #include "icinga/host.hpp" #include "icinga/service.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/application.hpp" using namespace icinga; StatusTable::StatusTable(void) { AddColumns(this); } void StatusTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "neb_callbacks", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "neb_callbacks_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "requests", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "requests_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "connections", Column(&StatusTable::ConnectionsAccessor, objectAccessor)); table->AddColumn(prefix + "connections_rate", Column(&StatusTable::ConnectionsRateAccessor, objectAccessor)); table->AddColumn(prefix + "service_checks", Column(&StatusTable::ServiceChecksAccessor, objectAccessor)); table->AddColumn(prefix + "service_checks_rate", Column(&StatusTable::ServiceChecksRateAccessor, objectAccessor)); table->AddColumn(prefix + "host_checks", Column(&StatusTable::HostChecksAccessor, objectAccessor)); table->AddColumn(prefix + "host_checks_rate", Column(&StatusTable::HostChecksRateAccessor, objectAccessor)); table->AddColumn(prefix + "forks", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "forks_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "log_messages", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "log_messages_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "external_commands", Column(&StatusTable::ExternalCommandsAccessor, objectAccessor)); table->AddColumn(prefix + "external_commands_rate", Column(&StatusTable::ExternalCommandsRateAccessor, objectAccessor)); table->AddColumn(prefix + "livechecks", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livechecks_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livecheck_overflows", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livecheck_overflows_rate", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "nagios_pid", Column(&StatusTable::NagiosPidAccessor, objectAccessor)); table->AddColumn(prefix + "enable_notifications", Column(&StatusTable::EnableNotificationsAccessor, objectAccessor)); table->AddColumn(prefix + "execute_service_checks", Column(&StatusTable::ExecuteServiceChecksAccessor, objectAccessor)); table->AddColumn(prefix + "accept_passive_service_checks", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "execute_host_checks", Column(&StatusTable::ExecuteHostChecksAccessor, objectAccessor)); table->AddColumn(prefix + "accept_passive_host_checks", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "enable_event_handlers", Column(&StatusTable::EnableEventHandlersAccessor, objectAccessor)); table->AddColumn(prefix + "obsess_over_services", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "obsess_over_hosts", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "check_service_freshness", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "check_host_freshness", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "enable_flap_detection", Column(&StatusTable::EnableFlapDetectionAccessor, objectAccessor)); table->AddColumn(prefix + "process_performance_data", Column(&StatusTable::ProcessPerformanceDataAccessor, objectAccessor)); table->AddColumn(prefix + "check_external_commands", Column(&Table::OneAccessor, objectAccessor)); table->AddColumn(prefix + "program_start", Column(&StatusTable::ProgramStartAccessor, objectAccessor)); table->AddColumn(prefix + "last_command_check", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "last_log_rotation", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "interval_length", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "num_hosts", Column(&StatusTable::NumHostsAccessor, objectAccessor)); table->AddColumn(prefix + "num_services", Column(&StatusTable::NumServicesAccessor, objectAccessor)); table->AddColumn(prefix + "program_version", Column(&StatusTable::ProgramVersionAccessor, objectAccessor)); table->AddColumn(prefix + "external_command_buffer_slots", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "external_command_buffer_usage", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "external_command_buffer_max", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "cached_log_messages", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livestatus_version", Column(&StatusTable::LivestatusVersionAccessor, objectAccessor)); table->AddColumn(prefix + "livestatus_active_connections", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livestatus_queued_connections", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "livestatus_threads", Column(&Table::ZeroAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_names", Column(&StatusTable::CustomVariableNamesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variable_values", Column(&StatusTable::CustomVariableValuesAccessor, objectAccessor)); table->AddColumn(prefix + "custom_variables", Column(&StatusTable::CustomVariablesAccessor, objectAccessor)); } String StatusTable::GetName(void) const { return "status"; } String StatusTable::GetPrefix(void) const { return "status"; } void StatusTable::FetchRows(const AddRowFunction& addRowFn) { Object::Ptr obj = new Object(); /* Return a fake row. */ addRowFn(obj, LivestatusGroupByNone, Empty); } Value StatusTable::ConnectionsAccessor(const Value&) { return LivestatusListener::GetConnections(); } Value StatusTable::ConnectionsRateAccessor(const Value&) { return (LivestatusListener::GetConnections() / (Utility::GetTime() - Application::GetStartTime())); } Value StatusTable::HostChecksAccessor(const Value&) { long timespan = static_cast(Utility::GetTime() - Application::GetStartTime()); return CIB::GetActiveHostChecksStatistics(timespan); } Value StatusTable::HostChecksRateAccessor(const Value&) { long timespan = static_cast(Utility::GetTime() - Application::GetStartTime()); return (CIB::GetActiveHostChecksStatistics(timespan) / (Utility::GetTime() - Application::GetStartTime())); } Value StatusTable::ServiceChecksAccessor(const Value&) { long timespan = static_cast(Utility::GetTime() - Application::GetStartTime()); return CIB::GetActiveServiceChecksStatistics(timespan); } Value StatusTable::ServiceChecksRateAccessor(const Value&) { long timespan = static_cast(Utility::GetTime() - Application::GetStartTime()); return (CIB::GetActiveServiceChecksStatistics(timespan) / (Utility::GetTime() - Application::GetStartTime())); } Value StatusTable::ExternalCommandsAccessor(const Value&) { return LivestatusQuery::GetExternalCommands(); } Value StatusTable::ExternalCommandsRateAccessor(const Value&) { return (LivestatusQuery::GetExternalCommands() / (Utility::GetTime() - Application::GetStartTime())); } Value StatusTable::NagiosPidAccessor(const Value&) { return Utility::GetPid(); } Value StatusTable::EnableNotificationsAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnableNotifications() ? 1 : 0); } Value StatusTable::ExecuteServiceChecksAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnableServiceChecks() ? 1 : 0); } Value StatusTable::ExecuteHostChecksAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnableHostChecks() ? 1 : 0); } Value StatusTable::EnableEventHandlersAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnableEventHandlers() ? 1 : 0); } Value StatusTable::EnableFlapDetectionAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnableFlapping() ? 1 : 0); } Value StatusTable::ProcessPerformanceDataAccessor(const Value&) { return (IcingaApplication::GetInstance()->GetEnablePerfdata() ? 1 : 0); } Value StatusTable::ProgramStartAccessor(const Value&) { return static_cast(Application::GetStartTime()); } Value StatusTable::NumHostsAccessor(const Value&) { return ConfigType::Get()->GetObjectCount(); } Value StatusTable::NumServicesAccessor(const Value&) { return ConfigType::Get()->GetObjectCount(); } Value StatusTable::ProgramVersionAccessor(const Value&) { return Application::GetAppVersion(); } Value StatusTable::LivestatusVersionAccessor(const Value&) { return Application::GetAppVersion(); } Value StatusTable::LivestatusActiveConnectionsAccessor(const Value&) { return LivestatusListener::GetClientsConnected(); } Value StatusTable::CustomVariableNamesAccessor(const Value&) { Dictionary::Ptr vars = IcingaApplication::GetInstance()->GetVars(); Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock olock(vars); for (const auto& kv : vars) { cv->Add(kv.first); } } return cv; } Value StatusTable::CustomVariableValuesAccessor(const Value&) { Dictionary::Ptr vars = IcingaApplication::GetInstance()->GetVars(); Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock olock(vars); for (const auto& kv : vars) { cv->Add(kv.second); } } return cv; } Value StatusTable::CustomVariablesAccessor(const Value&) { Dictionary::Ptr vars = IcingaApplication::GetInstance()->GetVars(); Array::Ptr cv = new Array(); if (!vars) return cv; { ObjectLock olock(vars); for (const auto& kv : vars) { Array::Ptr key_val = new Array(); key_val->Add(kv.first); key_val->Add(kv.second); cv->Add(key_val); } } return cv; } icinga2-2.8.1/lib/livestatus/statustable.hpp000066400000000000000000000066111322762156600210710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STATUSTABLE_H #define STATUSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API StatusTable : public Table { public: DECLARE_PTR_TYPEDEFS(StatusTable); StatusTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value ConnectionsAccessor(const Value& row); static Value ConnectionsRateAccessor(const Value& row); static Value ServiceChecksAccessor(const Value& row); static Value ServiceChecksRateAccessor(const Value& row); static Value HostChecksAccessor(const Value& row); static Value HostChecksRateAccessor(const Value& row); static Value ExternalCommandsAccessor(const Value& row); static Value ExternalCommandsRateAccessor(const Value& row); static Value NagiosPidAccessor(const Value& row); static Value EnableNotificationsAccessor(const Value& row); static Value ExecuteServiceChecksAccessor(const Value& row); static Value ExecuteHostChecksAccessor(const Value& row); static Value EnableEventHandlersAccessor(const Value& row); static Value EnableFlapDetectionAccessor(const Value& row); static Value ProcessPerformanceDataAccessor(const Value& row); static Value ProgramStartAccessor(const Value& row); static Value NumHostsAccessor(const Value& row); static Value NumServicesAccessor(const Value& row); static Value ProgramVersionAccessor(const Value& row); static Value LivestatusVersionAccessor(const Value& row); static Value LivestatusActiveConnectionsAccessor(const Value& row); static Value CustomVariableNamesAccessor(const Value& row); static Value CustomVariableValuesAccessor(const Value& row); static Value CustomVariablesAccessor(const Value& row); }; } #endif /* STATUSTABLE_H */ icinga2-2.8.1/lib/livestatus/stdaggregator.cpp000066400000000000000000000045161322762156600213700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/stdaggregator.hpp" #include using namespace icinga; StdAggregator::StdAggregator(const String& attr) : m_StdAttr(attr) { } StdAggregatorState *StdAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new StdAggregatorState(); return static_cast(*state); } void StdAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_StdAttr); Value value = column.ExtractValue(row); StdAggregatorState *pstate = EnsureState(state); pstate->StdSum += value; pstate->StdQSum += pow(value, 2); pstate->StdCount++; } double StdAggregator::GetResultAndFreeState(AggregatorState *state) const { StdAggregatorState *pstate = EnsureState(&state); double result = sqrt((pstate->StdQSum - (1 / pstate->StdCount) * pow(pstate->StdSum, 2)) / (pstate->StdCount - 1)); delete pstate; return result; } icinga2-2.8.1/lib/livestatus/stdaggregator.hpp000066400000000000000000000043671322762156600214010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STDAGGREGATOR_H #define STDAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API StdAggregatorState : public AggregatorState { StdAggregatorState(void) : StdSum(0), StdQSum(0), StdCount(0) { } double StdSum; double StdQSum; double StdCount; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API StdAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(StdAggregator); StdAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_StdAttr; static StdAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* STDAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/sumaggregator.cpp000066400000000000000000000042521322762156600213770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/sumaggregator.hpp" using namespace icinga; SumAggregator::SumAggregator(const String& attr) : m_SumAttr(attr) { } SumAggregatorState *SumAggregator::EnsureState(AggregatorState **state) { if (!*state) *state = new SumAggregatorState(); return static_cast(*state); } void SumAggregator::Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) { Column column = table->GetColumn(m_SumAttr); Value value = column.ExtractValue(row); SumAggregatorState *pstate = EnsureState(state); pstate->Sum += value; } double SumAggregator::GetResultAndFreeState(AggregatorState *state) const { SumAggregatorState *pstate = EnsureState(&state); double result = pstate->Sum; delete pstate; return result; } icinga2-2.8.1/lib/livestatus/sumaggregator.hpp000066400000000000000000000042651322762156600214100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef SUMAGGREGATOR_H #define SUMAGGREGATOR_H #include "livestatus/table.hpp" #include "livestatus/aggregator.hpp" namespace icinga { /** * @ingroup livestatus */ struct I2_LIVESTATUS_API SumAggregatorState : public AggregatorState { SumAggregatorState(void) : Sum(0) { } double Sum; }; /** * @ingroup livestatus */ class I2_LIVESTATUS_API SumAggregator : public Aggregator { public: DECLARE_PTR_TYPEDEFS(SumAggregator); SumAggregator(const String& attr); virtual void Apply(const Table::Ptr& table, const Value& row, AggregatorState **state) override; virtual double GetResultAndFreeState(AggregatorState *state) const override; private: String m_SumAttr; static SumAggregatorState *EnsureState(AggregatorState **state); }; } #endif /* SUMAGGREGATOR_H */ icinga2-2.8.1/lib/livestatus/table.cpp000066400000000000000000000131161322762156600176160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/table.hpp" #include "livestatus/statustable.hpp" #include "livestatus/contactgroupstable.hpp" #include "livestatus/contactstable.hpp" #include "livestatus/hostgroupstable.hpp" #include "livestatus/hoststable.hpp" #include "livestatus/servicegroupstable.hpp" #include "livestatus/servicestable.hpp" #include "livestatus/commandstable.hpp" #include "livestatus/commentstable.hpp" #include "livestatus/downtimestable.hpp" #include "livestatus/endpointstable.hpp" #include "livestatus/zonestable.hpp" #include "livestatus/timeperiodstable.hpp" #include "livestatus/logtable.hpp" #include "livestatus/statehisttable.hpp" #include "livestatus/filter.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include #include #include using namespace icinga; Table::Table(LivestatusGroupByType type) : m_GroupByType(type), m_GroupByObject(Empty) { } Table::Ptr Table::GetByName(const String& name, const String& compat_log_path, const unsigned long& from, const unsigned long& until) { if (name == "status") return new StatusTable(); else if (name == "contactgroups") return new ContactGroupsTable(); else if (name == "contacts") return new ContactsTable(); else if (name == "hostgroups") return new HostGroupsTable(); else if (name == "hosts") return new HostsTable(); else if (name == "hostsbygroup") return new HostsTable(LivestatusGroupByHostGroup); else if (name == "servicegroups") return new ServiceGroupsTable(); else if (name == "services") return new ServicesTable(); else if (name == "servicesbygroup") return new ServicesTable(LivestatusGroupByServiceGroup); else if (name == "servicesbyhostgroup") return new ServicesTable(LivestatusGroupByHostGroup); else if (name == "commands") return new CommandsTable(); else if (name == "comments") return new CommentsTable(); else if (name == "downtimes") return new DowntimesTable(); else if (name == "timeperiods") return new TimePeriodsTable(); else if (name == "log") return new LogTable(compat_log_path, from, until); else if (name == "statehist") return new StateHistTable(compat_log_path, from, until); else if (name == "endpoints") return new EndpointsTable(); else if (name == "zones") return new ZonesTable(); return Table::Ptr(); } void Table::AddColumn(const String& name, const Column& column) { std::pair item = std::make_pair(name, column); auto ret = m_Columns.insert(item); if (!ret.second) ret.first->second = column; } Column Table::GetColumn(const String& name) const { String dname = name; String prefix = GetPrefix() + "_"; if (dname.Find(prefix) == 0) dname = dname.SubStr(prefix.GetLength()); auto it = m_Columns.find(dname); if (it == m_Columns.end()) BOOST_THROW_EXCEPTION(std::invalid_argument("Column '" + dname + "' does not exist in table '" + GetName() + "'.")); return it->second; } std::vector Table::GetColumnNames(void) const { std::vector names; for (const auto& kv : m_Columns) { names.push_back(kv.first); } return names; } std::vector Table::FilterRows(const Filter::Ptr& filter, int limit) { std::vector rs; FetchRows(boost::bind(&Table::FilteredAddRow, this, boost::ref(rs), filter, limit, _1, _2, _3)); return rs; } bool Table::FilteredAddRow(std::vector& rs, const Filter::Ptr& filter, int limit, const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) { if (limit != -1 && static_cast(rs.size()) == limit) return false; if (!filter || filter->Apply(this, row)) { LivestatusRowValue rval; rval.Row = row; rval.GroupByType = groupByType; rval.GroupByObject = groupByObject; rs.push_back(rval); } return true; } Value Table::ZeroAccessor(const Value&) { return 0; } Value Table::OneAccessor(const Value&) { return 1; } Value Table::EmptyStringAccessor(const Value&) { return ""; } Value Table::EmptyArrayAccessor(const Value&) { return new Array(); } Value Table::EmptyDictionaryAccessor(const Value&) { return new Dictionary(); } LivestatusGroupByType Table::GetGroupByType(void) const { return m_GroupByType; } icinga2-2.8.1/lib/livestatus/table.hpp000066400000000000000000000062661322762156600176330ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TABLE_H #define TABLE_H #include "livestatus/column.hpp" #include "base/object.hpp" #include "base/dictionary.hpp" #include "base/array.hpp" #include namespace icinga { struct LivestatusRowValue { Value Row; LivestatusGroupByType GroupByType; Value GroupByObject; }; typedef boost::function AddRowFunction; class Filter; /** * @ingroup livestatus */ class I2_LIVESTATUS_API Table : public Object { public: DECLARE_PTR_TYPEDEFS(Table); static Table::Ptr GetByName(const String& name, const String& compat_log_path = "", const unsigned long& from = 0, const unsigned long& until = 0); virtual String GetName(void) const = 0; virtual String GetPrefix(void) const = 0; std::vector FilterRows(const intrusive_ptr& filter, int limit = -1); void AddColumn(const String& name, const Column& column); Column GetColumn(const String& name) const; std::vector GetColumnNames(void) const; virtual LivestatusGroupByType GetGroupByType(void) const; protected: Table(LivestatusGroupByType type = LivestatusGroupByNone); virtual void FetchRows(const AddRowFunction& addRowFn) = 0; static Value ZeroAccessor(const Value&); static Value OneAccessor(const Value&); static Value EmptyStringAccessor(const Value&); static Value EmptyArrayAccessor(const Value&); static Value EmptyDictionaryAccessor(const Value&); LivestatusGroupByType m_GroupByType; Value m_GroupByObject; private: std::map m_Columns; bool FilteredAddRow(std::vector& rs, const intrusive_ptr& filter, int limit, const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject); }; } #endif /* TABLE_H */ #include "livestatus/filter.hpp" icinga2-2.8.1/lib/livestatus/timeperiodstable.cpp000066400000000000000000000056101322762156600220630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/timeperiodstable.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/timeperiod.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include using namespace icinga; TimePeriodsTable::TimePeriodsTable(void) { AddColumns(this); } void TimePeriodsTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&TimePeriodsTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "alias", Column(&TimePeriodsTable::AliasAccessor, objectAccessor)); table->AddColumn(prefix + "in", Column(&TimePeriodsTable::InAccessor, objectAccessor)); } String TimePeriodsTable::GetName(void) const { return "timeperiod"; } String TimePeriodsTable::GetPrefix(void) const { return "timeperiod"; } void TimePeriodsTable::FetchRows(const AddRowFunction& addRowFn) { for (const TimePeriod::Ptr& tp : ConfigType::GetObjectsByType()) { if (!addRowFn(tp, LivestatusGroupByNone, Empty)) return; } } Value TimePeriodsTable::NameAccessor(const Value& row) { return static_cast(row)->GetName(); } Value TimePeriodsTable::AliasAccessor(const Value& row) { return static_cast(row)->GetDisplayName(); } Value TimePeriodsTable::InAccessor(const Value& row) { return (static_cast(row)->IsInside(Utility::GetTime()) ? 1 : 0); } icinga2-2.8.1/lib/livestatus/timeperiodstable.hpp000066400000000000000000000043001322762156600220630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TIMEPERIODSTABLE_H #define TIMEPERIODSTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API TimePeriodsTable : public Table { public: DECLARE_PTR_TYPEDEFS(TimePeriodsTable); TimePeriodsTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value AliasAccessor(const Value& row); static Value InAccessor(const Value& row); }; } #endif /* TIMEPERIODSTABLE_H */ icinga2-2.8.1/lib/livestatus/zonestable.cpp000066400000000000000000000065021322762156600206760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/zonestable.hpp" #include "remote/zone.hpp" #include "base/configtype.hpp" using namespace icinga; ZonesTable::ZonesTable(void) { AddColumns(this); } void ZonesTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { table->AddColumn(prefix + "name", Column(&ZonesTable::NameAccessor, objectAccessor)); table->AddColumn(prefix + "parent", Column(&ZonesTable::ParentAccessor, objectAccessor)); table->AddColumn(prefix + "endpoints", Column(&ZonesTable::EndpointsAccessor, objectAccessor)); table->AddColumn(prefix + "global", Column(&ZonesTable::GlobalAccessor, objectAccessor)); } String ZonesTable::GetName(void) const { return "zones"; } String ZonesTable::GetPrefix(void) const { return "zone"; } void ZonesTable::FetchRows(const AddRowFunction& addRowFn) { for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { if (!addRowFn(zone, LivestatusGroupByNone, Empty)) return; } } Value ZonesTable::NameAccessor(const Value& row) { Zone::Ptr zone = static_cast(row); if (!zone) return Empty; return zone->GetName(); } Value ZonesTable::ParentAccessor(const Value& row) { Zone::Ptr zone = static_cast(row); if (!zone) return Empty; Zone::Ptr parent_zone = zone->GetParent(); if (!parent_zone) return Empty; return parent_zone->GetName(); } Value ZonesTable::EndpointsAccessor(const Value& row) { Zone::Ptr zone = static_cast(row); if (!zone) return Empty; std::set endpoints = zone->GetEndpoints(); Array::Ptr endpoint_names = new Array(); for (const Endpoint::Ptr endpoint : endpoints) { endpoint_names->Add(endpoint->GetName()); } if (!endpoint_names) return Empty; return endpoint_names; } Value ZonesTable::GlobalAccessor(const Value& row) { Zone::Ptr zone = static_cast(row); if (!zone) return Empty; return zone->GetGlobal() ? 1 : 0; } icinga2-2.8.1/lib/livestatus/zonestable.hpp000066400000000000000000000043241322762156600207030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ZONESTABLE_H #define ZONESTABLE_H #include "livestatus/table.hpp" using namespace icinga; namespace icinga { /** * @ingroup livestatus */ class I2_LIVESTATUS_API ZonesTable : public Table { public: DECLARE_PTR_TYPEDEFS(ZonesTable); ZonesTable(void); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const override; virtual String GetPrefix(void) const override; protected: virtual void FetchRows(const AddRowFunction& addRowFn) override; static Value NameAccessor(const Value& row); static Value ParentAccessor(const Value& row); static Value EndpointsAccessor(const Value& row); static Value GlobalAccessor(const Value& row); }; } #endif /* ZONESTABLE_H */ icinga2-2.8.1/lib/methods/000077500000000000000000000000001322762156600152615ustar00rootroot00000000000000icinga2-2.8.1/lib/methods/CMakeLists.txt000066400000000000000000000033121322762156600200200ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkembedconfig_target(methods-itl.conf methods-itl.cpp) if(MSVC) set(WindowsSources clrchecktask.cpp) else() set(WindowsSources "") endif() set(methods_SOURCES clusterchecktask.cpp clusterzonechecktask.cpp exceptionchecktask.cpp icingachecktask.cpp methods-itl.cpp nullchecktask.cpp nulleventtask.cpp pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.cpp randomchecktask.cpp timeperiodtask.cpp ${WindowsSources} ) if(ICINGA2_UNITY_BUILD) mkunity_target(methods methods methods_SOURCES) endif() add_library(methods SHARED ${methods_SOURCES}) target_link_libraries(methods ${Boost_LIBRARIES} base config icinga) set_target_properties ( methods PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_METHODS_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS methods RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) icinga2-2.8.1/lib/methods/clrchecktask.cpp000066400000000000000000000162651322762156600204400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/clrchecktask.hpp" #include "icinga/pluginutility.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/function.hpp" #include "base/utility.hpp" #include "base/process.hpp" #include #include #include #include #include #import "mscorlib.tlb" #pragma comment(lib, "mscoree.lib") using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, ClrCheck, &ClrCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); static boost::once_flag l_OnceFlag = BOOST_ONCE_INIT; static boost::mutex l_ObjectsMutex; static std::map l_Objects; static mscorlib::_AppDomainPtr l_AppDomain; static void InitializeClr(void) { ICorRuntimeHost *runtimeHost; if (FAILED(CorBindToRuntimeEx(NULL, NULL, STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void **)&runtimeHost))) { return; } runtimeHost->Start(); IUnknownPtr punkAppDomain = NULL; runtimeHost->GetDefaultDomain(&punkAppDomain); punkAppDomain->QueryInterface(__uuidof(mscorlib::_AppDomain), (void **)&l_AppDomain); runtimeHost->Release(); } static variant_t CreateClrType(const String& assemblyName, const String& typeName) { boost::call_once(l_OnceFlag, &InitializeClr); try { mscorlib::_ObjectHandlePtr pObjectHandle; pObjectHandle = l_AppDomain->CreateInstanceFrom(assemblyName.CStr(), typeName.CStr()); return pObjectHandle->Unwrap(); } catch (_com_error& error) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not load .NET type: " + String(error.Description()))); } } static variant_t InvokeClrMethod(const variant_t& vtObject, const String& methodName, const Dictionary::Ptr& args) { CLSID clsid; HRESULT hr = CLSIDFromProgID(L"System.Collections.Hashtable", &clsid); mscorlib::IDictionaryPtr pHashtable; CoCreateInstance(clsid, NULL, CLSCTX_ALL, __uuidof(mscorlib::IDictionary), (void **)&pHashtable); ObjectLock olock(args); for (const Dictionary::Pair& kv : args) { String value = kv.second; pHashtable->Add(kv.first.CStr(), value.CStr()); } mscorlib::_ObjectPtr pObject; vtObject.pdispVal->QueryInterface(__uuidof(mscorlib::_Object), (void**)&pObject); mscorlib::_TypePtr pType = pObject->GetType(); SAFEARRAY *psa = SafeArrayCreateVector(VT_VARIANT, 0, 1); variant_t vtHashtable = static_cast(pHashtable); LONG idx = 0; SafeArrayPutElement(psa, &idx, &vtHashtable); variant_t result = pType->InvokeMember_3(methodName.CStr(), mscorlib::BindingFlags_InvokeMethod, NULL, vtObject, psa); SafeArrayDestroy(psa); return result; } static void FillCheckResult(const CheckResult::Ptr& cr, variant_t vtResult) { mscorlib::_ObjectPtr pObject; vtResult.pdispVal->QueryInterface(__uuidof(mscorlib::_Object), (void**)&pObject); mscorlib::_TypePtr pType = pObject->GetType(); SAFEARRAY *psa = SafeArrayCreateVector(VT_VARIANT, 0, 0); int lState = pType->InvokeMember_3("State", mscorlib::BindingFlags_GetField, NULL, vtResult, psa); cr->SetState(static_cast(lState)); bstr_t sOutput = pType->InvokeMember_3("Output", mscorlib::BindingFlags_GetField, NULL, vtResult, psa); cr->SetOutput(static_cast(sOutput)); bstr_t sPerformanceData = pType->InvokeMember_3("PerformanceData", mscorlib::BindingFlags_GetField, NULL, vtResult, psa); SafeArrayDestroy(psa); cr->SetPerformanceData(PluginUtility::SplitPerfdata(static_cast(sPerformanceData))); } void ClrCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); Value raw_command = commandObj->GetCommandLine(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); Dictionary::Ptr envMacros = new Dictionary(); Dictionary::Ptr env = commandObj->GetEnv(); if (env) { ObjectLock olock(env); for (const Dictionary::Pair& kv : env) { String name = kv.second; Value value = MacroProcessor::ResolveMacros(name, resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); envMacros->Set(kv.first, value); } } variant_t vtObject; { boost::mutex::scoped_lock lock(l_ObjectsMutex); auto it = l_Objects.find(checkable); if (it != l_Objects.end()) { vtObject = it->second; } else { String clr_assembly = MacroProcessor::ResolveMacros("$clr_assembly$", resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); String clr_type = MacroProcessor::ResolveMacros("$clr_type$", resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); if (resolvedMacros && !useResolvedMacros) return; vtObject = CreateClrType(clr_assembly, clr_type); l_Objects[checkable] = vtObject; } } try { variant_t vtResult = InvokeClrMethod(vtObject, "Check", envMacros); FillCheckResult(cr, vtResult); checkable->ProcessCheckResult(cr); } catch (_com_error& error) { cr->SetOutput("Failed to invoke .NET method: " + String(error.Description())); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); } } icinga2-2.8.1/lib/methods/clrchecktask.hpp000066400000000000000000000036311322762156600204360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLRCHECKTASK_H #define CLRCHECKTASK_H #include "methods/i2-methods.hpp" #include "base/process.hpp" #include "icinga/service.hpp" namespace icinga { /** * Implements service checks based CLR libraries. * * @ingroup methods */ class I2_METHODS_API ClrCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClrCheckTask(void); }; } #endif /* CLRCHECKTASK_H */ icinga2-2.8.1/lib/methods/clusterchecktask.cpp000066400000000000000000000071621322762156600213350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/clusterchecktask.hpp" #include "remote/apilistener.hpp" #include "remote/endpoint.hpp" #include "icinga/cib.hpp" #include "icinga/service.hpp" #include "icinga/icingaapplication.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/function.hpp" #include "base/configtype.hpp" #include using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { if (resolvedMacros && !useResolvedMacros) return; ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { cr->SetOutput("No API listener is configured for this instance."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } std::pair stats = listener->GetStatus(); Dictionary::Ptr status = stats.first; /* use feature stats perfdata */ std::pair feature_stats = CIB::GetFeatureStats(); cr->SetPerformanceData(feature_stats.second); String connected_endpoints = FormatArray(status->Get("conn_endpoints")); String not_connected_endpoints = FormatArray(status->Get("not_conn_endpoints")); if (status->Get("num_not_conn_endpoints") > 0) { cr->SetState(ServiceCritical); cr->SetOutput("Icinga 2 Cluster Problem: " + Convert::ToString(status->Get("num_not_conn_endpoints")) + " Endpoints (" + not_connected_endpoints + ") not connected."); } else { cr->SetState(ServiceOK); cr->SetOutput("Icinga 2 Cluster is running: Connected Endpoints: "+ Convert::ToString(status->Get("num_conn_endpoints")) + " (" + connected_endpoints + ")."); } checkable->ProcessCheckResult(cr); } String ClusterCheckTask::FormatArray(const Array::Ptr& arr) { bool first = true; String str; if (arr) { ObjectLock olock(arr); for (const Value& value : arr) { if (first) first = false; else str += ", "; str += Convert::ToString(value); } } return str; } icinga2-2.8.1/lib/methods/clusterchecktask.hpp000066400000000000000000000035701322762156600213410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLUSTERCHECKTASK_H #define CLUSTERCHECKTASK_H #include "icinga/service.hpp" namespace icinga { /** * Cluster check type. * * @ingroup methods */ class ClusterCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterCheckTask(void); static String FormatArray(const Array::Ptr& arr); }; } #endif /* CLUSTERCHECKTASK_H */ icinga2-2.8.1/lib/methods/clusterzonechecktask.cpp000066400000000000000000000123521322762156600222260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/clusterzonechecktask.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include "remote/apilistener.hpp" #include "remote/endpoint.hpp" #include "remote/zone.hpp" #include "base/function.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { cr->SetOutput("No API listener is configured for this instance."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); Value raw_command = commandObj->GetCommandLine(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); String zoneName = MacroProcessor::ResolveMacros("$cluster_zone$", resolvers, checkable->GetLastCheckResult(), NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); String missingLagWarning; String missingLagCritical; double lagWarning = MacroProcessor::ResolveMacros("$cluster_lag_warning$", resolvers, checkable->GetLastCheckResult(), &missingLagWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); double lagCritical = MacroProcessor::ResolveMacros("$cluster_lag_critical$", resolvers, checkable->GetLastCheckResult(), &missingLagCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros); if (resolvedMacros && !useResolvedMacros) return; if (zoneName.IsEmpty()) { cr->SetOutput("Macro 'cluster_zone' must be set."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } Zone::Ptr zone = Zone::GetByName(zoneName); if (!zone) { cr->SetOutput("Zone '" + zoneName + "' does not exist."); cr->SetState(ServiceUnknown); checkable->ProcessCheckResult(cr); return; } bool connected = false; double zoneLag = 0; for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) { if (endpoint->GetConnected()) connected = true; double eplag = ApiListener::CalculateZoneLag(endpoint); if (eplag > 0 && eplag > zoneLag) zoneLag = eplag; } if (!connected) { cr->SetState(ServiceCritical); cr->SetOutput("Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag)); } else { cr->SetState(ServiceOK); cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag)); } /* Check whether the thresholds have been resolved and compare them */ if (missingLagCritical.IsEmpty() && zoneLag > lagCritical) { cr->SetState(ServiceCritical); cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + " greater than critical threshold: " + Utility::FormatDuration(lagCritical)); } else if (missingLagWarning.IsEmpty() && zoneLag > lagWarning) { cr->SetState(ServiceWarning); cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + " greater than warning threshold: " + Utility::FormatDuration(lagWarning)); } Array::Ptr perfdata = new Array(); perfdata->Add(new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical)); cr->SetPerformanceData(perfdata); checkable->ProcessCheckResult(cr); } icinga2-2.8.1/lib/methods/clusterzonechecktask.hpp000066400000000000000000000035361322762156600222370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLUSTERZONECHECKTASK_H #define CLUSTERZONECHECKTASK_H #include "icinga/service.hpp" namespace icinga { /** * Cluster zone check type. * * @ingroup methods */ class ClusterZoneCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterZoneCheckTask(void); }; } #endif /* CLUSTERZONECHECKTASK_H */ icinga2-2.8.1/lib/methods/exceptionchecktask.cpp000066400000000000000000000041451322762156600216500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef _WIN32 # include #endif /* _WIN32 */ #include "methods/exceptionchecktask.hpp" #include "base/utility.hpp" #include "base/convert.hpp" #include "base/function.hpp" #include "base/logger.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { if (resolvedMacros && !useResolvedMacros) return; BOOST_THROW_EXCEPTION(ScriptError("Test") << boost::errinfo_api_function("Test")); } icinga2-2.8.1/lib/methods/exceptionchecktask.hpp000066400000000000000000000036501322762156600216550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXCEPTIONCHECKTASK_H #define EXCEPTIONCHECKTASK_H #include "icinga/service.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Test class for additional check types. Implements the "exception" check type. * * @ingroup methods */ class ExceptionCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ExceptionCheckTask(void); }; } #endif /* EXCEPTIONCHECKTASK_H */ icinga2-2.8.1/lib/methods/i2-methods.hpp000066400000000000000000000034541322762156600177530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2METHODS_H #define I2METHODS_H /** * @defgroup methods Icinga methods * * The methods library implements methods for various task (e.g. checks, event * handlers, etc.). */ #include "base/i2-base.hpp" #ifdef I2_METHODS_BUILD # define I2_METHODS_API I2_EXPORT #else /* I2_METHODS_BUILD */ # define I2_METHODS_API I2_IMPORT #endif /* I2_METHODS_BUILD */ #endif /* I2METHODS_H */ icinga2-2.8.1/lib/methods/icingachecktask.cpp000066400000000000000000000150631322762156600211050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/icingachecktask.hpp" #include "icinga/cib.hpp" #include "icinga/service.hpp" #include "icinga/icingaapplication.hpp" #include "base/application.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/function.hpp" #include "base/configtype.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { if (resolvedMacros && !useResolvedMacros) return; double interval = Utility::GetTime() - Application::GetStartTime(); if (interval > 60) interval = 60; /* use feature stats perfdata */ std::pair feature_stats = CIB::GetFeatureStats(); Array::Ptr perfdata = feature_stats.second; perfdata->Add(new PerfdataValue("active_host_checks", CIB::GetActiveHostChecksStatistics(interval) / interval)); perfdata->Add(new PerfdataValue("passive_host_checks", CIB::GetPassiveHostChecksStatistics(interval) / interval)); perfdata->Add(new PerfdataValue("active_host_checks_1min", CIB::GetActiveHostChecksStatistics(60))); perfdata->Add(new PerfdataValue("passive_host_checks_1min", CIB::GetPassiveHostChecksStatistics(60))); perfdata->Add(new PerfdataValue("active_host_checks_5min", CIB::GetActiveHostChecksStatistics(60 * 5))); perfdata->Add(new PerfdataValue("passive_host_checks_5min", CIB::GetPassiveHostChecksStatistics(60 * 5))); perfdata->Add(new PerfdataValue("active_host_checks_15min", CIB::GetActiveHostChecksStatistics(60 * 15))); perfdata->Add(new PerfdataValue("passive_host_checks_15min", CIB::GetPassiveHostChecksStatistics(60 * 15))); perfdata->Add(new PerfdataValue("active_service_checks", CIB::GetActiveServiceChecksStatistics(interval) / interval)); perfdata->Add(new PerfdataValue("passive_service_checks", CIB::GetPassiveServiceChecksStatistics(interval) / interval)); perfdata->Add(new PerfdataValue("active_service_checks_1min", CIB::GetActiveServiceChecksStatistics(60))); perfdata->Add(new PerfdataValue("passive_service_checks_1min", CIB::GetPassiveServiceChecksStatistics(60))); perfdata->Add(new PerfdataValue("active_service_checks_5min", CIB::GetActiveServiceChecksStatistics(60 * 5))); perfdata->Add(new PerfdataValue("passive_service_checks_5min", CIB::GetPassiveServiceChecksStatistics(60 * 5))); perfdata->Add(new PerfdataValue("active_service_checks_15min", CIB::GetActiveServiceChecksStatistics(60 * 15))); perfdata->Add(new PerfdataValue("passive_service_checks_15min", CIB::GetPassiveServiceChecksStatistics(60 * 15))); CheckableCheckStatistics scs = CIB::CalculateServiceCheckStats(); perfdata->Add(new PerfdataValue("min_latency", scs.min_latency)); perfdata->Add(new PerfdataValue("max_latency", scs.max_latency)); perfdata->Add(new PerfdataValue("avg_latency", scs.avg_latency)); perfdata->Add(new PerfdataValue("min_execution_time", scs.min_execution_time)); perfdata->Add(new PerfdataValue("max_execution_time", scs.max_execution_time)); perfdata->Add(new PerfdataValue("avg_execution_time", scs.avg_execution_time)); ServiceStatistics ss = CIB::CalculateServiceStats(); perfdata->Add(new PerfdataValue("num_services_ok", ss.services_ok)); perfdata->Add(new PerfdataValue("num_services_warning", ss.services_warning)); perfdata->Add(new PerfdataValue("num_services_critical", ss.services_critical)); perfdata->Add(new PerfdataValue("num_services_unknown", ss.services_unknown)); perfdata->Add(new PerfdataValue("num_services_pending", ss.services_pending)); perfdata->Add(new PerfdataValue("num_services_unreachable", ss.services_unreachable)); perfdata->Add(new PerfdataValue("num_services_flapping", ss.services_flapping)); perfdata->Add(new PerfdataValue("num_services_in_downtime", ss.services_in_downtime)); perfdata->Add(new PerfdataValue("num_services_acknowledged", ss.services_acknowledged)); double uptime = Utility::GetTime() - Application::GetStartTime(); perfdata->Add(new PerfdataValue("uptime", uptime)); HostStatistics hs = CIB::CalculateHostStats(); perfdata->Add(new PerfdataValue("num_hosts_up", hs.hosts_up)); perfdata->Add(new PerfdataValue("num_hosts_down", hs.hosts_down)); perfdata->Add(new PerfdataValue("num_hosts_pending", hs.hosts_pending)); perfdata->Add(new PerfdataValue("num_hosts_unreachable", hs.hosts_unreachable)); perfdata->Add(new PerfdataValue("num_hosts_flapping", hs.hosts_flapping)); perfdata->Add(new PerfdataValue("num_hosts_in_downtime", hs.hosts_in_downtime)); perfdata->Add(new PerfdataValue("num_hosts_acknowledged", hs.hosts_acknowledged)); cr->SetOutput("Icinga 2 has been running for " + Utility::FormatDuration(uptime) + ". Version: " + Application::GetAppVersion()); cr->SetPerformanceData(perfdata); double lastReloadFailed = Application::GetLastReloadFailed(); if (lastReloadFailed > 0) { cr->SetOutput(cr->GetOutput() + "; Last reload attempt failed at " + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", lastReloadFailed)); cr->SetState(ServiceWarning); } else cr->SetState(ServiceOK); service->ProcessCheckResult(cr); } icinga2-2.8.1/lib/methods/icingachecktask.hpp000066400000000000000000000035601322762156600211110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ICINGACHECKTASK_H #define ICINGACHECKTASK_H #include "methods/i2-methods.hpp" #include "icinga/service.hpp" namespace icinga { /** * Icinga check type. * * @ingroup methods */ class I2_METHODS_API IcingaCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IcingaCheckTask(void); }; } #endif /* ICINGACHECKTASK_H */ icinga2-2.8.1/lib/methods/methods-itl.conf000066400000000000000000000063531322762156600203700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ System.assert(Internal.run_with_activation_context(function() { var _Internal = Internal.clone() template CheckCommand "icinga-check-command" use (_Internal) { execute = _Internal.IcingaCheck } template CheckCommand "cluster-check-command" use (_Internal) { execute = _Internal.ClusterCheck } template CheckCommand "cluster-zone-check-command" use (_Internal) { execute = _Internal.ClusterZoneCheck } template CheckCommand "plugin-check-command" use (_Internal) default { execute = _Internal.PluginCheck } template CheckCommand "clr-check-command" use (_Internal) { if (_Internal.ClrCheck) { execute = _Internal.ClrCheck } else { execute = _Internal.NullCheck } } template NotificationCommand "plugin-notification-command" use (_Internal) default { execute = _Internal.PluginNotification } template EventCommand "plugin-event-command" use (_Internal) default { execute = _Internal.PluginEvent } template CheckCommand "random-check-command" use (_Internal) { execute = _Internal.RandomCheck } template CheckCommand "exception-check-command" use (_Internal) { execute = _Internal.ExceptionCheck } template CheckCommand "null-check-command" use (_Internal) { execute = _Internal.NullCheck } template EventCommand "null-event-command" use (_Internal) { execute = _Internal.NullEvent } template TimePeriod "empty-timeperiod" use (_Internal) { update = _Internal.EmptyTimePeriod } template TimePeriod "even-minutes-timeperiod" use (_Internal) { update = _Internal.EvenMinutesTimePeriod } })) var methods = [ "IcingaCheck", "ClusterCheck", "ClusterZoneCheck", "PluginCheck", "ClrCheck", "PluginNotification", "PluginEvent", "RandomCheck", "ExceptionCheck", "NullCheck", "NullEvent", "EmptyTimePeriod", "EvenMinutesTimePeriod" ] for (method in methods) { Internal.remove(method) } icinga2-2.8.1/lib/methods/nullchecktask.cpp000066400000000000000000000045651322762156600206320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef _WIN32 # include #endif /* _WIN32 */ #include "methods/nullchecktask.hpp" #include "icinga/icingaapplication.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/convert.hpp" #include "base/function.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void NullCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { if (resolvedMacros && !useResolvedMacros) return; String output = "Hello from "; output += IcingaApplication::GetInstance()->GetNodeName(); Array::Ptr perfdata = new Array(); perfdata->Add(new PerfdataValue("time", Convert::ToDouble(Utility::GetTime()))); cr->SetOutput(output); cr->SetPerformanceData(perfdata); cr->SetState(ServiceOK); service->ProcessCheckResult(cr); } icinga2-2.8.1/lib/methods/nullchecktask.hpp000066400000000000000000000036731322762156600206360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NULLCHECKTASK_H #define NULLCHECKTASK_H #include "methods/i2-methods.hpp" #include "icinga/service.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Test class for additional check types. Implements the "null" check type. * * @ingroup methods */ class I2_METHODS_API NullCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: NullCheckTask(void); }; } #endif /* NULLCHECKTASK_H */ icinga2-2.8.1/lib/methods/nulleventtask.cpp000066400000000000000000000034161322762156600206700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/nulleventtask.hpp" #include "base/function.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, NullEvent, &NullEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros"); void NullEventTask::ScriptFunc(const Checkable::Ptr&, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { } icinga2-2.8.1/lib/methods/nulleventtask.hpp000066400000000000000000000036571322762156600207040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NULLEVENTTASK_H #define NULLEVENTTASK_H #include "methods/i2-methods.hpp" #include "icinga/service.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Test class for additional event handler types. Implements the "null" event handler type. * * @ingroup methods */ class I2_METHODS_API NullEventTask { public: static void ScriptFunc(const Checkable::Ptr& service, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: NullEventTask(void); }; } #endif /* NULLEVENTTASK_H */ icinga2-2.8.1/lib/methods/pluginchecktask.cpp000066400000000000000000000076621322762156600211570ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/pluginchecktask.hpp" #include "icinga/pluginutility.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/function.hpp" #include "base/utility.hpp" #include "base/process.hpp" #include "base/convert.hpp" #include #include using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, resolvedMacros, useResolvedMacros, boost::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); if (!resolvedMacros || useResolvedMacros) Checkable::IncreasePendingChecks(); } void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) { Checkable::DecreasePendingChecks(); if (pr.ExitStatus > 3) { Process::Arguments parguments = Process::PrepareCommand(commandLine); Log(LogWarning, "PluginCheckTask") << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " << pr.ExitStatus << ", output: " << pr.Output; } String output = pr.Output.Trim(); std::pair co = PluginUtility::ParseCheckOutput(output); cr->SetCommand(commandLine); cr->SetOutput(co.first); cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); cr->SetExitStatus(pr.ExitStatus); cr->SetExecutionStart(pr.ExecutionStart); cr->SetExecutionEnd(pr.ExecutionEnd); checkable->ProcessCheckResult(cr); } icinga2-2.8.1/lib/methods/pluginchecktask.hpp000066400000000000000000000041071322762156600211530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PLUGINCHECKTASK_H #define PLUGINCHECKTASK_H #include "methods/i2-methods.hpp" #include "base/process.hpp" #include "icinga/service.hpp" namespace icinga { /** * Implements service checks based on external plugins. * * @ingroup methods */ class I2_METHODS_API PluginCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginCheckTask(void); static void ProcessFinishedHandler(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr); }; } #endif /* PLUGINCHECKTASK_H */ icinga2-2.8.1/lib/methods/plugineventtask.cpp000066400000000000000000000063271322762156600212200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/plugineventtask.hpp" #include "icinga/eventcommand.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/pluginutility.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/function.hpp" #include "base/utility.hpp" #include "base/process.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, PluginEvent, &PluginEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros"); void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { EventCommand::Ptr commandObj = checkable->GetEventCommand(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), resolvers, resolvedMacros, useResolvedMacros, boost::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2)); } void PluginEventTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) { if (pr.ExitStatus != 0) { Process::Arguments parguments = Process::PrepareCommand(commandLine); Log(LogNotice, "PluginEventTask") << "Event command for object '" << checkable->GetName() << "' (PID: " << pr.PID << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " << pr.ExitStatus << ", output: " << pr.Output; } } icinga2-2.8.1/lib/methods/plugineventtask.hpp000066400000000000000000000040211322762156600212120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PLUGINEVENTTASK_H #define PLUGINEVENTTASK_H #include "methods/i2-methods.hpp" #include "icinga/service.hpp" #include "base/process.hpp" namespace icinga { /** * Implements event handlers based on external plugins. * * @ingroup methods */ class I2_METHODS_API PluginEventTask { public: static void ScriptFunc(const Checkable::Ptr& service, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginEventTask(void); static void ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr); }; } #endif /* PLUGINEVENTTASK_H */ icinga2-2.8.1/lib/methods/pluginnotificationtask.cpp000066400000000000000000000077251322762156600225700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/pluginnotificationtask.hpp" #include "icinga/notification.hpp" #include "icinga/notificationcommand.hpp" #include "icinga/pluginutility.hpp" #include "icinga/service.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "base/function.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/process.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, PluginNotification, &PluginNotificationTask::ScriptFunc, "notification:user:cr:itype:author:comment:resolvedMacros:useResolvedMacros"); void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, int itype, const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { NotificationCommand::Ptr commandObj = notification->GetCommand(); NotificationType type = static_cast(itype); Checkable::Ptr checkable = notification->GetCheckable(); Dictionary::Ptr notificationExtra = new Dictionary(); notificationExtra->Set("type", Notification::NotificationTypeToString(type)); notificationExtra->Set("author", author); notificationExtra->Set("comment", comment); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("user", user)); resolvers.push_back(std::make_pair("notification", notificationExtra)); resolvers.push_back(std::make_pair("notification", notification)); if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("command", commandObj)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, resolvedMacros, useResolvedMacros, boost::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2)); } void PluginNotificationTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) { if (pr.ExitStatus != 0) { Process::Arguments parguments = Process::PrepareCommand(commandLine); Log(LogWarning, "PluginNotificationTask") << "Notification command for object '" << checkable->GetName() << "' (PID: " << pr.PID << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " << pr.ExitStatus << ", output: " << pr.Output; } } icinga2-2.8.1/lib/methods/pluginnotificationtask.hpp000066400000000000000000000043331322762156600225650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PLUGINNOTIFICATIONTASK_H #define PLUGINNOTIFICATIONTASK_H #include "methods/i2-methods.hpp" #include "icinga/notification.hpp" #include "icinga/service.hpp" #include "base/process.hpp" namespace icinga { /** * Implements sending notifications based on external plugins. * * @ingroup methods */ class I2_METHODS_API PluginNotificationTask { public: static void ScriptFunc(const Notification::Ptr& notification, const User::Ptr& user, const CheckResult::Ptr& cr, int itype, const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginNotificationTask(void); static void ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr); }; } #endif /* PLUGINNOTIFICATIONTASK_H */ icinga2-2.8.1/lib/methods/randomchecktask.cpp000066400000000000000000000046441322762156600211360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef _WIN32 # include #endif /* _WIN32 */ #include "methods/randomchecktask.hpp" #include "icinga/icingaapplication.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/convert.hpp" #include "base/function.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); void RandomCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { if (resolvedMacros && !useResolvedMacros) return; String output = "Hello from "; output += IcingaApplication::GetInstance()->GetNodeName(); Array::Ptr perfdata = new Array(); perfdata->Add(new PerfdataValue("time", Convert::ToDouble(Utility::GetTime()))); cr->SetOutput(output); cr->SetPerformanceData(perfdata); cr->SetState(static_cast(Utility::Random() % 4)); service->ProcessCheckResult(cr); } icinga2-2.8.1/lib/methods/randomchecktask.hpp000066400000000000000000000036241322762156600211400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef RANDOMCHECKTASK_H #define RANDOMCHECKTASK_H #include "icinga/service.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Test class for additional check types. Implements the "null" check type. * * @ingroup methods */ class RandomCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: RandomCheckTask(void); }; } #endif /* RANDOMCHECKTASK_H */ icinga2-2.8.1/lib/methods/timeperiodtask.cpp000066400000000000000000000044071322762156600210160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "methods/timeperiodtask.hpp" #include "base/function.hpp" using namespace icinga; REGISTER_SCRIPTFUNCTION_NS(Internal, EmptyTimePeriod, &TimePeriodTask::EmptyTimePeriodUpdate, "tp:begin:end"); REGISTER_SCRIPTFUNCTION_NS(Internal, EvenMinutesTimePeriod, &TimePeriodTask::EvenMinutesTimePeriodUpdate, "tp:begin:end"); Array::Ptr TimePeriodTask::EmptyTimePeriodUpdate(const TimePeriod::Ptr&, double, double) { Array::Ptr segments = new Array(); return segments; } Array::Ptr TimePeriodTask::EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr&, double begin, double end) { Array::Ptr segments = new Array(); for (long t = begin / 60 - 1; t * 60 < end; t++) { if ((t % 2) == 0) { Dictionary::Ptr segment = new Dictionary(); segment->Set("begin", t * 60); segment->Set("end", (t + 1) * 60); segments->Add(segment); } } return segments; } icinga2-2.8.1/lib/methods/timeperiodtask.hpp000066400000000000000000000035551322762156600210260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TIMEPERIODTASK_H #define TIMEPERIODTASK_H #include "icinga/timeperiod.hpp" namespace icinga { /** * Test timeperiod functions. * * @ingroup methods */ class TimePeriodTask { public: static Array::Ptr EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, double begin, double end); static Array::Ptr EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr& tp, double begin, double end); private: TimePeriodTask(void); }; } #endif /* TIMEPERIODTASK_H */ icinga2-2.8.1/lib/notification/000077500000000000000000000000001322762156600163045ustar00rootroot00000000000000icinga2-2.8.1/lib/notification/CMakeLists.txt000066400000000000000000000043421322762156600210470ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(notificationcomponent.ti notificationcomponent.tcpp notificationcomponent.thpp) set(notification_SOURCES notificationcomponent.cpp notificationcomponent.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(notification notification notification_SOURCES) endif() add_library(notification SHARED ${notification_SOURCES}) target_link_libraries(notification ${Boost_LIBRARIES} base config icinga) set_target_properties ( notification PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_NOTIFICATION_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/notification.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) if(NOT WIN32) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")") install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/notification.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/notification.conf\")") else() install_if_not_exists(${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/notification.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() install(TARGETS notification RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2) set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/notification/notificationcomponent.cpp000066400000000000000000000121631322762156600234240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "notification/notificationcomponent.hpp" #include "notification/notificationcomponent.tcpp" #include "icinga/service.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" using namespace icinga; REGISTER_TYPE(NotificationComponent); REGISTER_STATSFUNCTION(NotificationComponent, &NotificationComponent::StatsFunc); void NotificationComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const NotificationComponent::Ptr& notification_component : ConfigType::GetObjectsByType()) { nodes->Set(notification_component->GetName(), 1); //add more stats } status->Set("notificationcomponent", nodes); } /** * Starts the component. */ void NotificationComponent::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "NotificationComponent") << "'" << GetName() << "' started."; Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationComponent::SendNotificationsHandler, this, _1, _2, _3, _4, _5)); m_NotificationTimer = new Timer(); m_NotificationTimer->SetInterval(5); m_NotificationTimer->OnTimerExpired.connect(boost::bind(&NotificationComponent::NotificationTimerHandler, this)); m_NotificationTimer->Start(); } void NotificationComponent::Stop(bool runtimeRemoved) { Log(LogInformation, "NotificationComponent") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } /** * Periodically sends notifications. * * @param - Event arguments for the timer. */ void NotificationComponent::NotificationTimerHandler(void) { double now = Utility::GetTime(); for (const Notification::Ptr& notification : ConfigType::GetObjectsByType()) { if (!notification->IsActive()) continue; if (notification->IsPaused() && GetEnableHA()) continue; Checkable::Ptr checkable = notification->GetCheckable(); if (!IcingaApplication::GetInstance()->GetEnableNotifications() || !checkable->GetEnableNotifications()) continue; if (notification->GetInterval() <= 0 && notification->GetNoMoreNotifications()) continue; if (notification->GetNextNotification() > now) continue; bool reachable = checkable->IsReachable(DependencyNotification); { ObjectLock olock(notification); notification->SetNextNotification(Utility::GetTime() + notification->GetInterval()); } { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); ObjectLock olock(checkable); if (checkable->GetStateType() == StateTypeSoft) continue; if ((service && service->GetState() == ServiceOK) || (!service && host->GetState() == HostUp)) continue; if (!reachable || checkable->IsInDowntime() || checkable->IsAcknowledged()) continue; } try { Log(LogNotice, "NotificationComponent") << "Attempting to send reminder notification '" << notification->GetName() << "'"; notification->BeginExecuteNotification(NotificationProblem, checkable->GetLastCheckResult(), false, true); } catch (const std::exception& ex) { Log(LogWarning, "NotificationComponent") << "Exception occured during notification for object '" << GetName() << "': " << DiagnosticInformation(ex); } } } /** * Processes icinga::SendNotifications messages. */ void NotificationComponent::SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { checkable->SendNotifications(type, cr, author, text); } icinga2-2.8.1/lib/notification/notificationcomponent.hpp000066400000000000000000000044451322762156600234350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef NOTIFICATIONCOMPONENT_H #define NOTIFICATIONCOMPONENT_H #include "notification/notificationcomponent.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/timer.hpp" namespace icinga { /** * @ingroup notification */ class NotificationComponent : public ObjectImpl { public: DECLARE_OBJECT(NotificationComponent); DECLARE_OBJECTNAME(NotificationComponent); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Timer::Ptr m_NotificationTimer; void NotificationTimerHandler(void); void SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text); }; } #endif /* NOTIFICATIONCOMPONENT_H */ icinga2-2.8.1/lib/notification/notificationcomponent.ti000066400000000000000000000031531322762156600232550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library notification; namespace icinga { class NotificationComponent : ConfigObject { [config] bool enable_ha (EnableHA) { default {{{ return true; }}} }; }; } icinga2-2.8.1/lib/perfdata/000077500000000000000000000000001322762156600154045ustar00rootroot00000000000000icinga2-2.8.1/lib/perfdata/CMakeLists.txt000066400000000000000000000062621322762156600201520ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(gelfwriter.ti gelfwriter.tcpp gelfwriter.thpp) mkclass_target(graphitewriter.ti graphitewriter.tcpp graphitewriter.thpp) mkclass_target(influxdbwriter.ti influxdbwriter.tcpp influxdbwriter.thpp) mkclass_target(elasticsearchwriter.ti elasticsearchwriter.tcpp elasticsearchwriter.thpp) mkclass_target(opentsdbwriter.ti opentsdbwriter.tcpp opentsdbwriter.thpp) mkclass_target(perfdatawriter.ti perfdatawriter.tcpp perfdatawriter.thpp) set(perfdata_SOURCES gelfwriter.cpp gelfwriter.thpp graphitewriter.cpp graphitewriter.thpp influxdbwriter.cpp influxdbwriter.thpp elasticsearchwriter.cpp elasticsearchwriter.thpp opentsdbwriter.cpp opentsdbwriter.thpp perfdatawriter.cpp perfdatawriter.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(perfdata perfdata perfdata_SOURCES) endif() add_library(perfdata SHARED ${perfdata_SOURCES}) target_link_libraries(perfdata ${Boost_LIBRARIES} base config icinga) set_target_properties ( perfdata PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_PERFDATA_BUILD FOLDER Components VERSION ${SPEC_VERSION} ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/gelf.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/graphite.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/influxdb.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/elasticsearch.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/opentsdb.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install_if_not_exists( ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/perfdata.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available ) install( TARGETS perfdata RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/spool/icinga2/perfdata\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/spool/icinga2/tmp\")") set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE) icinga2-2.8.1/lib/perfdata/elasticsearchwriter.cpp000066400000000000000000000466001322762156600221650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/elasticsearchwriter.hpp" #include "perfdata/elasticsearchwriter.tcpp" #include "remote/url.hpp" #include "remote/httprequest.hpp" #include "remote/httpresponse.hpp" #include "icinga/compatutility.hpp" #include "icinga/service.hpp" #include "icinga/checkcommand.hpp" #include "base/tcpsocket.hpp" #include "base/stream.hpp" #include "base/base64.hpp" #include "base/json.hpp" #include "base/utility.hpp" #include "base/networkstream.hpp" #include "base/perfdatavalue.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(ElasticsearchWriter); REGISTER_STATSFUNCTION(ElasticsearchWriter, &ElasticsearchWriter::StatsFunc); ElasticsearchWriter::ElasticsearchWriter(void) : m_WorkQueue(10000000, 1) { } void ElasticsearchWriter::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_WorkQueue.SetName("ElasticsearchWriter, " + GetName()); } void ElasticsearchWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const ElasticsearchWriter::Ptr& elasticsearchwriter : ConfigType::GetObjectsByType()) { size_t workQueueItems = elasticsearchwriter->m_WorkQueue.GetLength(); double workQueueItemRate = elasticsearchwriter->m_WorkQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr stats = new Dictionary(); stats->Set("work_queue_items", workQueueItems); stats->Set("work_queue_item_rate", workQueueItemRate); nodes->Set(elasticsearchwriter->GetName(), stats); perfdata->Add(new PerfdataValue("elasticsearchwriter_" + elasticsearchwriter->GetName() + "_work_queue_items", workQueueItems)); perfdata->Add(new PerfdataValue("elasticsearchwriter_" + elasticsearchwriter->GetName() + "_work_queue_item_rate", workQueueItemRate)); } status->Set("elasticsearchwriter", nodes); } void ElasticsearchWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); m_EventPrefix = "icinga2.event."; Log(LogInformation, "ElasticsearchWriter") << "'" << GetName() << "' started."; m_WorkQueue.SetExceptionCallback(boost::bind(&ElasticsearchWriter::ExceptionHandler, this, _1)); /* Setup timer for periodically flushing m_DataBuffer */ m_FlushTimer = new Timer(); m_FlushTimer->SetInterval(GetFlushInterval()); m_FlushTimer->OnTimerExpired.connect(boost::bind(&ElasticsearchWriter::FlushTimeout, this)); m_FlushTimer->Start(); m_FlushTimer->Reschedule(0); /* Register for new metrics. */ Checkable::OnNewCheckResult.connect(boost::bind(&ElasticsearchWriter::CheckResultHandler, this, _1, _2)); Checkable::OnStateChange.connect(boost::bind(&ElasticsearchWriter::StateChangeHandler, this, _1, _2, _3)); Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&ElasticsearchWriter::NotificationSentToAllUsersHandler, this, _1, _2, _3, _4, _5, _6, _7)); } void ElasticsearchWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "ElasticsearchWriter") << "'" << GetName() << "' stopped."; m_WorkQueue.Join(); ObjectImpl::Stop(runtimeRemoved); } void ElasticsearchWriter::AddCheckResult(const Dictionary::Ptr& fields, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { String prefix = "check_result."; fields->Set(prefix + "output", cr->GetOutput()); fields->Set(prefix + "check_source", cr->GetCheckSource()); fields->Set(prefix + "exit_status", cr->GetExitStatus()); fields->Set(prefix + "command", cr->GetCommand()); fields->Set(prefix + "state", cr->GetState()); fields->Set(prefix + "vars_before", cr->GetVarsBefore()); fields->Set(prefix + "vars_after", cr->GetVarsAfter()); fields->Set(prefix + "execution_start", FormatTimestamp(cr->GetExecutionStart())); fields->Set(prefix + "execution_end", FormatTimestamp(cr->GetExecutionEnd())); fields->Set(prefix + "schedule_start", FormatTimestamp(cr->GetScheduleStart())); fields->Set(prefix + "schedule_end", FormatTimestamp(cr->GetScheduleEnd())); /* Add extra calculated field. */ fields->Set(prefix + "latency", cr->CalculateLatency()); fields->Set(prefix + "execution_time", cr->CalculateExecutionTime()); if (!GetEnableSendPerfdata()) return; Array::Ptr perfdata = cr->GetPerformanceData(); if (perfdata) { ObjectLock olock(perfdata); for (const Value& val : perfdata) { PerfdataValue::Ptr pdv; if (val.IsObjectType()) pdv = val; else { try { pdv = PerfdataValue::Parse(val); } catch (const std::exception&) { Log(LogWarning, "ElasticsearchWriter") << "Ignoring invalid perfdata value: '" << val << "' for object '" << checkable->GetName() << "'."; } } String escapedKey = pdv->GetLabel(); boost::replace_all(escapedKey, " ", "_"); boost::replace_all(escapedKey, ".", "_"); boost::replace_all(escapedKey, "\\", "_"); boost::algorithm::replace_all(escapedKey, "::", "."); String perfdataPrefix = prefix + "perfdata." + escapedKey; fields->Set(perfdataPrefix + ".value", pdv->GetValue()); if (pdv->GetMin()) fields->Set(perfdataPrefix + ".min", pdv->GetMin()); if (pdv->GetMax()) fields->Set(perfdataPrefix + ".max", pdv->GetMax()); if (pdv->GetWarn()) fields->Set(perfdataPrefix + ".warn", pdv->GetWarn()); if (pdv->GetCrit()) fields->Set(perfdataPrefix + ".crit", pdv->GetCrit()); } } } void ElasticsearchWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { m_WorkQueue.Enqueue(boost::bind(&ElasticsearchWriter::InternalCheckResultHandler, this, checkable, cr)); } void ElasticsearchWriter::InternalCheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { AssertOnWorkQueue(); CONTEXT("Elasticwriter processing check result for '" + checkable->GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) return; Host::Ptr host; Service::Ptr service; boost::tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields = new Dictionary(); if (service) { fields->Set("service", service->GetShortName()); fields->Set("state", service->GetState()); fields->Set("last_state", service->GetLastState()); fields->Set("last_hard_state", service->GetLastHardState()); } else { fields->Set("state", host->GetState()); fields->Set("last_state", host->GetLastState()); fields->Set("last_hard_state", host->GetLastHardState()); } fields->Set("host", host->GetName()); fields->Set("state_type", checkable->GetStateType()); fields->Set("current_check_attempt", checkable->GetCheckAttempt()); fields->Set("max_check_attempts", checkable->GetMaxCheckAttempts()); fields->Set("reachable", checkable->IsReachable()); CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("check_command", commandObj->GetName()); double ts = Utility::GetTime(); if (cr) { AddCheckResult(fields, checkable, cr); ts = cr->GetExecutionEnd(); } Enqueue("checkresult", fields, ts); } void ElasticsearchWriter::StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type) { m_WorkQueue.Enqueue(boost::bind(&ElasticsearchWriter::StateChangeHandlerInternal, this, checkable, cr, type)); } void ElasticsearchWriter::StateChangeHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type) { AssertOnWorkQueue(); CONTEXT("Elasticwriter processing state change '" + checkable->GetName() + "'"); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields = new Dictionary(); fields->Set("current_check_attempt", checkable->GetCheckAttempt()); fields->Set("max_check_attempts", checkable->GetMaxCheckAttempts()); fields->Set("host", host->GetName()); if (service) { fields->Set("service", service->GetShortName()); fields->Set("state", service->GetState()); fields->Set("last_state", service->GetLastState()); fields->Set("last_hard_state", service->GetLastHardState()); } else { fields->Set("state", host->GetState()); fields->Set("last_state", host->GetLastState()); fields->Set("last_hard_state", host->GetLastHardState()); } CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("check_command", commandObj->GetName()); double ts = Utility::GetTime(); if (cr) { AddCheckResult(fields, checkable, cr); ts = cr->GetExecutionEnd(); } Enqueue("statechange", fields, ts); } void ElasticsearchWriter::NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { m_WorkQueue.Enqueue(boost::bind(&ElasticsearchWriter::NotificationSentToAllUsersHandlerInternal, this, notification, checkable, users, type, cr, author, text)); } void ElasticsearchWriter::NotificationSentToAllUsersHandlerInternal(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { AssertOnWorkQueue(); CONTEXT("Elasticwriter processing notification to all users '" + checkable->GetName() + "'"); Log(LogDebug, "ElasticsearchWriter") << "Processing notification for '" << checkable->GetName() << "'"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); String notificationTypeString = Notification::NotificationTypeToString(type); Dictionary::Ptr fields = new Dictionary(); if (service) { fields->Set("service", service->GetShortName()); fields->Set("state", service->GetState()); fields->Set("last_state", service->GetLastState()); fields->Set("last_hard_state", service->GetLastHardState()); } else { fields->Set("state", host->GetState()); fields->Set("last_state", host->GetLastState()); fields->Set("last_hard_state", host->GetLastHardState()); } fields->Set("host", host->GetName()); Array::Ptr userNames = new Array(); for (const User::Ptr& user : users) { userNames->Add(user->GetName()); } fields->Set("users", userNames); fields->Set("notification_type", notificationTypeString); fields->Set("author", author); fields->Set("text", text); CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("check_command", commandObj->GetName()); double ts = Utility::GetTime(); if (cr) { AddCheckResult(fields, checkable, cr); ts = cr->GetExecutionEnd(); } Enqueue("notification", fields, ts); } void ElasticsearchWriter::Enqueue(String type, const Dictionary::Ptr& fields, double ts) { /* Atomically buffer the data point. */ boost::mutex::scoped_lock lock(m_DataBufferMutex); /* Format the timestamps to dynamically select the date datatype inside the index. */ fields->Set("@timestamp", FormatTimestamp(ts)); fields->Set("timestamp", FormatTimestamp(ts)); String eventType = m_EventPrefix + type; fields->Set("type", eventType); /* Every payload needs a line describing the index above. * We do it this way to avoid problems with a near full queue. */ String indexBody = "{ \"index\" : { \"_type\" : \"" + eventType + "\" } }\n"; String fieldsBody = JsonEncode(fields); Log(LogDebug, "ElasticsearchWriter") << "Add to fields to message list: '" << fieldsBody << "'."; m_DataBuffer.push_back(indexBody + fieldsBody); /* Flush if we've buffered too much to prevent excessive memory use. */ if (static_cast(m_DataBuffer.size()) >= GetFlushThreshold()) { Log(LogDebug, "ElasticsearchWriter") << "Data buffer overflow writing " << m_DataBuffer.size() << " data points"; Flush(); } } void ElasticsearchWriter::FlushTimeout(void) { /* Prevent new data points from being added to the array, there is a * race condition where they could disappear. */ boost::mutex::scoped_lock lock(m_DataBufferMutex); /* Flush if there are any data available. */ if (m_DataBuffer.size() > 0) { Log(LogDebug, "ElasticsearchWriter") << "Timer expired writing " << m_DataBuffer.size() << " data points"; Flush(); } } void ElasticsearchWriter::Flush(void) { /* Ensure you hold a lock against m_DataBuffer so that things * don't go missing after creating the body and clearing the buffer. */ String body = boost::algorithm::join(m_DataBuffer, "\n"); m_DataBuffer.clear(); SendRequest(body); } void ElasticsearchWriter::SendRequest(const String& body) { Url::Ptr url = new Url(); url->SetScheme(GetEnableTls() ? "https" : "http"); url->SetHost(GetHost()); url->SetPort(GetPort()); std::vector path; /* Specify the index path. Best practice is a daily rotation. * Example: http://localhost:9200/icinga2-2017.09.11?pretty=1 */ path.push_back(GetIndex() + "-" + Utility::FormatDateTime("%Y.%m.%d", Utility::GetTime())); /* Use the bulk message format. */ path.push_back("_bulk"); url->SetPath(path); Stream::Ptr stream = Connect(); HttpRequest req(stream); /* Specify required headers by Elasticsearch. */ req.AddHeader("Accept", "application/json"); req.AddHeader("Content-Type", "application/json"); /* Send authentication if configured. */ String username = GetUsername(); String password = GetPassword(); if (!username.IsEmpty() && !password.IsEmpty()) req.AddHeader("Authorization", "Basic " + Base64::Encode(username + ":" + password)); req.RequestMethod = "POST"; req.RequestUrl = url; /* Don't log the request body to debug log, this is already done above. */ Log(LogDebug, "ElasticsearchWriter") << "Sending " << req.RequestMethod << " request" << ((!username.IsEmpty() && !password.IsEmpty()) ? " with basic auth" : "" ) << " to '" << url->Format() << "'."; try { req.WriteBody(body.CStr(), body.GetLength()); req.Finish(); } catch (const std::exception& ex) { Log(LogWarning, "ElasticsearchWriter") << "Cannot write to HTTP API on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } HttpResponse resp(stream, req); StreamReadContext context; try { resp.Parse(context, true); } catch (const std::exception& ex) { Log(LogWarning, "ElasticsearchWriter") << "Cannot read from HTTP API on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } if (resp.StatusCode > 299) { if (resp.StatusCode == 401) { /* More verbose error logging with Elasticsearch is hidden behind a proxy. */ if (!username.IsEmpty() && !password.IsEmpty()) { Log(LogCritical, "ElasticsearchWriter") << "401 Unauthorized. Please ensure that the user '" << username << "' is able to authenticate against the HTTP API/Proxy."; } else { Log(LogCritical, "ElasticsearchWriter") << "401 Unauthorized. The HTTP API requires authentication but no username/password has been configured."; } return; } Log(LogWarning, "ElasticsearchWriter") << "Unexpected response code " << resp.StatusCode; /* Finish parsing the headers and body. */ while (!resp.Complete) resp.Parse(context, true); String contentType = resp.Headers->Get("content-type"); if (contentType != "application/json") { Log(LogWarning, "ElasticsearchWriter") << "Unexpected Content-Type: " << contentType; return; } size_t responseSize = resp.GetBodySize(); boost::scoped_array buffer(new char[responseSize + 1]); resp.ReadBody(buffer.get(), responseSize); buffer.get()[responseSize] = '\0'; Dictionary::Ptr jsonResponse; try { jsonResponse = JsonDecode(buffer.get()); } catch (...) { Log(LogWarning, "ElasticsearchWriter") << "Unable to parse JSON response:\n" << buffer.get(); return; } String error = jsonResponse->Get("error"); Log(LogCritical, "ElasticsearchWriter") << "Elasticsearch error message:\n" << error; } } Stream::Ptr ElasticsearchWriter::Connect(void) { TcpSocket::Ptr socket = new TcpSocket(); Log(LogNotice, "ElasticsearchWriter") << "Connecting to Elasticsearch on host '" << GetHost() << "' port '" << GetPort() << "'."; try { socket->Connect(GetHost(), GetPort()); } catch (const std::exception& ex) { Log(LogWarning, "ElasticsearchWriter") << "Can't connect to Elasticsearch on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } if (GetEnableTls()) { boost::shared_ptr sslContext; try { sslContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath()); } catch (const std::exception& ex) { Log(LogWarning, "ElasticsearchWriter") << "Unable to create SSL context."; throw ex; } TlsStream::Ptr tlsStream = new TlsStream(socket, GetHost(), RoleClient, sslContext); try { tlsStream->Handshake(); } catch (const std::exception& ex) { Log(LogWarning, "ElasticsearchWriter") << "TLS handshake with host '" << GetHost() << "' on port " << GetPort() << " failed."; throw ex; } return tlsStream; } else { return new NetworkStream(socket); } } void ElasticsearchWriter::AssertOnWorkQueue(void) { ASSERT(m_WorkQueue.IsWorkerThread()); } void ElasticsearchWriter::ExceptionHandler(boost::exception_ptr exp) { Log(LogCritical, "ElasticsearchWriter", "Exception during Elastic operation: Verify that your backend is operational!"); Log(LogDebug, "ElasticsearchWriter") << "Exception during Elasticsearch operation: " << DiagnosticInformation(exp); } String ElasticsearchWriter::FormatTimestamp(double ts) { /* The date format must match the default dynamic date detection * pattern in indexes. This enables applications like Kibana to * detect a qualified timestamp index for time-series data. * * Example: 2017-09-11T10:56:21.463+0200 * * References: * https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-field-mapping.html#date-detection * https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html * https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html */ int milliSeconds = static_cast((ts - static_cast(ts)) * 1000); return Utility::FormatDateTime("%Y-%m-%dT%H:%M:%S", ts) + "." + Convert::ToString(milliSeconds) + Utility::FormatDateTime("%z", ts); } icinga2-2.8.1/lib/perfdata/elasticsearchwriter.hpp000066400000000000000000000070661322762156600221750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ELASTICSEARCHWRITER_H #define ELASTICSEARCHWRITER_H #include "perfdata/elasticsearchwriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/workqueue.hpp" #include "base/timer.hpp" namespace icinga { class ElasticsearchWriter : public ObjectImpl { public: DECLARE_OBJECT(ElasticsearchWriter); DECLARE_OBJECTNAME(ElasticsearchWriter); ElasticsearchWriter(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); static String FormatTimestamp(double ts); protected: virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: String m_EventPrefix; WorkQueue m_WorkQueue; Timer::Ptr m_FlushTimer; std::vector m_DataBuffer; boost::mutex m_DataBufferMutex; void AddCheckResult(const Dictionary::Ptr& fields, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type); void StateChangeHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type); void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void InternalCheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text); void NotificationSentToAllUsersHandlerInternal(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set& users, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text); void Enqueue(String type, const Dictionary::Ptr& fields, double ts); Stream::Ptr Connect(void); void AssertOnWorkQueue(void); void ExceptionHandler(boost::exception_ptr exp); void FlushTimeout(void); void Flush(void); void SendRequest(const String& body); }; } #endif /* ELASTICSEARCHWRITER_H */ icinga2-2.8.1/lib/perfdata/elasticsearchwriter.ti000066400000000000000000000013561322762156600220160ustar00rootroot00000000000000#include "base/configobject.hpp" library perfdata; namespace icinga { class ElasticsearchWriter : ConfigObject { [config, required] String host { default {{{ return "127.0.0.1"; }}} }; [config, required] String port { default {{{ return "9200"; }}} }; [config, required] String index { default {{{ return "icinga2"; }}} }; [config] bool enable_send_perfdata { default {{{ return false; }}} }; [config] String username; [config] String password; [config] bool enable_tls { default {{{ return false; }}} }; [config] String ca_path; [config] String cert_path; [config] String key_path; [config] int flush_interval { default {{{ return 10; }}} }; [config] int flush_threshold { default {{{ return 1024; }}} }; }; } icinga2-2.8.1/lib/perfdata/gelfwriter.cpp000066400000000000000000000337371322762156600202770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/gelfwriter.hpp" #include "perfdata/gelfwriter.tcpp" #include "icinga/service.hpp" #include "icinga/notification.hpp" #include "icinga/checkcommand.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/compatutility.hpp" #include "base/tcpsocket.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/stream.hpp" #include "base/networkstream.hpp" #include "base/context.hpp" #include "base/exception.hpp" #include "base/json.hpp" #include "base/statsfunction.hpp" #include using namespace icinga; REGISTER_TYPE(GelfWriter); REGISTER_STATSFUNCTION(GelfWriter, &GelfWriter::StatsFunc); GelfWriter::GelfWriter(void) : m_WorkQueue(10000000, 1) { } void GelfWriter::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_WorkQueue.SetName("GelfWriter, " + GetName()); } void GelfWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const GelfWriter::Ptr& gelfwriter : ConfigType::GetObjectsByType()) { size_t workQueueItems = gelfwriter->m_WorkQueue.GetLength(); double workQueueItemRate = gelfwriter->m_WorkQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr stats = new Dictionary(); stats->Set("work_queue_items", workQueueItems); stats->Set("work_queue_item_rate", workQueueItemRate); stats->Set("connected", gelfwriter->GetConnected()); stats->Set("source", gelfwriter->GetSource()); nodes->Set(gelfwriter->GetName(), stats); perfdata->Add(new PerfdataValue("gelfwriter_" + gelfwriter->GetName() + "_work_queue_items", workQueueItems)); perfdata->Add(new PerfdataValue("gelfwriter_" + gelfwriter->GetName() + "_work_queue_item_rate", workQueueItemRate)); } status->Set("gelfwriter", nodes); } void GelfWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "GelfWriter") << "'" << GetName() << "' started."; /* Register exception handler for WQ tasks. */ m_WorkQueue.SetExceptionCallback(boost::bind(&GelfWriter::ExceptionHandler, this, _1)); /* Timer for reconnecting */ m_ReconnectTimer = new Timer(); m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&GelfWriter::ReconnectTimerHandler, this)); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); /* Register event handlers. */ Checkable::OnNewCheckResult.connect(boost::bind(&GelfWriter::CheckResultHandler, this, _1, _2)); Checkable::OnNotificationSentToUser.connect(boost::bind(&GelfWriter::NotificationToUserHandler, this, _1, _2, _3, _4, _5, _6, _7, _8)); Checkable::OnStateChange.connect(boost::bind(&GelfWriter::StateChangeHandler, this, _1, _2, _3)); } void GelfWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "GelfWriter") << "'" << GetName() << "' stopped."; m_WorkQueue.Join(); ObjectImpl::Stop(runtimeRemoved); } void GelfWriter::AssertOnWorkQueue(void) { ASSERT(m_WorkQueue.IsWorkerThread()); } void GelfWriter::ExceptionHandler(boost::exception_ptr exp) { Log(LogCritical, "GelfWriter", "Exception during Graylog Gelf operation: Verify that your backend is operational!"); Log(LogDebug, "GelfWriter") << "Exception during Graylog Gelf operation: " << DiagnosticInformation(exp); if (GetConnected()) { m_Stream->Close(); SetConnected(false); } } void GelfWriter::Reconnect(void) { AssertOnWorkQueue(); double startTime = Utility::GetTime(); CONTEXT("Reconnecting to Graylog Gelf '" + GetName() + "'"); SetShouldConnect(true); if (GetConnected()) return; TcpSocket::Ptr socket = new TcpSocket(); Log(LogNotice, "GelfWriter") << "Reconnecting to Graylog Gelf on host '" << GetHost() << "' port '" << GetPort() << "'."; try { socket->Connect(GetHost(), GetPort()); } catch (const std::exception& ex) { Log(LogCritical, "GelfWriter") << "Can't connect to Graylog Gelf on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } m_Stream = new NetworkStream(socket); SetConnected(true); Log(LogInformation, "GelfWriter") << "Finished reconnecting to Graylog Gelf in " << std::setw(2) << Utility::GetTime() - startTime << " second(s)."; } void GelfWriter::ReconnectTimerHandler(void) { m_WorkQueue.Enqueue(boost::bind(&GelfWriter::Reconnect, this), PriorityNormal); } void GelfWriter::Disconnect(void) { AssertOnWorkQueue(); if (!GetConnected()) return; m_Stream->Close(); SetConnected(false); } void GelfWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { m_WorkQueue.Enqueue(boost::bind(&GelfWriter::CheckResultHandlerInternal, this, checkable, cr)); } void GelfWriter::CheckResultHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { AssertOnWorkQueue(); CONTEXT("GELF Processing check result for '" + checkable->GetName() + "'"); Log(LogDebug, "GelfWriter") << "Processing check result for '" << checkable->GetName() << "'"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields = new Dictionary(); if (service) { fields->Set("_service_name", service->GetShortName()); fields->Set("_service_state", Service::StateToString(service->GetState())); fields->Set("_last_state", service->GetLastState()); fields->Set("_last_hard_state", service->GetLastHardState()); } else { fields->Set("_last_state", host->GetLastState()); fields->Set("_last_hard_state", host->GetLastHardState()); } fields->Set("_hostname", host->GetName()); fields->Set("_type", "CHECK RESULT"); fields->Set("_state", service ? Service::StateToString(service->GetState()) : Host::StateToString(host->GetState())); fields->Set("_current_check_attempt", checkable->GetCheckAttempt()); fields->Set("_max_check_attempts", checkable->GetMaxCheckAttempts()); fields->Set("_reachable", checkable->IsReachable()); CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("_check_command", commandObj->GetName()); double ts = Utility::GetTime(); if (cr) { fields->Set("_latency", cr->CalculateLatency()); fields->Set("_execution_time", cr->CalculateExecutionTime()); fields->Set("short_message", CompatUtility::GetCheckResultOutput(cr)); fields->Set("full_message", cr->GetOutput()); fields->Set("_check_source", cr->GetCheckSource()); ts = cr->GetExecutionEnd(); } if (cr && GetEnableSendPerfdata()) { Array::Ptr perfdata = cr->GetPerformanceData(); if (perfdata) { ObjectLock olock(perfdata); for (const Value& val : perfdata) { PerfdataValue::Ptr pdv; if (val.IsObjectType()) pdv = val; else { try { pdv = PerfdataValue::Parse(val); } catch (const std::exception&) { Log(LogWarning, "GelfWriter") << "Ignoring invalid perfdata value: '" << val << "' for object '" << checkable->GetName() << "'."; } } String escaped_key = pdv->GetLabel(); boost::replace_all(escaped_key, " ", "_"); boost::replace_all(escaped_key, ".", "_"); boost::replace_all(escaped_key, "\\", "_"); boost::algorithm::replace_all(escaped_key, "::", "."); fields->Set("_" + escaped_key, pdv->GetValue()); if (pdv->GetMin()) fields->Set("_" + escaped_key + "_min", pdv->GetMin()); if (pdv->GetMax()) fields->Set("_" + escaped_key + "_max", pdv->GetMax()); if (pdv->GetWarn()) fields->Set("_" + escaped_key + "_warn", pdv->GetWarn()); if (pdv->GetCrit()) fields->Set("_" + escaped_key + "_crit", pdv->GetCrit()); } } } SendLogMessage(ComposeGelfMessage(fields, GetSource(), ts)); } void GelfWriter::NotificationToUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notificationType, CheckResult::Ptr const& cr, const String& author, const String& commentText, const String& commandName) { m_WorkQueue.Enqueue(boost::bind(&GelfWriter::NotificationToUserHandlerInternal, this, notification, checkable, user, notificationType, cr, author, commentText, commandName)); } void GelfWriter::NotificationToUserHandlerInternal(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notificationType, CheckResult::Ptr const& cr, const String& author, const String& commentText, const String& commandName) { AssertOnWorkQueue(); CONTEXT("GELF Processing notification to all users '" + checkable->GetName() + "'"); Log(LogDebug, "GelfWriter") << "Processing notification for '" << checkable->GetName() << "'"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); String notificationTypeString = Notification::NotificationTypeToString(notificationType); String authorComment = ""; if (notificationType == NotificationCustom || notificationType == NotificationAcknowledgement) { authorComment = author + ";" + commentText; } String output; double ts = Utility::GetTime(); if (cr) { output = CompatUtility::GetCheckResultOutput(cr); ts = cr->GetExecutionEnd(); } Dictionary::Ptr fields = new Dictionary(); if (service) { fields->Set("_type", "SERVICE NOTIFICATION"); //TODO: fix this to _service_name fields->Set("_service", service->GetShortName()); fields->Set("short_message", output); } else { fields->Set("_type", "HOST NOTIFICATION"); //TODO: why? fields->Set("short_message", "(" + CompatUtility::GetHostStateString(host) + ")"); } fields->Set("_state", service ? Service::StateToString(service->GetState()) : Host::StateToString(host->GetState())); fields->Set("_hostname", host->GetName()); fields->Set("_command", commandName); fields->Set("_notification_type", notificationTypeString); fields->Set("_comment", authorComment); CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("_check_command", commandObj->GetName()); SendLogMessage(ComposeGelfMessage(fields, GetSource(), ts)); } void GelfWriter::StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type) { m_WorkQueue.Enqueue(boost::bind(&GelfWriter::StateChangeHandlerInternal, this, checkable, cr, type)); } void GelfWriter::StateChangeHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type) { AssertOnWorkQueue(); CONTEXT("GELF Processing state change '" + checkable->GetName() + "'"); Log(LogDebug, "GelfWriter") << "Processing state change for '" << checkable->GetName() << "'"; Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields = new Dictionary(); fields->Set("_state", service ? Service::StateToString(service->GetState()) : Host::StateToString(host->GetState())); fields->Set("_type", "STATE CHANGE"); fields->Set("_current_check_attempt", checkable->GetCheckAttempt()); fields->Set("_max_check_attempts", checkable->GetMaxCheckAttempts()); fields->Set("_hostname", host->GetName()); if (service) { fields->Set("_service_name", service->GetShortName()); fields->Set("_service_state", Service::StateToString(service->GetState())); fields->Set("_last_state", service->GetLastState()); fields->Set("_last_hard_state", service->GetLastHardState()); } else { fields->Set("_last_state", host->GetLastState()); fields->Set("_last_hard_state", host->GetLastHardState()); } CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); if (commandObj) fields->Set("_check_command", commandObj->GetName()); double ts = Utility::GetTime(); if (cr) { fields->Set("short_message", CompatUtility::GetCheckResultOutput(cr)); fields->Set("full_message", cr->GetOutput()); fields->Set("_check_source", cr->GetCheckSource()); ts = cr->GetExecutionEnd(); } SendLogMessage(ComposeGelfMessage(fields, GetSource(), ts)); } String GelfWriter::ComposeGelfMessage(const Dictionary::Ptr& fields, const String& source, double ts) { fields->Set("version", "1.1"); fields->Set("host", source); fields->Set("timestamp", ts); return JsonEncode(fields); } void GelfWriter::SendLogMessage(const String& gelfMessage) { std::ostringstream msgbuf; msgbuf << gelfMessage; msgbuf << '\0'; String log = msgbuf.str(); ObjectLock olock(this); if (!GetConnected()) return; try { Log(LogDebug, "GelfWriter") << "Sending '" << log << "'."; m_Stream->Write(log.CStr(), log.GetLength()); } catch (const std::exception& ex) { Log(LogCritical, "GelfWriter") << "Cannot write to TCP socket on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } } icinga2-2.8.1/lib/perfdata/gelfwriter.hpp000066400000000000000000000067431322762156600203010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef GELFWRITER_H #define GELFWRITER_H #include "perfdata/gelfwriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/tcpsocket.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include namespace icinga { /** * An Icinga Gelf writer for Graylog. * * @ingroup perfdata */ class GelfWriter : public ObjectImpl { public: DECLARE_OBJECT(GelfWriter); DECLARE_OBJECTNAME(GelfWriter); GelfWriter(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); protected: virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Stream::Ptr m_Stream; WorkQueue m_WorkQueue; Timer::Ptr m_ReconnectTimer; void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void CheckResultHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void NotificationToUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const String& commandName); void NotificationToUserHandlerInternal(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user, NotificationType notification_type, const CheckResult::Ptr& cr, const String& author, const String& comment_text, const String& command_name); void StateChangeHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type); void StateChangeHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type); String ComposeGelfMessage(const Dictionary::Ptr& fields, const String& source, double ts); void SendLogMessage(const String& gelfMessage); void ReconnectTimerHandler(void); void Disconnect(void); void Reconnect(void); void AssertOnWorkQueue(void); void ExceptionHandler(boost::exception_ptr exp); }; } #endif /* GELFWRITER_H */ icinga2-2.8.1/lib/perfdata/gelfwriter.ti000066400000000000000000000036151322762156600201210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library perfdata; namespace icinga { class GelfWriter : ConfigObject { [config] String host { default {{{ return "127.0.0.1"; }}} }; [config] String port { default {{{ return "12201"; }}} }; [config] String source { default {{{ return "icinga2"; }}} }; [config] bool enable_send_perfdata { default {{{ return false; }}} }; [no_user_modify] bool connected; [no_user_modify] bool should_connect { default {{{ return true; }}} }; }; } icinga2-2.8.1/lib/perfdata/graphitewriter.cpp000066400000000000000000000266141322762156600211610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/graphitewriter.hpp" #include "perfdata/graphitewriter.tcpp" #include "icinga/service.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "base/tcpsocket.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/stream.hpp" #include "base/networkstream.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" #include #include #include #include using namespace icinga; REGISTER_TYPE(GraphiteWriter); REGISTER_STATSFUNCTION(GraphiteWriter, &GraphiteWriter::StatsFunc); GraphiteWriter::GraphiteWriter(void) : m_WorkQueue(10000000, 1) { } void GraphiteWriter::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_WorkQueue.SetName("GraphiteWriter, " + GetName()); } void GraphiteWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const GraphiteWriter::Ptr& graphitewriter : ConfigType::GetObjectsByType()) { size_t workQueueItems = graphitewriter->m_WorkQueue.GetLength(); double workQueueItemRate = graphitewriter->m_WorkQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr stats = new Dictionary(); stats->Set("work_queue_items", workQueueItems); stats->Set("work_queue_item_rate", workQueueItemRate); stats->Set("connected", graphitewriter->GetConnected()); nodes->Set(graphitewriter->GetName(), stats); perfdata->Add(new PerfdataValue("graphitewriter_" + graphitewriter->GetName() + "_work_queue_items", workQueueItems)); perfdata->Add(new PerfdataValue("graphitewriter_" + graphitewriter->GetName() + "_work_queue_item_rate", workQueueItemRate)); } status->Set("graphitewriter", nodes); } void GraphiteWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "GraphiteWriter") << "'" << GetName() << "' started."; /* Register exception handler for WQ tasks. */ m_WorkQueue.SetExceptionCallback(boost::bind(&GraphiteWriter::ExceptionHandler, this, _1)); /* Timer for reconnecting */ m_ReconnectTimer = new Timer(); m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&GraphiteWriter::ReconnectTimerHandler, this)); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); /* Register event handlers. */ Checkable::OnNewCheckResult.connect(boost::bind(&GraphiteWriter::CheckResultHandler, this, _1, _2)); } void GraphiteWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "GraphiteWriter") << "'" << GetName() << "' stopped."; m_WorkQueue.Join(); ObjectImpl::Stop(runtimeRemoved); } void GraphiteWriter::AssertOnWorkQueue(void) { ASSERT(m_WorkQueue.IsWorkerThread()); } void GraphiteWriter::ExceptionHandler(boost::exception_ptr exp) { Log(LogCritical, "GraphiteWriter", "Exception during Graphite operation: Verify that your backend is operational!"); Log(LogDebug, "GraphiteWriter") << "Exception during Graphite operation: " << DiagnosticInformation(exp); if (GetConnected()) { m_Stream->Close(); SetConnected(false); } } void GraphiteWriter::Reconnect(void) { AssertOnWorkQueue(); double startTime = Utility::GetTime(); CONTEXT("Reconnecting to Graphite '" + GetName() + "'"); SetShouldConnect(true); if (GetConnected()) return; TcpSocket::Ptr socket = new TcpSocket(); Log(LogNotice, "GraphiteWriter") << "Reconnecting to Graphite on host '" << GetHost() << "' port '" << GetPort() << "'."; try { socket->Connect(GetHost(), GetPort()); } catch (const std::exception& ex) { Log(LogCritical, "GraphiteWriter") << "Can't connect to Graphite on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } m_Stream = new NetworkStream(socket); SetConnected(true); Log(LogInformation, "GraphiteWriter") << "Finished reconnecting to Graphite in " << std::setw(2) << Utility::GetTime() - startTime << " second(s)."; } void GraphiteWriter::ReconnectTimerHandler(void) { m_WorkQueue.Enqueue(boost::bind(&GraphiteWriter::Reconnect, this), PriorityNormal); } void GraphiteWriter::Disconnect(void) { AssertOnWorkQueue(); if (!GetConnected()) return; m_Stream->Close(); SetConnected(false); } void GraphiteWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { m_WorkQueue.Enqueue(boost::bind(&GraphiteWriter::CheckResultHandlerInternal, this, checkable, cr)); } void GraphiteWriter::CheckResultHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { AssertOnWorkQueue(); CONTEXT("Processing check result for '" + checkable->GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) return; Host::Ptr host; Service::Ptr service; boost::tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); String prefix; if (service) { prefix = MacroProcessor::ResolveMacros(GetServiceNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1)); } else { prefix = MacroProcessor::ResolveMacros(GetHostNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1)); } String prefixPerfdata = prefix + ".perfdata"; String prefixMetadata = prefix + ".metadata"; double ts = cr->GetExecutionEnd(); if (GetEnableSendMetadata()) { if (service) { SendMetric(prefixMetadata, "state", service->GetState(), ts); } else { SendMetric(prefixMetadata, "state", host->GetState(), ts); } SendMetric(prefixMetadata, "current_attempt", checkable->GetCheckAttempt(), ts); SendMetric(prefixMetadata, "max_check_attempts", checkable->GetMaxCheckAttempts(), ts); SendMetric(prefixMetadata, "state_type", checkable->GetStateType(), ts); SendMetric(prefixMetadata, "reachable", checkable->IsReachable(), ts); SendMetric(prefixMetadata, "downtime_depth", checkable->GetDowntimeDepth(), ts); SendMetric(prefixMetadata, "acknowledgement", checkable->GetAcknowledgement(), ts); SendMetric(prefixMetadata, "latency", cr->CalculateLatency(), ts); SendMetric(prefixMetadata, "execution_time", cr->CalculateExecutionTime(), ts); } SendPerfdata(prefixPerfdata, cr, ts); } void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr& cr, double ts) { Array::Ptr perfdata = cr->GetPerformanceData(); if (!perfdata) return; ObjectLock olock(perfdata); for (const Value& val : perfdata) { PerfdataValue::Ptr pdv; if (val.IsObjectType()) pdv = val; else { try { pdv = PerfdataValue::Parse(val); } catch (const std::exception&) { Log(LogWarning, "GraphiteWriter") << "Ignoring invalid perfdata value: " << val; continue; } } String escapedKey = EscapeMetricLabel(pdv->GetLabel()); SendMetric(prefix, escapedKey + ".value", pdv->GetValue(), ts); if (GetEnableSendThresholds()) { if (pdv->GetCrit()) SendMetric(prefix, escapedKey + ".crit", pdv->GetCrit(), ts); if (pdv->GetWarn()) SendMetric(prefix, escapedKey + ".warn", pdv->GetWarn(), ts); if (pdv->GetMin()) SendMetric(prefix, escapedKey + ".min", pdv->GetMin(), ts); if (pdv->GetMax()) SendMetric(prefix, escapedKey + ".max", pdv->GetMax(), ts); } } } void GraphiteWriter::SendMetric(const String& prefix, const String& name, double value, double ts) { std::ostringstream msgbuf; msgbuf << prefix << "." << name << " " << Convert::ToString(value) << " " << static_cast(ts); Log(LogDebug, "GraphiteWriter") << "Add to metric list:'" << msgbuf.str() << "'."; // do not send \n to debug log msgbuf << "\n"; String metric = msgbuf.str(); ObjectLock olock(this); if (!GetConnected()) return; try { m_Stream->Write(metric.CStr(), metric.GetLength()); } catch (const std::exception& ex) { Log(LogCritical, "GraphiteWriter") << "Cannot write to TCP socket on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } } String GraphiteWriter::EscapeMetric(const String& str) { String result = str; //don't allow '.' in metric prefixes boost::replace_all(result, " ", "_"); boost::replace_all(result, ".", "_"); boost::replace_all(result, "\\", "_"); boost::replace_all(result, "/", "_"); return result; } String GraphiteWriter::EscapeMetricLabel(const String& str) { String result = str; //allow to pass '.' in perfdata labels boost::replace_all(result, " ", "_"); boost::replace_all(result, "\\", "_"); boost::replace_all(result, "/", "_"); boost::replace_all(result, "::", "."); return result; } Value GraphiteWriter::EscapeMacroMetric(const Value& value) { if (value.IsObjectType()) { Array::Ptr arr = value; Array::Ptr result = new Array(); ObjectLock olock(arr); for (const Value& arg : arr) { result->Add(EscapeMetric(arg)); } return Utility::Join(result, '.'); } else return EscapeMetric(value); } void GraphiteWriter::ValidateHostNameTemplate(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateHostNameTemplate(value, utils); if (!MacroProcessor::ValidateMacroString(value)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_name_template"), "Closing $ not found in macro format string '" + value + "'.")); } void GraphiteWriter::ValidateServiceNameTemplate(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateServiceNameTemplate(value, utils); if (!MacroProcessor::ValidateMacroString(value)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_name_template"), "Closing $ not found in macro format string '" + value + "'.")); } icinga2-2.8.1/lib/perfdata/graphitewriter.hpp000066400000000000000000000061621322762156600211620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef GRAPHITEWRITER_H #define GRAPHITEWRITER_H #include "perfdata/graphitewriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/tcpsocket.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include namespace icinga { /** * An Icinga graphite writer. * * @ingroup perfdata */ class GraphiteWriter : public ObjectImpl { public: DECLARE_OBJECT(GraphiteWriter); DECLARE_OBJECTNAME(GraphiteWriter); GraphiteWriter(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void ValidateHostNameTemplate(const String& value, const ValidationUtils& utils) override; virtual void ValidateServiceNameTemplate(const String& value, const ValidationUtils& utils) override; protected: virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Stream::Ptr m_Stream; WorkQueue m_WorkQueue; Timer::Ptr m_ReconnectTimer; void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void CheckResultHandlerInternal(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void SendMetric(const String& prefix, const String& name, double value, double ts); void SendPerfdata(const String& prefix, const CheckResult::Ptr& cr, double ts); static String EscapeMetric(const String& str); static String EscapeMetricLabel(const String& str); static Value EscapeMacroMetric(const Value& value); void ReconnectTimerHandler(void); void Disconnect(void); void Reconnect(void); void AssertOnWorkQueue(void); void ExceptionHandler(boost::exception_ptr exp); }; } #endif /* GRAPHITEWRITER_H */ icinga2-2.8.1/lib/perfdata/graphitewriter.ti000066400000000000000000000041371322762156600210070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library perfdata; namespace icinga { class GraphiteWriter : ConfigObject { [config] String host { default {{{ return "127.0.0.1"; }}} }; [config] String port { default {{{ return "2003"; }}} }; [config] String host_name_template { default {{{ return "icinga2.$host.name$.host.$host.check_command$"; }}} }; [config] String service_name_template { default {{{ return "icinga2.$host.name$.services.$service.name$.$service.check_command$"; }}} }; [config] bool enable_send_thresholds; [config] bool enable_send_metadata; [no_user_modify] bool connected; [no_user_modify] bool should_connect { default {{{ return true; }}} }; }; } icinga2-2.8.1/lib/perfdata/influxdbwriter.cpp000066400000000000000000000427751322762156600211770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/influxdbwriter.hpp" #include "perfdata/influxdbwriter.tcpp" #include "remote/url.hpp" #include "remote/httprequest.hpp" #include "remote/httpresponse.hpp" #include "icinga/service.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/checkcommand.hpp" #include "base/tcpsocket.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/stream.hpp" #include "base/json.hpp" #include "base/networkstream.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" #include "base/tlsutility.hpp" #include #include #include #include #include #include #include using namespace icinga; REGISTER_TYPE(InfluxdbWriter); REGISTER_STATSFUNCTION(InfluxdbWriter, &InfluxdbWriter::StatsFunc); InfluxdbWriter::InfluxdbWriter(void) : m_WorkQueue(10000000, 1) { } void InfluxdbWriter::OnConfigLoaded(void) { ObjectImpl::OnConfigLoaded(); m_WorkQueue.SetName("InfluxdbWriter, " + GetName()); } void InfluxdbWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { Dictionary::Ptr nodes = new Dictionary(); for (const InfluxdbWriter::Ptr& influxdbwriter : ConfigType::GetObjectsByType()) { size_t workQueueItems = influxdbwriter->m_WorkQueue.GetLength(); double workQueueItemRate = influxdbwriter->m_WorkQueue.GetTaskCount(60) / 60.0; size_t dataBufferItems = influxdbwriter->m_DataBuffer.size(); Dictionary::Ptr stats = new Dictionary(); stats->Set("work_queue_items", workQueueItems); stats->Set("work_queue_item_rate", workQueueItemRate); stats->Set("data_buffer_items", dataBufferItems); nodes->Set(influxdbwriter->GetName(), stats); perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_work_queue_items", workQueueItems)); perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_work_queue_item_rate", workQueueItemRate)); perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_data_queue_items", dataBufferItems)); } status->Set("influxdbwriter", nodes); } void InfluxdbWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "InfluxdbWriter") << "'" << GetName() << "' started."; /* Register exception handler for WQ tasks. */ m_WorkQueue.SetExceptionCallback(boost::bind(&InfluxdbWriter::ExceptionHandler, this, _1)); /* Setup timer for periodically flushing m_DataBuffer */ m_FlushTimer = new Timer(); m_FlushTimer->SetInterval(GetFlushInterval()); m_FlushTimer->OnTimerExpired.connect(boost::bind(&InfluxdbWriter::FlushTimeout, this)); m_FlushTimer->Start(); m_FlushTimer->Reschedule(0); /* Register for new metrics. */ Service::OnNewCheckResult.connect(boost::bind(&InfluxdbWriter::CheckResultHandler, this, _1, _2)); } void InfluxdbWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "InfluxdbWriter") << "'" << GetName() << "' stopped."; m_WorkQueue.Join(); ObjectImpl::Stop(runtimeRemoved); } void InfluxdbWriter::AssertOnWorkQueue(void) { ASSERT(m_WorkQueue.IsWorkerThread()); } void InfluxdbWriter::ExceptionHandler(boost::exception_ptr exp) { Log(LogCritical, "InfluxdbWriter", "Exception during InfluxDB operation: Verify that your backend is operational!"); Log(LogDebug, "InfluxdbWriter") << "Exception during InfluxDB operation: " << DiagnosticInformation(exp); //TODO: Close the connection, if we keep it open. } Stream::Ptr InfluxdbWriter::Connect() { TcpSocket::Ptr socket = new TcpSocket(); Log(LogNotice, "InfluxdbWriter") << "Reconnecting to InfluxDB on host '" << GetHost() << "' port '" << GetPort() << "'."; try { socket->Connect(GetHost(), GetPort()); } catch (const std::exception& ex) { Log(LogWarning, "InfluxdbWriter") << "Can't connect to InfluxDB on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } if (GetSslEnable()) { boost::shared_ptr sslContext; try { sslContext = MakeSSLContext(GetSslCert(), GetSslKey(), GetSslCaCert()); } catch (const std::exception& ex) { Log(LogWarning, "InfluxdbWriter") << "Unable to create SSL context."; throw ex; } TlsStream::Ptr tlsStream = new TlsStream(socket, GetHost(), RoleClient, sslContext); try { tlsStream->Handshake(); } catch (const std::exception& ex) { Log(LogWarning, "InfluxdbWriter") << "TLS handshake with host '" << GetHost() << "' failed."; throw ex; } return tlsStream; } else { return new NetworkStream(socket); } } void InfluxdbWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { m_WorkQueue.Enqueue(boost::bind(&InfluxdbWriter::InternalCheckResultHandler, this, checkable, cr)); } void InfluxdbWriter::InternalCheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { AssertOnWorkQueue(); CONTEXT("Processing check result for '" + checkable->GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) return; Host::Ptr host; Service::Ptr service; boost::tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); String prefix; double ts = cr->GetExecutionEnd(); // Clone the template and perform an in-place macro expansion of measurement and tag values Dictionary::Ptr tmpl_clean = service ? GetServiceTemplate() : GetHostTemplate(); Dictionary::Ptr tmpl = static_pointer_cast(tmpl_clean->Clone()); tmpl->Set("measurement", MacroProcessor::ResolveMacros(tmpl->Get("measurement"), resolvers, cr)); Dictionary::Ptr tags = tmpl->Get("tags"); if (tags) { ObjectLock olock(tags); for (const Dictionary::Pair& pair : tags) { // Prevent missing macros from warning; will return an empty value // which will be filtered out in SendMetric() String missing_macro; tags->Set(pair.first, MacroProcessor::ResolveMacros(pair.second, resolvers, cr, &missing_macro)); } } SendPerfdata(tmpl, checkable, cr, ts); } String InfluxdbWriter::FormatInteger(int val) { return Convert::ToString(val) + "i"; } String InfluxdbWriter::FormatBoolean(bool val) { return val ? "true" : "false"; } void InfluxdbWriter::SendPerfdata(const Dictionary::Ptr& tmpl, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, double ts) { Array::Ptr perfdata = cr->GetPerformanceData(); if (perfdata) { ObjectLock olock(perfdata); for (const Value& val : perfdata) { PerfdataValue::Ptr pdv; if (val.IsObjectType()) pdv = val; else { try { pdv = PerfdataValue::Parse(val); } catch (const std::exception&) { Log(LogWarning, "InfluxdbWriter") << "Ignoring invalid perfdata value: " << val; continue; } } Dictionary::Ptr fields = new Dictionary(); fields->Set("value", pdv->GetValue()); if (GetEnableSendThresholds()) { if (pdv->GetCrit()) fields->Set("crit", pdv->GetCrit()); if (pdv->GetWarn()) fields->Set("warn", pdv->GetWarn()); if (pdv->GetMin()) fields->Set("min", pdv->GetMin()); if (pdv->GetMax()) fields->Set("max", pdv->GetMax()); } SendMetric(tmpl, pdv->GetLabel(), fields, ts); } } if (GetEnableSendMetadata()) { Host::Ptr host; Service::Ptr service; boost::tie(host, service) = GetHostService(checkable); Dictionary::Ptr fields = new Dictionary(); if (service) fields->Set("state", FormatInteger(service->GetState())); else fields->Set("state", FormatInteger(host->GetState())); fields->Set("current_attempt", FormatInteger(checkable->GetCheckAttempt())); fields->Set("max_check_attempts", FormatInteger(checkable->GetMaxCheckAttempts())); fields->Set("state_type", FormatInteger(checkable->GetStateType())); fields->Set("reachable", FormatBoolean(checkable->IsReachable())); fields->Set("downtime_depth", FormatInteger(checkable->GetDowntimeDepth())); fields->Set("acknowledgement", FormatInteger(checkable->GetAcknowledgement())); fields->Set("latency", cr->CalculateLatency()); fields->Set("execution_time", cr->CalculateExecutionTime()); SendMetric(tmpl, Empty, fields, ts); } } String InfluxdbWriter::EscapeKey(const String& str) { // Iterate over the key name and escape commas and spaces with a backslash String result = str; boost::algorithm::replace_all(result, "\"", "\\\""); boost::algorithm::replace_all(result, "=", "\\="); boost::algorithm::replace_all(result, ",", "\\,"); boost::algorithm::replace_all(result, " ", "\\ "); // InfluxDB 'feature': although backslashes are allowed in keys they also act // as escape sequences when followed by ',' or ' '. When your tag is like // 'metric=C:\' bad things happen. Backslashes themselves cannot be escaped // and through experimentation they also escape '='. To be safe we replace // trailing backslashes with and underscore. size_t length = result.GetLength(); if (result[length - 1] == '\\') result[length - 1] = '_'; return result; } String InfluxdbWriter::EscapeField(const String& str) { //TODO: Evaluate whether boost::regex is really needed here. // Handle integers boost::regex integer("-?\\d+i"); if (boost::regex_match(str.GetData(), integer)) { return str; } // Handle numerics boost::regex numeric("-?\\d+(\\.\\d+)?((e|E)[+-]?\\d+)?"); if (boost::regex_match(str.GetData(), numeric)) { return str; } // Handle booleans boost::regex boolean_true("t|true", boost::regex::icase); if (boost::regex_match(str.GetData(), boolean_true)) return "true"; boost::regex boolean_false("f|false", boost::regex::icase); if (boost::regex_match(str.GetData(), boolean_false)) return "false"; // Handle NaNs if (boost::math::isnan(str)) return 0; // Otherwise it's a string and needs escaping and quoting String result = str; boost::algorithm::replace_all(result, "\"", "\\\""); return "\"" + result + "\""; } void InfluxdbWriter::SendMetric(const Dictionary::Ptr& tmpl, const String& label, const Dictionary::Ptr& fields, double ts) { std::ostringstream msgbuf; msgbuf << EscapeKey(tmpl->Get("measurement")); Dictionary::Ptr tags = tmpl->Get("tags"); if (tags) { ObjectLock olock(tags); for (const Dictionary::Pair& pair : tags) { // Empty macro expansion, no tag if (!pair.second.IsEmpty()) { msgbuf << "," << EscapeKey(pair.first) << "=" << EscapeKey(pair.second); } } } // Label is may be empty in the case of metadata if (!label.IsEmpty()) msgbuf << ",metric=" << EscapeKey(label); msgbuf << " "; { bool first = true; ObjectLock fieldLock(fields); for (const Dictionary::Pair& pair : fields) { if (first) first = false; else msgbuf << ","; msgbuf << EscapeKey(pair.first) << "=" << EscapeField(pair.second); } } msgbuf << " " << static_cast(ts); Log(LogDebug, "InfluxdbWriter") << "Add to metric list: '" << msgbuf.str() << "'."; // Atomically buffer the data point boost::mutex::scoped_lock lock(m_DataBufferMutex); m_DataBuffer.push_back(String(msgbuf.str())); // Flush if we've buffered too much to prevent excessive memory use if (static_cast(m_DataBuffer.size()) >= GetFlushThreshold()) { Log(LogDebug, "InfluxdbWriter") << "Data buffer overflow writing " << m_DataBuffer.size() << " data points"; Flush(); } } void InfluxdbWriter::FlushTimeout(void) { // Prevent new data points from being added to the array, there is a // race condition where they could disappear boost::mutex::scoped_lock lock(m_DataBufferMutex); // Flush if there are any data available if (m_DataBuffer.size() > 0) { Log(LogDebug, "InfluxdbWriter") << "Timer expired writing " << m_DataBuffer.size() << " data points"; Flush(); } } void InfluxdbWriter::Flush(void) { // Ensure you hold a lock against m_DataBuffer so that things // don't go missing after creating the body and clearing the buffer String body = boost::algorithm::join(m_DataBuffer, "\n"); m_DataBuffer.clear(); Stream::Ptr stream = Connect(); if (!stream) return; Url::Ptr url = new Url(); url->SetScheme(GetSslEnable() ? "https" : "http"); url->SetHost(GetHost()); url->SetPort(GetPort()); std::vector path; path.push_back("write"); url->SetPath(path); url->AddQueryElement("db", GetDatabase()); url->AddQueryElement("precision", "s"); if (!GetUsername().IsEmpty()) url->AddQueryElement("u", GetUsername()); if (!GetPassword().IsEmpty()) url->AddQueryElement("p", GetPassword()); HttpRequest req(stream); req.RequestMethod = "POST"; req.RequestUrl = url; try { req.WriteBody(body.CStr(), body.GetLength()); req.Finish(); } catch (const std::exception& ex) { Log(LogWarning, "InfluxdbWriter") << "Cannot write to TCP socket on host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } //TODO: Evaluate whether waiting for the result makes sense here. KeepAlive and close are options. HttpResponse resp(stream, req); StreamReadContext context; try { resp.Parse(context, true); } catch (const std::exception& ex) { Log(LogWarning, "InfluxdbWriter") << "Cannot read from TCP socket from host '" << GetHost() << "' port '" << GetPort() << "'."; throw ex; } if (resp.StatusCode != 204) { Log(LogWarning, "InfluxdbWriter") << "Unexpected response code " << resp.StatusCode; // Finish parsing the headers and body while (!resp.Complete) resp.Parse(context, true); String contentType = resp.Headers->Get("content-type"); if (contentType != "application/json") { Log(LogWarning, "InfluxdbWriter") << "Unexpected Content-Type: " << contentType; return; } size_t responseSize = resp.GetBodySize(); boost::scoped_array buffer(new char[responseSize + 1]); resp.ReadBody(buffer.get(), responseSize); buffer.get()[responseSize] = '\0'; Dictionary::Ptr jsonResponse; try { jsonResponse = JsonDecode(buffer.get()); } catch (...) { Log(LogWarning, "InfluxdbWriter") << "Unable to parse JSON response:\n" << buffer.get(); return; } String error = jsonResponse->Get("error"); Log(LogCritical, "InfluxdbWriter") << "InfluxDB error message:\n" << error; } } void InfluxdbWriter::ValidateHostTemplate(const Dictionary::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateHostTemplate(value, utils); String measurement = value->Get("measurement"); if (!MacroProcessor::ValidateMacroString(measurement)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_template")("measurement"), "Closing $ not found in macro format string '" + measurement + "'.")); Dictionary::Ptr tags = value->Get("tags"); if (tags) { ObjectLock olock(tags); for (const Dictionary::Pair& pair : tags) { if (!MacroProcessor::ValidateMacroString(pair.second)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_template")("tags")(pair.first), "Closing $ not found in macro format string '" + pair.second)); } } } void InfluxdbWriter::ValidateServiceTemplate(const Dictionary::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateServiceTemplate(value, utils); String measurement = value->Get("measurement"); if (!MacroProcessor::ValidateMacroString(measurement)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_template")("measurement"), "Closing $ not found in macro format string '" + measurement + "'.")); Dictionary::Ptr tags = value->Get("tags"); if (tags) { ObjectLock olock(tags); for (const Dictionary::Pair& pair : tags) { if (!MacroProcessor::ValidateMacroString(pair.second)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_template")("tags")(pair.first), "Closing $ not found in macro format string '" + pair.second)); } } } icinga2-2.8.1/lib/perfdata/influxdbwriter.hpp000066400000000000000000000064141322762156600211720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef INFLUXDBWRITER_H #define INFLUXDBWRITER_H #include "perfdata/influxdbwriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/tcpsocket.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include #include namespace icinga { /** * An Icinga InfluxDB writer. * * @ingroup perfdata */ class InfluxdbWriter : public ObjectImpl { public: DECLARE_OBJECT(InfluxdbWriter); DECLARE_OBJECTNAME(InfluxdbWriter); InfluxdbWriter(void); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void ValidateHostTemplate(const Dictionary::Ptr& value, const ValidationUtils& utils) override; virtual void ValidateServiceTemplate(const Dictionary::Ptr& value, const ValidationUtils& utils) override; protected: virtual void OnConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: WorkQueue m_WorkQueue; Timer::Ptr m_FlushTimer; std::vector m_DataBuffer; boost::mutex m_DataBufferMutex; void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void InternalCheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void SendPerfdata(const Dictionary::Ptr& tmpl, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, double ts); void SendMetric(const Dictionary::Ptr& tmpl, const String& label, const Dictionary::Ptr& fields, double ts); void FlushTimeout(void); void Flush(void); static String FormatInteger(int val); static String FormatBoolean(bool val); static String EscapeKey(const String& str); static String EscapeField(const String& str); Stream::Ptr Connect(); void AssertOnWorkQueue(void); void ExceptionHandler(boost::exception_ptr exp); }; } #endif /* INFLUXDBWRITER_H */ icinga2-2.8.1/lib/perfdata/influxdbwriter.ti000066400000000000000000000064641322762156600210240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library perfdata; namespace icinga { class InfluxdbWriter : ConfigObject { [config, required] String host { default {{{ return "127.0.0.1"; }}} }; [config, required] String port { default {{{ return "8086"; }}} }; [config, required] String database { default {{{ return "icinga2"; }}} }; [config] String username { default {{{ return ""; }}} }; [config, no_user_view] String password { default {{{ return ""; }}} }; [config] bool ssl_enable { default {{{ return false; }}} }; [config] String ssl_ca_cert { default {{{ return ""; }}} }; [config] String ssl_cert { default {{{ return ""; }}} }; [config] String ssl_key{ default {{{ return ""; }}} }; [config, required] Dictionary::Ptr host_template { default {{{ Dictionary::Ptr tags = new Dictionary(); tags->Set("hostname", "$host.name$"); Dictionary::Ptr tmpl = new Dictionary(); tmpl->Set("measurement", "$host.check_command$"); tmpl->Set("tags", tags); return tmpl; }}} }; [config, required] Dictionary::Ptr service_template { default {{{ Dictionary::Ptr tags = new Dictionary(); tags->Set("hostname", "$host.name$"); tags->Set("service", "$service.name$"); Dictionary::Ptr tmpl = new Dictionary(); tmpl->Set("measurement", "$service.check_command$"); tmpl->Set("tags", tags); return tmpl; }}} }; [config] bool enable_send_thresholds { default {{{ return false; }}} }; [config] bool enable_send_metadata { default {{{ return false; }}} }; [config] int flush_interval { default {{{ return 10; }}} }; [config] int flush_threshold { default {{{ return 1024; }}} }; }; validator InfluxdbWriter { Dictionary host_template { required measurement; String measurement; Dictionary "tags" { String "*"; }; }; Dictionary service_template { required measurement; String measurement; Dictionary "tags" { String "*"; }; }; }; } icinga2-2.8.1/lib/perfdata/opentsdbwriter.cpp000066400000000000000000000206111322762156600211630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/opentsdbwriter.hpp" #include "perfdata/opentsdbwriter.tcpp" #include "icinga/service.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "icinga/compatutility.hpp" #include "base/tcpsocket.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/stream.hpp" #include "base/networkstream.hpp" #include "base/exception.hpp" #include "base/statsfunction.hpp" #include #include #include #include using namespace icinga; REGISTER_TYPE(OpenTsdbWriter); REGISTER_STATSFUNCTION(OpenTsdbWriter, &OpenTsdbWriter::StatsFunc); void OpenTsdbWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const OpenTsdbWriter::Ptr& opentsdbwriter : ConfigType::GetObjectsByType()) { nodes->Set(opentsdbwriter->GetName(), 1); //add more stats } status->Set("opentsdbwriter", nodes); } void OpenTsdbWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "OpentsdbWriter") << "'" << GetName() << "' started."; m_ReconnectTimer = new Timer(); m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&OpenTsdbWriter::ReconnectTimerHandler, this)); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); Service::OnNewCheckResult.connect(boost::bind(&OpenTsdbWriter::CheckResultHandler, this, _1, _2)); } void OpenTsdbWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "OpentsdbWriter") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } void OpenTsdbWriter::ReconnectTimerHandler(void) { if (m_Stream) return; TcpSocket::Ptr socket = new TcpSocket(); Log(LogNotice, "OpenTsdbWriter") << "Reconnect to OpenTSDB TSD on host '" << GetHost() << "' port '" << GetPort() << "'."; try { socket->Connect(GetHost(), GetPort()); } catch (std::exception&) { Log(LogCritical, "OpenTsdbWriter") << "Can't connect to OpenTSDB TSD on host '" << GetHost() << "' port '" << GetPort() << "'."; return; } m_Stream = new NetworkStream(socket); } void OpenTsdbWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { CONTEXT("Processing check result for '" + checkable->GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) return; Service::Ptr service = dynamic_pointer_cast(checkable); Host::Ptr host; if (service) host = service->GetHost(); else host = static_pointer_cast(checkable); String metric; std::map tags; String escaped_hostName = EscapeMetric(host->GetName()); tags["host"] = escaped_hostName; double ts = cr->GetExecutionEnd(); if (service) { String serviceName = service->GetShortName(); String escaped_serviceName = EscapeMetric(serviceName); metric = "icinga.service." + escaped_serviceName; SendMetric(metric + ".state", tags, service->GetState(), ts); } else { metric = "icinga.host"; SendMetric(metric + ".state", tags, host->GetState(), ts); } SendMetric(metric + ".state_type", tags, checkable->GetStateType(), ts); SendMetric(metric + ".reachable", tags, checkable->IsReachable(), ts); SendMetric(metric + ".downtime_depth", tags, checkable->GetDowntimeDepth(), ts); SendMetric(metric + ".acknowledgement", tags, checkable->GetAcknowledgement(), ts); SendPerfdata(metric, tags, cr, ts); metric = "icinga.check"; if (service) { tags["type"] = "service"; String serviceName = service->GetShortName(); String escaped_serviceName = EscapeTag(serviceName); tags["service"] = escaped_serviceName; } else { tags["type"] = "host"; } SendMetric(metric + ".current_attempt", tags, checkable->GetCheckAttempt(), ts); SendMetric(metric + ".max_check_attempts", tags, checkable->GetMaxCheckAttempts(), ts); SendMetric(metric + ".latency", tags, cr->CalculateLatency(), ts); SendMetric(metric + ".execution_time", tags, cr->CalculateExecutionTime(), ts); } void OpenTsdbWriter::SendPerfdata(const String& metric, const std::map& tags, const CheckResult::Ptr& cr, double ts) { Array::Ptr perfdata = cr->GetPerformanceData(); if (!perfdata) return; ObjectLock olock(perfdata); for (const Value& val : perfdata) { PerfdataValue::Ptr pdv; if (val.IsObjectType()) pdv = val; else { try { pdv = PerfdataValue::Parse(val); } catch (const std::exception&) { Log(LogWarning, "OpenTsdbWriter") << "Ignoring invalid perfdata value: " << val; continue; } } String escaped_key = EscapeMetric(pdv->GetLabel()); boost::algorithm::replace_all(escaped_key, "::", "."); SendMetric(metric + "." + escaped_key, tags, pdv->GetValue(), ts); if (pdv->GetCrit()) SendMetric(metric + "." + escaped_key + "_crit", tags, pdv->GetCrit(), ts); if (pdv->GetWarn()) SendMetric(metric + "." + escaped_key + "_warn", tags, pdv->GetWarn(), ts); if (pdv->GetMin()) SendMetric(metric + "." + escaped_key + "_min", tags, pdv->GetMin(), ts); if (pdv->GetMax()) SendMetric(metric + "." + escaped_key + "_max", tags, pdv->GetMax(), ts); } } void OpenTsdbWriter::SendMetric(const String& metric, const std::map& tags, double value, double ts) { String tags_string = ""; for (const Dictionary::Pair& tag : tags) { tags_string += " " + tag.first + "=" + Convert::ToString(tag.second); } std::ostringstream msgbuf; /* * must be (http://opentsdb.net/docs/build/html/user_guide/writing.html) * put * "tags" must include at least one tag, we use "host=HOSTNAME" */ msgbuf << "put " << metric << " " << static_cast(ts) << " " << Convert::ToString(value) << " " << tags_string; Log(LogDebug, "OpenTsdbWriter") << "Add to metric list:'" << msgbuf.str() << "'."; /* do not send \n to debug log */ msgbuf << "\n"; String put = msgbuf.str(); ObjectLock olock(this); if (!m_Stream) return; try { m_Stream->Write(put.CStr(), put.GetLength()); } catch (const std::exception& ex) { Log(LogCritical, "OpenTsdbWriter") << "Cannot write to OpenTSDB TSD on host '" << GetHost() << "' port '" << GetPort() + "'."; m_Stream.reset(); } } /* for metric and tag name rules, see * http://opentsdb.net/docs/build/html/user_guide/writing.html#metrics-and-tags */ String OpenTsdbWriter::EscapeTag(const String& str) { String result = str; boost::replace_all(result, " ", "_"); boost::replace_all(result, "\\", "_"); return result; } String OpenTsdbWriter::EscapeMetric(const String& str) { String result = str; boost::replace_all(result, " ", "_"); boost::replace_all(result, ".", "_"); boost::replace_all(result, "\\", "_"); return result; } icinga2-2.8.1/lib/perfdata/opentsdbwriter.hpp000066400000000000000000000051041322762156600211700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OPENTSDBWRITER_H #define OPENTSDBWRITER_H #include "perfdata/opentsdbwriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/tcpsocket.hpp" #include "base/timer.hpp" #include namespace icinga { /** * An Icinga opentsdb writer. * * @ingroup perfdata */ class OpenTsdbWriter : public ObjectImpl { public: DECLARE_OBJECT(OpenTsdbWriter); DECLARE_OBJECTNAME(OpenTsdbWriter); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: Stream::Ptr m_Stream; Timer::Ptr m_ReconnectTimer; void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void SendMetric(const String& metric, const std::map& tags, double value, double ts); void SendPerfdata(const String& metric, const std::map& tags, const CheckResult::Ptr& cr, double ts); static String EscapeTag(const String& str); static String EscapeMetric(const String& str); void ReconnectTimerHandler(void); }; } #endif /* OPENTSDBWRITER_H */ icinga2-2.8.1/lib/perfdata/opentsdbwriter.ti000066400000000000000000000032271322762156600210210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library perfdata; namespace icinga { class OpenTsdbWriter : ConfigObject { [config] String host { default {{{ return "127.0.0.1"; }}} }; [config] String port { default {{{ return "4242"; }}} }; }; } icinga2-2.8.1/lib/perfdata/perfdatawriter.cpp000066400000000000000000000143161322762156600211400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "perfdata/perfdatawriter.hpp" #include "perfdata/perfdatawriter.tcpp" #include "icinga/service.hpp" #include "icinga/macroprocessor.hpp" #include "icinga/icingaapplication.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include "base/context.hpp" #include "base/exception.hpp" #include "base/application.hpp" #include "base/statsfunction.hpp" using namespace icinga; REGISTER_TYPE(PerfdataWriter); REGISTER_STATSFUNCTION(PerfdataWriter, &PerfdataWriter::StatsFunc); void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) { Dictionary::Ptr nodes = new Dictionary(); for (const PerfdataWriter::Ptr& perfdatawriter : ConfigType::GetObjectsByType()) { nodes->Set(perfdatawriter->GetName(), 1); //add more stats } status->Set("perfdatawriter", nodes); } void PerfdataWriter::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); Log(LogInformation, "PerfdataWriter") << "'" << GetName() << "' started."; Checkable::OnNewCheckResult.connect(boost::bind(&PerfdataWriter::CheckResultHandler, this, _1, _2)); m_RotationTimer = new Timer(); m_RotationTimer->OnTimerExpired.connect(boost::bind(&PerfdataWriter::RotationTimerHandler, this)); m_RotationTimer->SetInterval(GetRotationInterval()); m_RotationTimer->Start(); RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); } void PerfdataWriter::Stop(bool runtimeRemoved) { Log(LogInformation, "PerfdataWriter") << "'" << GetName() << "' stopped."; ObjectImpl::Stop(runtimeRemoved); } Value PerfdataWriter::EscapeMacroMetric(const Value& value) { if (value.IsObjectType()) return Utility::Join(value, ';'); else return value; } void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) { CONTEXT("Writing performance data for object '" + checkable->GetName() + "'"); if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) return; Service::Ptr service = dynamic_pointer_cast(checkable); Host::Ptr host; if (service) host = service->GetHost(); else host = static_pointer_cast(checkable); MacroProcessor::ResolverList resolvers; if (service) resolvers.push_back(std::make_pair("service", service)); resolvers.push_back(std::make_pair("host", host)); resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance())); if (service) { String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr, NULL, &PerfdataWriter::EscapeMacroMetric); { ObjectLock olock(this); if (!m_ServiceOutputFile.good()) return; m_ServiceOutputFile << line << "\n"; } } else { String line = MacroProcessor::ResolveMacros(GetHostFormatTemplate(), resolvers, cr, NULL, &PerfdataWriter::EscapeMacroMetric); { ObjectLock olock(this); if (!m_HostOutputFile.good()) return; m_HostOutputFile << line << "\n"; } } } void PerfdataWriter::RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path) { ObjectLock olock(this); if (output.good()) { output.close(); if (Utility::PathExists(temp_path)) { String finalFile = perfdata_path + "." + Convert::ToString((long)Utility::GetTime()); if (rename(temp_path.CStr(), finalFile.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(temp_path)); } } } output.open(temp_path.CStr()); if (!output.good()) Log(LogWarning, "PerfdataWriter") << "Could not open perfdata file '" << temp_path << "' for writing. Perfdata will be lost."; } void PerfdataWriter::RotationTimerHandler(void) { RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); } void PerfdataWriter::ValidateHostFormatTemplate(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateHostFormatTemplate(value, utils); if (!MacroProcessor::ValidateMacroString(value)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_format_template"), "Closing $ not found in macro format string '" + value + "'.")); } void PerfdataWriter::ValidateServiceFormatTemplate(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateServiceFormatTemplate(value, utils); if (!MacroProcessor::ValidateMacroString(value)) BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_format_template"), "Closing $ not found in macro format string '" + value + "'.")); } icinga2-2.8.1/lib/perfdata/perfdatawriter.hpp000066400000000000000000000051701322762156600211430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PERFDATAWRITER_H #define PERFDATAWRITER_H #include "perfdata/perfdatawriter.thpp" #include "icinga/service.hpp" #include "base/configobject.hpp" #include "base/timer.hpp" #include namespace icinga { /** * An Icinga perfdata writer. * * @ingroup icinga */ class PerfdataWriter : public ObjectImpl { public: DECLARE_OBJECT(PerfdataWriter); DECLARE_OBJECTNAME(PerfdataWriter); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); virtual void ValidateHostFormatTemplate(const String& value, const ValidationUtils& utils) override; virtual void ValidateServiceFormatTemplate(const String& value, const ValidationUtils& utils) override; protected: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; private: void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); static Value EscapeMacroMetric(const Value& value); Timer::Ptr m_RotationTimer; void RotationTimerHandler(void); std::ofstream m_ServiceOutputFile; std::ofstream m_HostOutputFile; void RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path); }; } #endif /* PERFDATAWRITER_H */ icinga2-2.8.1/lib/perfdata/perfdatawriter.ti000066400000000000000000000057551322762156600210010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/application.hpp" library perfdata; namespace icinga { class PerfdataWriter : ConfigObject { [config] String host_perfdata_path { default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/perfdata/host-perfdata"; }}} }; [config] String service_perfdata_path { default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/perfdata/service-perfdata"; }}} }; [config] String host_temp_path { default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/tmp/host-perfdata"; }}} }; [config] String service_temp_path { default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/tmp/service-perfdata"; }}} }; [config] String host_format_template { default {{{ return "DATATYPE::HOSTPERFDATA\t" "TIMET::$host.last_check$\t" "HOSTNAME::$host.name$\t" "HOSTPERFDATA::$host.perfdata$\t" "HOSTCHECKCOMMAND::$host.check_command$\t" "HOSTSTATE::$host.state$\t" "HOSTSTATETYPE::$host.state_type$"; }}} }; [config] String service_format_template { default {{{ return "DATATYPE::SERVICEPERFDATA\t" "TIMET::$service.last_check$\t" "HOSTNAME::$host.name$\t" "SERVICEDESC::$service.name$\t" "SERVICEPERFDATA::$service.perfdata$\t" "SERVICECHECKCOMMAND::$service.check_command$\t" "HOSTSTATE::$host.state$\t" "HOSTSTATETYPE::$host.state_type$\t" "SERVICESTATE::$service.state$\t" "SERVICESTATETYPE::$service.state_type$"; }}} }; [config] double rotation_interval { default {{{ return 30; }}} }; }; } icinga2-2.8.1/lib/remote/000077500000000000000000000000001322762156600151115ustar00rootroot00000000000000icinga2-2.8.1/lib/remote/CMakeLists.txt000066400000000000000000000061521322762156600176550ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. mkclass_target(apilistener.ti apilistener.tcpp apilistener.thpp) mkclass_target(apiuser.ti apiuser.tcpp apiuser.thpp) mkclass_target(endpoint.ti endpoint.tcpp endpoint.thpp) mkclass_target(zone.ti zone.tcpp zone.thpp) set(remote_SOURCES actionshandler.cpp apiaction.cpp apiclient.cpp apifunction.cpp apilistener.cpp apilistener.thpp apilistener-configsync.cpp apilistener-filesync.cpp apiuser.cpp apiuser.thpp authority.cpp consolehandler.cpp configfileshandler.cpp configpackageshandler.cpp configpackageutility.cpp configobjectutility.cpp configstageshandler.cpp createobjecthandler.cpp deleteobjecthandler.cpp endpoint.cpp endpoint.thpp eventshandler.cpp eventqueue.cpp filterutility.cpp httpchunkedencoding.cpp httpclientconnection.cpp httpserverconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp httputility.cpp infohandler.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp jsonrpcconnection-pki.cpp messageorigin.cpp modifyobjecthandler.cpp statushandler.cpp objectqueryhandler.cpp templatequeryhandler.cpp pkiutility.cpp typequeryhandler.cpp url.cpp variablequeryhandler.cpp zone.cpp zone.thpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(remote remote remote_SOURCES) endif() add_library(remote SHARED ${remote_SOURCES}) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(remote ${Boost_LIBRARIES} base config) set_target_properties ( remote PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_REMOTE_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS remote RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS remote LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() #install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/log\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/zones\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/certs\")") install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/certificate-requests\")") icinga2-2.8.1/lib/remote/actionshandler.cpp000066400000000000000000000072211322762156600206150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/actionshandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "remote/apiaction.hpp" #include "base/exception.hpp" #include "base/serializer.hpp" #include "base/logger.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/actions", ActionsHandler); bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() != 3) return false; if (request.RequestMethod != "POST") return false; String actionName = request.RequestUrl->GetPath()[2]; ApiAction::Ptr action = ApiAction::GetByName(actionName); if (!action) { HttpUtility::SendJsonError(response, 404, "Action '" + actionName + "' does not exist."); return true; } QueryDescription qd; const std::vector& types = action->GetTypes(); std::vector objs; String permission = "actions/" + actionName; if (!types.empty()) { qd.Types = std::set(types.begin(), types.end()); qd.Permission = permission; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } } else { FilterUtility::CheckPermission(user, permission); objs.push_back(ConfigObject::Ptr()); } Array::Ptr results = new Array(); Log(LogNotice, "ApiActionHandler") << "Running action " << actionName; for (const ConfigObject::Ptr& obj : objs) { try { results->Add(action->Invoke(obj, params)); } catch (const std::exception& ex) { Dictionary::Ptr fail = new Dictionary(); fail->Set("code", 500); fail->Set("status", "Action execution failed: '" + DiagnosticInformation(ex, false) + "'."); if (HttpUtility::GetLastParameter(params, "verboseErrors")) fail->Set("diagnostic information", DiagnosticInformation(ex)); results->Add(fail); } } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/actionshandler.hpp000066400000000000000000000034551322762156600206270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ACTIONSHANDLER_H #define ACTIONSHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ActionsHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ActionsHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* ACTIONSHANDLER_H */ icinga2-2.8.1/lib/remote/apiaction.cpp000066400000000000000000000044441322762156600175720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apiaction.hpp" #include "base/singleton.hpp" using namespace icinga; ApiAction::ApiAction(const std::vector& types, const Callback& action) : m_Types(types), m_Callback(action) { } Value ApiAction::Invoke(const ConfigObject::Ptr& target, const Dictionary::Ptr& params) { return m_Callback(target, params); } const std::vector& ApiAction::GetTypes(void) const { return m_Types; } ApiAction::Ptr ApiAction::GetByName(const String& name) { return ApiActionRegistry::GetInstance()->GetItem(name); } void ApiAction::Register(const String& name, const ApiAction::Ptr& action) { ApiActionRegistry::GetInstance()->Register(name, action); } void ApiAction::Unregister(const String& name) { ApiActionRegistry::GetInstance()->Unregister(name); } ApiActionRegistry *ApiActionRegistry::GetInstance(void) { return Singleton::GetInstance(); } icinga2-2.8.1/lib/remote/apiaction.hpp000066400000000000000000000063111322762156600175720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APIACTION_H #define APIACTION_H #include "remote/i2-remote.hpp" #include "base/registry.hpp" #include "base/value.hpp" #include "base/dictionary.hpp" #include "base/configobject.hpp" #include #include #include #include #include namespace icinga { /** * An API action. * * @ingroup remote */ class I2_REMOTE_API ApiAction : public Object { public: DECLARE_PTR_TYPEDEFS(ApiAction); typedef boost::function Callback; ApiAction(const std::vector& registerTypes, const Callback& function); Value Invoke(const ConfigObject::Ptr& target, const Dictionary::Ptr& params); const std::vector& GetTypes(void) const; static ApiAction::Ptr GetByName(const String& name); static void Register(const String& name, const ApiAction::Ptr& action); static void Unregister(const String& name); private: std::vector m_Types; Callback m_Callback; }; /** * A registry for API actions. * * @ingroup remote */ class I2_REMOTE_API ApiActionRegistry : public Registry { public: static ApiActionRegistry *GetInstance(void); }; #define REGISTER_APIACTION(name, types, callback) \ INITIALIZE_ONCE([]() { \ String registerName = #name; \ boost::algorithm::replace_all(registerName, "_", "-"); \ std::vector registerTypes; \ String typeNames = types; \ if (!typeNames.IsEmpty()) \ boost::algorithm::split(registerTypes, typeNames, boost::is_any_of(";")); \ ApiAction::Ptr action = new ApiAction(registerTypes, callback); \ ApiActionRegistry::GetInstance()->Register(registerName, action); \ }) } #endif /* APIACTION_H */ icinga2-2.8.1/lib/remote/apiclient.cpp000066400000000000000000000303641322762156600175730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apiclient.hpp" #include "base/base64.hpp" #include "base/json.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" using namespace icinga; ApiClient::ApiClient(const String& host, const String& port, const String& user, const String& password) : m_Connection(new HttpClientConnection(host, port, true)), m_User(user), m_Password(password) { m_Connection->Start(); } void ApiClient::GetTypes(const TypesCompletionCallback& callback) const { Url::Ptr url = new Url(); url->SetScheme("https"); url->SetHost(m_Connection->GetHost()); url->SetPort(m_Connection->GetPort()); std::vector path; path.push_back("v1"); path.push_back("types"); url->SetPath(path); try { boost::shared_ptr req = m_Connection->NewRequest(); req->RequestMethod = "GET"; req->RequestUrl = url; req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password)); req->AddHeader("Accept", "application/json"); m_Connection->SubmitRequest(req, boost::bind(TypesHttpCompletionCallback, _1, _2, callback)); } catch (const std::exception& ex) { callback(boost::current_exception(), std::vector()); } } void ApiClient::TypesHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const TypesCompletionCallback& callback) { Dictionary::Ptr result; String body; char buffer[1024]; size_t count; while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); try { if (response.StatusCode < 200 || response.StatusCode > 299) { std::string message = "HTTP request failed; Code: " + Convert::ToString(response.StatusCode) + "; Body: " + body; BOOST_THROW_EXCEPTION(ScriptError(message)); } std::vector types; result = JsonDecode(body); Array::Ptr results = result->Get("results"); ObjectLock olock(results); for (const Dictionary::Ptr typeInfo : results) { ApiType::Ptr type = new ApiType();; type->Abstract = typeInfo->Get("abstract"); type->BaseName = typeInfo->Get("base"); type->Name = typeInfo->Get("name"); type->PluralName = typeInfo->Get("plural_name"); // TODO: attributes types.push_back(type); } callback(boost::exception_ptr(), types); } catch (const std::exception& ex) { Log(LogCritical, "ApiClient") << "Error while decoding response: " << DiagnosticInformation(ex); callback(boost::current_exception(), std::vector()); } } void ApiClient::GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback, const std::vector& names, const std::vector& attrs, const std::vector& joins, bool all_joins) const { Url::Ptr url = new Url(); url->SetScheme("https"); url->SetHost(m_Connection->GetHost()); url->SetPort(m_Connection->GetPort()); std::vector path; path.push_back("v1"); path.push_back("objects"); path.push_back(pluralType); url->SetPath(path); std::map > params; for (const String& name : names) { params[pluralType.ToLower()].push_back(name); } for (const String& attr : attrs) { params["attrs"].push_back(attr); } for (const String& join : joins) { params["joins"].push_back(join); } params["all_joins"].push_back(all_joins ? "1" : "0"); url->SetQuery(params); try { boost::shared_ptr req = m_Connection->NewRequest(); req->RequestMethod = "GET"; req->RequestUrl = url; req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password)); req->AddHeader("Accept", "application/json"); m_Connection->SubmitRequest(req, boost::bind(ObjectsHttpCompletionCallback, _1, _2, callback)); } catch (const std::exception& ex) { callback(boost::current_exception(), std::vector()); } } void ApiClient::ObjectsHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const ObjectsCompletionCallback& callback) { Dictionary::Ptr result; String body; char buffer[1024]; size_t count; while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); try { if (response.StatusCode < 200 || response.StatusCode > 299) { std::string message = "HTTP request failed; Code: " + Convert::ToString(response.StatusCode) + "; Body: " + body; BOOST_THROW_EXCEPTION(ScriptError(message)); } std::vector objects; result = JsonDecode(body); Array::Ptr results = result->Get("results"); if (results) { ObjectLock olock(results); for (const Dictionary::Ptr objectInfo : results) { ApiObject::Ptr object = new ApiObject(); object->Name = objectInfo->Get("name"); object->Type = objectInfo->Get("type"); Dictionary::Ptr attrs = objectInfo->Get("attrs"); if (attrs) { ObjectLock olock(attrs); for (const Dictionary::Pair& kv : attrs) { object->Attrs[object->Type.ToLower() + "." + kv.first] = kv.second; } } Dictionary::Ptr joins = objectInfo->Get("joins"); if (joins) { ObjectLock olock(joins); for (const Dictionary::Pair& kv : joins) { Dictionary::Ptr attrs = kv.second; if (attrs) { ObjectLock olock(attrs); for (const Dictionary::Pair& kv2 : attrs) { object->Attrs[kv.first + "." + kv2.first] = kv2.second; } } } } Array::Ptr used_by = objectInfo->Get("used_by"); if (used_by) { ObjectLock olock(used_by); for (const Dictionary::Ptr& refInfo : used_by) { ApiObjectReference ref; ref.Name = refInfo->Get("name"); ref.Type = refInfo->Get("type"); object->UsedBy.push_back(ref); } } objects.push_back(object); } } callback(boost::exception_ptr(), objects); } catch (const std::exception& ex) { Log(LogCritical, "ApiClient") << "Error while decoding response: " << DiagnosticInformation(ex); callback(boost::current_exception(), std::vector()); } } void ApiClient::ExecuteScript(const String& session, const String& command, bool sandboxed, const ExecuteScriptCompletionCallback& callback) const { Url::Ptr url = new Url(); url->SetScheme("https"); url->SetHost(m_Connection->GetHost()); url->SetPort(m_Connection->GetPort()); std::vector path; path.push_back("v1"); path.push_back("console"); path.push_back("execute-script"); url->SetPath(path); std::map > params; params["session"].push_back(session); params["command"].push_back(command); params["sandboxed"].push_back(sandboxed ? "1" : "0"); url->SetQuery(params); try { boost::shared_ptr req = m_Connection->NewRequest(); req->RequestMethod = "POST"; req->RequestUrl = url; req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password)); req->AddHeader("Accept", "application/json"); m_Connection->SubmitRequest(req, boost::bind(ExecuteScriptHttpCompletionCallback, _1, _2, callback)); } catch (const std::exception& ex) { callback(boost::current_exception(), Empty); } } void ApiClient::ExecuteScriptHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const ExecuteScriptCompletionCallback& callback) { Dictionary::Ptr result; String body; char buffer[1024]; size_t count; while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); try { if (response.StatusCode < 200 || response.StatusCode > 299) { std::string message = "HTTP request failed; Code: " + Convert::ToString(response.StatusCode) + "; Body: " + body; BOOST_THROW_EXCEPTION(ScriptError(message)); } result = JsonDecode(body); Array::Ptr results = result->Get("results"); Value result; String errorMessage = "Unexpected result from API."; if (results && results->GetLength() > 0) { Dictionary::Ptr resultInfo = results->Get(0); errorMessage = resultInfo->Get("status"); if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299) { result = resultInfo->Get("result"); } else { DebugInfo di; Dictionary::Ptr debugInfo = resultInfo->Get("debug_info"); if (debugInfo) { di.Path = debugInfo->Get("path"); di.FirstLine = debugInfo->Get("first_line"); di.FirstColumn = debugInfo->Get("first_column"); di.LastLine = debugInfo->Get("last_line"); di.LastColumn = debugInfo->Get("last_column"); } bool incompleteExpression = resultInfo->Get("incomplete_expression"); BOOST_THROW_EXCEPTION(ScriptError(errorMessage, di, incompleteExpression)); } } callback(boost::exception_ptr(), result); } catch (const std::exception& ex) { callback(boost::current_exception(), Empty); } } void ApiClient::AutocompleteScript(const String& session, const String& command, bool sandboxed, const AutocompleteScriptCompletionCallback& callback) const { Url::Ptr url = new Url(); url->SetScheme("https"); url->SetHost(m_Connection->GetHost()); url->SetPort(m_Connection->GetPort()); std::vector path; path.push_back("v1"); path.push_back("console"); path.push_back("auto-complete-script"); url->SetPath(path); std::map > params; params["session"].push_back(session); params["command"].push_back(command); params["sandboxed"].push_back(sandboxed ? "1" : "0"); url->SetQuery(params); try { boost::shared_ptr req = m_Connection->NewRequest(); req->RequestMethod = "POST"; req->RequestUrl = url; req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password)); req->AddHeader("Accept", "application/json"); m_Connection->SubmitRequest(req, boost::bind(AutocompleteScriptHttpCompletionCallback, _1, _2, callback)); } catch (const std::exception& ex) { callback(boost::current_exception(), Array::Ptr()); } } void ApiClient::AutocompleteScriptHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const AutocompleteScriptCompletionCallback& callback) { Dictionary::Ptr result; String body; char buffer[1024]; size_t count; while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); try { if (response.StatusCode < 200 || response.StatusCode > 299) { std::string message = "HTTP request failed; Code: " + Convert::ToString(response.StatusCode) + "; Body: " + body; BOOST_THROW_EXCEPTION(ScriptError(message)); } result = JsonDecode(body); Array::Ptr results = result->Get("results"); Array::Ptr suggestions; String errorMessage = "Unexpected result from API."; if (results && results->GetLength() > 0) { Dictionary::Ptr resultInfo = results->Get(0); errorMessage = resultInfo->Get("status"); if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299) suggestions = resultInfo->Get("suggestions"); else BOOST_THROW_EXCEPTION(ScriptError(errorMessage)); } callback(boost::exception_ptr(), suggestions); } catch (const std::exception& ex) { callback(boost::current_exception(), Array::Ptr()); } } icinga2-2.8.1/lib/remote/apiclient.hpp000066400000000000000000000105401322762156600175720ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APICLIENT_H #define APICLIENT_H #include "remote/httpclientconnection.hpp" #include "base/value.hpp" #include "base/exception.hpp" #include namespace icinga { struct ApiFieldAttributes { public: bool Config; bool Navigation; bool NoUserModify; bool NouserView; bool Required; bool State; }; class ApiType; struct ApiField { public: String Name; int ID; int ArrayRank; ApiFieldAttributes FieldAttributes; String TypeName; intrusive_ptr Type; }; class I2_REMOTE_API ApiType : public Object { public: DECLARE_PTR_TYPEDEFS(ApiType); String Name; String PluralName; String BaseName; ApiType::Ptr Base; bool Abstract; std::map Fields; std::vector PrototypeKeys; }; struct ApiObjectReference { public: String Name; String Type; }; struct I2_REMOTE_API ApiObject : public Object { public: DECLARE_PTR_TYPEDEFS(ApiObject); String Name; String Type; std::map Attrs; std::vector UsedBy; }; class I2_REMOTE_API ApiClient : public Object { public: DECLARE_PTR_TYPEDEFS(ApiClient); ApiClient(const String& host, const String& port, const String& user, const String& password); typedef boost::function&)> TypesCompletionCallback; void GetTypes(const TypesCompletionCallback& callback) const; typedef boost::function&)> ObjectsCompletionCallback; void GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback, const std::vector& names = std::vector(), const std::vector& attrs = std::vector(), const std::vector& joins = std::vector(), bool all_joins = false) const; typedef boost::function ExecuteScriptCompletionCallback; void ExecuteScript(const String& session, const String& command, bool sandboxed, const ExecuteScriptCompletionCallback& callback) const; typedef boost::function AutocompleteScriptCompletionCallback; void AutocompleteScript(const String& session, const String& command, bool sandboxed, const AutocompleteScriptCompletionCallback& callback) const; private: HttpClientConnection::Ptr m_Connection; String m_User; String m_Password; static void TypesHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const TypesCompletionCallback& callback); static void ObjectsHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const ObjectsCompletionCallback& callback); static void ExecuteScriptHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const ExecuteScriptCompletionCallback& callback); static void AutocompleteScriptHttpCompletionCallback(HttpRequest& request, HttpResponse& response, const AutocompleteScriptCompletionCallback& callback); }; } #endif /* APICLIENT_H */ icinga2-2.8.1/lib/remote/apifunction.cpp000066400000000000000000000043121322762156600201340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apifunction.hpp" #include "base/singleton.hpp" using namespace icinga; ApiFunction::ApiFunction(const Callback& function) : m_Callback(function) { } Value ApiFunction::Invoke(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& arguments) { return m_Callback(origin, arguments); } ApiFunction::Ptr ApiFunction::GetByName(const String& name) { return ApiFunctionRegistry::GetInstance()->GetItem(name); } void ApiFunction::Register(const String& name, const ApiFunction::Ptr& function) { ApiFunctionRegistry::GetInstance()->Register(name, function); } void ApiFunction::Unregister(const String& name) { ApiFunctionRegistry::GetInstance()->Unregister(name); } ApiFunctionRegistry *ApiFunctionRegistry::GetInstance(void) { return Singleton::GetInstance(); } icinga2-2.8.1/lib/remote/apifunction.hpp000066400000000000000000000053001322762156600201370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APIFUNCTION_H #define APIFUNCTION_H #include "remote/i2-remote.hpp" #include "remote/messageorigin.hpp" #include "base/registry.hpp" #include "base/value.hpp" #include "base/dictionary.hpp" #include #include namespace icinga { /** * An API function. * * @ingroup base */ class I2_REMOTE_API ApiFunction : public Object { public: DECLARE_PTR_TYPEDEFS(ApiFunction); typedef boost::function Callback; ApiFunction(const Callback& function); Value Invoke(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& arguments); static ApiFunction::Ptr GetByName(const String& name); static void Register(const String& name, const ApiFunction::Ptr& function); static void Unregister(const String& name); private: Callback m_Callback; }; /** * A registry for API functions. * * @ingroup base */ class I2_REMOTE_API ApiFunctionRegistry : public Registry { public: static ApiFunctionRegistry *GetInstance(void); }; #define REGISTER_APIFUNCTION(name, ns, callback) \ INITIALIZE_ONCE([]() { \ ApiFunction::Ptr func = new ApiFunction(callback); \ ApiFunctionRegistry::GetInstance()->Register(#ns "::" #name, func); \ }) } #endif /* APIFUNCTION_H */ icinga2-2.8.1/lib/remote/apilistener-configsync.cpp000066400000000000000000000334161322762156600223030ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "remote/configobjectutility.hpp" #include "remote/jsonrpc.hpp" #include "base/configtype.hpp" #include "base/json.hpp" #include "base/convert.hpp" #include "config/vmops.hpp" #include #include #include using namespace icinga; REGISTER_APIFUNCTION(UpdateObject, config, &ApiListener::ConfigUpdateObjectAPIHandler); REGISTER_APIFUNCTION(DeleteObject, config, &ApiListener::ConfigDeleteObjectAPIHandler); INITIALIZE_ONCE([]() { ConfigObject::OnActiveChanged.connect(&ApiListener::ConfigUpdateObjectHandler); ConfigObject::OnVersionChanged.connect(&ApiListener::ConfigUpdateObjectHandler); }); void ApiListener::ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; if (object->IsActive()) { /* Sync object config */ listener->UpdateConfigObject(object, cookie); } else if (!object->IsActive() && object->GetExtension("ConfigObjectDeleted")) { /* Delete object */ listener->DeleteConfigObject(object, cookie); } } Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Log(LogNotice, "ApiListener") << "Received update for object: " << JsonEncode(params); /* check permissions */ ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return Empty; String objType = params->Get("type"); String objName = params->Get("name"); Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); /* discard messages if the client is not configured on this node */ if (!endpoint) { Log(LogNotice, "ApiListener") << "Discarding 'config update object' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } /* discard messages if the sender is in a child zone */ if (!Zone::GetLocalZone()->IsChildOf(endpoint->GetZone())) { Log(LogNotice, "ApiListener") << "Discarding 'config update object' message from '" << origin->FromClient->GetIdentity() << "' for object '" << objName << "' of type '" << objType << "'. Sender is in a child zone."; return Empty; } /* ignore messages if the endpoint does not accept config */ if (!listener->GetAcceptConfig()) { Log(LogWarning, "ApiListener") << "Ignoring config update from '" << origin->FromClient->GetIdentity() << "' for object '" << objName << "' of type '" << objType << "'. '" << listener->GetName() << "' does not accept config."; return Empty; } /* update the object */ double objVersion = params->Get("version"); Type::Ptr ptype = Type::GetByName(objType); ConfigType *ctype = dynamic_cast(ptype.get()); if (!ctype) { Log(LogCritical, "ApiListener") << "Config type '" << objType << "' does not exist."; return Empty; } ConfigObject::Ptr object = ctype->GetObject(objName); String config = params->Get("config"); bool newObject = false; if (!object && !config.IsEmpty()) { newObject = true; /* object does not exist, create it through the API */ Array::Ptr errors = new Array(); if (!ConfigObjectUtility::CreateObject(ptype, objName, config, errors)) { Log(LogCritical, "ApiListener") << "Could not create object '" << objName << "':"; ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "ApiListener", error); } return Empty; } object = ctype->GetObject(objName); if (!object) return Empty; /* object was created, update its version */ object->SetVersion(objVersion, false, origin); } if (!object) return Empty; /* update object attributes if version was changed or if this is a new object */ if (newObject || objVersion <= object->GetVersion()) { Log(LogNotice, "ApiListener") << "Discarding config update for object '" << object->GetName() << "': Object version " << std::fixed << object->GetVersion() << " is more recent than the received version " << std::fixed << objVersion << "."; return Empty; } Log(LogNotice, "ApiListener") << "Processing config update for object '" << object->GetName() << "': Object version " << object->GetVersion() << " is older than the received version " << objVersion << "."; Dictionary::Ptr modified_attributes = params->Get("modified_attributes"); if (modified_attributes) { ObjectLock olock(modified_attributes); for (const Dictionary::Pair& kv : modified_attributes) { /* update all modified attributes * but do not update the object version yet. * This triggers cluster events otherwise. */ object->ModifyAttribute(kv.first, kv.second, false); } } /* check whether original attributes changed and restore them locally */ Array::Ptr newOriginalAttributes = params->Get("original_attributes"); Dictionary::Ptr objOriginalAttributes = object->GetOriginalAttributes(); if (newOriginalAttributes && objOriginalAttributes) { std::vector restoreAttrs; { ObjectLock xlock(objOriginalAttributes); for (const Dictionary::Pair& kv : objOriginalAttributes) { /* original attribute was removed, restore it */ if (!newOriginalAttributes->Contains(kv.first)) restoreAttrs.push_back(kv.first); } } for (const String& key : restoreAttrs) { /* do not update the object version yet. */ object->RestoreAttribute(key, false); } } /* keep the object version in sync with the sender */ object->SetVersion(objVersion, false, origin); return Empty; } Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Log(LogNotice, "ApiListener") << "Received update for object: " << JsonEncode(params); /* check permissions */ ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return Empty; if (!listener->GetAcceptConfig()) { Log(LogWarning, "ApiListener") << "Ignoring config update. '" << listener->GetName() << "' does not accept config."; return Empty; } Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) { Log(LogNotice, "ApiListener") << "Discarding 'config update object' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } /* discard messages if the sender is in a child zone */ if (!Zone::GetLocalZone()->IsChildOf(endpoint->GetZone())) { Log(LogWarning, "ApiListener") << "Discarding 'config update object' message from '" << origin->FromClient->GetIdentity() << "'."; return Empty; } /* delete the object */ Type::Ptr ptype = Type::GetByName(params->Get("type")); ConfigType *ctype = dynamic_cast(ptype.get()); if (!ctype) { Log(LogCritical, "ApiListener") << "Config type '" << params->Get("type") << "' does not exist."; return Empty; } ConfigObject::Ptr object = ctype->GetObject(params->Get("name")); if (!object) { Log(LogNotice, "ApiListener") << "Could not delete non-existent object '" << params->Get("name") << "' with type '" << params->Get("type") << "'."; return Empty; } if (object->GetPackage() != "_api") { Log(LogCritical, "ApiListener") << "Could not delete object '" << object->GetName() << "': Not created by the API."; return Empty; } Array::Ptr errors = new Array(); if (!ConfigObjectUtility::DeleteObject(object, true, errors)) { Log(LogCritical, "ApiListener", "Could not delete object:"); ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "ApiListener", error); } } return Empty; } void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, const JsonRpcConnection::Ptr& client) { /* only send objects to zones which have access to the object */ if (client) { Zone::Ptr target_zone = client->GetEndpoint()->GetZone(); if (target_zone && !target_zone->CanAccessObject(object)) { Log(LogDebug, "ApiListener") << "Not sending 'update config' message to unauthorized zone '" << target_zone->GetName() << "'" << " for object: '" << object->GetName() << "'."; return; } } if (object->GetPackage() != "_api" && object->GetVersion() == 0) return; Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "config::UpdateObject"); Dictionary::Ptr params = new Dictionary(); params->Set("name", object->GetName()); params->Set("type", object->GetReflectionType()->GetName()); params->Set("version", object->GetVersion()); if (object->GetPackage() == "_api") { String file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName()); std::ifstream fp(file.CStr(), std::ifstream::binary); if (!fp) return; String content((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); params->Set("config", content); } Dictionary::Ptr original_attributes = object->GetOriginalAttributes(); Dictionary::Ptr modified_attributes = new Dictionary(); Array::Ptr newOriginalAttributes = new Array(); if (original_attributes) { ObjectLock olock(original_attributes); for (const Dictionary::Pair& kv : original_attributes) { std::vector tokens; boost::algorithm::split(tokens, kv.first, boost::is_any_of(".")); Value value = object; for (const String& token : tokens) { value = VMOps::GetField(value, token); } modified_attributes->Set(kv.first, value); newOriginalAttributes->Add(kv.first); } } params->Set("modified_attributes", modified_attributes); /* only send the original attribute keys */ params->Set("original_attributes", newOriginalAttributes); message->Set("params", params); #ifdef I2_DEBUG Log(LogDebug, "ApiListener") << "Sent update for object '" << object->GetName() << "': " << JsonEncode(params); #endif /* I2_DEBUG */ if (client) JsonRpc::SendMessage(client->GetStream(), message); else { Zone::Ptr target = static_pointer_cast(object->GetZone()); if (!target) target = Zone::GetLocalZone(); RelayMessage(origin, target, message, false); } } void ApiListener::DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, const JsonRpcConnection::Ptr& client) { if (object->GetPackage() != "_api") return; /* only send objects to zones which have access to the object */ if (client) { Zone::Ptr target_zone = client->GetEndpoint()->GetZone(); if (target_zone && !target_zone->CanAccessObject(object)) { Log(LogDebug, "ApiListener") << "Not sending 'delete config' message to unauthorized zone '" << target_zone->GetName() << "'" << " for object: '" << object->GetName() << "'."; return; } } Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "config::DeleteObject"); Dictionary::Ptr params = new Dictionary(); params->Set("name", object->GetName()); params->Set("type", object->GetReflectionType()->GetName()); params->Set("version", object->GetVersion()); message->Set("params", params); #ifdef I2_DEBUG Log(LogDebug, "ApiListener") << "Sent delete for object '" << object->GetName() << "': " << JsonEncode(params); #endif /* I2_DEBUG */ if (client) JsonRpc::SendMessage(client->GetStream(), message); else { Zone::Ptr target = static_pointer_cast(object->GetZone()); if (!target) target = Zone::GetLocalZone(); RelayMessage(origin, target, message, false); } } /* Initial sync on connect for new endpoints */ void ApiListener::SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient) { Endpoint::Ptr endpoint = aclient->GetEndpoint(); ASSERT(endpoint); Zone::Ptr azone = endpoint->GetZone(); Log(LogInformation, "ApiListener") << "Syncing runtime objects to endpoint '" << endpoint->GetName() << "'."; for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { /* don't sync objects for non-matching parent-child zones */ if (!azone->CanAccessObject(object)) continue; /* send the config object to the connected client */ UpdateConfigObject(object, MessageOrigin::Ptr(), aclient); } } Log(LogInformation, "ApiListener") << "Finished syncing runtime objects to endpoint '" << endpoint->GetName() << "'."; } icinga2-2.8.1/lib/remote/apilistener-filesync.cpp000066400000000000000000000255311322762156600217540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "config/configcompiler.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/convert.hpp" #include "base/exception.hpp" #include #include using namespace icinga; REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler); void ApiListener::ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file) { CONTEXT("Creating config update for file '" + file + "'"); Log(LogNotice, "ApiListener") << "Creating config update for file '" << file << "'."; std::ifstream fp(file.CStr(), std::ifstream::binary); if (!fp) return; String content((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); Dictionary::Ptr update; if (Utility::Match("*.conf", file)) update = config.UpdateV1; else update = config.UpdateV2; update->Set(file.SubStr(path.GetLength()), content); } Dictionary::Ptr ApiListener::MergeConfigUpdate(const ConfigDirInformation& config) { Dictionary::Ptr result = new Dictionary(); if (config.UpdateV1) config.UpdateV1->CopyTo(result); if (config.UpdateV2) config.UpdateV2->CopyTo(result); return result; } ConfigDirInformation ApiListener::LoadConfigDir(const String& dir) { ConfigDirInformation config; config.UpdateV1 = new Dictionary(); config.UpdateV2 = new Dictionary(); Utility::GlobRecursive(dir, "*", boost::bind(&ApiListener::ConfigGlobHandler, boost::ref(config), dir, _1), GlobFile); return config; } bool ApiListener::UpdateConfigDir(const ConfigDirInformation& oldConfigInfo, const ConfigDirInformation& newConfigInfo, const String& configDir, bool authoritative) { bool configChange = false; Dictionary::Ptr oldConfig = MergeConfigUpdate(oldConfigInfo); Dictionary::Ptr newConfig = MergeConfigUpdate(newConfigInfo); double oldTimestamp; if (!oldConfig->Contains("/.timestamp")) oldTimestamp = 0; else oldTimestamp = oldConfig->Get("/.timestamp"); double newTimestamp; if (!newConfig->Contains("/.timestamp")) newTimestamp = Utility::GetTime(); else newTimestamp = newConfig->Get("/.timestamp"); /* skip update if our configuration files are more recent */ if (oldTimestamp >= newTimestamp) { Log(LogNotice, "ApiListener") << "Our configuration is more recent than the received configuration update." << " Ignoring configuration file update for path '" << configDir << "'. Current timestamp '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", oldTimestamp) << "' (" << std::fixed << std::setprecision(6) << oldTimestamp << ") >= received timestamp '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", newTimestamp) << "' (" << newTimestamp << ")."; return false; } size_t numBytes = 0; { ObjectLock olock(newConfig); for (const Dictionary::Pair& kv : newConfig) { if (oldConfig->Get(kv.first) != kv.second) { if (!Utility::Match("*/.timestamp", kv.first)) configChange = true; String path = configDir + "/" + kv.first; Log(LogInformation, "ApiListener") << "Updating configuration file: " << path; /* Sync string content only. */ String content = kv.second; /* Generate a directory tree (zones/1/2/3 might not exist yet). */ Utility::MkDirP(Utility::DirName(path), 0755); std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fp << content; fp.close(); numBytes += content.GetLength(); } } } Log(LogInformation, "ApiListener") << "Applying configuration file update for path '" << configDir << "' (" << numBytes << " Bytes). Received timestamp '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", newTimestamp) << "' (" << std::fixed << std::setprecision(6) << newTimestamp << "), Current timestamp '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", oldTimestamp) << "' (" << oldTimestamp << ")."; ObjectLock xlock(oldConfig); for (const Dictionary::Pair& kv : oldConfig) { if (!newConfig->Contains(kv.first)) { configChange = true; String path = configDir + "/" + kv.first; (void) unlink(path.CStr()); } } String tsPath = configDir + "/.timestamp"; if (!Utility::PathExists(tsPath)) { std::ofstream fp(tsPath.CStr(), std::ofstream::out | std::ostream::trunc); fp << std::fixed << newTimestamp; fp.close(); } if (authoritative) { String authPath = configDir + "/.authoritative"; if (!Utility::PathExists(authPath)) { std::ofstream fp(authPath.CStr(), std::ofstream::out | std::ostream::trunc); fp.close(); } } return configChange; } void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const { ConfigDirInformation newConfigInfo; newConfigInfo.UpdateV1 = new Dictionary(); newConfigInfo.UpdateV2 = new Dictionary(); for (const ZoneFragment& zf : ConfigCompiler::GetZoneDirs(zone->GetName())) { ConfigDirInformation newConfigPart = LoadConfigDir(zf.Path); { ObjectLock olock(newConfigPart.UpdateV1); for (const Dictionary::Pair& kv : newConfigPart.UpdateV1) { newConfigInfo.UpdateV1->Set("/" + zf.Tag + kv.first, kv.second); } } { ObjectLock olock(newConfigPart.UpdateV2); for (const Dictionary::Pair& kv : newConfigPart.UpdateV2) { newConfigInfo.UpdateV2->Set("/" + zf.Tag + kv.first, kv.second); } } } int sumUpdates = newConfigInfo.UpdateV1->GetLength() + newConfigInfo.UpdateV2->GetLength(); if (sumUpdates == 0) return; String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName(); Log(LogInformation, "ApiListener") << "Copying " << sumUpdates << " zone configuration files for zone '" << zone->GetName() << "' to '" << oldDir << "'."; Utility::MkDirP(oldDir, 0700); ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir); UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, true); } void ApiListener::SyncZoneDirs(void) const { for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { try { SyncZoneDir(zone); } catch (const std::exception&) { continue; } } } void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient) { Endpoint::Ptr endpoint = aclient->GetEndpoint(); ASSERT(endpoint); Zone::Ptr azone = endpoint->GetZone(); Zone::Ptr lzone = Zone::GetLocalZone(); /* don't try to send config updates to our master */ if (!azone->IsChildOf(lzone)) return; Dictionary::Ptr configUpdateV1 = new Dictionary(); Dictionary::Ptr configUpdateV2 = new Dictionary(); String zonesDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones"; for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { String zoneDir = zonesDir + "/" + zone->GetName(); if (!zone->IsChildOf(azone) && !zone->IsGlobal()) continue; if (!Utility::PathExists(zoneDir)) continue; Log(LogInformation, "ApiListener") << "Syncing configuration files for " << (zone->IsGlobal() ? "global " : "") << "zone '" << zone->GetName() << "' to endpoint '" << endpoint->GetName() << "'."; ConfigDirInformation config = LoadConfigDir(zonesDir + "/" + zone->GetName()); configUpdateV1->Set(zone->GetName(), config.UpdateV1); configUpdateV2->Set(zone->GetName(), config.UpdateV2); } Dictionary::Ptr params = new Dictionary(); params->Set("update", configUpdateV1); params->Set("update_v2", configUpdateV2); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "config::Update"); message->Set("params", params); aclient->SendMessage(message); } Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { if (!origin->FromClient->GetEndpoint() || (origin->FromZone && !Zone::GetLocalZone()->IsChildOf(origin->FromZone))) return Empty; ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { Log(LogCritical, "ApiListener", "No instance available."); return Empty; } if (!listener->GetAcceptConfig()) { Log(LogWarning, "ApiListener") << "Ignoring config update. '" << listener->GetName() << "' does not accept config."; return Empty; } Log(LogInformation, "ApiListener") << "Applying config update from endpoint '" << origin->FromClient->GetEndpoint()->GetName() << "' of zone '" << GetFromZoneName(origin->FromZone) << "'."; Dictionary::Ptr updateV1 = params->Get("update"); Dictionary::Ptr updateV2 = params->Get("update_v2"); bool configChange = false; ObjectLock olock(updateV1); for (const Dictionary::Pair& kv : updateV1) { Zone::Ptr zone = Zone::GetByName(kv.first); if (!zone) { Log(LogWarning, "ApiListener") << "Ignoring config update for unknown zone '" << kv.first << "'."; continue; } if (ConfigCompiler::HasZoneConfigAuthority(kv.first)) { Log(LogWarning, "ApiListener") << "Ignoring config update for zone '" << kv.first << "' because we have an authoritative version of the zone's config."; continue; } String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName(); Utility::MkDirP(oldDir, 0700); ConfigDirInformation newConfigInfo; newConfigInfo.UpdateV1 = kv.second; if (updateV2) newConfigInfo.UpdateV2 = updateV2->Get(kv.first); Dictionary::Ptr newConfig = kv.second; ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir); if (UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, false)) configChange = true; } if (configChange) { Log(LogInformation, "ApiListener", "Restarting after configuration change."); Application::RequestRestart(); } return Empty; } icinga2-2.8.1/lib/remote/apilistener.cpp000066400000000000000000001211731322762156600201410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apilistener.hpp" #include "remote/apilistener.tcpp" #include "remote/jsonrpcconnection.hpp" #include "remote/endpoint.hpp" #include "remote/jsonrpc.hpp" #include "remote/apifunction.hpp" #include "base/convert.hpp" #include "base/netstring.hpp" #include "base/json.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/stdiostream.hpp" #include "base/perfdatavalue.hpp" #include "base/application.hpp" #include "base/context.hpp" #include "base/statsfunction.hpp" #include "base/exception.hpp" #include using namespace icinga; REGISTER_TYPE(ApiListener); boost::signals2::signal ApiListener::OnMasterChanged; ApiListener::Ptr ApiListener::m_Instance; REGISTER_STATSFUNCTION(ApiListener, &ApiListener::StatsFunc); REGISTER_APIFUNCTION(Hello, icinga, &ApiListener::HelloAPIHandler); ApiListener::ApiListener(void) : m_SyncQueue(0, 4), m_LogMessageCount(0) { m_RelayQueue.SetName("ApiListener, RelayQueue"); m_SyncQueue.SetName("ApiListener, SyncQueue"); } String ApiListener::GetApiDir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/api/"; } String ApiListener::GetCertsDir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/certs/"; } String ApiListener::GetCaDir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/ca/"; } String ApiListener::GetCertificateRequestsDir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/certificate-requests/"; } String ApiListener::GetDefaultCertPath(void) { return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".crt"; } String ApiListener::GetDefaultKeyPath(void) { return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".key"; } String ApiListener::GetDefaultCaPath(void) { return GetCertsDir() + "/ca.crt"; } void ApiListener::CopyCertificateFile(const String& oldCertPath, const String& newCertPath) { struct stat st1, st2; if (!oldCertPath.IsEmpty() && stat(oldCertPath.CStr(), &st1) >= 0 && (stat(newCertPath.CStr(), &st2) < 0 || st1.st_mtime > st2.st_mtime)) { Log(LogWarning, "ApiListener") << "Copying '" << oldCertPath << "' certificate file to '" << newCertPath << "'"; Utility::MkDirP(Utility::DirName(newCertPath), 0700); Utility::CopyFile(oldCertPath, newCertPath); } } void ApiListener::OnConfigLoaded(void) { if (m_Instance) BOOST_THROW_EXCEPTION(ScriptError("Only one ApiListener object is allowed.", GetDebugInfo())); m_Instance = this; String defaultCertPath = GetDefaultCertPath(); String defaultKeyPath = GetDefaultKeyPath(); String defaultCaPath = GetDefaultCaPath(); /* Migrate certificate location < 2.8 to the new default path. */ String oldCertPath = GetCertPath(); String oldKeyPath = GetKeyPath(); String oldCaPath = GetCaPath(); CopyCertificateFile(oldCertPath, defaultCertPath); CopyCertificateFile(oldKeyPath, defaultKeyPath); CopyCertificateFile(oldCaPath, defaultCaPath); if (!oldCertPath.IsEmpty() && !oldKeyPath.IsEmpty() && !oldCaPath.IsEmpty()) { Log(LogWarning, "ApiListener", "Please read the upgrading documentation for v2.8: https://www.icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/"); } /* set up SSL context */ boost::shared_ptr cert; try { cert = GetX509Certificate(defaultCertPath); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '" + defaultCertPath + "'.", GetDebugInfo())); } try { SetIdentity(GetCertificateCN(cert)); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '" + defaultCertPath + "'.", GetDebugInfo())); } Log(LogInformation, "ApiListener") << "My API identity: " << GetIdentity(); UpdateSSLContext(); } void ApiListener::UpdateSSLContext(void) { boost::shared_ptr context; try { context = MakeSSLContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath()); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '" + GetDefaultCertPath() + "' key path: '" + GetDefaultKeyPath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo())); } if (!GetCrlPath().IsEmpty()) { try { AddCRLToSSLContext(context, GetCrlPath()); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot add certificate revocation list to SSL context for crl path: '" + GetCrlPath() + "'.", GetDebugInfo())); } } if (!GetCipherList().IsEmpty()) { try { SetCipherListToSSLContext(context, GetCipherList()); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot set cipher list to SSL context for cipher list: '" + GetCipherList() + "'.", GetDebugInfo())); } } if (!GetTlsProtocolmin().IsEmpty()){ try { SetTlsProtocolminToSSLContext(context, GetTlsProtocolmin()); } catch (const std::exception&) { BOOST_THROW_EXCEPTION(ScriptError("Cannot set minimum TLS protocol version to SSL context with tls_protocolmin: '" + GetTlsProtocolmin() + "'.", GetDebugInfo())); } } m_SSLContext = context; for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { client->Disconnect(); } } for (const JsonRpcConnection::Ptr& client : m_AnonymousClients) { client->Disconnect(); } } void ApiListener::OnAllConfigLoaded(void) { m_LocalEndpoint = Endpoint::GetByName(GetIdentity()); if (!m_LocalEndpoint) BOOST_THROW_EXCEPTION(ScriptError("Endpoint object for '" + GetIdentity() + "' is missing.", GetDebugInfo())); } /** * Starts the component. */ void ApiListener::Start(bool runtimeCreated) { Log(LogInformation, "ApiListener") << "'" << GetName() << "' started."; SyncZoneDirs(); ObjectImpl::Start(runtimeCreated); { boost::mutex::scoped_lock(m_LogLock); RotateLogFile(); OpenLogFile(); } /* create the primary JSON-RPC listener */ if (!AddListener(GetBindHost(), GetBindPort())) { Log(LogCritical, "ApiListener") << "Cannot add listener on host '" << GetBindHost() << "' for port '" << GetBindPort() << "'."; Application::Exit(EXIT_FAILURE); } m_Timer = new Timer(); m_Timer->OnTimerExpired.connect(boost::bind(&ApiListener::ApiTimerHandler, this)); m_Timer->SetInterval(5); m_Timer->Start(); m_Timer->Reschedule(0); m_ReconnectTimer = new Timer(); m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&ApiListener::ApiReconnectTimerHandler, this)); m_ReconnectTimer->SetInterval(60); m_ReconnectTimer->Start(); m_ReconnectTimer->Reschedule(0); m_AuthorityTimer = new Timer(); m_AuthorityTimer->OnTimerExpired.connect(boost::bind(&ApiListener::UpdateObjectAuthority)); m_AuthorityTimer->SetInterval(30); m_AuthorityTimer->Start(); m_CleanupCertificateRequestsTimer = new Timer(); m_CleanupCertificateRequestsTimer->OnTimerExpired.connect(boost::bind(&ApiListener::CleanupCertificateRequestsTimerHandler, this)); m_CleanupCertificateRequestsTimer->SetInterval(3600); m_CleanupCertificateRequestsTimer->Start(); m_CleanupCertificateRequestsTimer->Reschedule(0); OnMasterChanged(true); } void ApiListener::Stop(bool runtimeDeleted) { ObjectImpl::Stop(runtimeDeleted); Log(LogInformation, "ApiListener") << "'" << GetName() << "' stopped."; boost::mutex::scoped_lock lock(m_LogLock); CloseLogFile(); } ApiListener::Ptr ApiListener::GetInstance(void) { return m_Instance; } Endpoint::Ptr ApiListener::GetMaster(void) const { Zone::Ptr zone = Zone::GetLocalZone(); if (!zone) return Endpoint::Ptr(); std::vector names; for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) if (endpoint->GetConnected() || endpoint->GetName() == GetIdentity()) names.push_back(endpoint->GetName()); std::sort(names.begin(), names.end()); return Endpoint::GetByName(*names.begin()); } bool ApiListener::IsMaster(void) const { Endpoint::Ptr master = GetMaster(); if (!master) return false; return master == GetLocalEndpoint(); } /** * Creates a new JSON-RPC listener on the specified port. * * @param node The host the listener should be bound to. * @param service The port to listen on. */ bool ApiListener::AddListener(const String& node, const String& service) { ObjectLock olock(this); boost::shared_ptr sslContext = m_SSLContext; if (!sslContext) { Log(LogCritical, "ApiListener", "SSL context is required for AddListener()"); return false; } Log(LogInformation, "ApiListener") << "Adding new listener on port '" << service << "'"; TcpSocket::Ptr server = new TcpSocket(); try { server->Bind(node, service, AF_UNSPEC); } catch (const std::exception&) { Log(LogCritical, "ApiListener") << "Cannot bind TCP socket for host '" << node << "' on port '" << service << "'."; return false; } boost::thread thread(boost::bind(&ApiListener::ListenerThreadProc, this, server)); thread.detach(); m_Servers.insert(server); return true; } void ApiListener::ListenerThreadProc(const Socket::Ptr& server) { Utility::SetThreadName("API Listener"); server->Listen(); for (;;) { try { Socket::Ptr client = server->Accept(); boost::thread thread(boost::bind(&ApiListener::NewClientHandler, this, client, String(), RoleServer)); thread.detach(); } catch (const std::exception&) { Log(LogCritical, "ApiListener", "Cannot accept new connection."); } } } /** * Creates a new JSON-RPC client and connects to the specified endpoint. * * @param endpoint The endpoint. */ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint) { { ObjectLock olock(this); boost::shared_ptr sslContext = m_SSLContext; if (!sslContext) { Log(LogCritical, "ApiListener", "SSL context is required for AddConnection()"); return; } } String host = endpoint->GetHost(); String port = endpoint->GetPort(); Log(LogInformation, "ApiListener") << "Reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host << "' and port '" << port << "'"; TcpSocket::Ptr client = new TcpSocket(); try { endpoint->SetConnecting(true); client->Connect(host, port); NewClientHandler(client, endpoint->GetName(), RoleClient); endpoint->SetConnecting(false); } catch (const std::exception& ex) { endpoint->SetConnecting(false); client->Close(); std::ostringstream info; info << "Cannot connect to host '" << host << "' on port '" << port << "'"; Log(LogCritical, "ApiListener", info.str()); Log(LogDebug, "ApiListener") << info.str() << "\n" << DiagnosticInformation(ex); } Log(LogInformation, "ApiListener") << "Finished reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host << "' and port '" << port << "'"; } void ApiListener::NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role) { try { NewClientHandlerInternal(client, hostname, role); } catch (const std::exception& ex) { Log(LogCritical, "ApiListener") << "Exception while handling new API client connection: " << DiagnosticInformation(ex, false); Log(LogDebug, "ApiListener") << "Exception while handling new API client connection: " << DiagnosticInformation(ex); } } /** * Processes a new client connection. * * @param client The new client. */ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const String& hostname, ConnectionRole role) { CONTEXT("Handling new API client connection"); String conninfo; if (role == RoleClient) conninfo = "to"; else conninfo = "from"; conninfo += " " + client->GetPeerAddress(); TlsStream::Ptr tlsStream; { ObjectLock olock(this); try { tlsStream = new TlsStream(client, hostname, role, m_SSLContext); } catch (const std::exception&) { Log(LogCritical, "ApiListener") << "Cannot create TLS stream from client connection (" << conninfo << ")"; return; } } try { tlsStream->Handshake(); } catch (const std::exception& ex) { Log(LogCritical, "ApiListener") << "Client TLS handshake failed (" << conninfo << ")"; return; } boost::shared_ptr cert = tlsStream->GetPeerCertificate(); String identity; Endpoint::Ptr endpoint; bool verify_ok = false; if (cert) { try { identity = GetCertificateCN(cert); } catch (const std::exception&) { Log(LogCritical, "ApiListener") << "Cannot get certificate common name from cert path: '" << GetDefaultCertPath() << "'."; return; } verify_ok = tlsStream->IsVerifyOK(); if (!hostname.IsEmpty()) { if (identity != hostname) { Log(LogWarning, "ApiListener") << "Unexpected certificate common name while connecting to endpoint '" << hostname << "': got '" << identity << "'"; return; } else if (!verify_ok) { Log(LogWarning, "ApiListener") << "Certificate validation failed for endpoint '" << hostname << "': " << tlsStream->GetVerifyError(); } } if (verify_ok) endpoint = Endpoint::GetByName(identity); { Log log(LogInformation, "ApiListener"); log << "New client connection for identity '" << identity << "' " << conninfo; if (!verify_ok) log << " (certificate validation failed: " << tlsStream->GetVerifyError() << ")"; else if (!endpoint) log << " (no Endpoint object found for identity)"; } } else { Log(LogInformation, "ApiListener") << "New client connection " << conninfo << " (no client certificate)"; } ClientType ctype; if (role == RoleClient) { Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "icinga::Hello"); message->Set("params", new Dictionary()); JsonRpc::SendMessage(tlsStream, message); ctype = ClientJsonRpc; } else { tlsStream->WaitForData(5); if (!tlsStream->IsDataAvailable()) { Log(LogWarning, "ApiListener") << "No data received on new API connection for identity '" << identity << "'. Ensure that the remote endpoints are properly configured in a cluster setup."; return; } char firstByte; tlsStream->Peek(&firstByte, 1, false); if (firstByte >= '0' && firstByte <= '9') ctype = ClientJsonRpc; else ctype = ClientHttp; } if (ctype == ClientJsonRpc) { Log(LogNotice, "ApiListener", "New JSON-RPC client"); JsonRpcConnection::Ptr aclient = new JsonRpcConnection(identity, verify_ok, tlsStream, role); aclient->Start(); if (endpoint) { bool needSync = !endpoint->GetConnected(); endpoint->AddClient(aclient); m_SyncQueue.Enqueue(boost::bind(&ApiListener::SyncClient, this, aclient, endpoint, needSync)); } else AddAnonymousClient(aclient); } else { Log(LogNotice, "ApiListener", "New HTTP client"); HttpServerConnection::Ptr aclient = new HttpServerConnection(identity, verify_ok, tlsStream); aclient->Start(); AddHttpClient(aclient); } } void ApiListener::SyncClient(const JsonRpcConnection::Ptr& aclient, const Endpoint::Ptr& endpoint, bool needSync) { Zone::Ptr eZone = endpoint->GetZone(); try { { ObjectLock olock(endpoint); endpoint->SetSyncing(true); } Zone::Ptr myZone = Zone::GetLocalZone(); if (myZone->GetParent() == eZone) { Log(LogInformation, "ApiListener") << "Requesting new certificate for this Icinga instance from endpoint '" << endpoint->GetName() << "'."; JsonRpcConnection::SendCertificateRequest(aclient, MessageOrigin::Ptr(), String()); if (Utility::PathExists(ApiListener::GetCertificateRequestsDir())) Utility::Glob(ApiListener::GetCertificateRequestsDir() + "/*.json", boost::bind(&JsonRpcConnection::SendCertificateRequest, aclient, MessageOrigin::Ptr(), _1), GlobFile); } /* Make sure that the config updates are synced * before the logs are replayed. */ Log(LogInformation, "ApiListener") << "Sending config updates for endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; /* sync zone file config */ SendConfigUpdate(aclient); Log(LogInformation, "ApiListener") << "Finished sending config file updates for endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; /* sync runtime config */ SendRuntimeConfigObjects(aclient); Log(LogInformation, "ApiListener") << "Finished sending runtime config updates for endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; if (!needSync) { ObjectLock olock2(endpoint); endpoint->SetSyncing(false); return; } Log(LogInformation, "ApiListener") << "Sending replay log for endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; ReplayLog(aclient); if (eZone == Zone::GetLocalZone()) UpdateObjectAuthority(); Log(LogInformation, "ApiListener") << "Finished sending replay log for endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; } catch (const std::exception& ex) { { ObjectLock olock2(endpoint); endpoint->SetSyncing(false); } Log(LogCritical, "ApiListener") << "Error while syncing endpoint '" << endpoint->GetName() << "': " << DiagnosticInformation(ex, false); Log(LogDebug, "ApiListener") << "Error while syncing endpoint '" << endpoint->GetName() << "': " << DiagnosticInformation(ex); } Log(LogInformation, "ApiListener") << "Finished syncing endpoint '" << endpoint->GetName() << "' in zone '" << eZone->GetName() << "'."; } void ApiListener::ApiTimerHandler(void) { double now = Utility::GetTime(); std::vector files; Utility::Glob(GetApiDir() + "log/*", boost::bind(&ApiListener::LogGlobHandler, boost::ref(files), _1), GlobFile); std::sort(files.begin(), files.end()); for (int ts : files) { bool need = false; for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { if (endpoint == GetLocalEndpoint()) continue; if (endpoint->GetLogDuration() >= 0 && ts < now - endpoint->GetLogDuration()) continue; if (ts > endpoint->GetLocalLogPosition()) { need = true; break; } } if (!need) { String path = GetApiDir() + "log/" + Convert::ToString(ts); Log(LogNotice, "ApiListener") << "Removing old log file: " << path; (void)unlink(path.CStr()); } } for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { if (!endpoint->GetConnected()) continue; double ts = endpoint->GetRemoteLogPosition(); if (ts == 0) continue; Dictionary::Ptr lparams = new Dictionary(); lparams->Set("log_position", ts); Dictionary::Ptr lmessage = new Dictionary(); lmessage->Set("jsonrpc", "2.0"); lmessage->Set("method", "log::SetLogPosition"); lmessage->Set("params", lparams); double maxTs = 0; for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { if (client->GetTimestamp() > maxTs) maxTs = client->GetTimestamp(); } for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { if (client->GetTimestamp() != maxTs) client->Disconnect(); else client->SendMessage(lmessage); } Log(LogNotice, "ApiListener") << "Setting log position for identity '" << endpoint->GetName() << "': " << Utility::FormatDateTime("%Y/%m/%d %H:%M:%S", ts); } } void ApiListener::ApiReconnectTimerHandler(void) { Zone::Ptr my_zone = Zone::GetLocalZone(); for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { /* don't connect to global zones */ if (zone->GetGlobal()) continue; /* only connect to endpoints in a) the same zone b) our parent zone c) immediate child zones */ if (my_zone != zone && my_zone != zone->GetParent() && zone != my_zone->GetParent()) { Log(LogDebug, "ApiListener") << "Not connecting to Zone '" << zone->GetName() << "' because it's not in the same zone, a parent or a child zone."; continue; } for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) { /* don't connect to ourselves */ if (endpoint == GetLocalEndpoint()) { Log(LogDebug, "ApiListener") << "Not connecting to Endpoint '" << endpoint->GetName() << "' because that's us."; continue; } /* don't try to connect to endpoints which don't have a host and port */ if (endpoint->GetHost().IsEmpty() || endpoint->GetPort().IsEmpty()) { Log(LogDebug, "ApiListener") << "Not connecting to Endpoint '" << endpoint->GetName() << "' because the host/port attributes are missing."; continue; } /* don't try to connect if there's already a connection attempt */ if (endpoint->GetConnecting()) { Log(LogDebug, "ApiListener") << "Not connecting to Endpoint '" << endpoint->GetName() << "' because we're already trying to connect to it."; continue; } /* don't try to connect if we're already connected */ if (endpoint->GetConnected()) { Log(LogDebug, "ApiListener") << "Not connecting to Endpoint '" << endpoint->GetName() << "' because we're already connected to it."; continue; } boost::thread thread(boost::bind(&ApiListener::AddConnection, this, endpoint)); thread.detach(); } } Endpoint::Ptr master = GetMaster(); if (master) Log(LogNotice, "ApiListener") << "Current zone master: " << master->GetName(); std::vector names; for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) if (endpoint->GetConnected()) names.push_back(endpoint->GetName() + " (" + Convert::ToString(endpoint->GetClients().size()) + ")"); Log(LogNotice, "ApiListener") << "Connected endpoints: " << Utility::NaturalJoin(names); } static void CleanupCertificateRequest(const String& path, double expiryTime) { #ifndef _WIN32 struct stat statbuf; if (lstat(path.CStr(), &statbuf) < 0) return; #else /* _WIN32 */ struct _stat statbuf; if (_stat(path.CStr(), &statbuf) < 0) return; #endif /* _WIN32 */ if (statbuf.st_mtime < expiryTime) (void) unlink(path.CStr()); } void ApiListener::CleanupCertificateRequestsTimerHandler(void) { String requestsDir = GetCertificateRequestsDir(); if (Utility::PathExists(requestsDir)) { /* remove certificate requests that are older than a week */ double expiryTime = Utility::GetTime() - 7 * 24 * 60 * 60; Utility::Glob(requestsDir + "/*.json", boost::bind(&CleanupCertificateRequest, _1, expiryTime), GlobFile); } } void ApiListener::RelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log) { if (!IsActive()) return; m_RelayQueue.Enqueue(boost::bind(&ApiListener::SyncRelayMessage, this, origin, secobj, message, log), PriorityNormal, true); } void ApiListener::PersistMessage(const Dictionary::Ptr& message, const ConfigObject::Ptr& secobj) { double ts = message->Get("ts"); ASSERT(ts != 0); Dictionary::Ptr pmessage = new Dictionary(); pmessage->Set("timestamp", ts); pmessage->Set("message", JsonEncode(message)); if (secobj) { Dictionary::Ptr secname = new Dictionary(); secname->Set("type", secobj->GetReflectionType()->GetName()); secname->Set("name", secobj->GetName()); pmessage->Set("secobj", secname); } boost::mutex::scoped_lock lock(m_LogLock); if (m_LogFile) { NetString::WriteStringToStream(m_LogFile, JsonEncode(pmessage)); m_LogMessageCount++; SetLogMessageTimestamp(ts); if (m_LogMessageCount > 50000) { CloseLogFile(); RotateLogFile(); OpenLogFile(); } } } void ApiListener::SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message) { ObjectLock olock(endpoint); if (!endpoint->GetSyncing()) { Log(LogNotice, "ApiListener") << "Sending message '" << message->Get("method") << "' to '" << endpoint->GetName() << "'"; double maxTs = 0; for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { if (client->GetTimestamp() > maxTs) maxTs = client->GetTimestamp(); } for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { if (client->GetTimestamp() != maxTs) continue; client->SendMessage(message); } } } bool ApiListener::RelayMessageOne(const Zone::Ptr& targetZone, const MessageOrigin::Ptr& origin, const Dictionary::Ptr& message, const Endpoint::Ptr& currentMaster) { ASSERT(targetZone); Zone::Ptr myZone = Zone::GetLocalZone(); /* only relay the message to a) the same zone, b) the parent zone and c) direct child zones. Exception is a global zone. */ if (!targetZone->GetGlobal() && targetZone != myZone && targetZone != myZone->GetParent() && targetZone->GetParent() != myZone) { return true; } Endpoint::Ptr myEndpoint = GetLocalEndpoint(); std::vector skippedEndpoints; bool relayed = false, log_needed = false, log_done = false; std::set targetEndpoints; if (targetZone->GetGlobal()) { targetEndpoints = myZone->GetEndpoints(); for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { /* Fetch immediate child zone members */ if (zone->GetParent() == myZone) { std::set endpoints = zone->GetEndpoints(); targetEndpoints.insert(endpoints.begin(), endpoints.end()); } } } else { targetEndpoints = targetZone->GetEndpoints(); } for (const Endpoint::Ptr& endpoint : targetEndpoints) { /* don't relay messages to ourselves */ if (endpoint == GetLocalEndpoint()) continue; log_needed = true; /* don't relay messages to disconnected endpoints */ if (!endpoint->GetConnected()) { if (targetZone == myZone) log_done = false; continue; } log_done = true; /* don't relay the message to the zone through more than one endpoint unless this is our own zone */ if (relayed && targetZone != myZone) { skippedEndpoints.push_back(endpoint); continue; } /* don't relay messages back to the endpoint which we got the message from */ if (origin && origin->FromClient && endpoint == origin->FromClient->GetEndpoint()) { skippedEndpoints.push_back(endpoint); continue; } /* don't relay messages back to the zone which we got the message from */ if (origin && origin->FromZone && targetZone == origin->FromZone) { skippedEndpoints.push_back(endpoint); continue; } /* only relay message to the master if we're not currently the master */ if (currentMaster != myEndpoint && currentMaster != endpoint) { skippedEndpoints.push_back(endpoint); continue; } relayed = true; SyncSendMessage(endpoint, message); } if (!skippedEndpoints.empty()) { double ts = message->Get("ts"); for (const Endpoint::Ptr& endpoint : skippedEndpoints) endpoint->SetLocalLogPosition(ts); } return !log_needed || log_done; } void ApiListener::SyncRelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log) { double ts = Utility::GetTime(); message->Set("ts", ts); Log(LogNotice, "ApiListener") << "Relaying '" << message->Get("method") << "' message"; if (origin && origin->FromZone) message->Set("originZone", origin->FromZone->GetName()); Zone::Ptr target_zone; if (secobj) { if (secobj->GetReflectionType() == Zone::TypeInstance) target_zone = static_pointer_cast(secobj); else target_zone = static_pointer_cast(secobj->GetZone()); } if (!target_zone) target_zone = Zone::GetLocalZone(); Endpoint::Ptr master = GetMaster(); bool need_log = !RelayMessageOne(target_zone, origin, message, master); for (const Zone::Ptr& zone : target_zone->GetAllParents()) { if (!RelayMessageOne(zone, origin, message, master)) need_log = true; } if (log && need_log) PersistMessage(message, secobj); } /* must hold m_LogLock */ void ApiListener::OpenLogFile(void) { String path = GetApiDir() + "log/current"; Utility::MkDirP(Utility::DirName(path), 0750); std::fstream *fp = new std::fstream(path.CStr(), std::fstream::out | std::ofstream::app); if (!fp->good()) { Log(LogWarning, "ApiListener") << "Could not open spool file: " << path; return; } m_LogFile = new StdioStream(fp, true); m_LogMessageCount = 0; SetLogMessageTimestamp(Utility::GetTime()); } /* must hold m_LogLock */ void ApiListener::CloseLogFile(void) { if (!m_LogFile) return; m_LogFile->Close(); m_LogFile.reset(); } /* must hold m_LogLock */ void ApiListener::RotateLogFile(void) { double ts = GetLogMessageTimestamp(); if (ts == 0) ts = Utility::GetTime(); String oldpath = GetApiDir() + "log/current"; String newpath = GetApiDir() + "log/" + Convert::ToString(static_cast(ts)+1); (void) rename(oldpath.CStr(), newpath.CStr()); } void ApiListener::LogGlobHandler(std::vector& files, const String& file) { String name = Utility::BaseName(file); if (name == "current") return; int ts; try { ts = Convert::ToLong(name); } catch (const std::exception&) { return; } files.push_back(ts); } void ApiListener::ReplayLog(const JsonRpcConnection::Ptr& client) { Endpoint::Ptr endpoint = client->GetEndpoint(); if (endpoint->GetLogDuration() == 0) { ObjectLock olock2(endpoint); endpoint->SetSyncing(false); return; } CONTEXT("Replaying log for Endpoint '" + endpoint->GetName() + "'"); int count = -1; double peer_ts = endpoint->GetLocalLogPosition(); double logpos_ts = peer_ts; bool last_sync = false; Endpoint::Ptr target_endpoint = client->GetEndpoint(); ASSERT(target_endpoint); Zone::Ptr target_zone = target_endpoint->GetZone(); if (!target_zone) { ObjectLock olock2(endpoint); endpoint->SetSyncing(false); return; } for (;;) { boost::mutex::scoped_lock lock(m_LogLock); CloseLogFile(); RotateLogFile(); if (count == -1 || count > 50000) { OpenLogFile(); lock.unlock(); } else { last_sync = true; } count = 0; std::vector files; Utility::Glob(GetApiDir() + "log/*", boost::bind(&ApiListener::LogGlobHandler, boost::ref(files), _1), GlobFile); std::sort(files.begin(), files.end()); for (int ts : files) { String path = GetApiDir() + "log/" + Convert::ToString(ts); if (ts < peer_ts) continue; Log(LogNotice, "ApiListener") << "Replaying log: " << path; std::fstream *fp = new std::fstream(path.CStr(), std::fstream::in | std::fstream::binary); StdioStream::Ptr logStream = new StdioStream(fp, true); String message; StreamReadContext src; while (true) { Dictionary::Ptr pmessage; try { StreamReadStatus srs = NetString::ReadStringFromStream(logStream, &message, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; pmessage = JsonDecode(message); } catch (const std::exception&) { Log(LogWarning, "ApiListener") << "Unexpected end-of-file for cluster log: " << path; /* Log files may be incomplete or corrupted. This is perfectly OK. */ break; } if (pmessage->Get("timestamp") <= peer_ts) continue; Dictionary::Ptr secname = pmessage->Get("secobj"); if (secname) { ConfigObject::Ptr secobj = ConfigObject::GetObject(secname->Get("type"), secname->Get("name")); if (!secobj) continue; if (!target_zone->CanAccessObject(secobj)) continue; } try { NetString::WriteStringToStream(client->GetStream(), pmessage->Get("message")); count++; } catch (const std::exception& ex) { Log(LogWarning, "ApiListener") << "Error while replaying log for endpoint '" << endpoint->GetName() << "': " << DiagnosticInformation(ex, false); Log(LogDebug, "ApiListener") << "Error while replaying log for endpoint '" << endpoint->GetName() << "': " << DiagnosticInformation(ex); break; } peer_ts = pmessage->Get("timestamp"); if (ts > logpos_ts + 10) { logpos_ts = ts; Dictionary::Ptr lparams = new Dictionary(); lparams->Set("log_position", logpos_ts); Dictionary::Ptr lmessage = new Dictionary(); lmessage->Set("jsonrpc", "2.0"); lmessage->Set("method", "log::SetLogPosition"); lmessage->Set("params", lparams); JsonRpc::SendMessage(client->GetStream(), lmessage); } } logStream->Close(); } if (count > 0) { Log(LogInformation, "ApiListener") << "Replayed " << count << " messages."; } Log(LogNotice, "ApiListener") << "Replayed " << count << " messages."; if (last_sync) { { ObjectLock olock2(endpoint); endpoint->SetSyncing(false); } OpenLogFile(); break; } } } void ApiListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) { std::pair stats; ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; stats = listener->GetStatus(); ObjectLock olock(stats.second); for (const Dictionary::Pair& kv : stats.second) perfdata->Add(new PerfdataValue("api_" + kv.first, kv.second)); status->Set("api", stats.first); } std::pair ApiListener::GetStatus(void) { Dictionary::Ptr status = new Dictionary(); Dictionary::Ptr perfdata = new Dictionary(); /* cluster stats */ status->Set("identity", GetIdentity()); double allEndpoints = 0; Array::Ptr allNotConnectedEndpoints = new Array(); Array::Ptr allConnectedEndpoints = new Array(); Zone::Ptr my_zone = Zone::GetLocalZone(); Dictionary::Ptr connectedZones = new Dictionary(); for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { /* only check endpoints in a) the same zone b) our parent zone c) immediate child zones */ if (my_zone != zone && my_zone != zone->GetParent() && zone != my_zone->GetParent()) { Log(LogDebug, "ApiListener") << "Not checking connection to Zone '" << zone->GetName() << "' because it's not in the same zone, a parent or a child zone."; continue; } bool zoneConnected = false; int countZoneEndpoints = 0; double zoneLag = 0; Array::Ptr zoneEndpoints = new Array(); for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) { zoneEndpoints->Add(endpoint->GetName()); if (endpoint->GetName() == GetIdentity()) continue; double eplag = CalculateZoneLag(endpoint); if (eplag > 0 && eplag > zoneLag) zoneLag = eplag; allEndpoints++; countZoneEndpoints++; if (!endpoint->GetConnected()) { allNotConnectedEndpoints->Add(endpoint->GetName()); } else { allConnectedEndpoints->Add(endpoint->GetName()); zoneConnected = true; } } /* if there's only one endpoint inside the zone, we're not connected - that's us, fake it */ if (zone->GetEndpoints().size() == 1 && countZoneEndpoints == 0) zoneConnected = true; Dictionary::Ptr zoneStats = new Dictionary(); zoneStats->Set("connected", zoneConnected); zoneStats->Set("client_log_lag", zoneLag); zoneStats->Set("endpoints", zoneEndpoints); String parentZoneName; Zone::Ptr parentZone = zone->GetParent(); if (parentZone) parentZoneName = parentZone->GetName(); zoneStats->Set("parent_zone", parentZoneName); connectedZones->Set(zone->GetName(), zoneStats); } status->Set("num_endpoints", allEndpoints); status->Set("num_conn_endpoints", allConnectedEndpoints->GetLength()); status->Set("num_not_conn_endpoints", allNotConnectedEndpoints->GetLength()); status->Set("conn_endpoints", allConnectedEndpoints); status->Set("not_conn_endpoints", allNotConnectedEndpoints); status->Set("zones", connectedZones); /* connection stats */ size_t jsonRpcClients = GetAnonymousClients().size(); size_t httpClients = GetHttpClients().size(); size_t workQueueItems = JsonRpcConnection::GetWorkQueueLength(); size_t workQueueCount = JsonRpcConnection::GetWorkQueueCount(); size_t syncQueueItems = m_SyncQueue.GetLength(); size_t relayQueueItems = m_RelayQueue.GetLength(); double workQueueItemRate = JsonRpcConnection::GetWorkQueueRate(); double syncQueueItemRate = m_SyncQueue.GetTaskCount(60) / 60.0; double relayQueueItemRate = m_RelayQueue.GetTaskCount(60) / 60.0; Dictionary::Ptr jsonRpc = new Dictionary(); jsonRpc->Set("clients", jsonRpcClients); jsonRpc->Set("work_queue_items", workQueueItems); jsonRpc->Set("work_queue_count", workQueueCount); jsonRpc->Set("sync_queue_items", syncQueueItems); jsonRpc->Set("relay_queue_items", relayQueueItems); jsonRpc->Set("work_queue_item_rate", workQueueItemRate); jsonRpc->Set("sync_queue_item_rate", syncQueueItemRate); jsonRpc->Set("relay_queue_item_rate", relayQueueItemRate); Dictionary::Ptr http = new Dictionary(); http->Set("clients", httpClients); status->Set("json_rpc", jsonRpc); status->Set("http", http); /* performance data */ perfdata->Set("num_endpoints", allEndpoints); perfdata->Set("num_conn_endpoints", Convert::ToDouble(allConnectedEndpoints->GetLength())); perfdata->Set("num_not_conn_endpoints", Convert::ToDouble(allNotConnectedEndpoints->GetLength())); perfdata->Set("num_json_rpc_clients", jsonRpcClients); perfdata->Set("num_http_clients", httpClients); perfdata->Set("num_json_rpc_work_queue_items", workQueueItems); perfdata->Set("num_json_rpc_work_queue_count", workQueueCount); perfdata->Set("num_json_rpc_sync_queue_items", syncQueueItems); perfdata->Set("num_json_rpc_relay_queue_items", relayQueueItems); perfdata->Set("num_json_rpc_work_queue_item_rate", workQueueItemRate); perfdata->Set("num_json_rpc_sync_queue_item_rate", syncQueueItemRate); perfdata->Set("num_json_rpc_relay_queue_item_rate", relayQueueItemRate); return std::make_pair(status, perfdata); } double ApiListener::CalculateZoneLag(const Endpoint::Ptr& endpoint) { double remoteLogPosition = endpoint->GetRemoteLogPosition(); double eplag = Utility::GetTime() - remoteLogPosition; if ((endpoint->GetSyncing() || !endpoint->GetConnected()) && remoteLogPosition != 0) return eplag; return 0; } void ApiListener::AddAnonymousClient(const JsonRpcConnection::Ptr& aclient) { boost::mutex::scoped_lock lock(m_AnonymousClientsLock); m_AnonymousClients.insert(aclient); } void ApiListener::RemoveAnonymousClient(const JsonRpcConnection::Ptr& aclient) { boost::mutex::scoped_lock lock(m_AnonymousClientsLock); m_AnonymousClients.erase(aclient); } std::set ApiListener::GetAnonymousClients(void) const { boost::mutex::scoped_lock lock(m_AnonymousClientsLock); return m_AnonymousClients; } void ApiListener::AddHttpClient(const HttpServerConnection::Ptr& aclient) { boost::mutex::scoped_lock lock(m_HttpClientsLock); m_HttpClients.insert(aclient); } void ApiListener::RemoveHttpClient(const HttpServerConnection::Ptr& aclient) { boost::mutex::scoped_lock lock(m_HttpClientsLock); m_HttpClients.erase(aclient); } std::set ApiListener::GetHttpClients(void) const { boost::mutex::scoped_lock lock(m_HttpClientsLock); return m_HttpClients; } Value ApiListener::HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { return Empty; } Endpoint::Ptr ApiListener::GetLocalEndpoint(void) const { return m_LocalEndpoint; } void ApiListener::ValidateTlsProtocolmin(const String& value, const ValidationUtils& utils) { ObjectImpl::ValidateTlsProtocolmin(value, utils); if (value != SSL_TXT_TLSV1 #ifdef SSL_TXT_TLSV1_1 && value != SSL_TXT_TLSV1_1 && value != SSL_TXT_TLSV1_2 #endif /* SSL_TXT_TLSV1_1 */ ) { String message = "Invalid TLS version. Must be one of '" SSL_TXT_TLSV1 "'"; #ifdef SSL_TXT_TLSV1_1 message += ", '" SSL_TXT_TLSV1_1 "' or '" SSL_TXT_TLSV1_2 "'"; #endif /* SSL_TXT_TLSV1_1 */ BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("tls_protocolmin"), message)); } } bool ApiListener::IsHACluster(void) { Zone::Ptr zone = Zone::GetLocalZone(); if (!zone) return false; return zone->IsSingleInstance(); } /* Provide a helper function for zone origin name. */ String ApiListener::GetFromZoneName(const Zone::Ptr& fromZone) { String fromZoneName; if (fromZone) { fromZoneName = fromZone->GetName(); } else { Zone::Ptr lzone = Zone::GetLocalZone(); if (lzone) fromZoneName = lzone->GetName(); } return fromZoneName; } icinga2-2.8.1/lib/remote/apilistener.hpp000066400000000000000000000163341322762156600201500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APILISTENER_H #define APILISTENER_H #include "remote/apilistener.thpp" #include "remote/jsonrpcconnection.hpp" #include "remote/httpserverconnection.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include "base/configobject.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include "base/tcpsocket.hpp" #include "base/tlsstream.hpp" #include namespace icinga { class JsonRpcConnection; /** * @ingroup remote */ struct ConfigDirInformation { Dictionary::Ptr UpdateV1; Dictionary::Ptr UpdateV2; }; /** * @ingroup remote */ class I2_REMOTE_API ApiListener : public ObjectImpl { public: DECLARE_OBJECT(ApiListener); DECLARE_OBJECTNAME(ApiListener); static boost::signals2::signal OnMasterChanged; ApiListener(void); static String GetApiDir(void); static String GetCertsDir(void); static String GetCaDir(void); static String GetCertificateRequestsDir(void); void UpdateSSLContext(void); static ApiListener::Ptr GetInstance(void); Endpoint::Ptr GetMaster(void) const; bool IsMaster(void) const; Endpoint::Ptr GetLocalEndpoint(void) const; void SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message); void RelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); std::pair GetStatus(void); void AddAnonymousClient(const JsonRpcConnection::Ptr& aclient); void RemoveAnonymousClient(const JsonRpcConnection::Ptr& aclient); std::set GetAnonymousClients(void) const; void AddHttpClient(const HttpServerConnection::Ptr& aclient); void RemoveHttpClient(const HttpServerConnection::Ptr& aclient); std::set GetHttpClients(void) const; static double CalculateZoneLag(const Endpoint::Ptr& endpoint); /* filesync */ static Value ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); /* configsync */ static void ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie); static Value ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Value HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static void UpdateObjectAuthority(void); static bool IsHACluster(void); static String GetFromZoneName(const Zone::Ptr& fromZone); static String GetDefaultCertPath(void); static String GetDefaultKeyPath(void); static String GetDefaultCaPath(void); protected: virtual void OnConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeDeleted) override; virtual void ValidateTlsProtocolmin(const String& value, const ValidationUtils& utils) override; private: boost::shared_ptr m_SSLContext; std::set m_Servers; mutable boost::mutex m_AnonymousClientsLock; mutable boost::mutex m_HttpClientsLock; std::set m_AnonymousClients; std::set m_HttpClients; Timer::Ptr m_Timer; Timer::Ptr m_ReconnectTimer; Timer::Ptr m_AuthorityTimer; Timer::Ptr m_CleanupCertificateRequestsTimer; Endpoint::Ptr m_LocalEndpoint; static ApiListener::Ptr m_Instance; void ApiTimerHandler(void); void ApiReconnectTimerHandler(void); void CleanupCertificateRequestsTimerHandler(void); bool AddListener(const String& node, const String& service); void AddConnection(const Endpoint::Ptr& endpoint); void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role); void NewClientHandlerInternal(const Socket::Ptr& client, const String& hostname, ConnectionRole role); void ListenerThreadProc(const Socket::Ptr& server); WorkQueue m_RelayQueue; WorkQueue m_SyncQueue; boost::mutex m_LogLock; Stream::Ptr m_LogFile; size_t m_LogMessageCount; bool RelayMessageOne(const Zone::Ptr& zone, const MessageOrigin::Ptr& origin, const Dictionary::Ptr& message, const Endpoint::Ptr& currentMaster); void SyncRelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log); void PersistMessage(const Dictionary::Ptr& message, const ConfigObject::Ptr& secobj); void OpenLogFile(void); void RotateLogFile(void); void CloseLogFile(void); static void LogGlobHandler(std::vector& files, const String& file); void ReplayLog(const JsonRpcConnection::Ptr& client); static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath); /* filesync */ static ConfigDirInformation LoadConfigDir(const String& dir); static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config); static bool UpdateConfigDir(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig, const String& configDir, bool authoritative); void SyncZoneDirs(void) const; void SyncZoneDir(const Zone::Ptr& zone) const; static void ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file); void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient); /* configsync */ void UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, const JsonRpcConnection::Ptr& client = JsonRpcConnection::Ptr()); void DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, const JsonRpcConnection::Ptr& client = JsonRpcConnection::Ptr()); void SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient); void SyncClient(const JsonRpcConnection::Ptr& aclient, const Endpoint::Ptr& endpoint, bool needSync); }; } #endif /* APILISTENER_H */ icinga2-2.8.1/lib/remote/apilistener.ti000066400000000000000000000050441322762156600177710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/i2-remote.hpp" #include "base/configobject.hpp" #include "base/application.hpp" library remote; namespace icinga { class ApiListener : ConfigObject { [config, deprecated] String cert_path; [config, deprecated] String key_path; [config, deprecated] String ca_path; [config] String crl_path; [config] String cipher_list { default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}} }; [config] String tls_protocolmin { default {{{ return "TLSv1"; }}} }; [config] String bind_host; [config] String bind_port { default {{{ return "5665"; }}} }; [config] bool accept_config; [config] bool accept_commands; [config] String ticket_salt; [config] Array::Ptr access_control_allow_origin { default {{{ return new Array(); }}} }; [config] bool access_control_allow_credentials { default {{{ return true; }}} }; [config] String access_control_allow_headers { default {{{ return "Authorization"; }}} }; [config] String access_control_allow_methods { default {{{ return "GET, POST, PUT, DELETE"; }}} }; [state, no_user_modify] Timestamp log_message_timestamp; [no_user_modify] String identity; }; } icinga2-2.8.1/lib/remote/apiuser.cpp000066400000000000000000000034041322762156600172660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/apiuser.hpp" #include "remote/apiuser.tcpp" #include "base/configtype.hpp" using namespace icinga; REGISTER_TYPE(ApiUser); ApiUser::Ptr ApiUser::GetByClientCN(const String& cn) { for (const ApiUser::Ptr& user : ConfigType::GetObjectsByType()) { if (user->GetClientCN() == cn) return user; } return ApiUser::Ptr(); } icinga2-2.8.1/lib/remote/apiuser.hpp000066400000000000000000000034061322762156600172750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef APIUSER_H #define APIUSER_H #include "remote/i2-remote.hpp" #include "remote/apiuser.thpp" namespace icinga { /** * @ingroup remote */ class I2_REMOTE_API ApiUser : public ObjectImpl { public: DECLARE_OBJECT(ApiUser); DECLARE_OBJECTNAME(ApiUser); static ApiUser::Ptr GetByClientCN(const String& cn); }; } #endif /* APIUSER_H */ icinga2-2.8.1/lib/remote/apiuser.ti000066400000000000000000000034701322762156600171230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" #include "base/function.hpp" library remote; namespace icinga { class ApiUser : ConfigObject { [config, no_user_view] String password; [config] String client_cn (ClientCN); [config] array(Value) permissions; }; validator ApiUser { Array permissions { String "*"; Dictionary "*" { required permission; String permission; Function filter; }; }; }; } icinga2-2.8.1/lib/remote/authority.cpp000066400000000000000000000054501322762156600176510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/zone.hpp" #include "remote/apilistener.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" using namespace icinga; void ApiListener::UpdateObjectAuthority(void) { Zone::Ptr my_zone = Zone::GetLocalZone(); std::vector endpoints; Endpoint::Ptr my_endpoint; if (my_zone) { my_endpoint = Endpoint::GetLocalEndpoint(); int num_total = 0; for (const Endpoint::Ptr& endpoint : my_zone->GetEndpoints()) { num_total++; if (endpoint != my_endpoint && !endpoint->GetConnected()) continue; endpoints.push_back(endpoint); } double mainTime = Application::GetMainTime(); if (num_total > 1 && endpoints.size() <= 1 && (mainTime == 0 || Utility::GetTime() - mainTime < 60)) return; std::sort(endpoints.begin(), endpoints.end(), [](const ConfigObject::Ptr& a, const ConfigObject::Ptr& b) { return a->GetName() < b->GetName(); } ); } for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { if (!object->IsActive() || object->GetHAMode() != HARunOnce) continue; bool authority; if (!my_zone) authority = true; else authority = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()] == my_endpoint; object->SetAuthority(authority); } } } icinga2-2.8.1/lib/remote/configfileshandler.cpp000066400000000000000000000100021322762156600214340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/configfileshandler.hpp" #include "remote/configpackageutility.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/exception.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler); bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestMethod != "GET") return false; const std::vector& urlPath = request.RequestUrl->GetPath(); if (urlPath.size() >= 4) params->Set("package", urlPath[3]); if (urlPath.size() >= 5) params->Set("stage", urlPath[4]); if (urlPath.size() >= 6) { std::vector tmpPath(urlPath.begin() + 5, urlPath.end()); params->Set("path", boost::algorithm::join(tmpPath, "/")); } if (request.Headers->Get("accept") == "application/json") { HttpUtility::SendJsonError(response, 400, "Invalid Accept header. Either remove the Accept header or set it to 'application/octet-stream'."); return true; } FilterUtility::CheckPermission(user, "config/query"); String packageName = HttpUtility::GetLastParameter(params, "package"); String stageName = HttpUtility::GetLastParameter(params, "stage"); if (!ConfigPackageUtility::ValidateName(packageName)) { HttpUtility::SendJsonError(response, 400, "Invalid package name."); return true; } if (!ConfigPackageUtility::ValidateName(stageName)) { HttpUtility::SendJsonError(response, 400, "Invalid stage name."); return true; } String relativePath = HttpUtility::GetLastParameter(params, "path"); if (ConfigPackageUtility::ContainsDotDot(relativePath)) { HttpUtility::SendJsonError(response, 400, "Path contains '..' (not allowed)."); return true; } String path = ConfigPackageUtility::GetPackageDir() + "/" + packageName + "/" + stageName + "/" + relativePath; if (!Utility::PathExists(path)) { HttpUtility::SendJsonError(response, 404, "Path not found."); return true; } try { std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary); fp.exceptions(std::ifstream::badbit); String content((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); response.SetStatus(200, "OK"); response.AddHeader("Content-Type", "application/octet-stream"); response.WriteBody(content.CStr(), content.GetLength()); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 500, "Could not read file.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); } return true; } icinga2-2.8.1/lib/remote/configfileshandler.hpp000066400000000000000000000035011322762156600214470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGFILESHANDLER_H #define CONFIGFILESHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ConfigFilesHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ConfigFilesHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* CONFIGFILESHANDLER_H */ icinga2-2.8.1/lib/remote/configobjectutility.cpp000066400000000000000000000167211322762156600217040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/configobjectutility.hpp" #include "remote/configpackageutility.hpp" #include "remote/apilistener.hpp" #include "config/configcompiler.hpp" #include "config/configitem.hpp" #include "base/configwriter.hpp" #include "base/exception.hpp" #include "base/serializer.hpp" #include "base/dependencygraph.hpp" #include #include #include using namespace icinga; String ConfigObjectUtility::GetConfigDir(void) { return ConfigPackageUtility::GetPackageDir() + "/_api/" + ConfigPackageUtility::GetActiveStage("_api"); } String ConfigObjectUtility::GetObjectConfigPath(const Type::Ptr& type, const String& fullName) { String typeDir = type->GetPluralName(); boost::algorithm::to_lower(typeDir); return GetConfigDir() + "/conf.d/" + typeDir + "/" + EscapeName(fullName) + ".conf"; } String ConfigObjectUtility::EscapeName(const String& name) { return Utility::EscapeString(name, "<>:\"/\\|?*", true); } String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName, bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs) { NameComposer *nc = dynamic_cast(type.get()); Dictionary::Ptr nameParts; String name; if (nc) { nameParts = nc->ParseName(fullName); name = nameParts->Get("name"); } else name = fullName; Dictionary::Ptr allAttrs = new Dictionary(); if (attrs) { attrs->CopyTo(allAttrs); ObjectLock olock(attrs); for (const Dictionary::Pair& kv : attrs) { int fid = type->GetFieldId(kv.first.SubStr(0, kv.first.FindFirstOf("."))); if (fid < 0) BOOST_THROW_EXCEPTION(ScriptError("Invalid attribute specified: " + kv.first)); Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FAConfig) || kv.first == "name") BOOST_THROW_EXCEPTION(ScriptError("Attribute is marked for internal use only and may not be set: " + kv.first)); } } if (nameParts) nameParts->CopyTo(allAttrs); allAttrs->Remove("name"); /* update the version for config sync */ allAttrs->Set("version", Utility::GetTime()); std::ostringstream config; ConfigWriter::EmitConfigItem(config, type->GetName(), name, false, ignoreOnError, templates, allAttrs); ConfigWriter::EmitRaw(config, "\n"); return config.str(); } bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName, const String& config, const Array::Ptr& errors) { { boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex()); if (!ConfigPackageUtility::PackageExists("_api")) { ConfigPackageUtility::CreatePackage("_api"); String stage = ConfigPackageUtility::CreateStage("_api"); ConfigPackageUtility::ActivateStage("_api", stage); } } String path = GetObjectConfigPath(type, fullName); Utility::MkDirP(Utility::DirName(path), 0700); if (Utility::PathExists(path)) { errors->Add("Configuration file '" + path + "' already exists."); return false; } std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc); fp << config; fp.close(); Expression *expr = ConfigCompiler::CompileFile(path, String(), "_api"); try { ActivationScope ascope; ScriptFrame frame; expr->Evaluate(frame); delete expr; expr = NULL; WorkQueue upq; std::vector newItems; if (!ConfigItem::CommitItems(ascope.GetContext(), upq, newItems) || !ConfigItem::ActivateItems(upq, newItems, true)) { if (errors) { if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } for (const boost::exception_ptr& ex : upq.GetExceptions()) { errors->Add(DiagnosticInformation(ex)); } } return false; } ApiListener::UpdateObjectAuthority(); } catch (const std::exception& ex) { delete expr; if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } if (errors) errors->Add(DiagnosticInformation(ex)); return false; } return true; } bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors) { std::vector parents = DependencyGraph::GetParents(object); Type::Ptr type = object->GetReflectionType(); if (!parents.empty() && !cascade) { if (errors) errors->Add("Object '" + object->GetName() + "' of type '" + type->GetName() + "' cannot be deleted because other objects depend on it. " "Use cascading delete to delete it anyway."); return false; } for (const Object::Ptr& pobj : parents) { ConfigObject::Ptr parentObj = dynamic_pointer_cast(pobj); if (!parentObj) continue; DeleteObjectHelper(parentObj, cascade, errors); } ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, object->GetName()); try { /* mark this object for cluster delete event */ object->SetExtension("ConfigObjectDeleted", true); /* triggers signal for DB IDO and other interfaces */ object->Deactivate(true); if (item) item->Unregister(); else object->Unregister(); } catch (const std::exception& ex) { if (errors) errors->Add(DiagnosticInformation(ex)); return false; } String path = GetObjectConfigPath(object->GetReflectionType(), object->GetName()); if (Utility::PathExists(path)) { if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } } return true; } bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors) { if (object->GetPackage() != "_api") { if (errors) errors->Add("Object cannot be deleted because it was not created using the API."); return false; } return DeleteObjectHelper(object, cascade, errors); } icinga2-2.8.1/lib/remote/configobjectutility.hpp000066400000000000000000000046761322762156600217170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGOBJECTUTILITY_H #define CONFIGOBJECTUTILITY_H #include "remote/i2-remote.hpp" #include "base/array.hpp" #include "base/configobject.hpp" #include "base/dictionary.hpp" #include "base/type.hpp" namespace icinga { /** * Helper functions. * * @ingroup remote */ class I2_REMOTE_API ConfigObjectUtility { public: static String GetConfigDir(void); static String GetObjectConfigPath(const Type::Ptr& type, const String& fullName); static String CreateObjectConfig(const Type::Ptr& type, const String& fullName, bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs); static bool CreateObject(const Type::Ptr& type, const String& fullName, const String& config, const Array::Ptr& errors); static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors); private: static String EscapeName(const String& name); static bool DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors); }; } #endif /* CONFIGOBJECTUTILITY_H */ icinga2-2.8.1/lib/remote/configpackageshandler.cpp000066400000000000000000000127611322762156600221260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/configpackageshandler.hpp" #include "remote/configpackageutility.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/exception.hpp" #include using namespace icinga; REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler); bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod == "GET") HandleGet(user, request, response); else if (request.RequestMethod == "POST") HandlePost(user, request, response, params); else if (request.RequestMethod == "DELETE") HandleDelete(user, request, response, params); else return false; return true; } void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { FilterUtility::CheckPermission(user, "config/query"); std::vector packages = ConfigPackageUtility::GetPackages(); Array::Ptr results = new Array(); { boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex()); for (const String& package : packages) { Dictionary::Ptr packageInfo = new Dictionary(); packageInfo->Set("name", package); packageInfo->Set("stages", Array::FromVector(ConfigPackageUtility::GetStages(package))); packageInfo->Set("active-stage", ConfigPackageUtility::GetActiveStage(package)); results->Add(packageInfo); } } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); } void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { FilterUtility::CheckPermission(user, "config/modify"); if (request.RequestUrl->GetPath().size() >= 4) params->Set("package", request.RequestUrl->GetPath()[3]); String packageName = HttpUtility::GetLastParameter(params, "package"); if (!ConfigPackageUtility::ValidateName(packageName)) { HttpUtility::SendJsonError(response, 400, "Invalid package name."); return; } Dictionary::Ptr result1 = new Dictionary(); try { boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex()); ConfigPackageUtility::CreatePackage(packageName); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 500, "Could not create package.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); } result1->Set("code", 200); result1->Set("status", "Created package."); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); } void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { FilterUtility::CheckPermission(user, "config/modify"); if (request.RequestUrl->GetPath().size() >= 4) params->Set("package", request.RequestUrl->GetPath()[3]); String packageName = HttpUtility::GetLastParameter(params, "package"); if (!ConfigPackageUtility::ValidateName(packageName)) { HttpUtility::SendJsonError(response, 400, "Invalid package name."); return; } int code = 200; String status = "Deleted package."; Dictionary::Ptr result1 = new Dictionary(); try { ConfigPackageUtility::DeletePackage(packageName); } catch (const std::exception& ex) { code = 500; status = "Failed to delete package."; if (HttpUtility::GetLastParameter(params, "verboseErrors")) result1->Set("diagnostic information", DiagnosticInformation(ex)); } result1->Set("package", packageName); result1->Set("code", code); result1->Set("status", status); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(code, (code == 200) ? "OK" : "Internal Server Error"); HttpUtility::SendJsonBody(response, result); } icinga2-2.8.1/lib/remote/configpackageshandler.hpp000066400000000000000000000042641322762156600221320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGMODULESHANDLER_H #define CONFIGMODULESHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ConfigPackagesHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ConfigPackagesHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; private: void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response); void HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params); void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params); }; } #endif /* CONFIGMODULESHANDLER_H */ icinga2-2.8.1/lib/remote/configpackageutility.cpp000066400000000000000000000253321322762156600220270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/configpackageutility.hpp" #include "base/application.hpp" #include "base/exception.hpp" #include "base/scriptglobal.hpp" #include "base/utility.hpp" #include #include #include #include using namespace icinga; String ConfigPackageUtility::GetPackageDir(void) { return Application::GetLocalStateDir() + "/lib/icinga2/api/packages"; } void ConfigPackageUtility::CreatePackage(const String& name) { String path = GetPackageDir() + "/" + name; if (Utility::PathExists(path)) BOOST_THROW_EXCEPTION(std::invalid_argument("Package already exists.")); Utility::MkDirP(path, 0700); WritePackageConfig(name); } void ConfigPackageUtility::DeletePackage(const String& name) { String path = GetPackageDir() + "/" + name; if (!Utility::PathExists(path)) BOOST_THROW_EXCEPTION(std::invalid_argument("Package does not exist.")); Utility::RemoveDirRecursive(path); Application::RequestRestart(); } std::vector ConfigPackageUtility::GetPackages(void) { std::vector packages; Utility::Glob(GetPackageDir() + "/*", boost::bind(&ConfigPackageUtility::CollectDirNames, _1, boost::ref(packages)), GlobDirectory); return packages; } void ConfigPackageUtility::CollectDirNames(const String& path, std::vector& dirs) { String name = Utility::BaseName(path); dirs.push_back(name); } bool ConfigPackageUtility::PackageExists(const String& name) { return Utility::PathExists(GetPackageDir() + "/" + name); } String ConfigPackageUtility::CreateStage(const String& packageName, const Dictionary::Ptr& files) { String stageName = Utility::NewUniqueID(); String path = GetPackageDir() + "/" + packageName; if (!Utility::PathExists(path)) BOOST_THROW_EXCEPTION(std::invalid_argument("Package does not exist.")); path += "/" + stageName; Utility::MkDirP(path, 0700); Utility::MkDirP(path + "/conf.d", 0700); Utility::MkDirP(path + "/zones.d", 0700); WriteStageConfig(packageName, stageName); bool foundDotDot = false; if (files) { ObjectLock olock(files); for (const Dictionary::Pair& kv : files) { if (ContainsDotDot(kv.first)) { foundDotDot = true; break; } String filePath = path + "/" + kv.first; Log(LogInformation, "ConfigPackageUtility") << "Updating configuration file: " << filePath; // Pass the directory and generate a dir tree, if it does not already exist Utility::MkDirP(Utility::DirName(filePath), 0750); std::ofstream fp(filePath.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fp << kv.second; fp.close(); } } if (foundDotDot) { Utility::RemoveDirRecursive(path); BOOST_THROW_EXCEPTION(std::invalid_argument("Path must not contain '..'.")); } return stageName; } void ConfigPackageUtility::WritePackageConfig(const String& packageName) { String stageName = GetActiveStage(packageName); String includePath = GetPackageDir() + "/" + packageName + "/include.conf"; std::ofstream fpInclude(includePath.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fpInclude << "include \"*/include.conf\"\n"; fpInclude.close(); String activePath = GetPackageDir() + "/" + packageName + "/active.conf"; std::ofstream fpActive(activePath.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fpActive << "if (!globals.contains(\"ActiveStages\")) {\n" << " globals.ActiveStages = {}\n" << "}\n" << "\n" << "if (globals.contains(\"ActiveStageOverride\")) {\n" << " var arr = ActiveStageOverride.split(\":\")\n" << " if (arr[0] == \"" << packageName << "\") {\n" << " if (arr.len() < 2) {\n" << " log(LogCritical, \"Config\", \"Invalid value for ActiveStageOverride\")\n" << " } else {\n" << " ActiveStages[\"" << packageName << "\"] = arr[1]\n" << " }\n" << " }\n" << "}\n" << "\n" << "if (!ActiveStages.contains(\"" << packageName << "\")) {\n" << " ActiveStages[\"" << packageName << "\"] = \"" << stageName << "\"\n" << "}\n"; fpActive.close(); } void ConfigPackageUtility::WriteStageConfig(const String& packageName, const String& stageName) { String path = GetPackageDir() + "/" + packageName + "/" + stageName + "/include.conf"; std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fp << "include \"../active.conf\"\n" << "if (ActiveStages[\"" << packageName << "\"] == \"" << stageName << "\") {\n" << " include_recursive \"conf.d\"\n" << " include_zones \"" << packageName << "\", \"zones.d\"\n" << "}\n"; fp.close(); } void ConfigPackageUtility::ActivateStage(const String& packageName, const String& stageName) { String activeStagePath = GetPackageDir() + "/" + packageName + "/active-stage"; std::ofstream fpActiveStage(activeStagePath.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fpActiveStage << stageName; fpActiveStage.close(); WritePackageConfig(packageName); } void ConfigPackageUtility::TryActivateStageCallback(const ProcessResult& pr, const String& packageName, const String& stageName, bool reload) { String logFile = GetPackageDir() + "/" + packageName + "/" + stageName + "/startup.log"; std::ofstream fpLog(logFile.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fpLog << pr.Output; fpLog.close(); String statusFile = GetPackageDir() + "/" + packageName + "/" + stageName + "/status"; std::ofstream fpStatus(statusFile.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc); fpStatus << pr.ExitStatus; fpStatus.close(); /* validation went fine, activate stage and reload */ if (pr.ExitStatus == 0) { { boost::mutex::scoped_lock lock(GetStaticMutex()); ActivateStage(packageName, stageName); } if (reload) Application::RequestRestart(); } else { Log(LogCritical, "ConfigPackageUtility") << "Config validation failed for package '" << packageName << "' and stage '" << stageName << "'."; } } void ConfigPackageUtility::AsyncTryActivateStage(const String& packageName, const String& stageName, bool reload) { VERIFY(Application::GetArgC() >= 1); // prepare arguments Array::Ptr args = new Array(); args->Add(Application::GetExePath(Application::GetArgV()[0])); args->Add("daemon"); args->Add("--validate"); args->Add("--define"); args->Add("ActiveStageOverride=" + packageName + ":" + stageName); Process::Ptr process = new Process(Process::PrepareCommand(args)); process->SetTimeout(300); process->Run(boost::bind(&TryActivateStageCallback, _1, packageName, stageName, reload)); } void ConfigPackageUtility::DeleteStage(const String& packageName, const String& stageName) { String path = GetPackageDir() + "/" + packageName + "/" + stageName; if (!Utility::PathExists(path)) BOOST_THROW_EXCEPTION(std::invalid_argument("Stage does not exist.")); if (GetActiveStage(packageName) == stageName) BOOST_THROW_EXCEPTION(std::invalid_argument("Active stage cannot be deleted.")); Utility::RemoveDirRecursive(path); } std::vector ConfigPackageUtility::GetStages(const String& packageName) { std::vector stages; Utility::Glob(GetPackageDir() + "/" + packageName + "/*", boost::bind(&ConfigPackageUtility::CollectDirNames, _1, boost::ref(stages)), GlobDirectory); return stages; } String ConfigPackageUtility::GetActiveStage(const String& packageName) { String path = GetPackageDir() + "/" + packageName + "/active-stage"; std::ifstream fp; fp.open(path.CStr()); String stage; std::getline(fp, stage.GetData()); fp.close(); if (fp.fail()) return ""; return stage.Trim(); } std::vector > ConfigPackageUtility::GetFiles(const String& packageName, const String& stageName) { std::vector > paths; Utility::GlobRecursive(GetPackageDir() + "/" + packageName + "/" + stageName, "*", boost::bind(&ConfigPackageUtility::CollectPaths, _1, boost::ref(paths)), GlobDirectory | GlobFile); return paths; } void ConfigPackageUtility::CollectPaths(const String& path, std::vector >& paths) { #ifndef _WIN32 struct stat statbuf; int rc = lstat(path.CStr(), &statbuf); if (rc < 0) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("lstat") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); paths.push_back(std::make_pair(path, S_ISDIR(statbuf.st_mode))); #else /* _WIN32 */ struct _stat statbuf; int rc = _stat(path.CStr(), &statbuf); if (rc < 0) BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("_stat") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); paths.push_back(std::make_pair(path, ((statbuf.st_mode & S_IFMT) == S_IFDIR))); #endif /* _WIN32 */ } bool ConfigPackageUtility::ContainsDotDot(const String& path) { std::vector tokens; boost::algorithm::split(tokens, path, boost::is_any_of("/\\")); for (const String& part : tokens) { if (part == "..") return true; } return false; } bool ConfigPackageUtility::ValidateName(const String& name) { if (name.IsEmpty()) return false; /* check for path injection */ if (ContainsDotDot(name)) return false; boost::regex expr("^[^a-zA-Z0-9_\\-]*$", boost::regex::icase); boost::smatch what; return (!boost::regex_search(name.GetData(), what, expr)); } boost::mutex& ConfigPackageUtility::GetStaticMutex(void) { static boost::mutex mutex; return mutex; } icinga2-2.8.1/lib/remote/configpackageutility.hpp000066400000000000000000000062731322762156600220370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGMODULEUTILITY_H #define CONFIGMODULEUTILITY_H #include "remote/i2-remote.hpp" #include "base/application.hpp" #include "base/dictionary.hpp" #include "base/process.hpp" #include "base/string.hpp" #include namespace icinga { /** * Helper functions. * * @ingroup remote */ class I2_REMOTE_API ConfigPackageUtility { public: static String GetPackageDir(void); static void CreatePackage(const String& name); static void DeletePackage(const String& name); static std::vector GetPackages(void); static bool PackageExists(const String& name); static String CreateStage(const String& packageName, const Dictionary::Ptr& files = Dictionary::Ptr()); static void DeleteStage(const String& packageName, const String& stageName); static std::vector GetStages(const String& packageName); static String GetActiveStage(const String& packageName); static void ActivateStage(const String& packageName, const String& stageName); static void AsyncTryActivateStage(const String& packageName, const String& stageName, bool reload); static std::vector > GetFiles(const String& packageName, const String& stageName); static bool ContainsDotDot(const String& path); static bool ValidateName(const String& name); static boost::mutex& GetStaticMutex(void); private: static void CollectDirNames(const String& path, std::vector& dirs); static void CollectPaths(const String& path, std::vector >& paths); static void WritePackageConfig(const String& packageName); static void WriteStageConfig(const String& packageName, const String& stageName); static void TryActivateStageCallback(const ProcessResult& pr, const String& packageName, const String& stageName, bool reload); }; } #endif /* CONFIGMODULEUTILITY_H */ icinga2-2.8.1/lib/remote/configstageshandler.cpp000066400000000000000000000157141322762156600216370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/configstageshandler.hpp" #include "remote/configpackageutility.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/application.hpp" #include "base/exception.hpp" #include using namespace icinga; REGISTER_URLHANDLER("/v1/config/stages", ConfigStagesHandler); bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 5) return false; if (request.RequestMethod == "GET") HandleGet(user, request, response, params); else if (request.RequestMethod == "POST") HandlePost(user, request, response, params); else if (request.RequestMethod == "DELETE") HandleDelete(user, request, response, params); else return false; return true; } void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { FilterUtility::CheckPermission(user, "config/query"); if (request.RequestUrl->GetPath().size() >= 4) params->Set("package", request.RequestUrl->GetPath()[3]); if (request.RequestUrl->GetPath().size() >= 5) params->Set("stage", request.RequestUrl->GetPath()[4]); String packageName = HttpUtility::GetLastParameter(params, "package"); String stageName = HttpUtility::GetLastParameter(params, "stage"); if (!ConfigPackageUtility::ValidateName(packageName)) return HttpUtility::SendJsonError(response, 400, "Invalid package name."); if (!ConfigPackageUtility::ValidateName(stageName)) return HttpUtility::SendJsonError(response, 400, "Invalid stage name."); Array::Ptr results = new Array(); std::vector > paths = ConfigPackageUtility::GetFiles(packageName, stageName); String prefixPath = ConfigPackageUtility::GetPackageDir() + "/" + packageName + "/" + stageName + "/"; typedef std::pair kv_pair; for (const kv_pair& kv : paths) { Dictionary::Ptr stageInfo = new Dictionary(); stageInfo->Set("type", (kv.second ? "directory" : "file")); stageInfo->Set("name", kv.first.SubStr(prefixPath.GetLength())); results->Add(stageInfo); } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); } void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { FilterUtility::CheckPermission(user, "config/modify"); if (request.RequestUrl->GetPath().size() >= 4) params->Set("package", request.RequestUrl->GetPath()[3]); String packageName = HttpUtility::GetLastParameter(params, "package"); if (!ConfigPackageUtility::ValidateName(packageName)) return HttpUtility::SendJsonError(response, 400, "Invalid package name."); bool reload = true; if (params->Contains("reload")) reload = HttpUtility::GetLastParameter(params, "reload"); Dictionary::Ptr files = params->Get("files"); String stageName; try { if (!files) BOOST_THROW_EXCEPTION(std::invalid_argument("Parameter 'files' must be specified.")); boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex()); stageName = ConfigPackageUtility::CreateStage(packageName, files); /* validate the config. on success, activate stage and reload */ ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName, reload); } catch (const std::exception& ex) { return HttpUtility::SendJsonError(response, 500, "Stage creation failed.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); } Dictionary::Ptr result1 = new Dictionary(); String responseStatus = "Created stage. "; responseStatus += (reload ? " Icinga2 will reload." : " Icinga2 reload skipped."); result1->Set("package", packageName); result1->Set("stage", stageName); result1->Set("code", 200); result1->Set("status", responseStatus); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); } void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { FilterUtility::CheckPermission(user, "config/modify"); if (request.RequestUrl->GetPath().size() >= 4) params->Set("package", request.RequestUrl->GetPath()[3]); if (request.RequestUrl->GetPath().size() >= 5) params->Set("stage", request.RequestUrl->GetPath()[4]); String packageName = HttpUtility::GetLastParameter(params, "package"); String stageName = HttpUtility::GetLastParameter(params, "stage"); if (!ConfigPackageUtility::ValidateName(packageName)) return HttpUtility::SendJsonError(response, 400, "Invalid package name."); if (!ConfigPackageUtility::ValidateName(stageName)) return HttpUtility::SendJsonError(response, 400, "Invalid stage name."); try { ConfigPackageUtility::DeleteStage(packageName, stageName); } catch (const std::exception& ex) { return HttpUtility::SendJsonError(response, 500, "Failed to delete stage.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); } Dictionary::Ptr result1 = new Dictionary(); result1->Set("code", 200); result1->Set("status", "Stage deleted."); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); } icinga2-2.8.1/lib/remote/configstageshandler.hpp000066400000000000000000000043141322762156600216360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONFIGSTAGESHANDLER_H #define CONFIGSTAGESHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ConfigStagesHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ConfigStagesHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; private: void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params); void HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params); void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params); }; } #endif /* CONFIGSTAGESHANDLER_H */ icinga2-2.8.1/lib/remote/consolehandler.cpp000066400000000000000000000214261322762156600206220ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/consolehandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "config/configcompiler.hpp" #include "base/configtype.hpp" #include "base/configwriter.hpp" #include "base/scriptglobal.hpp" #include "base/logger.hpp" #include "base/serializer.hpp" #include "base/timer.hpp" #include "base/initialize.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/console", ConsoleHandler); static boost::mutex l_QueryMutex; static std::map l_ApiScriptFrames; static Timer::Ptr l_FrameCleanupTimer; static boost::mutex l_ApiScriptMutex; static void ScriptFrameCleanupHandler(void) { boost::mutex::scoped_lock lock(l_ApiScriptMutex); std::vector cleanup_keys; typedef std::pair KVPair; for (const KVPair& kv : l_ApiScriptFrames) { if (kv.second.Seen < Utility::GetTime() - 1800) cleanup_keys.push_back(kv.first); } for (const String& key : cleanup_keys) l_ApiScriptFrames.erase(key); } INITIALIZE_ONCE([]() { l_FrameCleanupTimer = new Timer(); l_FrameCleanupTimer->OnTimerExpired.connect(boost::bind(ScriptFrameCleanupHandler)); l_FrameCleanupTimer->SetInterval(30); l_FrameCleanupTimer->Start(); }); bool ConsoleHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 3) return false; if (request.RequestMethod != "POST") return false; QueryDescription qd; String methodName = request.RequestUrl->GetPath()[2]; FilterUtility::CheckPermission(user, "console"); String session = HttpUtility::GetLastParameter(params, "session"); if (session.IsEmpty()) session = Utility::NewUniqueID(); String command = HttpUtility::GetLastParameter(params, "command"); bool sandboxed = HttpUtility::GetLastParameter(params, "sandboxed"); if (methodName == "execute-script") return ExecuteScriptHelper(request, response, command, session, sandboxed); else if (methodName == "auto-complete-script") return AutocompleteScriptHelper(request, response, command, session, sandboxed); HttpUtility::SendJsonError(response, 400, "Invalid method specified: " + methodName); return true; } bool ConsoleHandler::ExecuteScriptHelper(HttpRequest& request, HttpResponse& response, const String& command, const String& session, bool sandboxed) { Log(LogNotice, "Console") << "Executing expression: " << command; ApiScriptFrame& lsf = l_ApiScriptFrames[session]; lsf.Seen = Utility::GetTime(); if (!lsf.Locals) lsf.Locals = new Dictionary(); String fileName = "<" + Convert::ToString(lsf.NextLine) + ">"; lsf.NextLine++; lsf.Lines[fileName] = command; Array::Ptr results = new Array(); Dictionary::Ptr resultInfo = new Dictionary(); Expression *expr = NULL; Value exprResult; try { expr = ConfigCompiler::CompileText(fileName, command); ScriptFrame frame; frame.Locals = lsf.Locals; frame.Self = lsf.Locals; frame.Sandboxed = sandboxed; exprResult = expr->Evaluate(frame); resultInfo->Set("code", 200); resultInfo->Set("status", "Executed successfully."); resultInfo->Set("result", Serialize(exprResult, 0)); } catch (const ScriptError& ex) { DebugInfo di = ex.GetDebugInfo(); std::ostringstream msgbuf; msgbuf << di.Path << ": " << lsf.Lines[di.Path] << "\n" << String(di.Path.GetLength() + 2, ' ') << String(di.FirstColumn, ' ') << String(di.LastColumn - di.FirstColumn + 1, '^') << "\n" << ex.what() << "\n"; resultInfo->Set("code", 500); resultInfo->Set("status", String(msgbuf.str())); resultInfo->Set("incomplete_expression", ex.IsIncompleteExpression()); Dictionary::Ptr debugInfo = new Dictionary(); debugInfo->Set("path", di.Path); debugInfo->Set("first_line", di.FirstLine); debugInfo->Set("first_column", di.FirstColumn); debugInfo->Set("last_line", di.LastLine); debugInfo->Set("last_column", di.LastColumn); resultInfo->Set("debug_info", debugInfo); } catch (...) { delete expr; throw; } delete expr; results->Add(resultInfo); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } bool ConsoleHandler::AutocompleteScriptHelper(HttpRequest& request, HttpResponse& response, const String& command, const String& session, bool sandboxed) { Log(LogInformation, "Console") << "Auto-completing expression: " << command; ApiScriptFrame& lsf = l_ApiScriptFrames[session]; lsf.Seen = Utility::GetTime(); if (!lsf.Locals) lsf.Locals = new Dictionary(); Array::Ptr results = new Array(); Dictionary::Ptr resultInfo = new Dictionary(); ScriptFrame frame; frame.Locals = lsf.Locals; frame.Self = lsf.Locals; frame.Sandboxed = sandboxed; resultInfo->Set("code", 200); resultInfo->Set("status", "Auto-completed successfully."); resultInfo->Set("suggestions", Array::FromVector(GetAutocompletionSuggestions(command, frame))); results->Add(resultInfo); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } static void AddSuggestion(std::vector& matches, const String& word, const String& suggestion) { if (suggestion.Find(word) != 0) return; matches.push_back(suggestion); } static void AddSuggestions(std::vector& matches, const String& word, const String& pword, bool withFields, const Value& value) { String prefix; if (!pword.IsEmpty()) prefix = pword + "."; if (value.IsObjectType()) { Dictionary::Ptr dict = value; ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } if (withFields) { Type::Ptr type = value.GetReflectionType(); for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); AddSuggestion(matches, word, prefix + field.Name); } while (type) { Object::Ptr prototype = type->GetPrototype(); Dictionary::Ptr dict = dynamic_pointer_cast(prototype); if (dict) { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } type = type->GetBaseType(); } } } std::vector ConsoleHandler::GetAutocompletionSuggestions(const String& word, ScriptFrame& frame) { std::vector matches; for (const String& keyword : ConfigWriter::GetKeywords()) { AddSuggestion(matches, word, keyword); } { ObjectLock olock(frame.Locals); for (const Dictionary::Pair& kv : frame.Locals) { AddSuggestion(matches, word, kv.first); } } { ObjectLock olock(ScriptGlobal::GetGlobals()); for (const Dictionary::Pair& kv : ScriptGlobal::GetGlobals()) { AddSuggestion(matches, word, kv.first); } } { Array::Ptr imports = ScriptFrame::GetImports(); ObjectLock olock(imports); for (const Value& import : imports) { AddSuggestions(matches, word, "", false, import); } } String::SizeType cperiod = word.RFind("."); if (cperiod != String::NPos) { String pword = word.SubStr(0, cperiod); Value value; try { Expression *expr = ConfigCompiler::CompileText("temp", pword); if (expr) value = expr->Evaluate(frame); AddSuggestions(matches, word, pword, true, value); } catch (...) { /* Ignore the exception */ } } return matches; } icinga2-2.8.1/lib/remote/consolehandler.hpp000066400000000000000000000046341322762156600206310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CONSOLEHANDLER_H #define CONSOLEHANDLER_H #include "remote/httphandler.hpp" #include "base/scriptframe.hpp" namespace icinga { struct I2_REMOTE_API ApiScriptFrame { double Seen; int NextLine; std::map Lines; Dictionary::Ptr Locals; ApiScriptFrame(void) : Seen(0), NextLine(1) { } }; class I2_REMOTE_API ConsoleHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ConsoleHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; static std::vector GetAutocompletionSuggestions(const String& word, ScriptFrame& frame); private: static bool ExecuteScriptHelper(HttpRequest& request, HttpResponse& response, const String& command, const String& session, bool sandboxed); static bool AutocompleteScriptHelper(HttpRequest& request, HttpResponse& response, const String& command, const String& session, bool sandboxed); }; } #endif /* CONSOLEHANDLER_H */ icinga2-2.8.1/lib/remote/createobjecthandler.cpp000066400000000000000000000107421322762156600216110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/createobjecthandler.hpp" #include "remote/configobjectutility.hpp" #include "remote/httputility.hpp" #include "remote/jsonrpcconnection.hpp" #include "remote/filterutility.hpp" #include "remote/apiaction.hpp" #include "remote/zone.hpp" #include "base/configtype.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/objects", CreateObjectHandler); bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() != 4) return false; if (request.RequestMethod != "PUT") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } FilterUtility::CheckPermission(user, "objects/create/" + type->GetName()); String name = request.RequestUrl->GetPath()[3]; Array::Ptr templates = params->Get("templates"); Dictionary::Ptr attrs = params->Get("attrs"); /* Put created objects into the local zone if not explicitly defined. * This allows additional zone members to sync the * configuration at some later point. */ Zone::Ptr localZone = Zone::GetLocalZone(); String localZoneName; if (localZone) { localZoneName = localZone->GetName(); if (!attrs) { attrs = new Dictionary(); attrs->Set("zone", localZoneName); } else if (!attrs->Contains("zone")) { attrs->Set("zone", localZoneName); } } Dictionary::Ptr result1 = new Dictionary(); String status; Array::Ptr errors = new Array(); bool ignoreOnError = false; if (params->Contains("ignore_on_error")) ignoreOnError = HttpUtility::GetLastParameter(params, "ignore_on_error"); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); String config; try { config = ConfigObjectUtility::CreateObjectConfig(type, name, ignoreOnError, templates, attrs); } catch (const std::exception& ex) { errors->Add(DiagnosticInformation(ex)); result1->Set("errors", errors); result1->Set("code", 500); result1->Set("status", "Object could not be created."); response.SetStatus(500, "Object could not be created"); HttpUtility::SendJsonBody(response, result); return true; } if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) { result1->Set("errors", errors); result1->Set("code", 500); result1->Set("status", "Object could not be created."); response.SetStatus(500, "Object could not be created"); HttpUtility::SendJsonBody(response, result); return true; } ConfigType *ctype = dynamic_cast(type.get()); ConfigObject::Ptr obj = ctype->GetObject(name); result1->Set("code", 200); if (obj) result1->Set("status", "Object was created"); else if (!obj && ignoreOnError) result1->Set("status", "Object was not created but 'ignore_on_error' was set to true"); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/createobjecthandler.hpp000066400000000000000000000035061322762156600216160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CREATEOBJECTHANDLER_H #define CREATEOBJECTHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API CreateObjectHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(CreateObjectHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* CREATEOBJECTHANDLER_H */ icinga2-2.8.1/lib/remote/deleteobjecthandler.cpp000066400000000000000000000075541322762156600216170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/deleteobjecthandler.hpp" #include "remote/configobjectutility.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "remote/apiaction.hpp" #include "config/configitem.hpp" #include "base/exception.hpp" #include "base/serializer.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/objects", DeleteObjectHandler); bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "DELETE") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/delete/" + type->GetName(); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } bool cascade = HttpUtility::GetLastParameter(params, "cascade"); Array::Ptr results = new Array(); bool success = true; for (const ConfigObject::Ptr& obj : objs) { Dictionary::Ptr result1 = new Dictionary(); result1->Set("type", type->GetName()); result1->Set("name", obj->GetName()); results->Add(result1); Array::Ptr errors = new Array(); if (!ConfigObjectUtility::DeleteObject(obj, cascade, errors)) { result1->Set("code", 500); result1->Set("status", "Object could not be deleted."); result1->Set("errors", errors); success = false; } else { result1->Set("code", 200); result1->Set("status", "Object was deleted."); } } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); if (!success) response.SetStatus(500, "One or more objects could not be deleted"); else response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/deleteobjecthandler.hpp000066400000000000000000000035061322762156600216150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef DELETEOBJECTHANDLER_H #define DELETEOBJECTHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API DeleteObjectHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(DeleteObjectHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* DELETEOBJECTHANDLER_H */ icinga2-2.8.1/lib/remote/endpoint.cpp000066400000000000000000000074131322762156600174420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/endpoint.hpp" #include "remote/endpoint.tcpp" #include "remote/apilistener.hpp" #include "remote/jsonrpcconnection.hpp" #include "remote/zone.hpp" #include "base/configtype.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "base/convert.hpp" using namespace icinga; REGISTER_TYPE(Endpoint); boost::signals2::signal Endpoint::OnConnected; boost::signals2::signal Endpoint::OnDisconnected; void Endpoint::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); if (!m_Zone) BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName() + "' does not belong to a zone.", GetDebugInfo())); } void Endpoint::SetCachedZone(const Zone::Ptr& zone) { if (m_Zone) BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName() + "' is in more than one zone.", GetDebugInfo())); m_Zone = zone; } void Endpoint::AddClient(const JsonRpcConnection::Ptr& client) { bool was_master = ApiListener::GetInstance()->IsMaster(); { boost::mutex::scoped_lock lock(m_ClientsLock); m_Clients.insert(client); } bool is_master = ApiListener::GetInstance()->IsMaster(); if (was_master != is_master) ApiListener::OnMasterChanged(is_master); OnConnected(this, client); } void Endpoint::RemoveClient(const JsonRpcConnection::Ptr& client) { bool was_master = ApiListener::GetInstance()->IsMaster(); { boost::mutex::scoped_lock lock(m_ClientsLock); m_Clients.erase(client); Log(LogWarning, "ApiListener") << "Removing API client for endpoint '" << GetName() << "'. " << m_Clients.size() << " API clients left."; SetConnecting(false); } bool is_master = ApiListener::GetInstance()->IsMaster(); if (was_master != is_master) ApiListener::OnMasterChanged(is_master); OnDisconnected(this, client); } std::set Endpoint::GetClients(void) const { boost::mutex::scoped_lock lock(m_ClientsLock); return m_Clients; } Zone::Ptr Endpoint::GetZone(void) const { return m_Zone; } bool Endpoint::GetConnected(void) const { boost::mutex::scoped_lock lock(m_ClientsLock); return !m_Clients.empty(); } Endpoint::Ptr Endpoint::GetLocalEndpoint(void) { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return Endpoint::Ptr(); return listener->GetLocalEndpoint(); } icinga2-2.8.1/lib/remote/endpoint.hpp000066400000000000000000000052031322762156600174420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ENDPOINT_H #define ENDPOINT_H #include "remote/i2-remote.hpp" #include "remote/endpoint.thpp" #include namespace icinga { class JsonRpcConnection; class Zone; /** * An endpoint that can be used to send and receive messages. * * @ingroup remote */ class I2_REMOTE_API Endpoint : public ObjectImpl { public: DECLARE_OBJECT(Endpoint); DECLARE_OBJECTNAME(Endpoint); static boost::signals2::signal&)> OnConnected; static boost::signals2::signal&)> OnDisconnected; void AddClient(const intrusive_ptr& client); void RemoveClient(const intrusive_ptr& client); std::set > GetClients(void) const; intrusive_ptr GetZone(void) const; virtual bool GetConnected(void) const override; static Endpoint::Ptr GetLocalEndpoint(void); void SetCachedZone(const intrusive_ptr& zone); protected: virtual void OnAllConfigLoaded(void) override; private: mutable boost::mutex m_ClientsLock; std::set > m_Clients; intrusive_ptr m_Zone; }; } #endif /* ENDPOINT_H */ icinga2-2.8.1/lib/remote/endpoint.ti000066400000000000000000000036231322762156600172730ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library remote; namespace icinga { class Endpoint : ConfigObject { load_after Zone; [config] String host; [config, required] String port { default {{{ return "5665"; }}} }; [config] double log_duration { default {{{ return 86400; }}} }; [state] Timestamp local_log_position; [state] Timestamp remote_log_position; [no_user_modify] bool connecting; [no_user_modify] bool syncing; [no_user_modify, no_storage] bool connected { get; }; }; } icinga2-2.8.1/lib/remote/eventqueue.cpp000066400000000000000000000107421322762156600200070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/eventqueue.hpp" #include "remote/filterutility.hpp" #include "base/singleton.hpp" #include "base/logger.hpp" using namespace icinga; EventQueue::EventQueue(const String& name) : m_Name(name), m_Filter(NULL) { } EventQueue::~EventQueue(void) { delete m_Filter; } bool EventQueue::CanProcessEvent(const String& type) const { boost::mutex::scoped_lock lock(m_Mutex); return m_Types.find(type) != m_Types.end(); } void EventQueue::ProcessEvent(const Dictionary::Ptr& event) { ScriptFrame frame; frame.Sandboxed = true; try { if (!FilterUtility::EvaluateFilter(frame, m_Filter, event, "event")) return; } catch (const std::exception& ex) { Log(LogWarning, "EventQueue") << "Error occurred while evaluating event filter for queue '" << m_Name << "': " << DiagnosticInformation(ex); return; } boost::mutex::scoped_lock lock(m_Mutex); typedef std::pair > kv_pair; for (kv_pair& kv : m_Events) { kv.second.push_back(event); } m_CV.notify_all(); } void EventQueue::AddClient(void *client) { boost::mutex::scoped_lock lock(m_Mutex); auto result = m_Events.insert(std::make_pair(client, std::deque())); ASSERT(result.second); } void EventQueue::RemoveClient(void *client) { boost::mutex::scoped_lock lock(m_Mutex); m_Events.erase(client); } void EventQueue::UnregisterIfUnused(const String& name, const EventQueue::Ptr& queue) { boost::mutex::scoped_lock lock(queue->m_Mutex); if (queue->m_Events.empty()) Unregister(name); } void EventQueue::SetTypes(const std::set& types) { boost::mutex::scoped_lock lock(m_Mutex); m_Types = types; } void EventQueue::SetFilter(Expression *filter) { boost::mutex::scoped_lock lock(m_Mutex); delete m_Filter; m_Filter = filter; } Dictionary::Ptr EventQueue::WaitForEvent(void *client, double timeout) { boost::mutex::scoped_lock lock(m_Mutex); for (;;) { auto it = m_Events.find(client); ASSERT(it != m_Events.end()); if (!it->second.empty()) { Dictionary::Ptr result = *it->second.begin(); it->second.pop_front(); return result; } if (!m_CV.timed_wait(lock, boost::posix_time::milliseconds(timeout * 1000))) return Dictionary::Ptr(); } } std::vector EventQueue::GetQueuesForType(const String& type) { EventQueueRegistry::ItemMap queues = EventQueueRegistry::GetInstance()->GetItems(); std::vector availQueues; typedef std::pair kv_pair; for (const kv_pair& kv : queues) { if (kv.second->CanProcessEvent(type)) availQueues.push_back(kv.second); } return availQueues; } EventQueue::Ptr EventQueue::GetByName(const String& name) { return EventQueueRegistry::GetInstance()->GetItem(name); } void EventQueue::Register(const String& name, const EventQueue::Ptr& function) { EventQueueRegistry::GetInstance()->Register(name, function); } void EventQueue::Unregister(const String& name) { EventQueueRegistry::GetInstance()->Unregister(name); } EventQueueRegistry *EventQueueRegistry::GetInstance(void) { return Singleton::GetInstance(); } icinga2-2.8.1/lib/remote/eventqueue.hpp000066400000000000000000000057061322762156600200200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EVENTQUEUE_H #define EVENTQUEUE_H #include "remote/httphandler.hpp" #include "base/object.hpp" #include "config/expression.hpp" #include #include #include #include #include #include namespace icinga { class I2_REMOTE_API EventQueue : public Object { public: DECLARE_PTR_TYPEDEFS(EventQueue); EventQueue(const String& name); ~EventQueue(void); bool CanProcessEvent(const String& type) const; void ProcessEvent(const Dictionary::Ptr& event); void AddClient(void *client); void RemoveClient(void *client); void SetTypes(const std::set& types); void SetFilter(Expression *filter); Dictionary::Ptr WaitForEvent(void *client, double timeout = 5); static std::vector GetQueuesForType(const String& type); static void UnregisterIfUnused(const String& name, const EventQueue::Ptr& queue); static EventQueue::Ptr GetByName(const String& name); static void Register(const String& name, const EventQueue::Ptr& function); static void Unregister(const String& name); private: String m_Name; mutable boost::mutex m_Mutex; boost::condition_variable m_CV; std::set m_Types; Expression *m_Filter; std::map > m_Events; }; /** * A registry for API event queues. * * @ingroup base */ class I2_REMOTE_API EventQueueRegistry : public Registry { public: static EventQueueRegistry *GetInstance(void); }; } #endif /* EVENTQUEUE_H */ icinga2-2.8.1/lib/remote/eventshandler.cpp000066400000000000000000000074331322762156600204660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/eventshandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "config/configcompiler.hpp" #include "config/expression.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include using namespace icinga; REGISTER_URLHANDLER("/v1/events", EventsHandler); bool EventsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() != 2) return false; if (request.RequestMethod != "POST") return false; if (request.ProtocolVersion == HttpVersion10) { HttpUtility::SendJsonError(response, 400, "HTTP/1.0 not supported for event streams."); return true; } Array::Ptr types = params->Get("types"); if (!types) { HttpUtility::SendJsonError(response, 400, "'types' query parameter is required."); return true; } { ObjectLock olock(types); for (const String& type : types) { FilterUtility::CheckPermission(user, "events/" + type); } } String queueName = HttpUtility::GetLastParameter(params, "queue"); if (queueName.IsEmpty()) { HttpUtility::SendJsonError(response, 400, "'queue' query parameter is required."); return true; } String filter = HttpUtility::GetLastParameter(params, "filter"); Expression *ufilter = NULL; if (!filter.IsEmpty()) ufilter = ConfigCompiler::CompileText("", filter); /* create a new queue or update an existing one */ EventQueue::Ptr queue = EventQueue::GetByName(queueName); if (!queue) { queue = new EventQueue(queueName); EventQueue::Register(queueName, queue); } queue->SetTypes(types->ToSet()); queue->SetFilter(ufilter); queue->AddClient(&request); response.SetStatus(200, "OK"); response.AddHeader("Content-Type", "application/json"); for (;;) { Dictionary::Ptr result = queue->WaitForEvent(&request); if (!response.IsPeerConnected()) { queue->RemoveClient(&request); EventQueue::UnregisterIfUnused(queueName, queue); return true; } if (!result) continue; String body = JsonEncode(result); boost::algorithm::replace_all(body, "\n", ""); try { response.WriteBody(body.CStr(), body.GetLength()); response.WriteBody("\n", 1); } catch (const std::exception&) { queue->RemoveClient(&request); EventQueue::UnregisterIfUnused(queueName, queue); throw; } } } icinga2-2.8.1/lib/remote/eventshandler.hpp000066400000000000000000000035111322762156600204640ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EVENTSHANDLER_H #define EVENTSHANDLER_H #include "remote/httphandler.hpp" #include "remote/eventqueue.hpp" namespace icinga { class I2_REMOTE_API EventsHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(EventsHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* EVENTSHANDLER_H */ icinga2-2.8.1/lib/remote/filterutility.cpp000066400000000000000000000206751322762156600205400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/filterutility.hpp" #include "remote/httputility.hpp" #include "config/configcompiler.hpp" #include "config/expression.hpp" #include "base/json.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include using namespace icinga; Type::Ptr FilterUtility::TypeFromPluralName(const String& pluralName) { String uname = pluralName; boost::algorithm::to_lower(uname); for (const Type::Ptr&type : Type::GetAllTypes()) { String pname = type->GetPluralName(); boost::algorithm::to_lower(pname); if (uname == pname) return type; } return Type::Ptr(); } void ConfigObjectTargetProvider::FindTargets(const String& type, const boost::function& addTarget) const { Type::Ptr ptype = Type::GetByName(type); ConfigType *ctype = dynamic_cast(ptype.get()); if (ctype) { for (const ConfigObject::Ptr& object : ctype->GetObjects()) { addTarget(object); } } } Value ConfigObjectTargetProvider::GetTargetByName(const String& type, const String& name) const { ConfigObject::Ptr obj = ConfigObject::GetObject(type, name); if (!obj) BOOST_THROW_EXCEPTION(std::invalid_argument("Object does not exist.")); return obj; } bool ConfigObjectTargetProvider::IsValidType(const String& type) const { Type::Ptr ptype = Type::GetByName(type); if (!ptype) return false; return ConfigObject::TypeInstance->IsAssignableFrom(ptype); } String ConfigObjectTargetProvider::GetPluralName(const String& type) const { return Type::GetByName(type)->GetPluralName(); } bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName) { if (!filter) return true; Type::Ptr type = target->GetReflectionType(); String varName; if (variableName.IsEmpty()) varName = type->GetName().ToLower(); else varName = variableName; Dictionary::Ptr vars; if (frame.Self.IsEmpty()) { vars = new Dictionary(); frame.Self = vars; } else vars = frame.Self; vars->Set("obj", target); vars->Set(varName, target); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if ((field.Attributes & FANavigation) == 0) continue; Object::Ptr joinedObj = target->NavigateField(fid); if (field.NavigationName) vars->Set(field.NavigationName, joinedObj); else vars->Set(field.Name, joinedObj); } return Convert::ToBool(filter->Evaluate(frame)); } static void FilteredAddTarget(ScriptFrame& permissionFrame, Expression *permissionFilter, ScriptFrame& frame, Expression *ufilter, std::vector& result, const String& variableName, const Object::Ptr& target) { if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName) && FilterUtility::EvaluateFilter(frame, ufilter, target, variableName)) result.push_back(target); } void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **permissionFilter) { if (permissionFilter) *permissionFilter = NULL; if (permission.IsEmpty()) return; bool foundPermission = false; String requiredPermission = permission.ToLower(); Array::Ptr permissions = user->GetPermissions(); if (permissions) { ObjectLock olock(permissions); for (const Value& item : permissions) { String permission; Function::Ptr filter; if (item.IsObjectType()) { Dictionary::Ptr dict = item; permission = dict->Get("permission"); filter = dict->Get("filter"); } else permission = item; permission = permission.ToLower(); if (!Utility::Match(permission, requiredPermission)) continue; foundPermission = true; if (filter && permissionFilter) { std::vector args; args.push_back(new GetScopeExpression(ScopeLocal)); FunctionCallExpression *fexpr = new FunctionCallExpression(new IndexerExpression(MakeLiteral(filter), MakeLiteral("call")), args); if (!*permissionFilter) *permissionFilter = fexpr; else *permissionFilter = new LogicalOrExpression(*permissionFilter, fexpr); } } } if (!foundPermission) { Log(LogWarning, "FilterUtility") << "Missing permission: " << requiredPermission; BOOST_THROW_EXCEPTION(ScriptError("Missing permission: " + requiredPermission)); } } std::vector FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user, const String& variableName) { std::vector result; TargetProvider::Ptr provider; if (qd.Provider) provider = qd.Provider; else provider = new ConfigObjectTargetProvider(); Expression *permissionFilter; CheckPermission(user, qd.Permission, &permissionFilter); ScriptFrame permissionFrame; for (const String& type : qd.Types) { String attr = type; boost::algorithm::to_lower(attr); if (attr == "type") attr = "name"; if (query->Contains(attr)) { String name = HttpUtility::GetLastParameter(query, attr); Object::Ptr target = provider->GetTargetByName(type, name); if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName)) BOOST_THROW_EXCEPTION(ScriptError("Access denied to object '" + name + "' of type '" + type + "'")); result.push_back(target); } attr = provider->GetPluralName(type); boost::algorithm::to_lower(attr); if (query->Contains(attr)) { Array::Ptr names = query->Get(attr); if (names) { ObjectLock olock(names); for (const String& name : names) { Object::Ptr target = provider->GetTargetByName(type, name); if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName)) BOOST_THROW_EXCEPTION(ScriptError("Access denied to object '" + name + "' of type '" + type + "'")); result.push_back(target); } } } } if (query->Contains("filter") || result.empty()) { if (!query->Contains("type")) BOOST_THROW_EXCEPTION(std::invalid_argument("Type must be specified when using a filter.")); String type = HttpUtility::GetLastParameter(query, "type"); if (!provider->IsValidType(type)) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified.")); if (qd.Types.find(type) == qd.Types.end()) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified for this query.")); ScriptFrame frame; frame.Sandboxed = true; Dictionary::Ptr uvars = new Dictionary(); Expression *ufilter = NULL; if (query->Contains("filter")) { String filter = HttpUtility::GetLastParameter(query, "filter"); ufilter = ConfigCompiler::CompileText("", filter); } Dictionary::Ptr filter_vars = query->Get("filter_vars"); if (filter_vars) { ObjectLock olock(filter_vars); for (const Dictionary::Pair& kv : filter_vars) { uvars->Set(kv.first, kv.second); } } frame.Self = uvars; try { provider->FindTargets(type, boost::bind(&FilteredAddTarget, boost::ref(permissionFrame), permissionFilter, boost::ref(frame), ufilter, boost::ref(result), variableName, _1)); } catch (const std::exception& ex) { delete ufilter; throw; } delete ufilter; } return result; } icinga2-2.8.1/lib/remote/filterutility.hpp000066400000000000000000000063041322762156600205360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FILTERUTILITY_H #define FILTERUTILITY_H #include "remote/i2-remote.hpp" #include "remote/apiuser.hpp" #include "config/expression.hpp" #include "base/dictionary.hpp" #include "base/configobject.hpp" #include namespace icinga { class TargetProvider : public Object { public: DECLARE_PTR_TYPEDEFS(TargetProvider); virtual void FindTargets(const String& type, const boost::function& addTarget) const = 0; virtual Value GetTargetByName(const String& type, const String& name) const = 0; virtual bool IsValidType(const String& type) const = 0; virtual String GetPluralName(const String& type) const = 0; }; class ConfigObjectTargetProvider : public TargetProvider { public: DECLARE_PTR_TYPEDEFS(ConfigObjectTargetProvider); virtual void FindTargets(const String& type, const boost::function& addTarget) const override; virtual Value GetTargetByName(const String& type, const String& name) const override; virtual bool IsValidType(const String& type) const override; virtual String GetPluralName(const String& type) const override; }; struct QueryDescription { std::set Types; TargetProvider::Ptr Provider; String Permission; }; /** * Filter utilities. * * @ingroup remote */ class I2_REMOTE_API FilterUtility { public: static Type::Ptr TypeFromPluralName(const String& pluralName); static void CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **filter = NULL); static std::vector GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user, const String& variableName = String()); static bool EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName = String()); }; } #endif /* FILTERUTILITY_H */ icinga2-2.8.1/lib/remote/httpchunkedencoding.cpp000066400000000000000000000057571322762156600216630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httpchunkedencoding.hpp" #include using namespace icinga; StreamReadStatus HttpChunkedEncoding::ReadChunkFromStream(const Stream::Ptr& stream, char **data, size_t *size, ChunkReadContext& context, bool may_wait) { if (context.LengthIndicator == -1) { String line; StreamReadStatus status = stream->ReadLine(&line, context.StreamContext, may_wait); may_wait = false; if (status != StatusNewItem) return status; std::stringstream msgbuf; msgbuf << std::hex << line; msgbuf >> context.LengthIndicator; } StreamReadContext& scontext = context.StreamContext; if (scontext.Eof) return StatusEof; if (scontext.MustRead) { if (!scontext.FillFromStream(stream, may_wait)) { scontext.Eof = true; return StatusEof; } scontext.MustRead = false; } size_t NewlineLength = context.LengthIndicator ? 2 : 0; if (scontext.Size < (size_t)context.LengthIndicator + NewlineLength) { scontext.MustRead = true; return StatusNeedData; } *data = new char[context.LengthIndicator]; *size = context.LengthIndicator; memcpy(*data, scontext.Buffer, context.LengthIndicator); scontext.DropData(context.LengthIndicator + NewlineLength); context.LengthIndicator = -1; return StatusNewItem; } void HttpChunkedEncoding::WriteChunkToStream(const Stream::Ptr& stream, const char *data, size_t count) { std::ostringstream msgbuf; msgbuf << std::hex << count << "\r\n"; String lengthIndicator = msgbuf.str(); stream->Write(lengthIndicator.CStr(), lengthIndicator.GetLength()); stream->Write(data, count); if (count > 0) stream->Write("\r\n", 2); } icinga2-2.8.1/lib/remote/httpchunkedencoding.hpp000066400000000000000000000041651322762156600216600ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPCHUNKEDENCODING_H #define HTTPCHUNKEDENCODING_H #include "remote/i2-remote.hpp" #include "base/stream.hpp" namespace icinga { struct ChunkReadContext { StreamReadContext& StreamContext; int LengthIndicator; ChunkReadContext(StreamReadContext& scontext) : StreamContext(scontext), LengthIndicator(-1) { } }; /** * HTTP chunked encoding. * * @ingroup remote */ struct I2_REMOTE_API HttpChunkedEncoding { static StreamReadStatus ReadChunkFromStream(const Stream::Ptr& stream, char **data, size_t *size, ChunkReadContext& ccontext, bool may_wait = false); static void WriteChunkToStream(const Stream::Ptr& stream, const char *data, size_t count); }; } #endif /* HTTPCHUNKEDENCODING_H */ icinga2-2.8.1/lib/remote/httpclientconnection.cpp000066400000000000000000000120041322762156600220500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httpclientconnection.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/base64.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include "base/tcpsocket.hpp" #include "base/tlsstream.hpp" #include "base/networkstream.hpp" #include using namespace icinga; HttpClientConnection::HttpClientConnection(const String& host, const String& port, bool tls) : m_Host(host), m_Port(port), m_Tls(tls) { } void HttpClientConnection::Start(void) { /* Nothing to do here atm. */ } void HttpClientConnection::Reconnect(void) { if (m_Stream) m_Stream->Close(); m_Context.~StreamReadContext(); new (&m_Context) StreamReadContext(); m_Requests.clear(); m_CurrentResponse.reset(); TcpSocket::Ptr socket = new TcpSocket(); socket->Connect(m_Host, m_Port); if (m_Tls) m_Stream = new TlsStream(socket, m_Host, RoleClient); else ASSERT(!"Non-TLS HTTP connections not supported."); /* m_Stream = new NetworkStream(socket); -- does not currently work because the NetworkStream class doesn't support async I/O */ /* the stream holds an owning reference to this object through the callback we're registering here */ m_Stream->RegisterDataHandler(boost::bind(&HttpClientConnection::DataAvailableHandler, HttpClientConnection::Ptr(this), _1)); if (m_Stream->IsDataAvailable()) DataAvailableHandler(m_Stream); } Stream::Ptr HttpClientConnection::GetStream(void) const { return m_Stream; } String HttpClientConnection::GetHost(void) const { return m_Host; } String HttpClientConnection::GetPort(void) const { return m_Port; } bool HttpClientConnection::GetTls(void) const { return m_Tls; } void HttpClientConnection::Disconnect(void) { Log(LogDebug, "HttpClientConnection", "Http client disconnected"); m_Stream->Shutdown(); } bool HttpClientConnection::ProcessMessage(void) { bool res; if (m_Requests.empty()) { m_Stream->Close(); return false; } const std::pair, HttpCompletionCallback>& currentRequest = *m_Requests.begin(); HttpRequest& request = *currentRequest.first.get(); const HttpCompletionCallback& callback = currentRequest.second; if (!m_CurrentResponse) m_CurrentResponse = boost::make_shared(m_Stream, request); boost::shared_ptr currentResponse = m_CurrentResponse; HttpResponse& response = *currentResponse.get(); try { res = response.Parse(m_Context, false); } catch (const std::exception& ex) { callback(request, response); m_Stream->Shutdown(); return false; } if (response.Complete) { callback(request, response); m_Requests.pop_front(); m_CurrentResponse.reset(); return true; } return res; } void HttpClientConnection::DataAvailableHandler(const Stream::Ptr& stream) { ASSERT(stream == m_Stream); bool close = false; if (!m_Stream->IsEof()) { boost::mutex::scoped_lock lock(m_DataHandlerMutex); try { while (ProcessMessage()) ; /* empty loop body */ } catch (const std::exception& ex) { Log(LogWarning, "HttpClientConnection") << "Error while reading Http response: " << DiagnosticInformation(ex); close = true; Disconnect(); } } else close = true; if (close) m_Stream->Close(); } boost::shared_ptr HttpClientConnection::NewRequest(void) { Reconnect(); return boost::make_shared(m_Stream); } void HttpClientConnection::SubmitRequest(const boost::shared_ptr& request, const HttpCompletionCallback& callback) { m_Requests.push_back(std::make_pair(request, callback)); request->Finish(); } icinga2-2.8.1/lib/remote/httpclientconnection.hpp000066400000000000000000000053771322762156600220740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPCLIENTCONNECTION_H #define HTTPCLIENTCONNECTION_H #include "remote/httprequest.hpp" #include "remote/httpresponse.hpp" #include "base/stream.hpp" #include "base/timer.hpp" #include namespace icinga { /** * An HTTP client connection. * * @ingroup remote */ class I2_REMOTE_API HttpClientConnection : public Object { public: DECLARE_PTR_TYPEDEFS(HttpClientConnection); HttpClientConnection(const String& host, const String& port, bool tls = true); void Start(void); Stream::Ptr GetStream(void) const; String GetHost(void) const; String GetPort(void) const; bool GetTls(void) const; void Disconnect(void); boost::shared_ptr NewRequest(void); typedef boost::function HttpCompletionCallback; void SubmitRequest(const boost::shared_ptr& request, const HttpCompletionCallback& callback); private: String m_Host; String m_Port; bool m_Tls; Stream::Ptr m_Stream; std::deque, HttpCompletionCallback> > m_Requests; boost::shared_ptr m_CurrentResponse; boost::mutex m_DataHandlerMutex; StreamReadContext m_Context; void Reconnect(void); bool ProcessMessage(void); void DataAvailableHandler(const Stream::Ptr& stream); void ProcessMessageAsync(HttpRequest& request); }; } #endif /* HTTPCLIENTCONNECTION_H */ icinga2-2.8.1/lib/remote/httphandler.cpp000066400000000000000000000074311322762156600201370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httphandler.hpp" #include "remote/httputility.hpp" #include "base/singleton.hpp" #include "base/exception.hpp" #include using namespace icinga; Dictionary::Ptr HttpHandler::m_UrlTree; void HttpHandler::Register(const Url::Ptr& url, const HttpHandler::Ptr& handler) { if (!m_UrlTree) m_UrlTree = new Dictionary(); Dictionary::Ptr node = m_UrlTree; for (const String& elem : url->GetPath()) { Dictionary::Ptr children = node->Get("children"); if (!children) { children = new Dictionary(); node->Set("children", children); } Dictionary::Ptr sub_node = children->Get(elem); if (!sub_node) { sub_node = new Dictionary(); children->Set(elem, sub_node); } node = sub_node; } Array::Ptr handlers = node->Get("handlers"); if (!handlers) { handlers = new Array(); node->Set("handlers", handlers); } handlers->Add(handler); } void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { Dictionary::Ptr node = m_UrlTree; std::vector handlers; const std::vector& path = request.RequestUrl->GetPath(); for (std::vector::size_type i = 0; i <= path.size(); i++) { Array::Ptr current_handlers = node->Get("handlers"); if (current_handlers) { ObjectLock olock(current_handlers); for (const HttpHandler::Ptr current_handler : current_handlers) { handlers.push_back(current_handler); } } Dictionary::Ptr children = node->Get("children"); if (!children) { node.reset(); break; } if (i == path.size()) break; node = children->Get(path[i]); if (!node) break; } std::reverse(handlers.begin(), handlers.end()); Dictionary::Ptr params; try { params = HttpUtility::FetchRequestParameters(request); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 400, "Invalid request body: " + DiagnosticInformation(ex, false)); return; } bool processed = false; for (const HttpHandler::Ptr& handler : handlers) { if (handler->HandleRequest(user, request, response, params)) { processed = true; break; } } if (!processed) { String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/"); HttpUtility::SendJsonError(response, 404, "The requested path '" + path + "' could not be found or the request method is not valid for this path."); return; } } icinga2-2.8.1/lib/remote/httphandler.hpp000066400000000000000000000050641322762156600201440ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPHANDLER_H #define HTTPHANDLER_H #include "remote/i2-remote.hpp" #include "remote/httpresponse.hpp" #include "remote/apiuser.hpp" #include "base/registry.hpp" #include #include namespace icinga { /** * HTTP handler. * * @ingroup remote */ class I2_REMOTE_API HttpHandler : public Object { public: DECLARE_PTR_TYPEDEFS(HttpHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) = 0; static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler); static void ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response); private: static Dictionary::Ptr m_UrlTree; }; /** * Helper class for registering HTTP handlers. * * @ingroup remote */ class I2_REMOTE_API RegisterHttpHandler { public: RegisterHttpHandler(const String& url, const HttpHandler& function); }; #define REGISTER_URLHANDLER(url, klass) \ INITIALIZE_ONCE([]() { \ Url::Ptr uurl = new Url(url); \ HttpHandler::Ptr handler = new klass(); \ HttpHandler::Register(uurl, handler); \ }) } #endif /* HTTPHANDLER_H */ icinga2-2.8.1/lib/remote/httprequest.cpp000066400000000000000000000155641322762156600202200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httprequest.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/convert.hpp" #include #include #include #include using namespace icinga; HttpRequest::HttpRequest(const Stream::Ptr& stream) : Complete(false), ProtocolVersion(HttpVersion11), Headers(new Dictionary()), m_Stream(stream), m_State(HttpRequestStart) { } bool HttpRequest::Parse(StreamReadContext& src, bool may_wait) { if (!m_Stream) return false; if (m_State != HttpRequestBody) { String line; StreamReadStatus srs = m_Stream->ReadLine(&line, src, may_wait); if (srs != StatusNewItem) return false; if (m_State == HttpRequestStart) { /* ignore trailing new-lines */ if (line == "") return true; std::vector tokens; boost::algorithm::split(tokens, line, boost::is_any_of(" ")); Log(LogDebug, "HttpRequest") << "line: " << line << ", tokens: " << tokens.size(); if (tokens.size() != 3) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request")); RequestMethod = tokens[0]; RequestUrl = new class Url(tokens[1]); if (tokens[2] == "HTTP/1.0") ProtocolVersion = HttpVersion10; else if (tokens[2] == "HTTP/1.1") { ProtocolVersion = HttpVersion11; } else BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported HTTP version")); m_State = HttpRequestHeaders; } else if (m_State == HttpRequestHeaders) { if (line == "") { m_State = HttpRequestBody; /* we're done if the request doesn't contain a message body */ if (!Headers->Contains("content-length") && !Headers->Contains("transfer-encoding")) Complete = true; else m_Body = new FIFO(); return true; } else { String::SizeType pos = line.FindFirstOf(":"); if (pos == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request")); String key = line.SubStr(0, pos).ToLower().Trim(); String value = line.SubStr(pos + 1).Trim(); Headers->Set(key, value); if (key == "x-http-method-override") RequestMethod = value; } } else { VERIFY(!"Invalid HTTP request state."); } } else if (m_State == HttpRequestBody) { if (Headers->Get("transfer-encoding") == "chunked") { if (!m_ChunkContext) m_ChunkContext = boost::make_shared(boost::ref(src)); char *data; size_t size; StreamReadStatus srs = HttpChunkedEncoding::ReadChunkFromStream(m_Stream, &data, &size, *m_ChunkContext.get(), may_wait); if (srs != StatusNewItem) return false; m_Body->Write(data, size); delete [] data; if (size == 0) { Complete = true; return true; } } else { if (src.Eof) BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body")); if (src.MustRead) { if (!src.FillFromStream(m_Stream, false)) { src.Eof = true; BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body")); } src.MustRead = false; } size_t length_indicator = Convert::ToLong(Headers->Get("content-length")); if (src.Size < length_indicator) { src.MustRead = true; return false; } m_Body->Write(src.Buffer, length_indicator); src.DropData(length_indicator); Complete = true; return true; } } return true; } size_t HttpRequest::ReadBody(char *data, size_t count) { if (!m_Body) return 0; else return m_Body->Read(data, count, true); } void HttpRequest::AddHeader(const String& key, const String& value) { ASSERT(m_State == HttpRequestStart || m_State == HttpRequestHeaders); Headers->Set(key.ToLower(), value); } void HttpRequest::FinishHeaders(void) { if (m_State == HttpRequestStart) { String rqline = RequestMethod + " " + RequestUrl->Format(true) + " HTTP/1." + (ProtocolVersion == HttpVersion10 ? "0" : "1") + "\n"; m_Stream->Write(rqline.CStr(), rqline.GetLength()); m_State = HttpRequestHeaders; } if (m_State == HttpRequestHeaders) { AddHeader("User-Agent", "Icinga/" + Application::GetAppVersion()); if (ProtocolVersion == HttpVersion11) { AddHeader("Transfer-Encoding", "chunked"); if (!Headers->Contains("Host")) AddHeader("Host", RequestUrl->GetHost() + ":" + RequestUrl->GetPort()); } ObjectLock olock(Headers); for (const Dictionary::Pair& kv : Headers) { String header = kv.first + ": " + kv.second + "\n"; m_Stream->Write(header.CStr(), header.GetLength()); } m_Stream->Write("\n", 1); m_State = HttpRequestBody; } } void HttpRequest::WriteBody(const char *data, size_t count) { ASSERT(m_State == HttpRequestStart || m_State == HttpRequestHeaders || m_State == HttpRequestBody); if (ProtocolVersion == HttpVersion10) { if (!m_Body) m_Body = new FIFO(); m_Body->Write(data, count); } else { FinishHeaders(); HttpChunkedEncoding::WriteChunkToStream(m_Stream, data, count); } } void HttpRequest::Finish(void) { ASSERT(m_State != HttpRequestEnd); if (ProtocolVersion == HttpVersion10) { if (m_Body) AddHeader("Content-Length", Convert::ToString(m_Body->GetAvailableBytes())); FinishHeaders(); while (m_Body && m_Body->IsDataAvailable()) { char buffer[1024]; size_t rc = m_Body->Read(buffer, sizeof(buffer), true); m_Stream->Write(buffer, rc); } } else { if (m_State == HttpRequestStart || m_State == HttpRequestHeaders) FinishHeaders(); WriteBody(NULL, 0); m_Stream->Write("\r\n", 2); } m_State = HttpRequestEnd; } icinga2-2.8.1/lib/remote/httprequest.hpp000066400000000000000000000047271322762156600202240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPREQUEST_H #define HTTPREQUEST_H #include "remote/i2-remote.hpp" #include "remote/httpchunkedencoding.hpp" #include "remote/url.hpp" #include "base/stream.hpp" #include "base/fifo.hpp" #include "base/dictionary.hpp" namespace icinga { enum HttpVersion { HttpVersion10, HttpVersion11 }; enum HttpRequestState { HttpRequestStart, HttpRequestHeaders, HttpRequestBody, HttpRequestEnd }; /** * An HTTP request. * * @ingroup remote */ struct I2_REMOTE_API HttpRequest { public: bool Complete; String RequestMethod; Url::Ptr RequestUrl; HttpVersion ProtocolVersion; Dictionary::Ptr Headers; HttpRequest(const Stream::Ptr& stream); bool Parse(StreamReadContext& src, bool may_wait); size_t ReadBody(char *data, size_t count); void AddHeader(const String& key, const String& value); void WriteBody(const char *data, size_t count); void Finish(void); private: Stream::Ptr m_Stream; boost::shared_ptr m_ChunkContext; HttpRequestState m_State; FIFO::Ptr m_Body; void FinishHeaders(void); }; } #endif /* HTTPREQUEST_H */ icinga2-2.8.1/lib/remote/httpresponse.cpp000066400000000000000000000163201322762156600203550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httpresponse.hpp" #include "remote/httpchunkedencoding.hpp" #include "base/logger.hpp" #include #include #include "base/application.hpp" #include "base/convert.hpp" #include using namespace icinga; HttpResponse::HttpResponse(const Stream::Ptr& stream, const HttpRequest& request) : Complete(false), m_State(HttpResponseStart), m_Request(request), m_Stream(stream) { } void HttpResponse::SetStatus(int code, const String& message) { ASSERT(code >= 100 && code <= 599); ASSERT(!message.IsEmpty()); if (m_State != HttpResponseStart) { Log(LogWarning, "HttpResponse", "Tried to set Http response status after headers had already been sent."); return; } String status = "HTTP/"; if (m_Request.ProtocolVersion == HttpVersion10) status += "1.0"; else status += "1.1"; status += " " + Convert::ToString(code) + " " + message + "\r\n"; m_Stream->Write(status.CStr(), status.GetLength()); m_State = HttpResponseHeaders; } void HttpResponse::AddHeader(const String& key, const String& value) { m_Headers.push_back(key + ": " + value + "\r\n"); } void HttpResponse::FinishHeaders(void) { if (m_State == HttpResponseHeaders) { if (m_Request.ProtocolVersion == HttpVersion11) AddHeader("Transfer-Encoding", "chunked"); AddHeader("Server", "Icinga/" + Application::GetAppVersion()); for (const String& header : m_Headers) m_Stream->Write(header.CStr(), header.GetLength()); m_Stream->Write("\r\n", 2); m_State = HttpResponseBody; } } void HttpResponse::WriteBody(const char *data, size_t count) { ASSERT(m_State == HttpResponseHeaders || m_State == HttpResponseBody); if (m_Request.ProtocolVersion == HttpVersion10) { if (!m_Body) m_Body = new FIFO(); m_Body->Write(data, count); } else { FinishHeaders(); HttpChunkedEncoding::WriteChunkToStream(m_Stream, data, count); } } void HttpResponse::Finish(void) { ASSERT(m_State != HttpResponseEnd); if (m_Request.ProtocolVersion == HttpVersion10) { if (m_Body) AddHeader("Content-Length", Convert::ToString(m_Body->GetAvailableBytes())); FinishHeaders(); while (m_Body && m_Body->IsDataAvailable()) { char buffer[1024]; size_t rc = m_Body->Read(buffer, sizeof(buffer), true); m_Stream->Write(buffer, rc); } } else { WriteBody(NULL, 0); m_Stream->Write("\r\n", 2); } m_State = HttpResponseEnd; if (m_Request.ProtocolVersion == HttpVersion10 || m_Request.Headers->Get("connection") == "close") m_Stream->Shutdown(); } bool HttpResponse::Parse(StreamReadContext& src, bool may_wait) { if (m_State != HttpResponseBody) { String line; StreamReadStatus srs = m_Stream->ReadLine(&line, src, may_wait); if (srs != StatusNewItem) return false; if (m_State == HttpResponseStart) { /* ignore trailing new-lines */ if (line == "") return true; std::vector tokens; boost::algorithm::split(tokens, line, boost::is_any_of(" ")); Log(LogDebug, "HttpRequest") << "line: " << line << ", tokens: " << tokens.size(); if (tokens.size() < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP response (Status line)")); if (tokens[0] == "HTTP/1.0") ProtocolVersion = HttpVersion10; else if (tokens[0] == "HTTP/1.1") { ProtocolVersion = HttpVersion11; } else BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported HTTP version")); StatusCode = Convert::ToLong(tokens[1]); if (tokens.size() >= 3) StatusMessage = tokens[2]; // TODO: Join tokens[2..end] m_State = HttpResponseHeaders; } else if (m_State == HttpResponseHeaders) { if (!Headers) Headers = new Dictionary(); if (line == "") { m_State = HttpResponseBody; /* we're done if the request doesn't contain a message body */ if (!Headers->Contains("content-length") && !Headers->Contains("transfer-encoding")) Complete = true; else m_Body = new FIFO(); return true; } else { String::SizeType pos = line.FindFirstOf(":"); if (pos == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request")); String key = line.SubStr(0, pos).ToLower().Trim(); String value = line.SubStr(pos + 1).Trim(); Headers->Set(key, value); } } else { VERIFY(!"Invalid HTTP request state."); } } else if (m_State == HttpResponseBody) { if (Headers->Get("transfer-encoding") == "chunked") { if (!m_ChunkContext) m_ChunkContext = boost::make_shared(boost::ref(src)); char *data; size_t size; StreamReadStatus srs = HttpChunkedEncoding::ReadChunkFromStream(m_Stream, &data, &size, *m_ChunkContext.get(), may_wait); if (srs != StatusNewItem) return false; Log(LogNotice, "HttpResponse") << "Read " << size << " bytes"; m_Body->Write(data, size); delete[] data; if (size == 0) { Complete = true; return true; } } else { if (src.Eof) BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body")); if (src.MustRead) { if (!src.FillFromStream(m_Stream, false)) { src.Eof = true; BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body")); } src.MustRead = false; } size_t length_indicator = Convert::ToLong(Headers->Get("content-length")); if (src.Size < length_indicator) { src.MustRead = true; return false; } m_Body->Write(src.Buffer, length_indicator); src.DropData(length_indicator); Complete = true; return true; } } return true; } size_t HttpResponse::ReadBody(char *data, size_t count) { if (!m_Body) return 0; else return m_Body->Read(data, count, true); } size_t HttpResponse::GetBodySize(void) const { if (!m_Body) return 0; else return m_Body->GetAvailableBytes(); } bool HttpResponse::IsPeerConnected(void) const { return !m_Stream->IsEof(); } icinga2-2.8.1/lib/remote/httpresponse.hpp000066400000000000000000000050531322762156600203630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPRESPONSE_H #define HTTPRESPONSE_H #include "remote/httprequest.hpp" #include "base/stream.hpp" #include "base/fifo.hpp" #include namespace icinga { enum HttpResponseState { HttpResponseStart, HttpResponseHeaders, HttpResponseBody, HttpResponseEnd }; /** * An HTTP response. * * @ingroup remote */ struct I2_REMOTE_API HttpResponse { public: bool Complete; HttpVersion ProtocolVersion; int StatusCode; String StatusMessage; Dictionary::Ptr Headers; HttpResponse(const Stream::Ptr& stream, const HttpRequest& request); bool Parse(StreamReadContext& src, bool may_wait); size_t ReadBody(char *data, size_t count); size_t GetBodySize(void) const; void SetStatus(int code, const String& message); void AddHeader(const String& key, const String& value); void WriteBody(const char *data, size_t count); void Finish(void); bool IsPeerConnected(void) const; private: HttpResponseState m_State; boost::shared_ptr m_ChunkContext; const HttpRequest& m_Request; Stream::Ptr m_Stream; FIFO::Ptr m_Body; std::vector m_Headers; void FinishHeaders(void); }; } #endif /* HTTPRESPONSE_H */ icinga2-2.8.1/lib/remote/httpserverconnection.cpp000066400000000000000000000233601322762156600221070ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httpserverconnection.hpp" #include "remote/httphandler.hpp" #include "remote/httputility.hpp" #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "remote/jsonrpc.hpp" #include "base/base64.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include using namespace icinga; static boost::once_flag l_HttpServerConnectionOnceFlag = BOOST_ONCE_INIT; static Timer::Ptr l_HttpServerConnectionTimeoutTimer; HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream) : m_Stream(stream), m_Seen(Utility::GetTime()), m_CurrentRequest(stream), m_PendingRequests(0) { boost::call_once(l_HttpServerConnectionOnceFlag, &HttpServerConnection::StaticInitialize); m_RequestQueue.SetName("HttpServerConnection"); if (authenticated) m_ApiUser = ApiUser::GetByClientCN(identity); } void HttpServerConnection::StaticInitialize(void) { l_HttpServerConnectionTimeoutTimer = new Timer(); l_HttpServerConnectionTimeoutTimer->OnTimerExpired.connect(boost::bind(&HttpServerConnection::TimeoutTimerHandler)); l_HttpServerConnectionTimeoutTimer->SetInterval(15); l_HttpServerConnectionTimeoutTimer->Start(); } void HttpServerConnection::Start(void) { /* the stream holds an owning reference to this object through the callback we're registering here */ m_Stream->RegisterDataHandler(boost::bind(&HttpServerConnection::DataAvailableHandler, HttpServerConnection::Ptr(this))); if (m_Stream->IsDataAvailable()) DataAvailableHandler(); } ApiUser::Ptr HttpServerConnection::GetApiUser(void) const { return m_ApiUser; } TlsStream::Ptr HttpServerConnection::GetStream(void) const { return m_Stream; } void HttpServerConnection::Disconnect(void) { Log(LogDebug, "HttpServerConnection", "Http client disconnected"); ApiListener::Ptr listener = ApiListener::GetInstance(); listener->RemoveHttpClient(this); m_CurrentRequest.~HttpRequest(); new (&m_CurrentRequest) HttpRequest(Stream::Ptr()); m_Stream->Close(); } bool HttpServerConnection::ProcessMessage(void) { bool res; try { res = m_CurrentRequest.Parse(m_Context, false); } catch (const std::invalid_argument& ex) { HttpResponse response(m_Stream, m_CurrentRequest); response.SetStatus(400, "Bad request"); String msg = String("

Bad request

") + ex.what() + "

"; response.WriteBody(msg.CStr(), msg.GetLength()); response.Finish(); m_Stream->Shutdown(); return false; } catch (const std::exception& ex) { HttpResponse response(m_Stream, m_CurrentRequest); response.SetStatus(400, "Bad request"); String msg = "

Bad request

" + DiagnosticInformation(ex) + "

"; response.WriteBody(msg.CStr(), msg.GetLength()); response.Finish(); m_Stream->Shutdown(); return false; } if (m_CurrentRequest.Complete) { m_RequestQueue.Enqueue(boost::bind(&HttpServerConnection::ProcessMessageAsync, HttpServerConnection::Ptr(this), m_CurrentRequest)); m_Seen = Utility::GetTime(); m_PendingRequests++; m_CurrentRequest.~HttpRequest(); new (&m_CurrentRequest) HttpRequest(m_Stream); return true; } return res; } void HttpServerConnection::ProcessMessageAsync(HttpRequest& request) { String auth_header = request.Headers->Get("authorization"); String::SizeType pos = auth_header.FindFirstOf(" "); String username, password; if (pos != String::NPos && auth_header.SubStr(0, pos) == "Basic") { String credentials_base64 = auth_header.SubStr(pos + 1); String credentials = Base64::Decode(credentials_base64); String::SizeType cpos = credentials.FindFirstOf(":"); if (cpos != String::NPos) { username = credentials.SubStr(0, cpos); password = credentials.SubStr(cpos + 1); } } ApiUser::Ptr user; /* client_cn matched. */ if (m_ApiUser) user = m_ApiUser; else { user = ApiUser::GetByName(username); /* Deny authentication if 1) given password is empty 2) configured password does not match. */ if (password.IsEmpty()) user.reset(); else if (user && user->GetPassword() != password) user.reset(); } String requestUrl = request.RequestUrl->Format(); Log(LogInformation, "HttpServerConnection") << "Request: " << request.RequestMethod << " " << requestUrl << " (from " << m_Stream->GetSocket()->GetPeerAddress() << ", user: " << (user ? user->GetName() : "") << ")"; HttpResponse response(m_Stream, request); ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Array::Ptr headerAllowOrigin = listener->GetAccessControlAllowOrigin(); if (headerAllowOrigin->GetLength() != 0) { String origin = request.Headers->Get("origin"); { ObjectLock olock(headerAllowOrigin); for (const String& allowedOrigin : headerAllowOrigin) { if (allowedOrigin == origin) response.AddHeader("Access-Control-Allow-Origin", origin); } } if (listener->GetAccessControlAllowCredentials()) response.AddHeader("Access-Control-Allow-Credentials", "true"); String accessControlRequestMethodHeader = request.Headers->Get("access-control-request-method"); if (!accessControlRequestMethodHeader.IsEmpty()) { response.SetStatus(200, "OK"); response.AddHeader("Access-Control-Allow-Methods", listener->GetAccessControlAllowMethods()); response.AddHeader("Access-Control-Allow-Headers", listener->GetAccessControlAllowHeaders()); String msg = "Preflight OK"; response.WriteBody(msg.CStr(), msg.GetLength()); response.Finish(); m_PendingRequests--; return; } } String accept_header = request.Headers->Get("accept"); if (request.RequestMethod != "GET" && accept_header != "application/json") { response.SetStatus(400, "Wrong Accept header"); response.AddHeader("Content-Type", "text/html"); String msg = "

Accept header is missing or not set to 'application/json'.

"; response.WriteBody(msg.CStr(), msg.GetLength()); } else if (!user) { Log(LogWarning, "HttpServerConnection") << "Unauthorized request: " << request.RequestMethod << " " << requestUrl; response.SetStatus(401, "Unauthorized"); response.AddHeader("WWW-Authenticate", "Basic realm=\"Icinga 2\""); if (request.Headers->Get("accept") == "application/json") { Dictionary::Ptr result = new Dictionary(); result->Set("error", 401); result->Set("status", "Unauthorized. Please check your user credentials."); HttpUtility::SendJsonBody(response, result); } else { response.AddHeader("Content-Type", "text/html"); String msg = "

Unauthorized. Please check your user credentials.

"; response.WriteBody(msg.CStr(), msg.GetLength()); } } else { try { HttpHandler::ProcessRequest(user, request, response); } catch (const std::exception& ex) { Log(LogCritical, "HttpServerConnection") << "Unhandled exception while processing Http request: " << DiagnosticInformation(ex); response.SetStatus(503, "Unhandled exception"); String errorInfo = DiagnosticInformation(ex); if (request.Headers->Get("accept") == "application/json") { Dictionary::Ptr result = new Dictionary(); result->Set("error", 503); result->Set("status", errorInfo); HttpUtility::SendJsonBody(response, result); } else { response.AddHeader("Content-Type", "text/plain"); response.WriteBody(errorInfo.CStr(), errorInfo.GetLength()); } } } response.Finish(); m_PendingRequests--; } void HttpServerConnection::DataAvailableHandler(void) { bool close = false; if (!m_Stream->IsEof()) { boost::mutex::scoped_lock lock(m_DataHandlerMutex); try { while (ProcessMessage()) ; /* empty loop body */ } catch (const std::exception& ex) { Log(LogWarning, "HttpServerConnection") << "Error while reading Http request: " << DiagnosticInformation(ex); close = true; } } else close = true; if (close) Disconnect(); } void HttpServerConnection::CheckLiveness(void) { if (m_Seen < Utility::GetTime() - 10 && m_PendingRequests == 0) { Log(LogInformation, "HttpServerConnection") << "No messages for Http connection have been received in the last 10 seconds."; Disconnect(); } } void HttpServerConnection::TimeoutTimerHandler(void) { ApiListener::Ptr listener = ApiListener::GetInstance(); for (const HttpServerConnection::Ptr& client : listener->GetHttpClients()) { client->CheckLiveness(); } } icinga2-2.8.1/lib/remote/httpserverconnection.hpp000066400000000000000000000050341322762156600221120ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPSERVERCONNECTION_H #define HTTPSERVERCONNECTION_H #include "remote/httprequest.hpp" #include "remote/apiuser.hpp" #include "base/tlsstream.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" namespace icinga { /** * An API client connection. * * @ingroup remote */ class I2_REMOTE_API HttpServerConnection : public Object { public: DECLARE_PTR_TYPEDEFS(HttpServerConnection); HttpServerConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream); void Start(void); ApiUser::Ptr GetApiUser(void) const; bool IsAuthenticated(void) const; TlsStream::Ptr GetStream(void) const; void Disconnect(void); private: ApiUser::Ptr m_ApiUser; TlsStream::Ptr m_Stream; double m_Seen; HttpRequest m_CurrentRequest; boost::mutex m_DataHandlerMutex; WorkQueue m_RequestQueue; int m_PendingRequests; StreamReadContext m_Context; bool ProcessMessage(void); void DataAvailableHandler(void); static void StaticInitialize(void); static void TimeoutTimerHandler(void); void CheckLiveness(void); void ProcessMessageAsync(HttpRequest& request); }; } #endif /* HTTPSERVERCONNECTION_H */ icinga2-2.8.1/lib/remote/httputility.cpp000066400000000000000000000071561322762156600202310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/httputility.hpp" #include "base/json.hpp" #include "base/logger.hpp" using namespace icinga; Dictionary::Ptr HttpUtility::FetchRequestParameters(HttpRequest& request) { Dictionary::Ptr result; String body; char buffer[1024]; size_t count; while ((count = request.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); if (!body.IsEmpty()) { #ifdef I2_DEBUG Log(LogDebug, "HttpUtility") << "Request body: '" << body << "'"; #endif /* I2_DEBUG */ result = JsonDecode(body); } if (!result) result = new Dictionary(); typedef std::pair > kv_pair; for (const kv_pair& kv : request.RequestUrl->GetQuery()) { result->Set(kv.first, Array::FromVector(kv.second)); } return result; } void HttpUtility::SendJsonBody(HttpResponse& response, const Value& val) { response.AddHeader("Content-Type", "application/json"); String body = JsonEncode(val); response.WriteBody(body.CStr(), body.GetLength()); } Value HttpUtility::GetLastParameter(const Dictionary::Ptr& params, const String& key) { Value varr = params->Get(key); if (!varr.IsObjectType()) return varr; Array::Ptr arr = varr; if (arr->GetLength() == 0) return Empty; else return arr->Get(arr->GetLength() - 1); } void HttpUtility::SendJsonError(HttpResponse& response, const int code, const String& info, const String& diagnosticInformation) { Dictionary::Ptr result = new Dictionary(); response.SetStatus(code, HttpUtility::GetErrorNameByCode(code)); result->Set("error", code); if (!info.IsEmpty()) result->Set("status", info); if (!diagnosticInformation.IsEmpty()) result->Set("diagnostic information", diagnosticInformation); HttpUtility::SendJsonBody(response, result); } String HttpUtility::GetErrorNameByCode(const int code) { switch(code) { case 200: return "OK"; case 201: return "Created"; case 204: return "No Content"; case 304: return "Not Modified"; case 400: return "Bad Request"; case 401: return "Unauthorized"; case 403: return "Forbidden"; case 404: return "Not Found"; case 409: return "Conflict"; case 500: return "Internal Server Error"; default: return "Unknown Error Code"; } } icinga2-2.8.1/lib/remote/httputility.hpp000066400000000000000000000041701322762156600202270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef HTTPUTILITY_H #define HTTPUTILITY_H #include "remote/httprequest.hpp" #include "remote/httpresponse.hpp" #include "base/dictionary.hpp" namespace icinga { /** * Helper functions. * * @ingroup remote */ class I2_REMOTE_API HttpUtility { public: static Dictionary::Ptr FetchRequestParameters(HttpRequest& request); static void SendJsonBody(HttpResponse& response, const Value& val); static Value GetLastParameter(const Dictionary::Ptr& params, const String& key); static void SendJsonError(HttpResponse& response, const int code, const String& verbose = String(), const String& diagnosticInformation = String()); private: static String GetErrorNameByCode(int code); }; } #endif /* HTTPUTILITY_H */ icinga2-2.8.1/lib/remote/i2-remote.hpp000066400000000000000000000033771322762156600174370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef I2REMOTE_H #define I2REMOTE_H /** * @defgroup remote Remote library * * The Icinga library implements remote cluster functionality. */ #include "base/i2-base.hpp" #ifdef I2_REMOTE_BUILD # define I2_REMOTE_API I2_EXPORT #else /* I2_REMOTE_BUILD */ # define I2_REMOTE_API I2_IMPORT #endif /* I2_REMOTE_BUILD */ #endif /* I2REMOTE_H */ icinga2-2.8.1/lib/remote/infohandler.cpp000066400000000000000000000077331322762156600201200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/infohandler.hpp" #include "remote/httputility.hpp" #include "base/application.hpp" using namespace icinga; REGISTER_URLHANDLER("/", InfoHandler); bool InfoHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 2) return false; if (request.RequestMethod != "GET") return false; if (request.RequestUrl->GetPath().empty()) { response.SetStatus(302, "Found"); response.AddHeader("Location", "/v1"); return true; } if (request.RequestUrl->GetPath()[0] != "v1" || request.RequestUrl->GetPath().size() != 1) return false; response.SetStatus(200, "OK"); std::vector permInfo; Array::Ptr permissions = user->GetPermissions(); if (permissions) { ObjectLock olock(permissions); for (const Value& permission : permissions) { String name; bool hasFilter = false; if (permission.IsObjectType()) { Dictionary::Ptr dpermission = permission; name = dpermission->Get("permission"); hasFilter = dpermission->Contains("filter"); } else name = permission; if (hasFilter) name += " (filtered)"; permInfo.push_back(name); } } if (request.Headers->Get("accept") == "application/json") { Dictionary::Ptr result1 = new Dictionary(); result1->Set("user", user->GetName()); result1->Set("permissions", Array::FromVector(permInfo)); result1->Set("version", Application::GetAppVersion()); result1->Set("info", "More information about API requests is available in the documentation at https://docs.icinga.com/icinga2/latest."); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); HttpUtility::SendJsonBody(response, result); } else { response.AddHeader("Content-Type", "text/html"); String body = "Icinga 2

Hello from Icinga 2 (Version: " + Application::GetAppVersion() + ")!

"; body += "

You are authenticated as " + user->GetName() + ". "; if (!permInfo.empty()) { body += "Your user has the following permissions:

    "; for (const String& perm : permInfo) { body += "
  • " + perm + "
  • "; } body += "
"; } else body += "Your user does not have any permissions.

"; body += "

More information about API requests is available in the documentation.

"; response.WriteBody(body.CStr(), body.GetLength()); } return true; } icinga2-2.8.1/lib/remote/infohandler.hpp000066400000000000000000000034361322762156600201210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef INFOHANDLER_H #define INFOHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API InfoHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(InfoHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* INFOHANDLER_H */ icinga2-2.8.1/lib/remote/jsonrpc.cpp000066400000000000000000000063711322762156600173020ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/jsonrpc.hpp" #include "base/netstring.hpp" #include "base/json.hpp" #include "base/console.hpp" #include "base/scriptglobal.hpp" #include "base/convert.hpp" #include using namespace icinga; #ifdef I2_DEBUG static bool GetDebugJsonRpcCached(void) { static int debugJsonRpc = -1; if (debugJsonRpc != -1) return debugJsonRpc; debugJsonRpc = false; Dictionary::Ptr internal = ScriptGlobal::Get("Internal", &Empty); if (!internal) return false; Value vdebug; if (!internal->Get("DebugJsonRpc", &vdebug)) return false; debugJsonRpc = Convert::ToLong(vdebug); return debugJsonRpc; } #endif /* I2_DEBUG */ /** * Sends a message to the connected peer. * * @param message The message. */ void JsonRpc::SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message) { String json = JsonEncode(message); #ifdef I2_DEBUG if (GetDebugJsonRpcCached()) std::cerr << ConsoleColorTag(Console_ForegroundBlue) << ">> " << json << ConsoleColorTag(Console_Normal) << "\n"; #endif /* I2_DEBUG */ NetString::WriteStringToStream(stream, json); } StreamReadStatus JsonRpc::ReadMessage(const Stream::Ptr& stream, String *message, StreamReadContext& src, bool may_wait) { String jsonString; StreamReadStatus srs = NetString::ReadStringFromStream(stream, &jsonString, src, may_wait); if (srs != StatusNewItem) return srs; *message = jsonString; #ifdef I2_DEBUG if (GetDebugJsonRpcCached()) std::cerr << ConsoleColorTag(Console_ForegroundBlue) << "<< " << jsonString << ConsoleColorTag(Console_Normal) << "\n"; #endif /* I2_DEBUG */ return StatusNewItem; } Dictionary::Ptr JsonRpc::DecodeMessage(const String& message) { Value value = JsonDecode(message); if (!value.IsObjectType()) { BOOST_THROW_EXCEPTION(std::invalid_argument("JSON-RPC" " message must be a dictionary.")); } return value; } icinga2-2.8.1/lib/remote/jsonrpc.hpp000066400000000000000000000037401322762156600173040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef JSONRPC_H #define JSONRPC_H #include "base/stream.hpp" #include "base/dictionary.hpp" #include "remote/i2-remote.hpp" namespace icinga { /** * A JSON-RPC connection. * * @ingroup remote */ class I2_REMOTE_API JsonRpc { public: static void SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message); static StreamReadStatus ReadMessage(const Stream::Ptr& stream, String *message, StreamReadContext& src, bool may_wait = false); static Dictionary::Ptr DecodeMessage(const String& message); private: JsonRpc(void); }; } #endif /* JSONRPC_H */ icinga2-2.8.1/lib/remote/jsonrpcconnection-heartbeat.cpp000066400000000000000000000062001322762156600233060ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/jsonrpcconnection.hpp" #include "remote/messageorigin.hpp" #include "remote/apifunction.hpp" #include "base/initialize.hpp" #include "base/configtype.hpp" #include "base/logger.hpp" #include "base/utility.hpp" using namespace icinga; REGISTER_APIFUNCTION(Heartbeat, event, &JsonRpcConnection::HeartbeatAPIHandler); static Timer::Ptr l_HeartbeatTimer; INITIALIZE_ONCE([]() { l_HeartbeatTimer = new Timer(); l_HeartbeatTimer->OnTimerExpired.connect(boost::bind(&JsonRpcConnection::HeartbeatTimerHandler)); l_HeartbeatTimer->SetInterval(10); l_HeartbeatTimer->Start(); }); void JsonRpcConnection::HeartbeatTimerHandler(void) { for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { if (client->m_NextHeartbeat != 0 && client->m_NextHeartbeat < Utility::GetTime()) { Log(LogWarning, "JsonRpcConnection") << "Client for endpoint '" << endpoint->GetName() << "' has requested " << "heartbeat message but hasn't responded in time. Closing connection."; client->Disconnect(); continue; } Dictionary::Ptr request = new Dictionary(); request->Set("jsonrpc", "2.0"); request->Set("method", "event::Heartbeat"); Dictionary::Ptr params = new Dictionary(); params->Set("timeout", 120); request->Set("params", params); client->SendMessage(request); } } } Value JsonRpcConnection::HeartbeatAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Value vtimeout = params->Get("timeout"); if (!vtimeout.IsEmpty()) { origin->FromClient->m_NextHeartbeat = Utility::GetTime() + vtimeout; origin->FromClient->m_HeartbeatTimeout = vtimeout; } return Empty; } icinga2-2.8.1/lib/remote/jsonrpcconnection-pki.cpp000066400000000000000000000327451322762156600221470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/jsonrpcconnection.hpp" #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "remote/jsonrpc.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include #include #include using namespace icinga; static Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); REGISTER_APIFUNCTION(RequestCertificate, pki, &RequestCertificateHandler); static Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); REGISTER_APIFUNCTION(UpdateCertificate, pki, &UpdateCertificateHandler); Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { if (!params) return Empty; String certText = params->Get("cert_request"); boost::shared_ptr cert; Dictionary::Ptr result = new Dictionary(); /* Use the presented client certificate if not provided. */ if (certText.IsEmpty()) cert = origin->FromClient->GetStream()->GetPeerCertificate(); else cert = StringToCertificate(certText); ApiListener::Ptr listener = ApiListener::GetInstance(); boost::shared_ptr cacert = GetX509Certificate(listener->GetDefaultCaPath()); String cn = GetCertificateCN(cert); bool signedByCA = VerifyCertificate(cacert, cert); Log(LogInformation, "JsonRpcConnection") << "Received certificate request for CN '" << cn << "'" << (signedByCA ? "" : " not") << " signed by our CA."; if (signedByCA) { time_t now; time(&now); /* auto-renew all certificates which were created before 2017 to force an update of the CA, * because Icinga versions older than 2.4 sometimes create certificates with an invalid * serial number. */ time_t forceRenewalEnd = 1483228800; /* January 1st, 2017 */ time_t renewalStart = now + 30 * 24 * 60 * 60; if (X509_cmp_time(X509_get_notBefore(cert.get()), &forceRenewalEnd) != -1 && X509_cmp_time(X509_get_notAfter(cert.get()), &renewalStart) != -1) { Log(LogInformation, "JsonRpcConnection") << "The certificate for CN '" << cn << "' cannot be renewed yet."; result->Set("status_code", 1); result->Set("error", "The certificate for CN '" + cn + "' cannot be renewed yet."); return result; } } unsigned int n; unsigned char digest[EVP_MAX_MD_SIZE]; if (!X509_digest(cert.get(), EVP_sha256(), digest, &n)) { result->Set("status_code", 1); result->Set("error", "Could not calculate fingerprint for the X509 certificate for CN '" + cn + "'."); Log(LogWarning, "JsonRpcConnection") << "Could not calculate fingerprint for the X509 certificate requested for CN '" << cn << "'."; return result; } char certFingerprint[EVP_MAX_MD_SIZE*2+1]; for (unsigned int i = 0; i < n; i++) sprintf(certFingerprint + 2 * i, "%02x", digest[i]); result->Set("fingerprint_request", certFingerprint); String requestDir = ApiListener::GetCertificateRequestsDir(); String requestPath = requestDir + "/" + certFingerprint + ".json"; result->Set("ca", CertificateToString(cacert)); JsonRpcConnection::Ptr client = origin->FromClient; /* If we already have a signed certificate request, send it to the client. */ if (Utility::PathExists(requestPath)) { Dictionary::Ptr request = Utility::LoadJsonFile(requestPath); String certResponse = request->Get("cert_response"); if (!certResponse.IsEmpty()) { Log(LogInformation, "JsonRpcConnection") << "Sending certificate response for CN '" << cn << "' to endpoint '" << client->GetIdentity() << "'."; result->Set("cert", certResponse); result->Set("status_code", 0); Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "pki::UpdateCertificate"); message->Set("params", result); JsonRpc::SendMessage(client->GetStream(), message); return result; } } boost::shared_ptr newcert; boost::shared_ptr pubkey; X509_NAME *subject; Dictionary::Ptr message; String ticket; /* Check whether we are a signing instance or we * must delay the signing request. */ if (!Utility::PathExists(GetIcingaCADir() + "/ca.key")) goto delayed_request; if (!signedByCA) { String salt = listener->GetTicketSalt(); ticket = params->Get("ticket"); /* Auto-signing is disabled by either a) no TicketSalt * or b) the client did not include a ticket in its request. */ if (salt.IsEmpty() || ticket.IsEmpty()) goto delayed_request; String realTicket = PBKDF2_SHA1(cn, salt, 50000); if (ticket != realTicket) { Log(LogWarning, "JsonRpcConnection") << "Ticket for CN '" << cn << "' is invalid."; result->Set("status_code", 1); result->Set("error", "Invalid ticket for CN '" + cn + "'."); return result; } } pubkey = boost::shared_ptr(X509_get_pubkey(cert.get()), EVP_PKEY_free); subject = X509_get_subject_name(cert.get()); newcert = CreateCertIcingaCA(pubkey.get(), subject); /* verify that the new cert matches the CA we're using for the ApiListener; * this ensures that the CA we have in /var/lib/icinga2/ca matches the one * we're using for cluster connections (there's no point in sending a client * a certificate it wouldn't be able to use to connect to us anyway) */ if (!VerifyCertificate(cacert, newcert)) { Log(LogWarning, "JsonRpcConnection") << "The CA in '" << listener->GetDefaultCaPath() << "' does not match the CA which Icinga uses " << "for its own cluster connections. This is most likely a configuration problem."; goto delayed_request; } /* Send the signed certificate update. */ Log(LogInformation, "JsonRpcConnection") << "Sending certificate response for CN '" << cn << "' to endpoint '" << client->GetIdentity() << "'" << (!ticket.IsEmpty() ? " (auto-signing ticket)" : "" ) << "."; result->Set("cert", CertificateToString(newcert)); result->Set("status_code", 0); message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "pki::UpdateCertificate"); message->Set("params", result); JsonRpc::SendMessage(client->GetStream(), message); return result; delayed_request: /* Send a delayed certificate signing request. */ Utility::MkDirP(requestDir, 0700); Dictionary::Ptr request = new Dictionary(); request->Set("cert_request", CertificateToString(cert)); request->Set("ticket", params->Get("ticket")); Utility::SaveJsonFile(requestPath, 0600, request); JsonRpcConnection::SendCertificateRequest(JsonRpcConnection::Ptr(), origin, requestPath); result->Set("status_code", 2); result->Set("error", "Certificate request for CN '" + cn + "' is pending. Waiting for approval from the parent Icinga instance."); Log(LogInformation, "JsonRpcConnection") << "Certificate request for CN '" << cn << "' is pending. Waiting for approval."; return result; } void JsonRpcConnection::SendCertificateRequest(const JsonRpcConnection::Ptr& aclient, const MessageOrigin::Ptr& origin, const String& path) { Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "pki::RequestCertificate"); ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return; Dictionary::Ptr params = new Dictionary(); message->Set("params", params); /* Path is empty if this is our own request. */ if (path.IsEmpty()) { String ticketPath = ApiListener::GetCertsDir() + "/ticket"; std::ifstream fp(ticketPath.CStr()); String ticket((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); fp.close(); params->Set("ticket", ticket); } else { Dictionary::Ptr request = Utility::LoadJsonFile(path); if (request->Contains("cert_response")) return; params->Set("cert_request", request->Get("cert_request")); params->Set("ticket", request->Get("ticket")); } /* Send the request to a) the connected client * or b) the local zone and all parents. */ if (aclient) JsonRpc::SendMessage(aclient->GetStream(), message); else listener->RelayMessage(origin, Zone::GetLocalZone(), message, false); } Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { if (origin->FromZone && !Zone::GetLocalZone()->IsChildOf(origin->FromZone)) { Log(LogWarning, "ClusterEvents") << "Discarding 'update certificate' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return Empty; } String ca = params->Get("ca"); String cert = params->Get("cert"); ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) return Empty; boost::shared_ptr oldCert = GetX509Certificate(listener->GetDefaultCertPath()); boost::shared_ptr newCert = StringToCertificate(cert); String cn = GetCertificateCN(newCert); Log(LogInformation, "JsonRpcConnection") << "Received certificate update message for CN '" << cn << "'"; /* Check if this is a certificate update for a subordinate instance. */ boost::shared_ptr oldKey = boost::shared_ptr(X509_get_pubkey(oldCert.get()), EVP_PKEY_free); boost::shared_ptr newKey = boost::shared_ptr(X509_get_pubkey(newCert.get()), EVP_PKEY_free); if (X509_NAME_cmp(X509_get_subject_name(oldCert.get()), X509_get_subject_name(newCert.get())) != 0 || EVP_PKEY_cmp(oldKey.get(), newKey.get()) != 1) { String certFingerprint = params->Get("fingerprint_request"); /* Validate the fingerprint format. */ boost::regex expr("^[0-9a-f]+$"); if (!boost::regex_match(certFingerprint.GetData(), expr)) { Log(LogWarning, "JsonRpcConnection") << "Endpoint '" << origin->FromClient->GetIdentity() << "' sent an invalid certificate fingerprint: '" << certFingerprint << "' for CN '" << cn << "'."; return Empty; } String requestDir = ApiListener::GetCertificateRequestsDir(); String requestPath = requestDir + "/" + certFingerprint + ".json"; /* Save the received signed certificate request to disk. */ if (Utility::PathExists(requestPath)) { Log(LogInformation, "JsonRpcConnection") << "Saved certificate update for CN '" << cn << "'"; Dictionary::Ptr request = Utility::LoadJsonFile(requestPath); request->Set("cert_response", cert); Utility::SaveJsonFile(requestPath, 0644, request); } return Empty; } /* Update CA certificate. */ String caPath = listener->GetDefaultCaPath(); Log(LogInformation, "JsonRpcConnection") << "Updating CA certificate in '" << caPath << "'."; std::fstream cafp; String tempCaPath = Utility::CreateTempFile(caPath + ".XXXXXX", 0644, cafp); cafp << ca; cafp.close(); #ifdef _WIN32 _unlink(caPath.CStr()); #endif /* _WIN32 */ if (rename(tempCaPath.CStr(), caPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempCaPath)); } /* Update signed certificate. */ String certPath = listener->GetDefaultCertPath(); Log(LogInformation, "JsonRpcConnection") << "Updating client certificate for CN '" << cn << "' in '" << certPath << "'."; std::fstream certfp; String tempCertPath = Utility::CreateTempFile(certPath + ".XXXXXX", 0644, certfp); certfp << cert; certfp.close(); #ifdef _WIN32 _unlink(certPath.CStr()); #endif /* _WIN32 */ if (rename(tempCertPath.CStr(), certPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) << boost::errinfo_file_name(tempCertPath)); } /* Remove ticket for successful signing request. */ String ticketPath = ApiListener::GetCertsDir() + "/ticket"; if (unlink(ticketPath.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(ticketPath)); } /* Update the certificates at runtime and reconnect all endpoints. */ Log(LogInformation, "JsonRpcConnection") << "Updating the client certificate for CN '" << cn << "' at runtime and reconnecting the endpoints."; listener->UpdateSSLContext(); return Empty; } icinga2-2.8.1/lib/remote/jsonrpcconnection.cpp000066400000000000000000000235201322762156600213550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/jsonrpcconnection.hpp" #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "remote/jsonrpc.hpp" #include "base/configtype.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" #include "base/logger.hpp" #include "base/exception.hpp" #include "base/convert.hpp" #include using namespace icinga; static Value SetLogPositionHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); REGISTER_APIFUNCTION(SetLogPosition, log, &SetLogPositionHandler); static boost::once_flag l_JsonRpcConnectionOnceFlag = BOOST_ONCE_INIT; static Timer::Ptr l_JsonRpcConnectionTimeoutTimer; static WorkQueue *l_JsonRpcConnectionWorkQueues; static size_t l_JsonRpcConnectionWorkQueueCount; static int l_JsonRpcConnectionNextID; JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role) : m_ID(l_JsonRpcConnectionNextID++), m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream), m_Role(role), m_Timestamp(Utility::GetTime()), m_Seen(Utility::GetTime()), m_NextHeartbeat(0), m_HeartbeatTimeout(0) { boost::call_once(l_JsonRpcConnectionOnceFlag, &JsonRpcConnection::StaticInitialize); if (authenticated) m_Endpoint = Endpoint::GetByName(identity); } void JsonRpcConnection::StaticInitialize(void) { l_JsonRpcConnectionTimeoutTimer = new Timer(); l_JsonRpcConnectionTimeoutTimer->OnTimerExpired.connect(boost::bind(&JsonRpcConnection::TimeoutTimerHandler)); l_JsonRpcConnectionTimeoutTimer->SetInterval(15); l_JsonRpcConnectionTimeoutTimer->Start(); l_JsonRpcConnectionWorkQueueCount = Application::GetConcurrency(); l_JsonRpcConnectionWorkQueues = new WorkQueue[l_JsonRpcConnectionWorkQueueCount]; for (size_t i = 0; i < l_JsonRpcConnectionWorkQueueCount; i++) { l_JsonRpcConnectionWorkQueues[i].SetName("JsonRpcConnection, #" + Convert::ToString(i)); } } void JsonRpcConnection::Start(void) { /* the stream holds an owning reference to this object through the callback we're registering here */ m_Stream->RegisterDataHandler(boost::bind(&JsonRpcConnection::DataAvailableHandler, JsonRpcConnection::Ptr(this))); if (m_Stream->IsDataAvailable()) DataAvailableHandler(); } double JsonRpcConnection::GetTimestamp(void) const { return m_Timestamp; } String JsonRpcConnection::GetIdentity(void) const { return m_Identity; } bool JsonRpcConnection::IsAuthenticated(void) const { return m_Authenticated; } Endpoint::Ptr JsonRpcConnection::GetEndpoint(void) const { return m_Endpoint; } TlsStream::Ptr JsonRpcConnection::GetStream(void) const { return m_Stream; } ConnectionRole JsonRpcConnection::GetRole(void) const { return m_Role; } void JsonRpcConnection::SendMessage(const Dictionary::Ptr& message) { try { ObjectLock olock(m_Stream); if (m_Stream->IsEof()) return; JsonRpc::SendMessage(m_Stream, message); } catch (const std::exception& ex) { std::ostringstream info; info << "Error while sending JSON-RPC message for identity '" << m_Identity << "'"; Log(LogWarning, "JsonRpcConnection") << info.str() << "\n" << DiagnosticInformation(ex); Disconnect(); } } void JsonRpcConnection::Disconnect(void) { Log(LogWarning, "JsonRpcConnection") << "API client disconnected for identity '" << m_Identity << "'"; m_Stream->Close(); if (m_Endpoint) m_Endpoint->RemoveClient(this); else { ApiListener::Ptr listener = ApiListener::GetInstance(); listener->RemoveAnonymousClient(this); } } void JsonRpcConnection::MessageHandlerWrapper(const String& jsonString) { if (m_Stream->IsEof()) return; try { MessageHandler(jsonString); } catch (const std::exception& ex) { Log(LogWarning, "JsonRpcConnection") << "Error while reading JSON-RPC message for identity '" << m_Identity << "': " << DiagnosticInformation(ex); Disconnect(); return; } } void JsonRpcConnection::MessageHandler(const String& jsonString) { Dictionary::Ptr message = JsonRpc::DecodeMessage(jsonString); m_Seen = Utility::GetTime(); if (m_HeartbeatTimeout != 0) m_NextHeartbeat = Utility::GetTime() + m_HeartbeatTimeout; if (m_Endpoint && message->Contains("ts")) { double ts = message->Get("ts"); /* ignore old messages */ if (ts < m_Endpoint->GetRemoteLogPosition()) return; m_Endpoint->SetRemoteLogPosition(ts); } MessageOrigin::Ptr origin = new MessageOrigin(); origin->FromClient = this; if (m_Endpoint) { if (m_Endpoint->GetZone() != Zone::GetLocalZone()) origin->FromZone = m_Endpoint->GetZone(); else origin->FromZone = Zone::GetByName(message->Get("originZone")); } Value vmethod; if (!message->Get("method", &vmethod)) { Value vid; if (!message->Get("id", &vid)) return; Log(LogWarning, "JsonRpcConnection", "We received a JSON-RPC response message. This should never happen because we're only ever sending notifications."); return; } String method = vmethod; Log(LogNotice, "JsonRpcConnection") << "Received '" << method << "' message from '" << m_Identity << "'"; Dictionary::Ptr resultMessage = new Dictionary(); try { ApiFunction::Ptr afunc = ApiFunction::GetByName(method); if (!afunc) { Log(LogNotice, "JsonRpcConnection") << "Call to non-existent function '" << method << "' from endpoint '" << m_Identity << "'."; } else { resultMessage->Set("result", afunc->Invoke(origin, message->Get("params"))); } } catch (const std::exception& ex) { /* TODO: Add a user readable error message for the remote caller */ String diagInfo = DiagnosticInformation(ex); resultMessage->Set("error", diagInfo); Log(LogWarning, "JsonRpcConnection") << "Error while processing message for identity '" << m_Identity << "'\n" << diagInfo; } if (message->Contains("id")) { resultMessage->Set("jsonrpc", "2.0"); resultMessage->Set("id", message->Get("id")); SendMessage(resultMessage); } } bool JsonRpcConnection::ProcessMessage(void) { String message; StreamReadStatus srs = JsonRpc::ReadMessage(m_Stream, &message, m_Context, false); if (srs != StatusNewItem) return false; l_JsonRpcConnectionWorkQueues[m_ID % l_JsonRpcConnectionWorkQueueCount].Enqueue(boost::bind(&JsonRpcConnection::MessageHandlerWrapper, JsonRpcConnection::Ptr(this), message)); return true; } void JsonRpcConnection::DataAvailableHandler(void) { bool close = false; if (!m_Stream) return; if (!m_Stream->IsEof()) { boost::mutex::scoped_lock lock(m_DataHandlerMutex); try { while (ProcessMessage()) ; /* empty loop body */ } catch (const std::exception& ex) { Log(LogWarning, "JsonRpcConnection") << "Error while reading JSON-RPC message for identity '" << m_Identity << "': " << DiagnosticInformation(ex); Disconnect(); return; } } else close = true; if (close) Disconnect(); } Value SetLogPositionHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { if (!params) return Empty; double log_position = params->Get("log_position"); Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); if (!endpoint) return Empty; if (log_position > endpoint->GetLocalLogPosition()) endpoint->SetLocalLogPosition(log_position); return Empty; } void JsonRpcConnection::CheckLiveness(void) { if (m_Seen < Utility::GetTime() - 60 && (!m_Endpoint || !m_Endpoint->GetSyncing())) { Log(LogInformation, "JsonRpcConnection") << "No messages for identity '" << m_Identity << "' have been received in the last 60 seconds."; Disconnect(); } } void JsonRpcConnection::TimeoutTimerHandler(void) { ApiListener::Ptr listener = ApiListener::GetInstance(); for (const JsonRpcConnection::Ptr& client : listener->GetAnonymousClients()) { client->CheckLiveness(); } for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) { client->CheckLiveness(); } } } int JsonRpcConnection::GetWorkQueueCount(void) { return l_JsonRpcConnectionWorkQueueCount; } int JsonRpcConnection::GetWorkQueueLength(void) { int itemCount = 0; for (int i = 0; i < GetWorkQueueCount(); i++) { itemCount += l_JsonRpcConnectionWorkQueues[i].GetLength(); } return itemCount; } double JsonRpcConnection::GetWorkQueueRate(void) { double rate = 0.0; int count = GetWorkQueueCount(); /* If this is a standalone environment, we don't have any queues. */ if (count == 0) return 0.0; for (int i = 0; i < count; i++) { rate += l_JsonRpcConnectionWorkQueues[i].GetTaskCount(60) / 60.0; } return rate / count; } icinga2-2.8.1/lib/remote/jsonrpcconnection.hpp000066400000000000000000000066321322762156600213670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef JSONRPCCONNECTION_H #define JSONRPCCONNECTION_H #include "remote/endpoint.hpp" #include "base/tlsstream.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include "remote/i2-remote.hpp" namespace icinga { enum ClientRole { ClientInbound, ClientOutbound }; enum ClientType { ClientJsonRpc, ClientHttp }; class MessageOrigin; /** * An API client connection. * * @ingroup remote */ class I2_REMOTE_API JsonRpcConnection : public Object { public: DECLARE_PTR_TYPEDEFS(JsonRpcConnection); JsonRpcConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role); void Start(void); double GetTimestamp(void) const; String GetIdentity(void) const; bool IsAuthenticated(void) const; Endpoint::Ptr GetEndpoint(void) const; TlsStream::Ptr GetStream(void) const; ConnectionRole GetRole(void) const; void Disconnect(void); void SendMessage(const Dictionary::Ptr& request); static void HeartbeatTimerHandler(void); static Value HeartbeatAPIHandler(const intrusive_ptr& origin, const Dictionary::Ptr& params); static int GetWorkQueueCount(void); static int GetWorkQueueLength(void); static double GetWorkQueueRate(void); static void SendCertificateRequest(const JsonRpcConnection::Ptr& aclient, const intrusive_ptr& origin, const String& path); private: int m_ID; String m_Identity; bool m_Authenticated; Endpoint::Ptr m_Endpoint; TlsStream::Ptr m_Stream; ConnectionRole m_Role; double m_Timestamp; double m_Seen; double m_NextHeartbeat; double m_HeartbeatTimeout; boost::mutex m_DataHandlerMutex; StreamReadContext m_Context; bool ProcessMessage(void); void MessageHandlerWrapper(const String& jsonString); void MessageHandler(const String& jsonString); void DataAvailableHandler(void); static void StaticInitialize(void); static void TimeoutTimerHandler(void); void CheckLiveness(void); void CertificateRequestResponseHandler(const Dictionary::Ptr& message); }; } #endif /* JSONRPCCONNECTION_H */ icinga2-2.8.1/lib/remote/messageorigin.cpp000066400000000000000000000030411322762156600204470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/messageorigin.hpp" using namespace icinga; bool MessageOrigin::IsLocal(void) const { return !FromClient; } icinga2-2.8.1/lib/remote/messageorigin.hpp000066400000000000000000000034421322762156600204610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MESSAGEORIGIN_H #define MESSAGEORIGIN_H #include "remote/zone.hpp" #include "remote/jsonrpcconnection.hpp" namespace icinga { /** * @ingroup remote */ class I2_REMOTE_API MessageOrigin : public Object { public: DECLARE_PTR_TYPEDEFS(MessageOrigin); Zone::Ptr FromZone; JsonRpcConnection::Ptr FromClient; bool IsLocal(void) const; }; } #endif /* MESSAGEORIGIN_H */ icinga2-2.8.1/lib/remote/modifyobjecthandler.cpp000066400000000000000000000077761322762156600216520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/modifyobjecthandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "remote/apiaction.hpp" #include "base/exception.hpp" #include "base/serializer.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/objects", ModifyObjectHandler); bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "POST") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/modify/" + type->GetName(); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Value attrsVal = params->Get("attrs"); if (attrsVal.GetReflectionType() != Dictionary::TypeInstance) { HttpUtility::SendJsonError(response, 400, "Invalid type for 'attrs' attribute specified. Dictionary type is required.", Empty); return true; } Dictionary::Ptr attrs = attrsVal; Array::Ptr results = new Array(); for (const ConfigObject::Ptr& obj : objs) { Dictionary::Ptr result1 = new Dictionary(); result1->Set("type", type->GetName()); result1->Set("name", obj->GetName()); String key; try { if (attrs) { ObjectLock olock(attrs); for (const Dictionary::Pair& kv : attrs) { key = kv.first; obj->ModifyAttribute(kv.first, kv.second); } } result1->Set("code", 200); result1->Set("status", "Attributes updated."); } catch (const std::exception& ex) { result1->Set("code", 500); result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex)); } results->Add(result1); } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/modifyobjecthandler.hpp000066400000000000000000000035061322762156600216420ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef MODIFYOBJECTHANDLER_H #define MODIFYOBJECTHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ModifyObjectHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ModifyObjectHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* MODIFYOBJECTHANDLER_H */ icinga2-2.8.1/lib/remote/objectqueryhandler.cpp000066400000000000000000000207631322762156600215170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/objectqueryhandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/serializer.hpp" #include "base/dependencygraph.hpp" #include "base/configtype.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/objects", ObjectQueryHandler); Dictionary::Ptr ObjectQueryHandler::SerializeObjectAttrs(const Object::Ptr& object, const String& attrPrefix, const Array::Ptr& attrs, bool isJoin, bool allAttrs) { Type::Ptr type = object->GetReflectionType(); std::vector fids; if (isJoin && attrs) { ObjectLock olock(attrs); for (const String& attr : attrs) { if (attr == attrPrefix) { allAttrs = true; break; } } } if (!isJoin && (!attrs || attrs->GetLength() == 0)) allAttrs = true; if (allAttrs) { for (int fid = 0; fid < type->GetFieldCount(); fid++) { fids.push_back(fid); } } else if (attrs) { ObjectLock olock(attrs); for (const String& attr : attrs) { String userAttr; if (isJoin) { String::SizeType dpos = attr.FindFirstOf("."); if (dpos == String::NPos) continue; String userJoinAttr = attr.SubStr(0, dpos); if (userJoinAttr != attrPrefix) continue; userAttr = attr.SubStr(dpos + 1); } else userAttr = attr; int fid = type->GetFieldId(userAttr); if (fid < 0) BOOST_THROW_EXCEPTION(ScriptError("Invalid field specified: " + userAttr)); fids.push_back(fid); } } Dictionary::Ptr resultAttrs = new Dictionary(); for (int fid : fids) { Field field = type->GetFieldInfo(fid); Value val = object->GetField(fid); /* hide attributes which shouldn't be user-visible */ if (field.Attributes & FANoUserView) continue; /* hide internal navigation fields */ if (field.Attributes & FANavigation && !(field.Attributes & (FAConfig | FAState))) continue; Value sval = Serialize(val, FAConfig | FAState); resultAttrs->Set(field.Name, sval); } return resultAttrs; } bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/query/" + type->GetName(); Array::Ptr uattrs, ujoins, umetas; try { uattrs = params->Get("attrs"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, 400, "Invalid type for 'attrs' attribute specified. Array type is required.", Empty); return true; } try { ujoins = params->Get("joins"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, 400, "Invalid type for 'joins' attribute specified. Array type is required.", Empty); return true; } try { umetas = params->Get("meta"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, 400, "Invalid type for 'meta' attribute specified. Array type is required.", Empty); return true; } bool allJoins = HttpUtility::GetLastParameter(params, "all_joins"); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Array::Ptr results = new Array(); results->Reserve(objs.size()); std::set joinAttrs; std::set userJoinAttrs; if (ujoins) { ObjectLock olock(ujoins); for (const String& ujoin : ujoins) { userJoinAttrs.insert(ujoin.SubStr(0, ujoin.FindFirstOf("."))); } } for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) continue; if (!allJoins && userJoinAttrs.find(field.NavigationName) == userJoinAttrs.end()) continue; joinAttrs.insert(field.Name); } for (const ConfigObject::Ptr& obj : objs) { Dictionary::Ptr result1 = new Dictionary(); results->Add(result1); result1->Set("name", obj->GetName()); result1->Set("type", obj->GetReflectionType()->GetName()); Dictionary::Ptr metaAttrs = new Dictionary(); result1->Set("meta", metaAttrs); if (umetas) { ObjectLock olock(umetas); for (const String& meta : umetas) { if (meta == "used_by") { Array::Ptr used_by = new Array(); metaAttrs->Set("used_by", used_by); for (const Object::Ptr& pobj : DependencyGraph::GetParents((obj))) { ConfigObject::Ptr configObj = dynamic_pointer_cast(pobj); if (!configObj) continue; Dictionary::Ptr refInfo = new Dictionary(); refInfo->Set("type", configObj->GetReflectionType()->GetName()); refInfo->Set("name", configObj->GetName()); used_by->Add(refInfo); } } else if (meta == "location") { DebugInfo di = obj->GetDebugInfo(); Dictionary::Ptr dinfo = new Dictionary(); dinfo->Set("path", di.Path); dinfo->Set("first_line", di.FirstLine); dinfo->Set("first_column", di.FirstColumn); dinfo->Set("last_line", di.LastLine); dinfo->Set("last_column", di.LastColumn); metaAttrs->Set("location", dinfo); } else { HttpUtility::SendJsonError(response, 400, "Invalid field specified for meta: " + meta); return true; } } } try { result1->Set("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, 400, ex.what()); return true; } Dictionary::Ptr joins = new Dictionary(); result1->Set("joins", joins); for (const String& joinAttr : joinAttrs) { Object::Ptr joinedObj; int fid = type->GetFieldId(joinAttr); if (fid < 0) { HttpUtility::SendJsonError(response, 400, "Invalid field specified for join: " + joinAttr); return true; } Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) { HttpUtility::SendJsonError(response, 400, "Not a joinable field: " + joinAttr); return true; } joinedObj = obj->NavigateField(fid); if (!joinedObj) continue; String prefix = field.NavigationName; try { joins->Set(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, 400, ex.what()); return true; } } } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/objectqueryhandler.hpp000066400000000000000000000037501322762156600215210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef OBJECTQUERYHANDLER_H #define OBJECTQUERYHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API ObjectQueryHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(ObjectQueryHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; private: static Dictionary::Ptr SerializeObjectAttrs(const Object::Ptr& object, const String& attrPrefix, const Array::Ptr& attrs, bool isJoin, bool allAttrs); }; } #endif /* OBJECTQUERYHANDLER_H */ icinga2-2.8.1/lib/remote/pkiutility.cpp000066400000000000000000000301231322762156600200230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/pkiutility.hpp" #include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/console.hpp" #include "base/tlsstream.hpp" #include "base/tcpsocket.hpp" #include "base/json.hpp" #include "base/utility.hpp" #include "base/exception.hpp" #include "remote/jsonrpc.hpp" #include #include using namespace icinga; int PkiUtility::NewCa(void) { String caDir = ApiListener::GetCaDir(); String caCertFile = caDir + "/ca.crt"; String caKeyFile = caDir + "/ca.key"; if (Utility::PathExists(caCertFile) && Utility::PathExists(caKeyFile)) { Log(LogCritical, "cli") << "CA files '" << caCertFile << "' and '" << caKeyFile << "' already exist."; return 1; } Utility::MkDirP(caDir, 0700); MakeX509CSR("Icinga CA", caKeyFile, String(), caCertFile, true); return 0; } int PkiUtility::NewCert(const String& cn, const String& keyfile, const String& csrfile, const String& certfile) { try { MakeX509CSR(cn, keyfile, csrfile, certfile); } catch(std::exception&) { return 1; } return 0; } int PkiUtility::SignCsr(const String& csrfile, const String& certfile) { char errbuf[120]; InitializeOpenSSL(); BIO *csrbio = BIO_new_file(csrfile.CStr(), "r"); X509_REQ *req = PEM_read_bio_X509_REQ(csrbio, NULL, NULL, NULL); if (!req) { Log(LogCritical, "SSL") << "Could not read X509 certificate request from '" << csrfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\""; return 1; } BIO_free(csrbio); boost::shared_ptr pubkey = boost::shared_ptr(X509_REQ_get_pubkey(req), EVP_PKEY_free); boost::shared_ptr cert = CreateCertIcingaCA(pubkey.get(), X509_REQ_get_subject_name(req)); X509_REQ_free(req); WriteCert(cert, certfile); return 0; } boost::shared_ptr PkiUtility::FetchCert(const String& host, const String& port) { TcpSocket::Ptr client = new TcpSocket(); try { client->Connect(host, port); } catch (const std::exception& ex) { Log(LogCritical, "pki") << "Cannot connect to host '" << host << "' on port '" << port << "'"; Log(LogDebug, "pki") << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); return boost::shared_ptr(); } boost::shared_ptr sslContext; try { sslContext = MakeSSLContext(); } catch (const std::exception& ex) { Log(LogCritical, "pki") << "Cannot make SSL context."; Log(LogDebug, "pki") << "Cannot make SSL context:\n" << DiagnosticInformation(ex); return boost::shared_ptr(); } TlsStream::Ptr stream = new TlsStream(client, host, RoleClient, sslContext); try { stream->Handshake(); } catch (...) { } return stream->GetPeerCertificate(); } int PkiUtility::WriteCert(const boost::shared_ptr& cert, const String& trustedfile) { std::ofstream fpcert; fpcert.open(trustedfile.CStr()); fpcert << CertificateToString(cert); fpcert.close(); if (fpcert.fail()) { Log(LogCritical, "pki") << "Could not write certificate to file '" << trustedfile << "'."; return 1; } Log(LogInformation, "pki") << "Writing certificate to file '" << trustedfile << "'."; return 0; } int PkiUtility::GenTicket(const String& cn, const String& salt, std::ostream& ticketfp) { ticketfp << PBKDF2_SHA1(cn, salt, 50000) << "\n"; return 0; } int PkiUtility::RequestCertificate(const String& host, const String& port, const String& keyfile, const String& certfile, const String& cafile, const boost::shared_ptr& trustedCert, const String& ticket) { TcpSocket::Ptr client = new TcpSocket(); try { client->Connect(host, port); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Cannot connect to host '" << host << "' on port '" << port << "'"; Log(LogDebug, "cli") << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); return 1; } boost::shared_ptr sslContext; try { sslContext = MakeSSLContext(certfile, keyfile); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "'."; Log(LogDebug, "cli") << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "':\n" << DiagnosticInformation(ex); return 1; } TlsStream::Ptr stream = new TlsStream(client, host, RoleClient, sslContext); try { stream->Handshake(); } catch (const std::exception&) { Log(LogCritical, "cli", "Client TLS handshake failed."); return 1; } boost::shared_ptr peerCert = stream->GetPeerCertificate(); if (X509_cmp(peerCert.get(), trustedCert.get())) { Log(LogCritical, "cli", "Peer certificate does not match trusted certificate."); return 1; } Dictionary::Ptr request = new Dictionary(); String msgid = Utility::NewUniqueID(); request->Set("jsonrpc", "2.0"); request->Set("id", msgid); request->Set("method", "pki::RequestCertificate"); Dictionary::Ptr params = new Dictionary(); params->Set("ticket", String(ticket)); request->Set("params", params); JsonRpc::SendMessage(stream, request); String jsonString; Dictionary::Ptr response; StreamReadContext src; for (;;) { StreamReadStatus srs = JsonRpc::ReadMessage(stream, &jsonString, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; response = JsonRpc::DecodeMessage(jsonString); if (response && response->Contains("error")) { Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log (notice or debug)."); #ifdef I2_DEBUG /* we shouldn't expose master errors to the user in production environments */ Log(LogCritical, "cli", response->Get("error")); #endif /* I2_DEBUG */ return 1; } if (response && (response->Get("id") != msgid)) continue; break; } if (!response) { Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log."); return 1; } Dictionary::Ptr result = response->Get("result"); if (result->Contains("ca")) { try { StringToCertificate(result->Get("ca")); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Could not write CA file: " << DiagnosticInformation(ex, false); return 1; } Log(LogInformation, "cli") << "Writing CA certificate to file '" << cafile << "'."; std::ofstream fpca; fpca.open(cafile.CStr()); fpca << result->Get("ca"); fpca.close(); if (fpca.fail()) { Log(LogCritical, "cli") << "Could not open CA certificate file '" << cafile << "' for writing."; return 1; } } if (result->Contains("error")) { LogSeverity severity; Value vstatus; if (!result->Get("status_code", &vstatus)) vstatus = 1; int status = vstatus; if (status == 1) severity = LogCritical; else { severity = LogInformation; Log(severity, "cli", "!!!!!!"); } Log(severity, "cli") << "!!! " << result->Get("error"); if (status == 1) return 1; else { Log(severity, "cli", "!!!!!!"); return 0; } } try { StringToCertificate(result->Get("cert")); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Could not write certificate file: " << DiagnosticInformation(ex, false); return 1; } Log(LogInformation, "cli") << "Writing signed certificate to file '" << certfile << "'."; std::ofstream fpcert; fpcert.open(certfile.CStr()); fpcert << result->Get("cert"); fpcert.close(); if (fpcert.fail()) { Log(LogCritical, "cli") << "Could not write certificate to file '" << certfile << "'."; return 1; } return 0; } String PkiUtility::GetCertificateInformation(const boost::shared_ptr& cert) { BIO *out = BIO_new(BIO_s_mem()); String pre; pre = "\n Subject: "; BIO_write(out, pre.CStr(), pre.GetLength()); X509_NAME_print_ex(out, X509_get_subject_name(cert.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB); pre = "\n Issuer: "; BIO_write(out, pre.CStr(), pre.GetLength()); X509_NAME_print_ex(out, X509_get_issuer_name(cert.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB); pre = "\n Valid From: "; BIO_write(out, pre.CStr(), pre.GetLength()); ASN1_TIME_print(out, X509_get_notBefore(cert.get())); pre = "\n Valid Until: "; BIO_write(out, pre.CStr(), pre.GetLength()); ASN1_TIME_print(out, X509_get_notAfter(cert.get())); pre = "\n Fingerprint: "; BIO_write(out, pre.CStr(), pre.GetLength()); unsigned char md[EVP_MAX_MD_SIZE]; unsigned int diglen; X509_digest(cert.get(), EVP_sha1(), md, &diglen); char *data; long length = BIO_get_mem_data(out, &data); std::stringstream info; info << String(data, data + length); BIO_free(out); for (unsigned int i = 0; i < diglen; i++) { info << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast(md[i]) << ' '; } info << '\n'; return info.str(); } static void CollectRequestHandler(const Dictionary::Ptr& requests, const String& requestFile) { Dictionary::Ptr request = Utility::LoadJsonFile(requestFile); if (!request) return; Dictionary::Ptr result = new Dictionary(); String fingerprint = Utility::BaseName(requestFile); fingerprint = fingerprint.SubStr(0, fingerprint.GetLength() - 5); String certRequestText = request->Get("cert_request"); result->Set("cert_request", certRequestText); Value vcertResponseText; if (request->Get("cert_response", &vcertResponseText)) { String certResponseText = vcertResponseText; result->Set("cert_response", certResponseText); } boost::shared_ptr certRequest = StringToCertificate(certRequestText); /* XXX (requires OpenSSL >= 1.0.0) time_t now; time(&now); ASN1_TIME *tm = ASN1_TIME_adj(NULL, now, 0, 0); int day, sec; ASN1_TIME_diff(&day, &sec, tm, X509_get_notBefore(certRequest.get())); result->Set("timestamp", static_cast(now) + day * 24 * 60 * 60 + sec); */ BIO *out = BIO_new(BIO_s_mem()); ASN1_TIME_print(out, X509_get_notBefore(certRequest.get())); char *data; long length; length = BIO_get_mem_data(out, &data); result->Set("timestamp", String(data, data + length)); BIO_free(out); out = BIO_new(BIO_s_mem()); X509_NAME_print_ex(out, X509_get_subject_name(certRequest.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB); length = BIO_get_mem_data(out, &data); result->Set("subject", String(data, data + length)); BIO_free(out); requests->Set(fingerprint, result); } Dictionary::Ptr PkiUtility::GetCertificateRequests(void) { Dictionary::Ptr requests = new Dictionary(); String requestDir = ApiListener::GetCertificateRequestsDir(); if (Utility::PathExists(requestDir)) Utility::Glob(requestDir + "/*.json", boost::bind(&CollectRequestHandler, requests, _1), GlobFile); return requests; } icinga2-2.8.1/lib/remote/pkiutility.hpp000066400000000000000000000050241322762156600200320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef PKIUTILITY_H #define PKIUTILITY_H #include "remote/i2-remote.hpp" #include "base/dictionary.hpp" #include "base/string.hpp" #include namespace icinga { /** * @ingroup remote */ class I2_REMOTE_API PkiUtility { public: static int NewCa(void); static int NewCert(const String& cn, const String& keyfile, const String& csrfile, const String& certfile); static int SignCsr(const String& csrfile, const String& certfile); static boost::shared_ptr FetchCert(const String& host, const String& port); static int WriteCert(const boost::shared_ptr& cert, const String& trustedfile); static int GenTicket(const String& cn, const String& salt, std::ostream& ticketfp); static int RequestCertificate(const String& host, const String& port, const String& keyfile, const String& certfile, const String& cafile, const boost::shared_ptr& trustedcert, const String& ticket = String()); static String GetCertificateInformation(const boost::shared_ptr& certificate); static Dictionary::Ptr GetCertificateRequests(void); private: PkiUtility(void); }; } #endif /* PKIUTILITY_H */ icinga2-2.8.1/lib/remote/statushandler.cpp000066400000000000000000000075501322762156600205050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/statushandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/serializer.hpp" #include "base/statsfunction.hpp" using namespace icinga; REGISTER_URLHANDLER("/v1/status", StatusHandler); class StatusTargetProvider : public TargetProvider { public: DECLARE_PTR_TYPEDEFS(StatusTargetProvider); virtual void FindTargets(const String& type, const boost::function& addTarget) const override { typedef std::pair kv_pair; for (const kv_pair& kv : StatsFunctionRegistry::GetInstance()->GetItems()) { addTarget(GetTargetByName("Status", kv.first)); } } virtual Value GetTargetByName(const String& type, const String& name) const override { StatsFunction::Ptr func = StatsFunctionRegistry::GetInstance()->GetItem(name); if (!func) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name.")); Dictionary::Ptr result = new Dictionary(); Dictionary::Ptr status = new Dictionary(); Array::Ptr perfdata = new Array(); func->Invoke(status, perfdata); result->Set("name", name); result->Set("status", status); result->Set("perfdata", Serialize(perfdata, FAState)); return result; } virtual bool IsValidType(const String& type) const override { return type == "Status"; } virtual String GetPluralName(const String& type) const override { return "statuses"; } }; bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 3) return false; if (request.RequestMethod != "GET") return false; QueryDescription qd; qd.Types.insert("Status"); qd.Provider = new StatusTargetProvider(); qd.Permission = "status/query"; params->Set("type", "Status"); if (request.RequestUrl->GetPath().size() >= 3) params->Set("status", request.RequestUrl->GetPath()[2]); std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Array::Ptr results = Array::FromVector(objs); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/statushandler.hpp000066400000000000000000000034501322762156600205050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef STATUSHANDLER_H #define STATUSHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API StatusHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(StatusHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* STATUSHANDLER_H */ icinga2-2.8.1/lib/remote/templatequeryhandler.cpp000066400000000000000000000115531322762156600220610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/templatequeryhandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "config/configitem.hpp" #include "base/configtype.hpp" #include "base/scriptglobal.hpp" #include "base/logger.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/templates", TemplateQueryHandler); class TemplateTargetProvider : public TargetProvider { public: DECLARE_PTR_TYPEDEFS(TemplateTargetProvider); static Dictionary::Ptr GetTargetForTemplate(const ConfigItem::Ptr& item) { Dictionary::Ptr target = new Dictionary(); target->Set("name", item->GetName()); target->Set("type", item->GetType()->GetName()); DebugInfo di = item->GetDebugInfo(); Dictionary::Ptr dinfo = new Dictionary(); dinfo->Set("path", di.Path); dinfo->Set("first_line", di.FirstLine); dinfo->Set("first_column", di.FirstColumn); dinfo->Set("last_line", di.LastLine); dinfo->Set("last_column", di.LastColumn); target->Set("location", dinfo); return target; } virtual void FindTargets(const String& type, const boost::function& addTarget) const override { Type::Ptr ptype = Type::GetByName(type); for (const ConfigItem::Ptr& item : ConfigItem::GetItems(ptype)) { if (item->IsAbstract()) addTarget(GetTargetForTemplate(item)); } } virtual Value GetTargetByName(const String& type, const String& name) const override { Type::Ptr ptype = Type::GetByName(type); ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(ptype, name); if (!item || !item->IsAbstract()) BOOST_THROW_EXCEPTION(std::invalid_argument("Template does not exist.")); return GetTargetForTemplate(item); } virtual bool IsValidType(const String& type) const override { Type::Ptr ptype = Type::GetByName(type); if (!ptype) return false; return ConfigObject::TypeInstance->IsAssignableFrom(ptype); } virtual String GetPluralName(const String& type) const override { return Type::GetByName(type)->GetPluralName(); } }; bool TemplateQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "templates/query/" + type->GetName(); qd.Provider = new TemplateTargetProvider(); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user, "tmpl"); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No templates found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Array::Ptr results = new Array(); for (const Dictionary::Ptr& obj : objs) { results->Add(obj); } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/templatequeryhandler.hpp000066400000000000000000000035131322762156600220630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TEMPLATEQUERYHANDLER_H #define TEMPLATEQUERYHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API TemplateQueryHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(TemplateQueryHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* TEMPLATEQUERYHANDLER_H */ icinga2-2.8.1/lib/remote/typequeryhandler.cpp000066400000000000000000000131211322762156600212200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/typequeryhandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/configtype.hpp" #include "base/scriptglobal.hpp" #include "base/logger.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/types", TypeQueryHandler); class TypeTargetProvider : public TargetProvider { public: DECLARE_PTR_TYPEDEFS(TypeTargetProvider); virtual void FindTargets(const String& type, const boost::function& addTarget) const override { for (const Type::Ptr& target : Type::GetAllTypes()) { addTarget(target); } } virtual Value GetTargetByName(const String& type, const String& name) const override { Type::Ptr ptype = Type::GetByName(name); if (!ptype) BOOST_THROW_EXCEPTION(std::invalid_argument("Type does not exist.")); return ptype; } virtual bool IsValidType(const String& type) const override { return type == "Type"; } virtual String GetPluralName(const String& type) const override { return "types"; } }; bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 3) return false; if (request.RequestMethod != "GET") return false; QueryDescription qd; qd.Types.insert("Type"); qd.Permission = "types"; qd.Provider = new TypeTargetProvider(); if (params->Contains("type")) params->Set("name", params->Get("type")); params->Set("type", "Type"); if (request.RequestUrl->GetPath().size() >= 3) params->Set("name", request.RequestUrl->GetPath()[2]); std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Array::Ptr results = new Array(); for (const Type::Ptr& obj : objs) { Dictionary::Ptr result1 = new Dictionary(); results->Add(result1); Dictionary::Ptr resultAttrs = new Dictionary(); result1->Set("name", obj->GetName()); result1->Set("plural_name", obj->GetPluralName()); if (obj->GetBaseType()) result1->Set("base", obj->GetBaseType()->GetName()); result1->Set("abstract", obj->IsAbstract()); result1->Set("fields", resultAttrs); Dictionary::Ptr prototype = dynamic_pointer_cast(obj->GetPrototype()); Array::Ptr prototypeKeys = new Array(); result1->Set("prototype_keys", prototypeKeys); if (prototype) { ObjectLock olock(prototype); for (const Dictionary::Pair& kv : prototype) { prototypeKeys->Add(kv.first); } } int baseFieldCount = 0; if (obj->GetBaseType()) baseFieldCount = obj->GetBaseType()->GetFieldCount(); for (int fid = baseFieldCount; fid < obj->GetFieldCount(); fid++) { Field field = obj->GetFieldInfo(fid); Dictionary::Ptr fieldInfo = new Dictionary(); resultAttrs->Set(field.Name, fieldInfo); fieldInfo->Set("id", fid); fieldInfo->Set("type", field.TypeName); if (field.RefTypeName) fieldInfo->Set("ref_type", field.RefTypeName); if (field.Attributes & FANavigation) fieldInfo->Set("navigation_name", field.NavigationName); fieldInfo->Set("array_rank", field.ArrayRank); Dictionary::Ptr attributeInfo = new Dictionary(); fieldInfo->Set("attributes", attributeInfo); attributeInfo->Set("config", static_cast(field.Attributes & FAConfig)); attributeInfo->Set("state", static_cast(field.Attributes & FAState)); attributeInfo->Set("required", static_cast(field.Attributes & FARequired)); attributeInfo->Set("navigation", static_cast(field.Attributes & FANavigation)); attributeInfo->Set("no_user_modify", static_cast(field.Attributes & FANoUserModify)); attributeInfo->Set("no_user_view", static_cast(field.Attributes & FANoUserView)); attributeInfo->Set("deprecated", static_cast(field.Attributes & FADeprecated)); } } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/typequeryhandler.hpp000066400000000000000000000034671322762156600212410ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef TYPEQUERYHANDLER_H #define TYPEQUERYHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API TypeQueryHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(TypeQueryHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* TYPEQUERYHANDLER_H */ icinga2-2.8.1/lib/remote/url-characters.hpp000066400000000000000000000042421322762156600205430ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef URL_CHARACTERS_H #define URL_CHARACTERS_H #define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" #define NUMERIC "0123456789" #define UNRESERVED ALPHA NUMERIC "-._~" "%" #define GEN_DELIMS ":/?#[]@" #define SUB_DELIMS "!$&'()*+,;=" #define PCHAR UNRESERVED SUB_DELIMS ":@" #define PCHAR_ENCODE UNRESERVED ":@" #define ACSCHEME ALPHA NUMERIC ".-+" //authority = [ userinfo "@" ] host [ ":" port ] #define ACUSERINFO UNRESERVED SUB_DELIMS #define ACHOST UNRESERVED SUB_DELIMS #define ACPORT NUMERIC #define ACPATHSEGMENT PCHAR #define ACPATHSEGMENT_ENCODE PCHAR_ENCODE #define ACQUERY PCHAR "/?" #define ACQUERY_ENCODE PCHAR_ENCODE "/?" #define ACFRAGMENT PCHAR "/?" #define ACFRAGMENT_ENCODE PCHAR_ENCODE "/?" #endif /* URL_CHARACTERS_H */ icinga2-2.8.1/lib/remote/url.cpp000066400000000000000000000235701322762156600164260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/array.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include "remote/url.hpp" #include "remote/url-characters.hpp" #include using namespace icinga; Url::Url() { } Url::Url(const String& base_url) { String url = base_url; if (url.GetLength() == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Empty URL.")); size_t pHelper = String::NPos; if (url[0] != '/') pHelper = url.Find(":"); if (pHelper != String::NPos) { if (!ParseScheme(url.SubStr(0, pHelper))) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Scheme.")); url = url.SubStr(pHelper + 1); } if (*url.Begin() != '/') BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL: '/' expected after scheme.")); if (url.GetLength() == 1) { return; } if (*(url.Begin() + 1) == '/') { pHelper = url.Find("/", 2); if (pHelper == String::NPos) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL: Missing '/' after authority.")); if (!ParseAuthority(url.SubStr(0, pHelper))) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Authority")); url = url.SubStr(pHelper); } if (*url.Begin() == '/') { pHelper = url.FindFirstOf("#?"); if (!ParsePath(url.SubStr(1, pHelper - 1))) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Path")); if (pHelper != String::NPos) url = url.SubStr(pHelper); } else BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL: Missing path.")); if (*url.Begin() == '?') { pHelper = url.Find("#"); if (!ParseQuery(url.SubStr(1, pHelper - 1))) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Query")); if (pHelper != String::NPos) url = url.SubStr(pHelper); } if (*url.Begin() == '#') { if (!ParseFragment(url.SubStr(1))) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Fragment")); } } String Url::GetScheme(void) const { return m_Scheme; } String Url::GetAuthority(void) const { if (m_Host.IsEmpty()) return ""; String auth; if (!m_Username.IsEmpty()) { auth = m_Username; if (!m_Password.IsEmpty()) auth += ":" + m_Password; auth += "@"; } auth += m_Host; if (!m_Port.IsEmpty()) auth += ":" + m_Port; return auth; } String Url::GetUsername(void) const { return m_Username; } String Url::GetPassword(void) const { return m_Password; } String Url::GetHost(void) const { return m_Host; } String Url::GetPort(void) const { return m_Port; } const std::vector& Url::GetPath(void) const { return m_Path; } const std::map >& Url::GetQuery(void) const { return m_Query; } String Url::GetQueryElement(const String& name) const { auto it = m_Query.find(name); if (it == m_Query.end()) return String(); return it->second.back(); } const std::vector& Url::GetQueryElements(const String& name) const { auto it = m_Query.find(name); if (it == m_Query.end()) { static std::vector emptyVector; return emptyVector; } return it->second; } String Url::GetFragment(void) const { return m_Fragment; } void Url::SetScheme(const String& scheme) { m_Scheme = scheme; } void Url::SetUsername(const String& username) { m_Username = username; } void Url::SetPassword(const String& password) { m_Password = password; } void Url::SetHost(const String& host) { m_Host = host; } void Url::SetPort(const String& port) { m_Port = port; } void Url::SetPath(const std::vector& path) { m_Path = path; } void Url::SetQuery(const std::map >& query) { m_Query = query; } void Url::AddQueryElement(const String& name, const String& value) { auto it = m_Query.find(name); if (it == m_Query.end()) { m_Query[name] = std::vector(); m_Query[name].push_back(value); } else m_Query[name].push_back(value); } void Url::SetQueryElements(const String& name, const std::vector& values) { m_Query[name] = values; } void Url::SetFragment(const String& fragment) { m_Fragment = fragment; } String Url::Format(bool onlyPathAndQuery, bool printCredentials) const { String url; if (!onlyPathAndQuery) { if (!m_Scheme.IsEmpty()) url += m_Scheme + ":"; if (printCredentials && !GetAuthority().IsEmpty()) url += "//" + GetAuthority(); else if (!GetHost().IsEmpty()) url += "//" + GetHost() + (!GetPort().IsEmpty() ? ":" + GetPort() : ""); } if (m_Path.empty()) url += "/"; else { for (const String& segment : m_Path) { url += "/"; url += Utility::EscapeString(segment, ACPATHSEGMENT_ENCODE, false); } } String param; if (!m_Query.empty()) { typedef std::pair > kv_pair; for (const kv_pair& kv : m_Query) { String key = Utility::EscapeString(kv.first, ACQUERY_ENCODE, false); if (param.IsEmpty()) param = "?"; else param += "&"; // Just one (or one empty) value if (kv.second.size() == 1) { param += key; param += kv.second[0].IsEmpty() ? String() : "=" + Utility::EscapeString(kv.second[0], ACQUERY_ENCODE, false); continue; } // Array String temp; for (const String s : kv.second) { if (!temp.IsEmpty()) temp += "&"; temp += key; if (kv.second.size() > 1) temp += "[]"; if (!s.IsEmpty()) temp += "=" + Utility::EscapeString(s, ACQUERY_ENCODE, false); } param += temp; } } url += param; if (!m_Fragment.IsEmpty()) url += "#" + Utility::EscapeString(m_Fragment, ACFRAGMENT_ENCODE, false); return url; } bool Url::ParseScheme(const String& scheme) { m_Scheme = scheme; if (scheme.FindFirstOf(ALPHA) != 0) return false; return (ValidateToken(scheme, ACSCHEME)); } bool Url::ParseAuthority(const String& authority) { String auth = authority.SubStr(2); size_t pos = auth.Find("@"); if (pos != String::NPos && pos != 0) { if (!Url::ParseUserinfo(auth.SubStr(0, pos))) return false; auth = auth.SubStr(pos+1); } pos = auth.Find(":"); if (pos != String::NPos) { if (pos == 0 || pos == auth.GetLength() - 1 || !Url::ParsePort(auth.SubStr(pos+1))) return false; } m_Host = auth.SubStr(0, pos); return ValidateToken(m_Host, ACHOST); } bool Url::ParseUserinfo(const String& userinfo) { size_t pos = userinfo.Find(":"); m_Username = userinfo.SubStr(0, pos); if (!ValidateToken(m_Username, ACUSERINFO)) return false; m_Username = Utility::UnescapeString(m_Username); if (pos != String::NPos && pos != userinfo.GetLength() - 1) { m_Password = userinfo.SubStr(pos+1); if (!ValidateToken(m_Username, ACUSERINFO)) return false; m_Password = Utility::UnescapeString(m_Password); } else m_Password = ""; return true; } bool Url::ParsePort(const String& port) { m_Port = Utility::UnescapeString(port); if (!ValidateToken(m_Port, ACPORT)) return false; return true; } bool Url::ParsePath(const String& path) { std::string pathStr = path; boost::char_separator sep("/"); boost::tokenizer > tokens(pathStr, sep); for (const String& token : tokens) { if (token.IsEmpty()) continue; if (!ValidateToken(token, ACPATHSEGMENT)) return false; String decodedToken = Utility::UnescapeString(token); m_Path.push_back(decodedToken); } return true; } bool Url::ParseQuery(const String& query) { /* Tokenizer does not like String AT ALL */ std::string queryStr = query; boost::char_separator sep("&"); boost::tokenizer > tokens(queryStr, sep); for (const String& token : tokens) { size_t pHelper = token.Find("="); if (pHelper == 0) // /?foo=bar&=bar == invalid return false; String key = token.SubStr(0, pHelper); String value = Empty; if (pHelper != String::NPos && pHelper != token.GetLength() - 1) value = token.SubStr(pHelper+1); if (!ValidateToken(value, ACQUERY)) return false; value = Utility::UnescapeString(value); pHelper = key.Find("[]"); if (pHelper == 0 || (pHelper != String::NPos && pHelper != key.GetLength()-2)) return false; key = key.SubStr(0, pHelper); if (!ValidateToken(key, ACQUERY)) return false; key = Utility::UnescapeString(key); auto it = m_Query.find(key); if (it == m_Query.end()) { m_Query[key] = std::vector(); m_Query[key].push_back(value); } else m_Query[key].push_back(value); } return true; } bool Url::ParseFragment(const String& fragment) { m_Fragment = Utility::UnescapeString(fragment); return ValidateToken(fragment, ACFRAGMENT); } bool Url::ValidateToken(const String& token, const String& symbols) { for (const char ch : token) { if (symbols.FindFirstOf(ch) == String::NPos) return false; } return true; } icinga2-2.8.1/lib/remote/url.hpp000066400000000000000000000066221322762156600164320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef URL_H #define URL_H #include "remote/i2-remote.hpp" #include "base/object.hpp" #include "base/string.hpp" #include "base/array.hpp" #include "base/value.hpp" #include #include namespace icinga { /** * A url class to use with the API * * @ingroup base */ class I2_REMOTE_API Url : public Object { public: DECLARE_PTR_TYPEDEFS(Url); Url(); Url(const String& url); String Format(bool onlyPathAndQuery = false, bool printCredentials = false) const; String GetScheme(void) const; String GetAuthority(void) const; String GetUsername(void) const; String GetPassword(void) const; String GetHost(void) const; String GetPort(void) const; const std::vector& GetPath(void) const; const std::map >& GetQuery(void) const; String GetQueryElement(const String& name) const; const std::vector& GetQueryElements(const String& name) const; String GetFragment(void) const; void SetScheme(const String& scheme); void SetUsername(const String& username); void SetPassword(const String& password); void SetHost(const String& host); void SetPort(const String& port); void SetPath(const std::vector& path); void SetQuery(const std::map >& query); void AddQueryElement(const String& name, const String& query); void SetQueryElements(const String& name, const std::vector& query); void SetFragment(const String& fragment); private: String m_Scheme; String m_Username; String m_Password; String m_Host; String m_Port; std::vector m_Path; std::map > m_Query; String m_Fragment; bool ParseScheme(const String& scheme); bool ParseAuthority(const String& authority); bool ParseUserinfo(const String& userinfo); bool ParsePort(const String& port); bool ParsePath(const String& path); bool ParseQuery(const String& query); bool ParseFragment(const String& fragment); static bool ValidateToken(const String& token, const String& symbols); }; } #endif /* URL_H */ icinga2-2.8.1/lib/remote/variablequeryhandler.cpp000066400000000000000000000102461322762156600220310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/variablequeryhandler.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/configtype.hpp" #include "base/scriptglobal.hpp" #include "base/logger.hpp" #include "base/serializer.hpp" #include #include using namespace icinga; REGISTER_URLHANDLER("/v1/variables", VariableQueryHandler); class VariableTargetProvider : public TargetProvider { public: DECLARE_PTR_TYPEDEFS(VariableTargetProvider); static Dictionary::Ptr GetTargetForVar(const String& name, const Value& value) { Dictionary::Ptr target = new Dictionary(); target->Set("name", name); target->Set("type", value.GetReflectionType()->GetName()); target->Set("value", value); return target; } virtual void FindTargets(const String& type, const boost::function& addTarget) const override { { Dictionary::Ptr globals = ScriptGlobal::GetGlobals(); ObjectLock olock(globals); for (const Dictionary::Pair& kv : globals) { addTarget(GetTargetForVar(kv.first, kv.second)); } } } virtual Value GetTargetByName(const String& type, const String& name) const override { return GetTargetForVar(name, ScriptGlobal::Get(name)); } virtual bool IsValidType(const String& type) const override { return type == "Variable"; } virtual String GetPluralName(const String& type) const override { return "variables"; } }; bool VariableQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() > 3) return false; if (request.RequestMethod != "GET") return false; QueryDescription qd; qd.Types.insert("Variable"); qd.Permission = "variables"; qd.Provider = new VariableTargetProvider(); params->Set("type", "Variable"); if (request.RequestUrl->GetPath().size() >= 3) params->Set("variable", request.RequestUrl->GetPath()[2]); std::vector objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user, "variable"); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, 404, "No variables found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Array::Ptr results = new Array(); for (const Dictionary::Ptr& var : objs) { Dictionary::Ptr result1 = new Dictionary(); results->Add(result1); Dictionary::Ptr resultAttrs = new Dictionary(); result1->Set("name", var->Get("name")); result1->Set("type", var->Get("type")); result1->Set("value", Serialize(var->Get("value"), 0)); } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; } icinga2-2.8.1/lib/remote/variablequeryhandler.hpp000066400000000000000000000035131322762156600220350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef VARIABLEQUERYHANDLER_H #define VARIABLEQUERYHANDLER_H #include "remote/httphandler.hpp" namespace icinga { class I2_REMOTE_API VariableQueryHandler : public HttpHandler { public: DECLARE_PTR_TYPEDEFS(VariableQueryHandler); virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) override; }; } #endif /* VARIABLEQUERYHANDLER_H */ icinga2-2.8.1/lib/remote/zone.cpp000066400000000000000000000102101322762156600165620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "remote/zone.hpp" #include "remote/zone.tcpp" #include "remote/jsonrpcconnection.hpp" #include "base/objectlock.hpp" #include "base/logger.hpp" using namespace icinga; REGISTER_TYPE(Zone); void Zone::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); m_Parent = Zone::GetByName(GetParentRaw()); Zone::Ptr zone = m_Parent; int levels = 0; Array::Ptr endpoints = GetEndpointsRaw(); if (endpoints) { ObjectLock olock(endpoints); for (const String& endpoint : endpoints) { Endpoint::Ptr ep = Endpoint::GetByName(endpoint); if (ep) ep->SetCachedZone(this); } } while (zone) { m_AllParents.push_back(zone); zone = Zone::GetByName(zone->GetParentRaw()); levels++; if (levels > 32) BOOST_THROW_EXCEPTION(ScriptError("Infinite recursion detected while resolving zone graph. Check your zone hierarchy.", GetDebugInfo())); } } Zone::Ptr Zone::GetParent(void) const { return m_Parent; } std::set Zone::GetEndpoints(void) const { std::set result; Array::Ptr endpoints = GetEndpointsRaw(); if (endpoints) { ObjectLock olock(endpoints); for (const String& name : endpoints) { Endpoint::Ptr endpoint = Endpoint::GetByName(name); if (!endpoint) continue; result.insert(endpoint); } } return result; } std::vector Zone::GetAllParents(void) const { return m_AllParents; } bool Zone::CanAccessObject(const ConfigObject::Ptr& object) { Zone::Ptr object_zone; if (object->GetReflectionType() == Zone::TypeInstance) object_zone = static_pointer_cast(object); else object_zone = static_pointer_cast(object->GetZone()); if (!object_zone) object_zone = Zone::GetLocalZone(); if (object_zone->GetGlobal()) return true; return object_zone->IsChildOf(this); } bool Zone::IsChildOf(const Zone::Ptr& zone) { Zone::Ptr azone = this; while (azone) { if (azone == zone) return true; azone = azone->GetParent(); } return false; } bool Zone::IsGlobal(void) const { return GetGlobal(); } bool Zone::IsSingleInstance(void) const { Array::Ptr endpoints = GetEndpointsRaw(); return !endpoints || endpoints->GetLength() < 2; } Zone::Ptr Zone::GetLocalZone(void) { Endpoint::Ptr local = Endpoint::GetLocalEndpoint(); if (!local) return Zone::Ptr(); return local->GetZone(); } void Zone::ValidateEndpointsRaw(const Array::Ptr& value, const ValidationUtils& utils) { ObjectImpl::ValidateEndpointsRaw(value, utils); if (value && value->GetLength() > 2) { Log(LogWarning, "Zone") << "The Zone object '" << GetName() << "' has more than two endpoints." << " Due to a known issue this type of configuration is strongly" << " discouraged and may cause Icinga to use excessive amounts of CPU time."; } } icinga2-2.8.1/lib/remote/zone.hpp000066400000000000000000000044151322762156600166010ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef ZONE_H #define ZONE_H #include "remote/i2-remote.hpp" #include "remote/zone.thpp" #include "remote/endpoint.hpp" namespace icinga { /** * @ingroup remote */ class I2_REMOTE_API Zone : public ObjectImpl { public: DECLARE_OBJECT(Zone); DECLARE_OBJECTNAME(Zone); virtual void OnAllConfigLoaded(void) override; Zone::Ptr GetParent(void) const; std::set GetEndpoints(void) const; std::vector GetAllParents(void) const; bool CanAccessObject(const ConfigObject::Ptr& object); bool IsChildOf(const Zone::Ptr& zone); bool IsGlobal(void) const; bool IsSingleInstance(void) const; static Zone::Ptr GetLocalZone(void); protected: virtual void ValidateEndpointsRaw(const Array::Ptr& value, const ValidationUtils& utils) override; private: Zone::Ptr m_Parent; std::vector m_AllParents; }; } #endif /* ZONE_H */ icinga2-2.8.1/lib/remote/zone.ti000066400000000000000000000033271322762156600164270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/configobject.hpp" library remote; namespace icinga { class Zone : ConfigObject { [config, navigation] name(Zone) parent (ParentRaw) { navigate {{{ return Zone::GetByName(GetParentRaw()); }}} }; [config] array(name(Endpoint)) endpoints (EndpointsRaw); [config] bool global; }; } icinga2-2.8.1/mkdocs.yml000066400000000000000000000024001322762156600150470ustar00rootroot00000000000000site_name: Icinga 2 docs_dir: doc dev_addr: 0.0.0.0:8000 pages: - 'About Icinga 2': '01-about.md' - 'Getting Started': '02-getting-started.md' - 'Monitoring Basics': '03-monitoring-basics.md' - 'Configuring Icinga 2': '04-configuring-icinga-2.md' - 'Service Monitoring': '05-service-monitoring.md' - 'Distributed Monitoring': '06-distributed-monitoring.md' - 'Agent Based Monitoring': '07-agent-based-monitoring.md' - 'Advanced Topics': '08-advanced-topics.md' - 'Object Types': '09-object-types.md' - 'Icinga Template Library': '10-icinga-template-library.md' - 'CLI Commands': '11-cli-commands.md' - 'Icinga 2 API': '12-icinga2-api.md' - 'Addons': '13-addons.md' - 'Features': '14-features.md' - 'Troubleshooting': '15-troubleshooting.md' - 'Upgrading Icinga 2': '16-upgrading-icinga-2.md' - 'Language Reference': '17-language-reference.md' - 'Library Reference': '18-library-reference.md' - 'Technical Concepts': '19-technical-concepts.md' - 'Script Debugger': '20-script-debugger.md' - 'Development': '21-development.md' - 'SELinux': '22-selinux.md' - 'Migrating from Icinga 1.x': '23-migrating-from-icinga-1x.md' - 'Appendix': '24-appendix.md' theme: readthedocs markdown_extensions: - smarty extra_javascript: - scroll.js icinga2-2.8.1/plugins/000077500000000000000000000000001322762156600145315ustar00rootroot00000000000000icinga2-2.8.1/plugins/CMakeLists.txt000066400000000000000000000057031322762156600172760ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_executable ( check_nscp_api check_nscp_api.cpp ) target_link_libraries ( check_nscp_api ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SYSTEM_LIBRARY} base remote ) set_target_properties ( check_nscp_api PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_PLUGINS_BUILD FOLDER Plugins ) # Prefer the PluginDir constant which is set to /sbin on Windows if ( WIN32 ) install ( TARGETS check_nscp_api RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} ) else() install ( TARGETS check_nscp_api RUNTIME DESTINATION ${ICINGA2_PLUGINDIR} ) endif() if ( WIN32 ) add_definitions ( -DUNICODE -D_UNICODE ) add_library ( thresholds thresholds ) set_target_properties ( thresholds PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 FOLDER Plugins ) list ( APPEND check_SOURCES check_disk.cpp check_load.cpp check_memory.cpp check_network.cpp check_perfmon.cpp check_ping.cpp check_procs.cpp check_service.cpp check_swap.cpp check_update.cpp check_uptime.cpp check_users.cpp ) foreach ( source ${check_SOURCES} ) string ( REGEX REPLACE ".cpp\$" "" check_OUT "${source}" ) string ( REGEX REPLACE ".cpp\$" ".h" check_HEADER "${source}" ) add_executable ( ${check_OUT} ${source} ${check_HEADER} ) target_link_libraries ( ${check_OUT} thresholds Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY} ) set_target_properties ( ${check_OUT} PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL I2_PLUGINS_BUILD FOLDER Plugins ) endforeach ( source ) target_link_libraries ( check_load Pdh.lib ) target_link_libraries ( check_network Pdh.lib Iphlpapi.lib) target_link_libraries ( check_perfmon Pdh.lib ) target_link_libraries ( check_ping Ntdll.lib iphlpapi.lib Ws2_32.lib ) target_link_libraries ( check_procs Pdh.lib ) target_link_libraries ( check_uptime ${Boost_SYSTEM_LIBRARY} ) target_link_libraries ( check_users wtsapi32.lib ) install ( TARGETS check_disk check_load check_memory check_network check_perfmon check_procs check_ping check_service check_swap check_update check_uptime check_users RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} ) endif ( ) icinga2-2.8.1/plugins/README.md000066400000000000000000000036561322762156600160220ustar00rootroot00000000000000## Icinga 2 plugins for Windows This collection of plugins is intended to provide basic functionality checks on windows machines. They (mostly) conform to the [nagios developer guidelines](https://nagios-plugins.org/doc/guidelines.html), returning adequate exit codes and printing a pertinent string with performance data. ### Intallation The plugins are installed as part of Icinga 2. ### Requirements - Boost 1.41.0 - Windows Vista, Windows Server 2008 or newer ### Usage Call a plugin with the "--help" option to receive information about its usage. Most of them don't need any parameters to but all of them have a -w (warning) and -c (critical) option. Those accept, if not otherwise specified, value or percentage based thresholds or threshold ranges. A few examples: *./check_command.exe -w 12 -c !60%* Adds a warning threshold of 12 and an inversed critical threshold of 60% *./check_command.exe -w ![20%-80%] -c [0%-40%]* The warning threshold is outside of 20% to 80% and the critical threshold is the range from 0% to 40%. A critical state always overwrites a warning state, meaning the check would be critical with a value of 30%. ### License Icinga 2 Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) This program is free software; you can redistribute it and/or modify it under the tems of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. icinga2-2.8.1/plugins/check_disk.cpp000066400000000000000000000340621322762156600173310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include #include #include "check_disk.h" #define VERSION 1.1 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { std::vector vDrives; printInfoStruct printInfo{ }; po::variables_map vm; INT ret; ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; printInfo.warn.legal = !printInfo.warn.legal; printInfo.crit.legal = !printInfo.crit.legal; if (printInfo.drives.empty()) ret = check_drives(vDrives, printInfo.exclude_drives); else ret = check_drives(vDrives, printInfo); if (ret != -1) return ret; for (std::vector::iterator it = vDrives.begin(); it != vDrives.end(); ++it) { if (!getDriveSpaceValues(*it, printInfo.unit)) { std::wcout << "Failed to access drive at " << it->name << '\n'; return 3; } } return printOutput(printInfo, vDrives); } static INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc("Options"); desc.add_options() ("help,h", "Print usage message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning threshold") ("critical,c", po::wvalue(), "Critical threshold") ("path,p", po::wvalue>()->multitoken(), "Declare explicitly which drives to check (default checks all)") ("exclude_device,x", po::wvalue>()->multitoken(), "Exclude these drives from check") ("exclude-type,X", po::wvalue>()->multitoken(), "Exclude partition types (ignored)") ("iwarning,W", po::wvalue(), "Warning threshold for inodes (ignored)") ("icritical,K", po::wvalue(), "Critical threshold for inodes (ignored)") ("unit,u", po::wvalue(), "Assign unit possible are: B, kB, MB, GB, TB") ("show-used,U", "Show used space instead of the free space") ("megabytes,m", "use megabytes, overridden by -unit") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines disk space usage.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tDISK WARNING 29GB | disk=29GB;50%%;5;0;120\n\n" L"\"DISK\" being the type of the check, \"WARNING\" the returned status\n" L"and \"23.8304%%\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value.\n" L"This program will also print out additional performance data disk by disk\n\n" L"%s' exit codes denote the following:\n\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE < THRESHOLD\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE > THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::cout << "Version: " << VERSION << '\n'; if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("path")) printInfo.drives = vm["path"].as>(); if (vm.count("exclude_device")) printInfo.exclude_drives = vm["exclude_device"].as>(); if (vm.count("unit")) { try { printInfo.unit = parseBUnit(vm["unit"].as()); } catch (std::invalid_argument) { std::wcout << "Unknown unit Type " << vm["unit"].as() << '\n'; return 3; } } else { if (vm.count("megabytes")) printInfo.unit = BunitMB; else printInfo.unit = BunitB; } printInfo.showUsed = vm.count("show-used"); if (vm.count("debug")) debug = TRUE; return -1; } static INT printOutput(printInfoStruct& printInfo, std::vector& vDrives) { if (debug) std::wcout << "Constructing output string\n"; std::vector wsDrives, wsPerf; std::wstring unit = BunitStr(printInfo.unit); state state = OK; std::wstring output = L"DISK OK - free space:"; if (printInfo.showUsed) output = L"DISK OK - used space:"; double tCap = 0, tFree = 0, tUsed = 0; for (std::vector::iterator it = vDrives.begin(); it != vDrives.end(); it++) { tCap += it->cap; tFree += it->free; tUsed += it->used; if (printInfo.showUsed) { wsDrives.push_back(it->name + L" " + removeZero(it->used) + L" " + unit + L" (" + removeZero(std::round(it->used / it->cap * 100.0)) + L"%); "); wsPerf.push_back(L" " + it->name + L"=" + removeZero(it->used) + unit + L";" + printInfo.warn.pString(it->cap) + L";" + printInfo.crit.pString(it->cap) + L";0;" + removeZero(it->cap)); if (printInfo.crit.set && !printInfo.crit.rend(it->used, it->cap)) state = CRITICAL; if (state == OK && printInfo.warn.set && !printInfo.warn.rend(it->used, it->cap)) state = WARNING; } else { wsDrives.push_back(it->name + L" " + removeZero(it->free) + L" " + unit + L" (" + removeZero(std::round(it->free / it->cap * 100.0)) + L"%); "); wsPerf.push_back(L" " + it->name + L"=" + removeZero(it->free) + unit + L";" + printInfo.warn.pString(it->cap) + L";" + printInfo.crit.pString(it->cap) + L";0;" + removeZero(it->cap)); if ( printInfo.crit.rend(it->free, it->cap)) state = CRITICAL; if (state == OK && printInfo.warn.rend(it->free, it->cap)) state = WARNING; } } if (state == WARNING) { output = L"DISK WARNING - free space:"; if (printInfo.showUsed) output = L"DISK WARNING - used space:"; } if (state == CRITICAL) { output = L"DISK CRITICAL - free space:"; if (printInfo.showUsed) output = L"DISK CRITICAL - used space:"; } std::wcout << output; if (vDrives.size() > 1) { if (printInfo.showUsed) { std::wcout << "Total " << (printInfo.showUsed ? tUsed : tFree) << unit << " (" << removeZero(std::round(tUsed / tCap * 100.0)) << "%); "; } } for (std::vector::const_iterator it = wsDrives.begin(); it != wsDrives.end(); it++) std::wcout << *it; std::wcout << "|"; for (std::vector::const_iterator it = wsPerf.begin(); it != wsPerf.end(); it++) std::wcout << *it; std::wcout << '\n'; return state; } static INT check_drives(std::vector& vDrives, std::vector& vExclude_Drives) { DWORD dwResult, dwSize = 0, dwVolumePathNamesLen = MAX_PATH + 1; WCHAR szLogicalDrives[1024], szVolumeName[MAX_PATH], *szVolumePathNames = NULL; HANDLE hVolume = NULL; std::wstring wsLogicalDrives; size_t volumeNameEnd = 0; std::set sDrives; if (debug) std::wcout << "Getting logic drive string (includes network drives)\n"; dwResult = GetLogicalDriveStrings(MAX_PATH, szLogicalDrives); if (dwResult > MAX_PATH) goto die; if (debug) std::wcout << "Splitting string intoo single drive names\n"; LPTSTR szSingleDrive = szLogicalDrives; while (*szSingleDrive) { std::wstring drname = szSingleDrive; sDrives.insert(drname); szSingleDrive += wcslen(szSingleDrive) + 1; if (debug) std::wcout << "Got: " << drname << '\n'; } if (debug) std::wcout << "Getting volume mountpoints (includes NTFS folders)\n" << "Getting first volume\n"; hVolume = FindFirstVolume(szVolumeName, MAX_PATH); if (hVolume == INVALID_HANDLE_VALUE) goto die; if (debug) std::wcout << "Traversing through list of drives\n"; while (GetLastError() != ERROR_NO_MORE_FILES) { if (debug) std::wcout << "Path name for " << szVolumeName << "= \""; volumeNameEnd = wcslen(szVolumeName) - 1; szVolumePathNames = reinterpret_cast(new WCHAR[dwVolumePathNamesLen]); while (!GetVolumePathNamesForVolumeName(szVolumeName, szVolumePathNames, dwVolumePathNamesLen, &dwVolumePathNamesLen)) { if (GetLastError() != ERROR_MORE_DATA) break; delete[] reinterpret_cast(szVolumePathNames); szVolumePathNames = reinterpret_cast(new WCHAR[dwVolumePathNamesLen]); } if (debug) std::wcout << szVolumePathNames << "\"\n"; sDrives.insert(std::wstring(szVolumePathNames)); FindNextVolume(hVolume, szVolumeName, MAX_PATH); } if (debug) std::wcout << "Creating vector from found volumes, ignoring cd drives etc.:\n"; for (std::set::iterator it = sDrives.begin(); it != sDrives.end(); ++it) { UINT type = GetDriveType(it->c_str()); if (type == DRIVE_FIXED || type == DRIVE_REMOTE) { if (debug) std::wcout << "\t" << *it << '\n'; vDrives.push_back(drive(*it)); } } FindVolumeClose(hVolume); if (szVolumePathNames) delete[] reinterpret_cast(szVolumePathNames); if (!vExclude_Drives.empty()) { if (debug) std::wcout << "Removing excluded drives\n"; BOOST_FOREACH(const std::wstring wsDriveName, vExclude_Drives) { vDrives.erase(std::remove_if(vDrives.begin(), vDrives.end(), boost::bind(checkName, _1, wsDriveName + L'\\')), vDrives.end()); } } return -1; die: if (hVolume) FindVolumeClose(hVolume); die(); return 3; } static INT check_drives(std::vector& vDrives, printInfoStruct& printInfo) { if (!printInfo.exclude_drives.empty()) { if (debug) std::wcout << "Removing excluded drives from user input drives\n"; BOOST_FOREACH(std::wstring wsDrive, printInfo.exclude_drives) { printInfo.drives.erase(std::remove(printInfo.drives.begin(), printInfo.drives.end(), wsDrive), printInfo.drives.end()); } } if (debug) std::wcout << "Parsing user input drive names\n"; for (std::vector::iterator it = printInfo.drives.begin(); it != printInfo.drives.end(); ++it) { if (it->at(it->length() - 1) != *L"\\") it->append(L"\\"); if (std::wstring::npos == it->find(L":\\")) { std::wcout << "A \":\" is required after the drive name of " << *it << '\n'; return 3; } if (debug) std::wcout << "Added " << *it << '\n'; vDrives.push_back(drive(*it)); } return -1; } static BOOL getDriveSpaceValues(drive& drive, const Bunit& unit) { if (debug) std::wcout << "Getting free and used disk space for drive " << drive.name << '\n'; ULARGE_INTEGER tempFree, tempTotal, tempUsed; if (!GetDiskFreeSpaceEx(drive.name.c_str(), NULL, &tempTotal, &tempFree)) { return FALSE; } tempUsed.QuadPart = tempTotal.QuadPart - tempFree.QuadPart; if (debug) std::wcout << "\tcap: " << tempFree.QuadPart << '\n'; drive.cap = round((tempTotal.QuadPart / pow(1024.0, unit))); if (debug) std::wcout << "\tAfter conversion: " << drive.cap << '\n' << "\tfree: " << tempFree.QuadPart << '\n'; drive.free = round((tempFree.QuadPart / pow(1024.0, unit))); if (debug) std::wcout << "\tAfter conversion: " << drive.free << '\n' << "\tused: " << tempUsed.QuadPart << '\n'; drive.used = round((tempUsed.QuadPart / pow(1024.0, unit))); if (debug) std::wcout << "\tAfter conversion: " << drive.used << '\n' << '\n'; return TRUE; } static bool checkName(const drive& d, const std::wstring& s) { return (s == d.name); } icinga2-2.8.1/plugins/check_disk.h000066400000000000000000000043341322762156600167750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_DISK_H #define CHECK_DISK_H #include #include #include "boost/program_options.hpp" #include "thresholds.h" struct drive { std::wstring name; double cap, free, used; drive(std::wstring p) : name(p) { } }; struct printInfoStruct { threshold warn, crit; std::vector drives, exclude_drives; Bunit unit; BOOL showUsed; }; static INT parseArguments(int, wchar_t **, boost::program_options::variables_map&, printInfoStruct&); static INT printOutput(printInfoStruct&, std::vector&); static INT check_drives(std::vector&, std::vector&); static INT check_drives(std::vector&, printInfoStruct&); static BOOL getDriveSpaceValues(drive&, const Bunit&); static bool checkName(const drive& d, const std::wstring& s); #endif /*CHECK_DISK_H*/ icinga2-2.8.1/plugins/check_load.cpp000066400000000000000000000174471322762156600173260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include "check_load.h" #include "boost/algorithm/string/split.hpp" #include "boost/algorithm/string/classification.hpp" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { printInfoStruct printInfo{ }; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; ret = check_load(printInfo); if (ret != -1) return ret; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { wchar_t namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); wchar_t *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print usage message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning value (in percent)") ("critical,c", po::wvalue(), "Critical value (in percent)") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines CPU load.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tLOAD WARNING 67%% | load=67%%;50%%;90%%;0;100\n\n" L"\"LOAD\" being the type of the check, \"WARNING\" the returned status\n" L"and \"67%%\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value.\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::cout << "Version: " << VERSION << '\n'; if (vm.count("warning")) { try { std::wstring wthreshold = vm["warning"].as(); std::vector tokens; boost::algorithm::split(tokens, wthreshold, boost::algorithm::is_any_of(",")); printInfo.warn = threshold(tokens[0]); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { std::wstring cthreshold = vm["critical"].as(); std::vector tokens; boost::algorithm::split(tokens, cthreshold, boost::algorithm::is_any_of(",")); printInfo.crit = threshold(tokens[0]); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(printInfo.load)) state = WARNING; if (printInfo.crit.rend(printInfo.load)) state = CRITICAL; std::wstringstream perf; perf << L"% | load=" << printInfo.load << L"%;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;100" << '\n'; switch (state) { case OK: std::wcout << L"LOAD OK " << printInfo.load << perf.str(); break; case WARNING: std::wcout << L"LOAD WARNING " << printInfo.load << perf.str(); break; case CRITICAL: std::wcout << L"LOAD CRITICAL " << printInfo.load << perf.str(); break; } return state; } INT check_load(printInfoStruct& printInfo) { PDH_HQUERY phQuery = NULL; PDH_HCOUNTER phCounter; DWORD dwBufferSize = 0; DWORD CounterType; PDH_FMT_COUNTERVALUE DisplayValue; PDH_STATUS err; LPCWSTR path = L"\\Processor(_Total)\\% Idle Time"; if (debug) std::wcout << L"Creating query and adding counter" << '\n'; err = PdhOpenQuery(NULL, NULL, &phQuery); if (!SUCCEEDED(err)) goto die; err = PdhAddEnglishCounter(phQuery, path, NULL, &phCounter); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Collecting first batch of query data" << '\n'; err = PdhCollectQueryData(phQuery); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Sleep for one second" << '\n'; Sleep(1000); if (debug) std::wcout << L"Collecting second batch of query data" << '\n'; err = PdhCollectQueryData(phQuery); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Creating formatted counter array" << '\n'; err = PdhGetFormattedCounterValue(phCounter, PDH_FMT_DOUBLE, &CounterType, &DisplayValue); if (SUCCEEDED(err)) { if (DisplayValue.CStatus == PDH_CSTATUS_VALID_DATA) { if (debug) std::wcout << L"Recieved Value of " << DisplayValue.doubleValue << L" (idle)" << '\n'; printInfo.load = 100.0 - DisplayValue.doubleValue; } else { if (debug) std::wcout << L"Received data was not valid\n"; goto die; } if (debug) std::wcout << L"Finished collection. Cleaning up and returning" << '\n'; PdhCloseQuery(phQuery); return -1; } die: die(); if (phQuery) PdhCloseQuery(phQuery); return 3; } icinga2-2.8.1/plugins/check_load.h000066400000000000000000000034071322762156600167620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_LOAD_H #define CHECK_LOAD_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold warn, crit; DOUBLE load; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&); INT check_load(printInfoStruct&); #endif // !CHECK_LOAD_H icinga2-2.8.1/plugins/check_memory.cpp000066400000000000000000000166451322762156600177160ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include "check_memory.h" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { printInfoStruct printInfo = {}; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; ret = check_memory(printInfo); if (ret != -1) return ret; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR ** av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning threshold") ("critical,c", po::wvalue(), "Critical threshold") ("unit,u", po::wvalue(), "The unit to use for display (default MB)") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines physical memory.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tMEMORY WARNING - 50%% free | memory=2024MB;3000;500;0;4096\n\n" L"\"MEMORY\" being the type of the check, \"WARNING\" the returned status\n" L"and \"50%%\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too.\n" , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::wcout << L"Version: " << VERSION << '\n'; if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } printInfo.warn.legal = !printInfo.warn.legal; } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } printInfo.crit.legal = !printInfo.crit.legal; } if (vm.count("debug")) debug = TRUE; if (vm.count("unit")) { try { printInfo.unit = parseBUnit(vm["unit"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } return -1; } INT printOutput(printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(printInfo.aRam, printInfo.tRam)) state = WARNING; if (printInfo.crit.rend(printInfo.aRam, printInfo.tRam)) state = CRITICAL; switch (state) { case OK: std::wcout << L"MEMORY OK - " << printInfo.percentFree << L"% free | memory=" << printInfo.aRam << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tRam) << L";" << printInfo.crit.pString(printInfo.tRam) << L";0;" << printInfo.tRam << '\n'; break; case WARNING: std::wcout << L"MEMORY WARNING - " << printInfo.percentFree << L"% free | memory=" << printInfo.aRam << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tRam) << L";" << printInfo.crit.pString(printInfo.tRam) << L";0;" << printInfo.tRam << '\n'; break; case CRITICAL: std::wcout << L"MEMORY CRITICAL - " << printInfo.percentFree << L"% free | memory=" << printInfo.aRam << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tRam) << L";" << printInfo.crit.pString(printInfo.tRam) << L";0;" << printInfo.tRam << '\n'; break; } return state; } INT check_memory(printInfoStruct& printInfo) { if (debug) std::wcout << L"Accessing memory statistics via MemoryStatus" << '\n'; _MEMORYSTATUSEX *pMemBuf = new _MEMORYSTATUSEX; pMemBuf->dwLength = sizeof(*pMemBuf); GlobalMemoryStatusEx(pMemBuf); printInfo.tRam = round(pMemBuf->ullTotalPhys / pow(1024.0, printInfo.unit)); printInfo.aRam = round(pMemBuf->ullAvailPhys / pow(1024.0, printInfo.unit)); printInfo.percentFree = 100.0 * pMemBuf->ullAvailPhys / pMemBuf->ullTotalPhys; if (debug) std::wcout << L"Found pMemBuf->dwTotalPhys: " << pMemBuf->ullTotalPhys << '\n' << L"Found pMemBuf->dwAvailPhys: " << pMemBuf->ullAvailPhys << '\n'; delete pMemBuf; return -1; } icinga2-2.8.1/plugins/check_memory.h000066400000000000000000000035021322762156600173470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_MEMORY_H #define CHECK_MEMORY_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold warn, crit; DOUBLE tRam, aRam; DOUBLE percentFree; Bunit unit = BunitMB; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&); INT check_memory(printInfoStruct&); #endif // !CHECK_MEMORY_H icinga2-2.8.1/plugins/check_network.cpp000066400000000000000000000310401322762156600200610ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include #include "check_network.h" #include "boost/algorithm/string/replace.hpp" #define VERSION 1.2 namespace po = boost::program_options; static BOOL debug = FALSE; static BOOL noisatap = FALSE; INT wmain(INT argc, WCHAR **argv) { std::vector vInterfaces; std::map mapNames; printInfoStruct printInfo{}; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; if (!mapSystemNamesToFamiliarNames(mapNames)) return 3; ret = check_network(vInterfaces); if (ret != -1) return ret; return printOutput(printInfo, vInterfaces, mapNames); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc("Options"); desc.add_options() ("help,h", "print usage and exit") ("version,V", "print version and exit") ("debug,d", "Verbose/Debug output") ("noisatap,n", "Don't show ISATAP interfaces in output") ("warning,w", po::wvalue(), "warning value") ("critical,c", po::wvalue(), "critical value") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines network performance.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tNETWORK WARNING 1131B/s | network=1131B;1000;7000;0\n\n" L"\"NETWORK\" being the type of the check, \"WARNING\" the returned status\n" L"and \"1131B/s\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"This program will also print out additional performance data interface\n" L"by interface\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::cout << "Version: " << VERSION << '\n'; if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("debug")) debug = TRUE; if (vm.count("noisatap")) noisatap = TRUE; return -1; } INT printOutput(printInfoStruct& printInfo, CONST std::vector& vInterfaces, CONST std::map& mapNames) { if (debug) std::wcout << L"Constructing output string" << '\n'; long tIn = 0, tOut = 0; std::wstringstream tss, perfDataFirst; state state = OK; std::map::const_iterator mapIt; std::wstring wsFriendlyName; for (std::vector::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) { tIn += it->BytesInSec; tOut += it->BytesOutSec; if (debug) std::wcout << "Getting friendly name of " << it->name << '\n'; mapIt = mapNames.find(it->name); if (mapIt != mapNames.end()) { if (debug) std::wcout << "\tIs " << mapIt->second << '\n'; wsFriendlyName = mapIt->second; } else { if (debug) std::wcout << "\tNo friendly name found, using adapter name\n"; wsFriendlyName = it->name; } if(wsFriendlyName.find(L"isatap") != std::wstring::npos && noisatap) { if (debug) std::wcout << "\tSkipping isatap interface " << wsFriendlyName << "\n"; continue; } else { boost::algorithm::replace_all(wsFriendlyName, "'", "''"); tss << L"\'" << wsFriendlyName << L"_in\'=" << it->BytesInSec << L"B \'" << wsFriendlyName << L"_out\'=" << it->BytesOutSec << L"B "; } } if (printInfo.warn.rend(tIn + tOut)) state = WARNING; if (printInfo.crit.rend(tIn + tOut)) state = CRITICAL; perfDataFirst << L"network=" << tIn + tOut << L"B;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; "; switch (state) { case OK: std::wcout << L"NETWORK OK " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n'; break; case WARNING: std::wcout << L"NETWORK WARNING " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n'; break; case CRITICAL: std::wcout << L"NETWORK CRITICAL " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n'; break; } return state; } INT check_network(std::vector & vInterfaces) { CONST WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec"; CONST WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec"; PDH_HQUERY phQuery = NULL; PDH_HCOUNTER phCounterIn, phCounterOut; DWORD dwBufferSizeIn = 0, dwBufferSizeOut = 0, dwItemCount = 0; PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL; PDH_STATUS err; if (debug) std::wcout << L"Creating Query and adding counters" << '\n'; err = PdhOpenQuery(NULL, NULL, &phQuery); if (!SUCCEEDED(err)) goto die; err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn); if (!SUCCEEDED(err)) goto die; err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Collecting first batch of query data" << '\n'; err = PdhCollectQueryData(phQuery); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Sleep for one second" << '\n'; Sleep(1000); if (debug) std::wcout << L"Collecting second batch of query data" << '\n'; err = PdhCollectQueryData(phQuery); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Creating formatted counter arrays" << '\n'; err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn); if (err == PDH_MORE_DATA || SUCCEEDED(err)) pDisplayValuesIn = reinterpret_cast(new BYTE[dwItemCount*dwBufferSizeIn]); else goto die; err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut); if (err == PDH_MORE_DATA || SUCCEEDED(err)) pDisplayValuesOut = reinterpret_cast(new BYTE[dwItemCount*dwBufferSizeIn]); else goto die; err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn); if (!SUCCEEDED(err)) goto die; err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut); if (!SUCCEEDED(err)) goto die; if (debug) std::wcout << L"Going over counter array" << '\n'; for (DWORD i = 0; i < dwItemCount; i++) { nInterface *iface = new nInterface(std::wstring(pDisplayValuesIn[i].szName)); iface->BytesInSec = pDisplayValuesIn[i].FmtValue.longValue; iface->BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue; vInterfaces.push_back(*iface); if (debug) std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n'; } if (debug) std::wcout << L"Finished collection. Cleaning up and returning" << '\n'; if (phQuery) PdhCloseQuery(phQuery); if (pDisplayValuesIn) delete reinterpret_cast(pDisplayValuesIn); if (pDisplayValuesOut) delete reinterpret_cast(pDisplayValuesOut); return -1; die: die(err); if (phQuery) PdhCloseQuery(phQuery); if (pDisplayValuesIn) delete reinterpret_cast(pDisplayValuesIn); if (pDisplayValuesOut) delete reinterpret_cast(pDisplayValuesOut); return 3; } BOOL mapSystemNamesToFamiliarNames(std::map& mapNames) { DWORD dwSize = 0, dwRetVal = 0; ULONG family = AF_UNSPEC, flags = GAA_FLAG_INCLUDE_PREFIX, outBufLen = 0, Iterations = 0; LPVOID lpMsgBuf = NULL; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; /* PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL; PIP_ADAPTER_PREFIX pPrefix = NULL; */ outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses if (debug) std::wcout << "Mapping adapter system names to friendly names\n"; do { pAddresses = reinterpret_cast(new BYTE[outBufLen]); dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { delete[]pAddresses; pAddresses = NULL; } else break; } while (++Iterations < 3); if (dwRetVal != NO_ERROR) { std::wcout << "Failed to collect friendly adapter names\n"; delete[]pAddresses; return FALSE; } pCurrAddresses = pAddresses; std::wstringstream wssAdapterName; std::wstringstream wssFriendlyName; for (pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) { wssAdapterName.str(std::wstring()); wssFriendlyName.str(std::wstring()); wssAdapterName << pCurrAddresses->Description; wssFriendlyName << pCurrAddresses->FriendlyName; if (debug) std::wcout << "Got: " << wssAdapterName.str() << " -- " << wssFriendlyName.str() << '\n'; mapNames.insert(std::pair(wssAdapterName.str(), wssFriendlyName.str())); } delete[]pAddresses; return TRUE; } icinga2-2.8.1/plugins/check_network.h000066400000000000000000000040621322762156600175320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_NETWORK_H #define CHECK_NETWORK_H #include #include "thresholds.h" #include "boost/program_options.hpp" struct nInterface { std::wstring name; LONG BytesInSec, BytesOutSec; nInterface(std::wstring p) : name(p) { } }; struct printInfoStruct { threshold warn, crit; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&, CONST std::vector&, CONST std::map&); INT check_network(std::vector&); BOOL mapSystemNamesToFamiliarNames(std::map&); #endif // !CHECK_NETWORK_H icinga2-2.8.1/plugins/check_nscp_api.cpp000066400000000000000000000240471322762156600201750ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #define VERSION "1.0.0" #include "remote/httpclientconnection.hpp" #include "remote/httprequest.hpp" #include "remote/url-characters.hpp" #include "base/application.hpp" #include "base/json.hpp" #include "base/string.hpp" #include "base/exception.hpp" #include #include #include using namespace icinga; namespace po = boost::program_options; bool l_Debug = false; /* * This function is called by an 'HttpRequest' once the server answers. After doing a short check on the 'response' it * decodes it to a Dictionary and then tells 'QueryEndpoint()' that it's done */ static void ResultHttpCompletionCallback(const HttpRequest& request, HttpResponse& response, bool& ready, boost::condition_variable& cv, boost::mutex& mtx, Dictionary::Ptr& result) { String body; char buffer[1024]; size_t count; while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0) body += String(buffer, buffer + count); if (l_Debug) { std::cout << "Received answer\n" << "\tHTTP code: " << response.StatusCode << "\n" << "\tHTTP message: '" << response.StatusMessage << "'\n" << "\tHTTP body: '" << body << "'.\n"; } // Only try to decode the body if the 'HttpRequest' was successful if (response.StatusCode != 200) result = Dictionary::Ptr(); else result = JsonDecode(body); // Unlock our mutex, set ready and notify 'QueryEndpoint()' boost::mutex::scoped_lock lock(mtx); ready = true; cv.notify_all(); } /* * This function takes all the information required to query an nscp instance on * 'host':'port' with 'password'. The String 'endpoint' contains the specific * query name and all the arguments formatted as an URL. */ static Dictionary::Ptr QueryEndpoint(const String& host, const String& port, const String& password, const String& endpoint) { HttpClientConnection::Ptr m_Connection = new HttpClientConnection(host, port, true); try { bool ready = false; boost::condition_variable cv; boost::mutex mtx; Dictionary::Ptr result; boost::shared_ptr req = m_Connection->NewRequest(); req->RequestMethod = "GET"; // Url() will call Utillity::UnescapeString() which will thrown an exception if it finds a lonely % req->RequestUrl = new Url(endpoint); req->AddHeader("password", password); if (l_Debug) std::cout << "Sending request to 'https://" << host << ":" << port << req->RequestUrl->Format() << "'\n"; // Submits the request. The 'ResultHttpCompletionCallback' is called once the HttpRequest receives an answer, // which then sets 'ready' to true m_Connection->SubmitRequest(req, boost::bind(ResultHttpCompletionCallback, _1, _2, boost::ref(ready), boost::ref(cv), boost::ref(mtx), boost::ref(result))); // We need to spinlock here because our 'HttpRequest' works asynchronous boost::mutex::scoped_lock lock(mtx); while (!ready) { cv.wait(lock); } return result; } catch (const std::exception& ex) { // Exceptions should only happen in extreme edge cases we can't recover from std::cout << "Caught exception: " << DiagnosticInformation(ex, false) << '\n'; return Dictionary::Ptr(); } } /* * Takes a Dictionary 'result' and constructs an icinga compliant output string. * If 'result' is not in the expected format it returns 3 ("UNKNOWN") and prints an informative, icinga compliant, * output string. */ static int FormatOutput(const Dictionary::Ptr& result) { if (!result) { std::cout << "UNKNOWN: No data received.\n"; return 3; } if (l_Debug) std::cout << "\tJSON Body:\n" << result->ToString() << '\n'; Array::Ptr payloads = result->Get("payload"); if (!payloads) { std::cout << "UNKNOWN: Answer format error: Answer is missing 'payload'.\n"; return 3; } if (payloads->GetLength() == 0) { std::cout << "UNKNOWN: Answer format error: 'payload' was empty.\n"; return 3; } if (payloads->GetLength() > 1) { std::cout << "UNKNOWN: Answer format error: Multiple payloads are not supported."; return 3; } Dictionary::Ptr payload; try { payload = payloads->Get(0); } catch (const std::exception& ex) { std::cout << "UNKNOWN: Answer format error: 'payload' was not a Dictionary.\n"; return 3; } Array::Ptr lines; try { lines = payload->Get("lines"); } catch (const std::exception&) { std::cout << "UNKNOWN: Answer format error: 'payload' is missing 'lines'.\n"; return 3; } if (!lines) { std::cout << "UNKNOWN: Answer format error: 'lines' is Null.\n"; return 3; } std::stringstream ssout; ObjectLock olock(lines); for (const Value& vline : lines) { Dictionary::Ptr line; try { line = vline; } catch (const std::exception& ex) { std::cout << "UNKNOWN: Answer format error: 'lines' entry was not a Dictionary.\n"; return 3; } if (!line) { std::cout << "UNKNOWN: Answer format error: 'lines' entry was Null.\n"; return 3; } ssout << payload->Get("command") << ' ' << line->Get("message") << " | "; if (!line->Contains("perf")) { ssout << '\n'; break; } Array::Ptr perfs = line->Get("perf"); ObjectLock olock(perfs); for (const Dictionary::Ptr& perf : perfs) { ssout << "'" << perf->Get("alias") << "'="; Dictionary::Ptr values = perf->Contains("int_value") ? perf->Get("int_value") : perf->Get("float_value"); ssout << values->Get("value") << values->Get("unit") << ';' << values->Get("warning") << ';' << values->Get("critical"); if (values->Contains("minimum") || values->Contains("maximum")) { ssout << ';'; if (values->Contains("minimum")) ssout << values->Get("minimum"); if (values->Contains("maximum")) ssout << ';' << values->Get("maximum"); } ssout << ' '; } ssout << '\n'; } //TODO: Fix String state = static_cast(payload->Get("result")).ToUpper(); int creturn = state == "OK" ? 0 : state == "WARNING" ? 1 : state == "CRITICAL" ? 2 : state == "UNKNOWN" ? 3 : 4; if (creturn == 4) { std::cout << "check_nscp UNKNOWN Answer format error: 'result' was not a known state.\n"; return 3; } std::cout << ssout.rdbuf(); return creturn; } /* * Process arguments, initialize environment and shut down gracefully. */ int main(int argc, char **argv) { po::variables_map vm; po::options_description desc("Options"); desc.add_options() ("help,h", "Print usage message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("host,H", po::value()->required(), "REQUIRED: NSCP API Host") ("port,P", po::value()->default_value("8443"), "NSCP API Port (Default: 8443)") ("password", po::value()->required(), "REQUIRED: NSCP API Password") ("query,q", po::value()->required(), "REQUIRED: NSCP API Query endpoint") ("arguments,a", po::value>()->multitoken(), "NSCP API Query arguments for the endpoint"); po::basic_command_line_parser parser(argc, argv); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); if (vm.count("version")) { std::cout << "Version: " << VERSION << '\n'; Application::Exit(0); } if (vm.count("help")) { std::cout << argv[0] << " Help\n\tVersion: " << VERSION << '\n'; std::cout << "check_nscp_api is a program used to query the NSClient++ API.\n"; std::cout << desc; std::cout << "For detailed information on possible queries and their arguments refer to the NSClient++ documentation.\n"; Application::Exit(0); } vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; Application::Exit(3); } if (vm.count("debug")) { l_Debug = true; } // Create the URL string and escape certain characters since Url() follows RFC 3986 String endpoint = "/query/" + vm["query"].as(); if (!vm.count("arguments")) endpoint += '/'; else { endpoint += '?'; for (const String& argument : vm["arguments"].as>()) { String::SizeType pos = argument.FindFirstOf("="); if (pos == String::NPos) endpoint += Utility::EscapeString(argument, ACQUERY_ENCODE, false); else { String key = argument.SubStr(0, pos); String val = argument.SubStr(pos + 1); endpoint += Utility::EscapeString(key, ACQUERY_ENCODE, false) + "=" + Utility::EscapeString(val, ACQUERY_ENCODE, false); } endpoint += '&'; } } // This needs to happen for HttpRequest to work Application::InitializeBase(); Dictionary::Ptr result = QueryEndpoint(vm["host"].as(), vm["port"].as(), vm["password"].as(), endpoint); // Application::Exit() is the clean way to exit after calling InitializeBase() Application::Exit(FormatOutput(result)); return 255; } icinga2-2.8.1/plugins/check_perfmon.cpp000066400000000000000000000300771322762156600200470ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include "check_perfmon.h" #define VERSION 1.0 namespace po = boost::program_options; INT wmain(INT argc, WCHAR **argv) { po::variables_map variables_map; printInfoStruct stPrintInfo; if (!ParseArguments(argc, argv, variables_map, stPrintInfo)) return 3; if (variables_map.count("print-objects")) { PrintObjects(); return 0; } if (variables_map.count("print-object-info")) { PrintObjectInfo(stPrintInfo); return 0; } if (QueryPerfData(stPrintInfo)) return PrintOutput(variables_map, stPrintInfo); else return 3; } BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR szNamePath[MAX_PATH + 1]; GetModuleFileName(NULL, szNamePath, MAX_PATH); WCHAR *szProgName = PathFindFileName(szNamePath); po::options_description desc("Options"); desc.add_options() ("help,h", "Print help page and exit") ("version,V", "Print version and exit") ("warning,w", po::wvalue(), "Warning thershold") ("critical,c", po::wvalue(), "Critical threshold") ("performance-counter,P", po::wvalue(), "The performance counter string to use") ("performance-wait", po::value(), "Sleep in milliseconds between the two perfomance querries (Default: 1000ms)") ("fmt-countertype", po::wvalue(), "Value type of counter: 'double'(default), 'long', 'int64'") ("print-objects", "Prints all available objects to console") ("print-object-info", "Prints all available instances and counters of --performance-counter, do not use a full perfomance counter string here") ("perf-syntax", po::wvalue(), "Use this string as name for the performance counter (graphite compatibility)") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return FALSE; } if (vm.count("version")) { std::wcout << "Version: " << VERSION << '\n'; return FALSE; } if (vm.count("help")) { std::wcout << szProgName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s runs a check against a performance counter.\n" L"You can use the following options to define its behaviour:\n\n", szProgName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tPERFMON CRITICAL \"\\Processor(_Total)\\%% Idle Time\" = 40.34 | " L"perfmon=40.34;20;40;; \"\\Processor(_Total)\\%% Idle Time\"=40.34\n\n" L"\"tPERFMON\" being the type of the check, \"CRITICAL\" the returned status\n" L"and \"40.34\" is the performance counters value.\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were exceeded\n" L" 1\tWARNING,\n\tThe warning was broken, but not the critical threshold\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tNo check could be performed\n\n" , szProgName); return 0; } if (vm.count("warning")) { try { printInfo.tWarn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::wcout << e.what() << '\n'; return FALSE; } } if (vm.count("critical")) { try { printInfo.tCrit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::wcout << e.what() << '\n'; return FALSE; } } if (vm.count("fmt-countertype")) { if (!vm["fmt-countertype"].as().compare(L"int64")) printInfo.dwRequestedType = PDH_FMT_LARGE; else if (!vm["fmt-countertype"].as().compare(L"long")) printInfo.dwRequestedType = PDH_FMT_LONG; else if (vm["fmt-countertype"].as().compare(L"double")) { std::wcout << "Unknown value type " << vm["fmt-countertype"].as() << '\n'; return FALSE; } } if (vm.count("performance-counter")) printInfo.wsFullPath = vm["performance-counter"].as(); if (vm.count("performance-wait")) printInfo.dwPerformanceWait = vm["performance-wait"].as(); return TRUE; } BOOL GetIntstancesAndCountersOfObject(CONST std::wstring wsObject, std::vector& vecInstances, std::vector& vecCounters) { LPWSTR szDataSource = NULL, szMachineName = NULL, mszCounterList = NULL, mszInstanceList = NULL; DWORD dwCounterListLength = 0, dwInstanceListLength = 0; std::wstringstream wssInstanceName, wssCounterName; LPWSTR szObjectName = new WCHAR[wsObject.length() + 1]; StrCpyW(szObjectName, wsObject.c_str()); PDH_STATUS status = PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList, &dwCounterListLength, mszInstanceList, &dwInstanceListLength, PERF_DETAIL_WIZARD, 0); if (status != PDH_MORE_DATA) { delete[]szObjectName; return FALSE; } mszCounterList = new WCHAR[dwCounterListLength + 1]; mszInstanceList = new WCHAR[dwInstanceListLength + 1]; status = PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList, &dwCounterListLength, mszInstanceList, &dwInstanceListLength, PERF_DETAIL_WIZARD, 0); if (FAILED(status)) { delete[]mszCounterList; delete[]mszInstanceList; delete[]szObjectName; return FALSE; } if (dwInstanceListLength) { for (DWORD c = 0; c < dwInstanceListLength-1; ++c) { if (mszInstanceList[c]) wssInstanceName << mszInstanceList[c]; else { vecInstances.push_back(wssInstanceName.str()); wssInstanceName.str(L""); } } } if (dwCounterListLength) { for (DWORD c = 0; c < dwCounterListLength-1; ++c) { if (mszCounterList[c]) { wssCounterName << mszCounterList[c]; } else { vecCounters.push_back(wssCounterName.str()); wssCounterName.str(L""); } } } delete[]mszCounterList; delete[]mszInstanceList; delete[]szObjectName; return TRUE; } VOID PrintObjects() { LPWSTR szDataSource = NULL, szMachineName = NULL, mszObjectList = NULL; DWORD dwBufferLength = 0; PDH_STATUS status = PdhEnumObjects(szDataSource, szMachineName, mszObjectList, &dwBufferLength, PERF_DETAIL_WIZARD, FALSE); //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means if (status != PDH_MORE_DATA) goto die; mszObjectList = new WCHAR[dwBufferLength + 2]; status = PdhEnumObjects(szDataSource, szMachineName, mszObjectList, &dwBufferLength, PERF_DETAIL_WIZARD, FALSE); if (FAILED(status)) goto die; DWORD c = 0; while (++c < dwBufferLength) { if (mszObjectList[c] == '\0') std::wcout << '\n'; else std::wcout << mszObjectList[c]; } delete[]mszObjectList; return; die: FormatPDHError(status); delete[]mszObjectList; } VOID PrintObjectInfo(CONST printInfoStruct& pI) { if (pI.wsFullPath.empty()) { std::wcout << "No object given!\n"; return; } std::vector vecInstances, vecCounters; if (!GetIntstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) { std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n' << "Make sure it exists!\n"; return; } std::wcout << "Instances of " << pI.wsFullPath << ":\n"; if (vecInstances.empty()) std::wcout << "> Has no instances\n"; else { for (std::vector::iterator it = vecInstances.begin(); it != vecInstances.end(); ++it) { std::wcout << "> " << *it << '\n'; } } std::wcout << std::endl; std::wcout << "Performance Counters of " << pI.wsFullPath << ":\n"; if (vecCounters.empty()) std::wcout << "> Has no counters\n"; else { for (std::vector::iterator it = vecCounters.begin(); it != vecCounters.end(); ++it) { std::wcout << "> " << *it << '\n'; } } std::wcout << std::endl; } BOOL QueryPerfData(printInfoStruct& pI) { PDH_HQUERY hQuery = NULL; PDH_HCOUNTER hCounter = NULL; PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL; DWORD dwBufferSize = 0, dwItemCount = 0; if (pI.wsFullPath.empty()) { std::wcout << "No performance counter path given!\n"; return FALSE; } PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery); if (FAILED(status)) goto die; status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter); if (FAILED(status)) goto die; status = PdhCollectQueryData(hQuery); if (FAILED(status)) goto die; /* /* Most counters need two queries to provide a value. /* Those which need only one will return the second. */ Sleep(pI.dwPerformanceWait); status = PdhCollectQueryData(hQuery); if (FAILED(status)) goto die; status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues); if (status != PDH_MORE_DATA) goto die; pDisplayValues = reinterpret_cast(new BYTE[dwBufferSize]); status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues); if (FAILED(status)) goto die; switch (pI.dwRequestedType) { case (PDH_FMT_LONG): pI.dValue = pDisplayValues[0].FmtValue.longValue; break; case (PDH_FMT_LARGE): pI.dValue = pDisplayValues[0].FmtValue.largeValue; break; default: pI.dValue = pDisplayValues[0].FmtValue.doubleValue; break; } delete[]pDisplayValues; return TRUE; die: FormatPDHError(status); delete[]pDisplayValues; return FALSE; } INT PrintOutput(CONST po::variables_map& vm, printInfoStruct& pi) { std::wstringstream wssPerfData; if (vm.count("perf-syntax")) { wssPerfData << "\"" << vm["perf-syntax"].as() << "\"="; } else { wssPerfData << "\"" << pi.wsFullPath << "\"="; } wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;"; if (pi.tCrit.rend(pi.dValue)) { std::wcout << "PERFMON CRITICAL \"" << pi.wsFullPath << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n'; return 2; } if (pi.tWarn.rend(pi.dValue)) { std::wcout << "PERFMON WARNING \"" << pi.wsFullPath << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n'; return 1; } std::wcout << "PERFMON OK \"" << pi.wsFullPath << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n'; return 0; } VOID FormatPDHError(PDH_STATUS status) { HANDLE hPdhLibrary = NULL; LPWSTR pMessage = NULL; hPdhLibrary = LoadLibrary(L"pdh.dll"); if (NULL == hPdhLibrary) { std::wcout << "LoadLibrary failed with " << GetLastError() << '\n'; return; } if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY, hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) { std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n'; return; } std::wcout << pMessage << '\n'; LocalFree(pMessage); } icinga2-2.8.1/plugins/check_perfmon.h000066400000000000000000000042771322762156600175170ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_PERFMON_H #define CHECK_PERFMON_H #include #include #include #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold tWarn, tCrit; std::wstring wsFullPath; DOUBLE dValue; DWORD dwPerformanceWait = 1000, dwRequestedType = PDH_FMT_DOUBLE; }; BOOL ParseArguments(CONST INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); BOOL GetIntstancesAndCountersOfObject(CONST std::wstring, std::vector&, std::vector&); VOID PrintObjects(); VOID PrintObjectInfo(CONST printInfoStruct&); INT QueryPerfData(printInfoStruct&); INT PrintOutput(CONST boost::program_options::variables_map&, printInfoStruct&); VOID FormatPDHError(PDH_STATUS); #endif // !CHECK_PERFMON_H icinga2-2.8.1/plugins/check_ping.cpp000066400000000000000000000346661322762156600173460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN //else winsock will be included with windows.h and conflict with winsock2 #endif #include #include #include #include #include #include #include #include #include "check_ping.h" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { po::variables_map vm; printInfoStruct printInfo; response response; WSADATA dat; if (WSAStartup(MAKEWORD(2, 2), &dat)) { std::cout << "WSAStartup failed\n"; return 3; } if (parseArguments(argc, argv, vm, printInfo) != -1) return 3; if (!resolveHostname(printInfo.host, printInfo.ipv6, printInfo.ip)) return 3; if (printInfo.ipv6) { if (check_ping6(printInfo, response) != -1) return 3; } else { if (check_ping4(printInfo, response) != -1) return 3; } WSACleanup(); return printOutput(printInfo, response); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print usage message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("host,H", po::wvalue()->required(), "Target hostname or IP. If an IPv6 address is given, the '-6' option must be set") (",4", "--Host is an IPv4 address or if it's a hostname: Resolve it to an IPv4 address (default)") (",6", "--Host is an IPv6 address or if it's a hostname: Resolve it to an IPv6 address") ("timeout,t", po::value(), "Specify timeout for requests in ms (default=1000)") ("packets,p", po::value(), "Declare ping count (default=5)") ("warning,w", po::wvalue(), "Warning values: rtt,package loss") ("critical,c", po::wvalue(), "Critical values: rtt,package loss") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise & ~po::command_line_style::allow_guessing ) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to ping an ip4 address.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will take at least timeout times number of pings to run\n" L"Then it will output a string looking something like this:\n\n" L"\tPING WARNING RTA: 72ms Packet loss: 20% | ping=72ms;40;80;71;77 pl=20%;20;50;0;100\n\n" L"\"PING\" being the type of the check, \"WARNING\" the returned status\n" L"and \"RTA: 72ms Packet loss: 20%\" the relevant information.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. \n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) { std::cout << progName << " Version: " << VERSION << '\n'; return 0; } if (vm.count("-4") && vm.count("-6")) { std::cout << "Conflicting options \"4\" and \"6\"" << '\n'; return 3; } if (vm.count("-6")) printInfo.ipv6 = TRUE; if (vm.count("warning")) { std::vector sVec = splitMultiOptions(vm["warning"].as()); if (sVec.size() != 2) { std::cout << "Wrong format for warning thresholds" << '\n'; return 3; } try { printInfo.warn = threshold(*sVec.begin()); printInfo.wpl = threshold(sVec.back()); if (!printInfo.wpl.perc) { std::cout << "Packet loss must be percentage" << '\n'; return 3; } } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { std::vector sVec = splitMultiOptions(vm["critical"].as()); if (sVec.size() != 2) { std::cout << "Wrong format for critical thresholds" << '\n'; return 3; } try { printInfo.crit = threshold(*sVec.begin()); printInfo.cpl = threshold(sVec.back()); if (!printInfo.wpl.perc) { std::cout << "Packet loss must be percentage" << '\n'; return 3; } } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("timeout")) printInfo.timeout = vm["timeout"].as(); if (vm.count("packets")) printInfo.num = vm["packets"].as(); printInfo.host = vm["host"].as(); if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(printInfoStruct& printInfo, response& response) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; double plp = ((double)response.dropped / printInfo.num) * 100.0; if (printInfo.warn.rend(response.avg) || printInfo.wpl.rend(plp)) state = WARNING; if (printInfo.crit.rend(response.avg) || printInfo.cpl.rend(plp)) state = CRITICAL; std::wstringstream perf; perf << L"rta=" << response.avg << L"ms;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << " pl=" << removeZero(plp) << "%;" << printInfo.wpl.pString() << ";" << printInfo.cpl.pString() << ";0;100"; if (response.dropped == printInfo.num) { std::wcout << L"PING CRITICAL ALL CONNECTIONS DROPPED | " << perf.str() << '\n'; return 2; } switch (state) { case OK: std::wcout << L"PING OK RTA: " << response.avg << L"ms Packet loss: " << removeZero(plp) << "% | " << perf.str() << '\n'; break; case WARNING: std::wcout << L"PING WARNING RTA: " << response.avg << L"ms Packet loss: " << removeZero(plp) << "% | " << perf.str() << '\n'; break; case CRITICAL: std::wcout << L"PING CRITICAL RTA: " << response.avg << L"ms Packet loss: " << removeZero(plp) << "% | " << perf.str() << '\n'; break; } return state; } BOOL resolveHostname(CONST std::wstring hostname, BOOL ipv6, std::wstring& ipaddr) { ADDRINFOW *result = NULL; ADDRINFOW *ptr = NULL; ADDRINFOW hints; ZeroMemory(&hints, sizeof(hints)); wchar_t ipstringbuffer[46]; if (ipv6) hints.ai_family = AF_INET6; else hints.ai_family = AF_INET; if (debug) std::wcout << L"Resolving hostname \"" << hostname << L"\"\n"; DWORD ret = GetAddrInfoW(hostname.c_str(), NULL, &hints, &result); if (ret) { std::cout << "Failed to resolve hostname. Winsock Error Code: " << ret << '\n'; return false; } if (ipv6) { struct sockaddr_in6 *address6 = (struct sockaddr_in6 *) result->ai_addr; InetNtop(AF_INET6, &address6->sin6_addr, ipstringbuffer, 46); } else { struct sockaddr_in *address4 = (struct sockaddr_in *) result->ai_addr; InetNtop(AF_INET, &address4->sin_addr, ipstringbuffer, 46); } if (debug) std::wcout << L"Resolved to \"" << ipstringbuffer << L"\"\n"; ipaddr = ipstringbuffer; return true; } INT check_ping4(CONST printInfoStruct& pi, response& response) { in_addr ipDest4; HANDLE hIcmp; DWORD dwRet = 0, dwRepSize = 0; LPVOID repBuf = NULL; UINT rtt = 0; INT num = pi.num; LARGE_INTEGER frequency, timer1, timer2; LPCWSTR term; if (debug) std::wcout << L"Parsing ip address" << '\n'; if (RtlIpv4StringToAddress(pi.ip.c_str(), TRUE, &term, &ipDest4) == STATUS_INVALID_PARAMETER) { std::wcout << pi.ip << " is not a valid ip address\n"; return 3; } if (*term != L'\0') { std::wcout << pi.ip << " is not a valid ip address\n"; return 3; } if (debug) std::wcout << L"Creating Icmp File\n"; if ((hIcmp = IcmpCreateFile()) == INVALID_HANDLE_VALUE) goto die; dwRepSize = sizeof(ICMP_ECHO_REPLY) + 8; repBuf = reinterpret_cast(new BYTE[dwRepSize]); if (repBuf == NULL) goto die; QueryPerformanceFrequency(&frequency); do { QueryPerformanceCounter(&timer1); if (debug) std::wcout << L"Sending Icmp echo\n"; if (!IcmpSendEcho2(hIcmp, NULL, NULL, NULL, ipDest4.S_un.S_addr, NULL, 0, NULL, repBuf, dwRepSize, pi.timeout)) { response.dropped++; if (debug) std::wcout << L"Dropped: Response was 0" << '\n'; continue; } if (debug) std::wcout << "Ping recieved" << '\n'; PICMP_ECHO_REPLY pEchoReply = static_cast(repBuf); if (pEchoReply->Status != IP_SUCCESS) { response.dropped++; if (debug) std::wcout << L"Dropped: echo reply status " << pEchoReply->Status << '\n'; continue; } if (debug) std::wcout << L"Recorded rtt of " << pEchoReply->RoundTripTime << '\n'; rtt += pEchoReply->RoundTripTime; if (response.pMin == 0 || pEchoReply->RoundTripTime < response.pMin) response.pMin = pEchoReply->RoundTripTime; else if (pEchoReply->RoundTripTime > response.pMax) response.pMax = pEchoReply->RoundTripTime; QueryPerformanceCounter(&timer2); if (((timer2.QuadPart - timer1.QuadPart) * 1000 / frequency.QuadPart) < pi.timeout) Sleep(pi.timeout - ((timer2.QuadPart - timer1.QuadPart) * 1000 / frequency.QuadPart)); } while (--num); if (debug) std::wcout << L"All pings sent. Cleaning up and returning" << '\n'; if (hIcmp) IcmpCloseHandle(hIcmp); if (repBuf) delete reinterpret_cast(repBuf); response.avg = ((double)rtt / pi.num); return -1; die: die(); if (hIcmp) IcmpCloseHandle(hIcmp); if (repBuf) delete reinterpret_cast(repBuf); return 3; } INT check_ping6(CONST printInfoStruct& pi, response& response) { sockaddr_in6 ipDest6, ipSource6; IP_OPTION_INFORMATION ipInfo = { 30, 0, 0, 0, NULL }; DWORD dwRepSize = sizeof(ICMPV6_ECHO_REPLY) + 8; LPVOID repBuf = reinterpret_cast(new BYTE[dwRepSize]); HANDLE hIcmp = NULL; LARGE_INTEGER frequency, timer1, timer2; INT num = pi.num; UINT rtt = 0; if (debug) std::wcout << L"Parsing ip address" << '\n'; if (RtlIpv6StringToAddressEx(pi.ip.c_str(), &ipDest6.sin6_addr, &ipDest6.sin6_scope_id, &ipDest6.sin6_port)) { std::wcout << pi.ip << " is not a valid ipv6 address" << '\n'; return 3; } ipDest6.sin6_family = AF_INET6; ipSource6.sin6_addr = in6addr_any; ipSource6.sin6_family = AF_INET6; ipSource6.sin6_flowinfo = 0; ipSource6.sin6_port = 0; if (debug) std::wcout << L"Creating Icmp File" << '\n'; hIcmp = Icmp6CreateFile(); if (hIcmp == INVALID_HANDLE_VALUE) { goto die; } QueryPerformanceFrequency(&frequency); do { QueryPerformanceCounter(&timer1); if (debug) std::wcout << L"Sending Icmp echo" << '\n'; if (!Icmp6SendEcho2(hIcmp, NULL, NULL, NULL, &ipSource6, &ipDest6, NULL, 0, &ipInfo, repBuf, dwRepSize, pi.timeout)) { response.dropped++; if (debug) std::wcout << L"Dropped: Response was 0" << '\n'; continue; } if (debug) std::wcout << "Ping recieved" << '\n'; Icmp6ParseReplies(repBuf, dwRepSize); ICMPV6_ECHO_REPLY *pEchoReply = static_cast(repBuf); if (pEchoReply->Status != IP_SUCCESS) { response.dropped++; if (debug) std::wcout << L"Dropped: echo reply status " << pEchoReply->Status << '\n'; continue; } rtt += pEchoReply->RoundTripTime; if (debug) std::wcout << L"Recorded rtt of " << pEchoReply->RoundTripTime << '\n'; if (response.pMin == 0 || pEchoReply->RoundTripTime < response.pMin) response.pMin = pEchoReply->RoundTripTime; else if (pEchoReply->RoundTripTime > response.pMax) response.pMax = pEchoReply->RoundTripTime; QueryPerformanceCounter(&timer2); if (((timer2.QuadPart - timer1.QuadPart) * 1000 / frequency.QuadPart) < pi.timeout) Sleep(pi.timeout - ((timer2.QuadPart - timer1.QuadPart) * 1000 / frequency.QuadPart)); } while (--num); if (debug) std::wcout << L"All pings sent. Cleaning up and returning" << '\n'; if (hIcmp) IcmpCloseHandle(hIcmp); if (repBuf) delete reinterpret_cast(repBuf); response.avg = ((double)rtt / pi.num); return -1; die: die(GetLastError()); if (hIcmp) IcmpCloseHandle(hIcmp); if (repBuf) delete reinterpret_cast(repBuf); return 3; } icinga2-2.8.1/plugins/check_ping.h000066400000000000000000000040731322762156600170000ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_PING_H #define CHECK_PING_H #include "thresholds.h" #include "boost/program_options.hpp" struct response { DOUBLE avg; UINT pMin = 0, pMax = 0, dropped = 0; }; struct printInfoStruct { threshold warn, crit; threshold wpl, cpl; std::wstring host, ip; BOOL ipv6 = FALSE; DWORD timeout = 1000; INT num = 5; }; INT printOutput(printInfoStruct&, response&); INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT check_ping4(CONST printInfoStruct&, response&); INT check_ping6(CONST printInfoStruct&, response&); BOOL resolveHostname(CONST std::wstring, BOOL, std::wstring&); #endif // !CHECK_PING_H icinga2-2.8.1/plugins/check_procs.cpp000066400000000000000000000241661322762156600175310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include "check_procs.h" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { po::variables_map vm; printInfoStruct printInfo = { }; INT r = parseArguments(argc, argv, vm, printInfo); if (r != -1) return r; if(!printInfo.user.empty()) return printOutput(countProcs(printInfo.user), printInfo); return printOutput(countProcs(), printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("user,u", po::wvalue(), "Count only processes of user") ("warning,w", po::wvalue(), "Warning threshold") ("critical,c", po::wvalue(), "Critical threshold") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines processes.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tPROCS WARNING 67 | load=67;50;90;0\n\n" L"\"PROCS\" being the type of the check, \"WARNING\" the returned status\n" L"and \"67\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"For \"-user\" option keep in mind you need root to see other users processes\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) { std::wcout << "Version: " << VERSION << '\n'; return 0; } if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("user")) printInfo.user = vm["user"].as(); if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(CONST INT numProcs, printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(numProcs)) state = WARNING; if (printInfo.crit.rend(numProcs)) state = CRITICAL; std::wstring user = L""; if (!printInfo.user.empty()) user.append(L" processes of user ").append(printInfo.user); switch (state) { case OK: std::wcout << L"PROCS OK " << numProcs << user << L" | procs=" << numProcs << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case WARNING: std::wcout << L"PROCS WARNING " << numProcs << user << L" | procs=" << numProcs << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case CRITICAL: std::wcout << L"PROCS CRITICAL " << numProcs << user << L" | procs=" << numProcs << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; } return state; } INT countProcs() { if (debug) std::wcout << L"Counting all processes" << '\n'; HANDLE hProcessSnap = NULL; PROCESSENTRY32 pe32; if (debug) std::wcout << L"Creating snapshot" << '\n'; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return -1; pe32.dwSize = sizeof(PROCESSENTRY32); if (debug) std::wcout << L"Grabbing first proccess" << '\n'; if (!Process32First(hProcessSnap, &pe32)) { CloseHandle(hProcessSnap); return -1; } INT numProcs = 0; if (debug) std::wcout << L"Counting processes..." << '\n'; do { ++numProcs; } while (Process32Next(hProcessSnap, &pe32)); if (debug) std::wcout << L"Found " << numProcs << L" processes. Cleaning up udn returning" << '\n'; if (hProcessSnap) CloseHandle(hProcessSnap); return numProcs; } INT countProcs(CONST std::wstring user) { if (debug) std::wcout << L"Counting all processes of user" << user << '\n'; CONST WCHAR *wuser = user.c_str(); INT numProcs = 0; HANDLE hProcessSnap, hProcess = NULL, hToken = NULL; PROCESSENTRY32 pe32; DWORD dwReturnLength, dwAcctName, dwDomainName; PTOKEN_USER pSIDTokenUser = NULL; SID_NAME_USE sidNameUse; LPWSTR AcctName, DomainName; if (debug) std::wcout << L"Creating snapshot" << '\n'; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) goto die; pe32.dwSize = sizeof(PROCESSENTRY32); if (debug) std::wcout << L"Grabbing first proccess" << '\n'; if (!Process32First(hProcessSnap, &pe32)) goto die; if (debug) std::wcout << L"Counting processes..." << '\n'; do { if (debug) std::wcout << L"Getting process token" << '\n'; //get ProcessToken hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) //Won't count pid 0 (system idle) and 4/8 (Sytem) continue; //Get dwReturnLength in first call dwReturnLength = 1; if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue; pSIDTokenUser = reinterpret_cast(new BYTE[dwReturnLength]); memset(pSIDTokenUser, 0, dwReturnLength); if (debug) std::wcout << L"Received token, saving information" << '\n'; //write Info in pSIDTokenUser if (!GetTokenInformation(hToken, TokenUser, pSIDTokenUser, dwReturnLength, NULL)) continue; AcctName = NULL; DomainName = NULL; dwAcctName = 1; dwDomainName = 1; if (debug) std::wcout << L"Looking up SID" << '\n'; //get dwAcctName and dwDomainName size if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName, (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue; AcctName = reinterpret_cast(new WCHAR[dwAcctName]); DomainName = reinterpret_cast(new WCHAR[dwDomainName]); if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName, (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse)) continue; if (debug) std::wcout << L"Comparing " << AcctName << L" to " << wuser << '\n'; if (!wcscmp(AcctName, wuser)) { ++numProcs; if (debug) std::wcout << L"Is process of " << wuser << L" (" << numProcs << L")" << '\n'; } delete[] reinterpret_cast(AcctName); delete[] reinterpret_cast(DomainName); } while (Process32Next(hProcessSnap, &pe32)); die: if (hProcessSnap) CloseHandle(hProcessSnap); if (hProcess) CloseHandle(hProcess); if (hToken) CloseHandle(hToken); if (pSIDTokenUser) delete[] reinterpret_cast(pSIDTokenUser); return numProcs; } icinga2-2.8.1/plugins/check_procs.h000066400000000000000000000034571322762156600171760ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_PROCS_H #define CHECK_PROCS_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold warn, crit; std::wstring user; }; INT countProcs(); INT countProcs(CONST std::wstring); INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(CONST INT, printInfoStruct&); #endif // !CHECK_PROCS_H icinga2-2.8.1/plugins/check_service.cpp000066400000000000000000000217331322762156600200400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include "check_service.h" #define VERSION 1.1 namespace po = boost::program_options; static BOOL debug; INT wmain(INT argc, WCHAR **argv) { po::variables_map vm; printInfoStruct printInfo; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; if (vm.count("description")) printInfo.service = GetServiceByDescription(vm["service"].as()); if (printInfo.service.empty()) { std::wcout << "Could not find service matching description\n"; return 3; } printInfo.ServiceState = ServiceStatus(printInfo); if (printInfo.ServiceState == -1) return 3; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("D", "Verbose/Debug output") ("service,s", po::wvalue(), "Service name to check") ("description,d", "Use \"service\" to match on description") ("warn,w", "Return warning (1) instead of critical (2),\n when service is not running") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check the status of a service.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tSERVICE CRITICAL NOT_RUNNING | service=4;!4;!4;1;7\n\n" L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n" L"and \"1\" is the returned value.\n" L"A service is either running (Code 0x04) or not running (any other).\n" L"For more information consult the msdn on service state transitions.\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"%s' thresholds work differently, since a service is either running or not\n" L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n" L"or critical state respectively.\n\n" , progName, progName); std::cout << '\n'; return 0; } if (vm.count("version")) { std::cout << "Version: " << VERSION << '\n'; return 0; } if (!vm.count("service")) { std::cout << "Argument \"service\" is required.\n" << desc << '\n'; return 3; } printInfo.service = vm["service"].as(); printInfo.warn = vm.count("warn"); if (vm.count("D")) debug = TRUE; return -1; } INT printOutput(CONST printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; std::wstring perf; state state = OK; if (!printInfo.ServiceState) { std::wcout << L"SERVICE CRITICAL NOTFOUND | service=" << printInfo.ServiceState << ";;;1;7" << '\n'; return 3; } if (printInfo.ServiceState != 0x04) printInfo.warn ? state = WARNING : state = CRITICAL; switch (state) { case OK: std::wcout << L"SERVICE \"" << printInfo.service << "\" OK RUNNING | service=4;;;1;7" << '\n'; break; case WARNING: std::wcout << L"SERVICE \"" << printInfo.service << "\" WARNING NOT RUNNING | service=" << printInfo.ServiceState << ";;;1;7" << '\n'; break; case CRITICAL: std::wcout << L"SERVICE \"" << printInfo.service << "\" CRITICAL NOT RUNNING | service=" << printInfo.ServiceState << ";;;1;7" << '\n'; break; } return state; } std::wstring GetServiceByDescription(CONST std::wstring& description) { SC_HANDLE hSCM = NULL; LPBYTE lpBuf = NULL; DWORD cbBufSize = 0; DWORD lpServicesReturned = 0; DWORD pcbBytesNeeded = 0; DWORD lpResumeHandle = 0;; if (debug) std::wcout << L"Opening SC Manager" << '\n'; hSCM = OpenSCManager(NULL, NULL, GENERIC_READ); if (hSCM == NULL) goto die; if (debug) std::wcout << L"Determining initially required memory" << '\n'; EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0, &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle); /* This should always be ERROR_INSUFFICIENT_BUFFER... But for some reason it is sometimes ERROR_MORE_DATA * See the MSDN on EnumServiceStatus for a glimpse of despair */ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER && GetLastError() != ERROR_MORE_DATA) goto die; LPENUM_SERVICE_STATUSW lpServices = reinterpret_cast(new BYTE[pcbBytesNeeded]); if (debug) std::wcout << L"Requesting Service Information. Entry point: " << lpResumeHandle << '\n'; EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, lpServices, pcbBytesNeeded, &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle); for (int index = 0; index < lpServicesReturned; index++) { LPWSTR lpCurrent = lpServices[index].lpServiceName; if (debug) { std::wcout << L"Opening Service \"" << lpServices[index].lpServiceName << L"\"\n"; } SC_HANDLE hService = OpenService(hSCM, lpCurrent, SERVICE_QUERY_CONFIG); if (hService == NULL) goto die; DWORD dwBytesNeeded = 0; if (debug) std::wcout << "Accessing config\n"; if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue; LPSERVICE_DESCRIPTION lpsd = reinterpret_cast(new BYTE[dwBytesNeeded]); if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, dwBytesNeeded, &dwBytesNeeded)) continue; if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, L"") != 0) { std::wstring desc(lpsd->lpDescription); if (debug) std::wcout << "Got description:\n" << desc << '\n'; size_t p = desc.find(description); if (desc.find(description) != desc.npos) return lpCurrent; } else if (debug) std::wcout << "No description found\n"; } CloseServiceHandle(hSCM); delete[] lpServices; return L""; die: die(); if (hSCM) CloseServiceHandle(hSCM); if (lpServices) delete[] lpServices; return L""; } DWORD ServiceStatus(CONST printInfoStruct& printInfo) { SC_HANDLE hSCM; SC_HANDLE hService; DWORD cbBufSize, lpServicesReturned, pcbBytesNeeded; DWORD lpResumeHandle = 0; LPBYTE lpBuf = NULL; if (debug) std::wcout << L"Opening SC Manager" << '\n'; hSCM = OpenSCManager(NULL, NULL, GENERIC_READ); if (hSCM == NULL) goto die; hService = OpenService(hSCM, printInfo.service.c_str(), SERVICE_QUERY_STATUS); if (hService == NULL) goto die; QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0, &cbBufSize); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto die; lpBuf = new BYTE[cbBufSize]; if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, lpBuf, cbBufSize, &cbBufSize)) { LPSERVICE_STATUS_PROCESS pInfo = (LPSERVICE_STATUS_PROCESS)lpBuf; return pInfo->dwCurrentState; } die: die(); if (hSCM) CloseServiceHandle(hSCM); if (hService) CloseServiceHandle(hService); if (lpBuf) delete [] lpBuf; return -1; } icinga2-2.8.1/plugins/check_service.h000066400000000000000000000035571322762156600175110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_SERVICE_H #define CHECK_SERVICE_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { BOOL warn; DWORD ServiceState; std::wstring service; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(CONST printInfoStruct&); std::wstring GetServiceByDescription(CONST std::wstring&); DWORD ServiceStatus(CONST printInfoStruct&); #endif // !CHECK_SERVICE_H icinga2-2.8.1/plugins/check_swap.cpp000066400000000000000000000162631322762156600173540ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include "check_swap.h" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { printInfoStruct printInfo = { }; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; ret = check_swap(printInfo); if (ret != -1) return ret; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning threshold") ("critical,c", po::wvalue(), "Critical threshold") ("unit,u", po::wvalue(), "The unit to use for display (default MB)") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines swap in percent.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tSWAP WARNING - 20%% free | swap=2000B;3000;500;0;10000\n\n" L"\"SWAP\" being the type of the check, \"WARNING\" the returned status\n" L"and \"20%%\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too.\n" , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::wcout << L"Version: " << VERSION << '\n'; if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } printInfo.warn.legal = !printInfo.warn.legal; } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } printInfo.crit.legal = !printInfo.crit.legal; } if (vm.count("debug")) debug = TRUE; if (vm.count("unit")) { try { printInfo.unit = parseBUnit(vm["unit"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } return -1; } INT printOutput(printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(printInfo.aSwap, printInfo.tSwap)) state = WARNING; if (printInfo.crit.rend(printInfo.aSwap, printInfo.tSwap)) state = CRITICAL; switch (state) { case OK: std::wcout << L"SWAP OK - " << printInfo.percentFree << L"% free | swap=" << printInfo.aSwap << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tSwap) << L";" << printInfo.crit.pString(printInfo.tSwap) << L";0;" << printInfo.tSwap << '\n'; break; case WARNING: std::wcout << L"SWAP WARNING - " << printInfo.percentFree << L"% free | swap=" << printInfo.aSwap << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tSwap) << L";" << printInfo.crit.pString(printInfo.tSwap) << L";0;" << printInfo.tSwap << '\n'; break; case CRITICAL: std::wcout << L"SWAP CRITICAL - " << printInfo.percentFree << L"% free | swap=" << printInfo.aSwap << BunitStr(printInfo.unit) << L";" << printInfo.warn.pString(printInfo.tSwap) << L";" << printInfo.crit.pString(printInfo.tSwap) << L";0;" << printInfo.tSwap << '\n'; break; } return state; } INT check_swap(printInfoStruct& printInfo) { MEMORYSTATUSEX MemBuf; MemBuf.dwLength = sizeof(MemBuf); if (!GlobalMemoryStatusEx(&MemBuf)) { die(); return 3; } printInfo.tSwap = round(MemBuf.ullTotalPageFile / pow(1024.0, printInfo.unit)); printInfo.aSwap = round(MemBuf.ullAvailPageFile / pow(1024.0, printInfo.unit)); printInfo.percentFree = 100.0 * MemBuf.ullAvailPageFile / MemBuf.ullTotalPageFile; return -1; } icinga2-2.8.1/plugins/check_swap.h000066400000000000000000000034741322762156600170210ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_SWAP_H #define CHECK_SWAP_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold warn, crit; DOUBLE tSwap, aSwap; DOUBLE percentFree; Bunit unit = BunitMB; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&); INT check_swap(printInfoStruct&); #endif // !CHECK_SWAP_H icinga2-2.8.1/plugins/check_update.cpp000066400000000000000000000177231322762156600176660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include #include "check_update.h" #define VERSION 1.0 #define CRITERIA L"(IsInstalled = 0 and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441') or (IsInstalled = 0 and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4')" namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { printInfoStruct printInfo = { FALSE, FALSE, 0, FALSE, FALSE, FALSE }; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; ret = check_update(printInfo); if (ret != -1) return ret; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", "Warn if there are important updates available") ("critical,c", "Critical if there are important updates that require a reboot") ("possible-reboot", "Treat \"update may need reboot\" as \"update needs reboot\"") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines required updates.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nAfter some time, it will then output a string like this one:\n\n" L"\tUPDATE WARNING 8 | updates=8;1;1;0\n\n" L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n" L"and \"8\" is the number of important updates updates.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"An update counts as important when it is part of the Security- or\n" L"CriticalUpdates group.\n" L"Consult the msdn on WSUS Classification GUIDs for more information.\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"%s works different from other plugins in that you do not set thresholds\n" L"but only activate them. Using \"-w\" triggers warning state if there are not\n" L"installed and non-optional updates. \"-c\" triggers critical if there are\n" L"non-optional updates that require a reboot.\n" L"The \"possible-reboot\" option is not recommended since this true for nearly\n" L"every update." , progName, progName); std::cout << '\n'; return 0; } if (vm.count("version")) { std::cout << "Version: " << VERSION << '\n'; return 0; } if (vm.count("warning")) printInfo.warn = TRUE; if (vm.count("critical")) printInfo.crit = TRUE; if (vm.count("possible-reboot")) printInfo.careForCanRequest = TRUE; if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(const printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; std::wstring output = L"UPDATE "; if (printInfo.important) state = WARNING; if (printInfo.reboot) state = CRITICAL; switch (state) { case OK: output.append(L"OK "); break; case WARNING: output.append(L"WARNING "); break; case CRITICAL: output.append(L"CRITICAL "); break; } std::wcout << output << printInfo.numUpdates << L" | update=" << printInfo.numUpdates << L";" << printInfo.warn << L";" << printInfo.crit << L";0;" << '\n'; return state; } INT check_update(printInfoStruct& printInfo) { if (debug) std::wcout << "Initializing COM library" << '\n'; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ISearchResult *pResult; IUpdateSession *pSession; IUpdateSearcher *pSearcher; BSTR criteria = NULL; HRESULT err; if (debug) std::wcout << "Creating UpdateSession and UpdateSearcher" << '\n'; CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&pSession); pSession->CreateUpdateSearcher(&pSearcher); /* IsInstalled = 0: All updates, including languagepacks and features BrowseOnly = 0: No features or languagepacks, security and unnamed BrowseOnly = 1: Nothing, broken RebootRequired = 1: Reboot required */ criteria = SysAllocString(CRITERIA); // https://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx // https://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx if (debug) std::wcout << L"Querrying updates from server" << '\n'; err = pSearcher->Search(criteria, &pResult); if (!SUCCEEDED(err)) goto die; SysFreeString(criteria); IUpdateCollection *pCollection; IUpdate *pUpdate; LONG updateSize; pResult->get_Updates(&pCollection); pCollection->get_Count(&updateSize); if (updateSize == 0) return -1; printInfo.numUpdates = updateSize; // printInfo.important = printInfo.warn; IInstallationBehavior *pIbehav; InstallationRebootBehavior updateReboot; for (LONG i = 0; i < updateSize; i++) { pCollection->get_Item(i, &pUpdate); if (debug) { std::wcout << L"Checking reboot behaviour of update number " << i << '\n'; } pUpdate->get_InstallationBehavior(&pIbehav); pIbehav->get_RebootBehavior(&updateReboot); if (updateReboot == irbAlwaysRequiresReboot) { printInfo.reboot = TRUE; if (debug) std::wcout << L"It requires reboot" << '\n'; continue; } if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot) if (debug) std::wcout << L"It requires reboot" << '\n'; printInfo.reboot = TRUE; } if (debug) std::wcout << L"Cleaning up and returning" << '\n'; SysFreeString(criteria); CoUninitialize(); return -1; die: die(err); CoUninitialize(); if (criteria) SysFreeString(criteria); return 3; } icinga2-2.8.1/plugins/check_update.h000066400000000000000000000035011322762156600173200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_UPDATE_H #define CHECK_UPDATE_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { BOOL warn, crit; LONG numUpdates; BOOL important, reboot, careForCanRequest; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(CONST printInfoStruct&); INT check_update(printInfoStruct&); #endif // !CHECK_UPDATE_H icinga2-2.8.1/plugins/check_uptime.cpp000066400000000000000000000167071322762156600177100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include "check_uptime.h" #include "boost/chrono.hpp" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug; INT wmain(INT argc, WCHAR **argv) { po::variables_map vm; printInfoStruct printInfo = { }; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; getUptime(printInfo); return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning threshold (Uses -unit)") ("critical,c", po::wvalue(), "Critical threshold (Uses -unit)") ("unit,u", po::wvalue(), "Unit to use:\nh\t- hours\nm\t- minutes\ns\t- seconds (default)\nms\t- milliseconds") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines uptime.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tUPTIME WARNING 712h | uptime=712h;700;1800;0\n\n" L"\"UPTIME\" being the type of the check, \"WARNING\" the returned status\n" L"and \"712h\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"Note that the returned time ins always rounded down,\n" L"4 hours and 44 minutes will show as 4h.\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too.\n" , progName); std::cout << '\n'; return 0; } if (vm.count("version")) { std::cout << VERSION << '\n'; return 0; } if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("unit")) { try{ printInfo.unit = parseTUnit(vm["unit"].as()); } catch (std::invalid_argument) { std::wcout << L"Unknown unit type " << vm["unit"].as() << '\n'; return 3; } } else printInfo.unit = TunitS; if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(printInfo.time)) state = WARNING; if (printInfo.crit.rend(printInfo.time)) state = CRITICAL; switch (state) { case OK: std::wcout << L"UPTIME OK " << printInfo.time << TunitStr(printInfo.unit) << L" | uptime=" << printInfo.time << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case WARNING: std::wcout << L"UPTIME WARNING " << printInfo.time << TunitStr(printInfo.unit) << L" | uptime=" << printInfo.time << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case CRITICAL: std::wcout << L"UPTIME CRITICAL " << printInfo.time << TunitStr(printInfo.unit) << L" | uptime=" << printInfo.time << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; } return state; } VOID getUptime(printInfoStruct& printInfo) { if (debug) std::wcout << L"Getting uptime in milliseconds" << '\n'; boost::chrono::milliseconds uptime = boost::chrono::milliseconds(GetTickCount64()); if (debug) std::wcout << L"Converting requested unit (default: seconds)" << '\n'; switch (printInfo.unit) { case TunitH: printInfo.time = boost::chrono::duration_cast(uptime).count(); break; case TunitM: printInfo.time = boost::chrono::duration_cast(uptime).count(); break; case TunitS: printInfo.time = boost::chrono::duration_cast(uptime).count(); break; case TunitMS: printInfo.time = uptime.count(); break; } } icinga2-2.8.1/plugins/check_uptime.h000066400000000000000000000034361322762156600173500ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_UPTIME_H #define CHECK_UPTIME_H #include "thresholds.h" #include "boost/program_options.hpp" struct printInfoStruct { threshold warn, crit; long long time; Tunit unit; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&); VOID getUptime(printInfoStruct&); #endif // !CHECK_UPTIME_H icinga2-2.8.1/plugins/check_users.cpp000066400000000000000000000171111322762156600175340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include #include #include "check_users.h" #define VERSION 1.0 namespace po = boost::program_options; static BOOL debug = FALSE; INT wmain(INT argc, WCHAR **argv) { printInfoStruct printInfo = { }; po::variables_map vm; INT ret = parseArguments(argc, argv, vm, printInfo); if (ret != -1) return ret; ret = check_users(printInfo); if (ret != -1) return ret; return printOutput(printInfo); } INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo) { WCHAR namePath[MAX_PATH]; GetModuleFileName(NULL, namePath, MAX_PATH); WCHAR *progName = PathFindFileName(namePath); po::options_description desc; desc.add_options() ("help,h", "Print help message and exit") ("version,V", "Print version and exit") ("debug,d", "Verbose/Debug output") ("warning,w", po::wvalue(), "Warning threshold") ("critical,c", po::wvalue(), "Critical threshold") ; po::basic_command_line_parser parser(ac, av); try { po::store( parser .options(desc) .style( po::command_line_style::unix_style | po::command_line_style::allow_long_disguise) .run(), vm); vm.notify(); } catch (std::exception& e) { std::cout << e.what() << '\n' << desc << '\n'; return 3; } if (vm.count("help")) { std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n'; wprintf( L"%s is a simple program to check a machines logged in users.\n" L"You can use the following options to define its behaviour:\n\n", progName); std::cout << desc; wprintf( L"\nIt will then output a string looking something like this:\n\n" L"\tUSERS WARNING 48 | users=48;10;50;0\n\n" L"\"USERS\" being the type of the check, \"WARNING\" the returned status\n" L"and \"48\" is the returned value.\n" L"The performance data is found behind the \"|\", in order:\n" L"returned value, warning threshold, critical threshold, minimal value and,\n" L"if applicable, the maximal value. Performance data will only be displayed when\n" L"you set at least one threshold\n\n" L"%s' exit codes denote the following:\n" L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n" L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n" L" 2\tCRITICAL,\n\tThe critical threshold was broken\n" L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n" L"Threshold syntax:\n\n" L"-w THRESHOLD\n" L"warn if threshold is broken, which means VALUE > THRESHOLD\n" L"(unless stated differently)\n\n" L"-w !THRESHOLD\n" L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n" L"-w [THR1-THR2]\n" L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n" L"-w ![THR1-THR2]\n" L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n" L"-w THRESHOLD%%\n" L"if the plugin accepts percentage based thresholds those will be used.\n" L"Does nothing if the plugin does not accept percentages, or only uses\n" L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n" L"to end with a percentage sign.\n\n" L"All of these options work with the critical threshold \"-c\" too." , progName); std::cout << '\n'; return 0; } if (vm.count("version")) std::wcout << L"Version: " << VERSION << '\n'; if (vm.count("warning")) { try { printInfo.warn = threshold(vm["warning"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("critical")) { try { printInfo.crit = threshold(vm["critical"].as()); } catch (std::invalid_argument& e) { std::cout << e.what() << '\n'; return 3; } } if (vm.count("debug")) debug = TRUE; return -1; } INT printOutput(printInfoStruct& printInfo) { if (debug) std::wcout << L"Constructing output string" << '\n'; state state = OK; if (printInfo.warn.rend(printInfo.users)) state = WARNING; if (printInfo.crit.rend(printInfo.users)) state = CRITICAL; switch (state) { case OK: std::wcout << L"USERS OK " << printInfo.users << L" User(s) logged in | users=" << printInfo.users << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case WARNING: std::wcout << L"USERS WARNING " << printInfo.users << L" User(s) logged in | users=" << printInfo.users << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; case CRITICAL: std::wcout << L"USERS CRITICAL " << printInfo.users << L" User(s) logged in | users=" << printInfo.users << L";" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n'; break; } return state; } INT check_users(printInfoStruct& printInfo) { DOUBLE users = 0; WTS_SESSION_INFOW *pSessionInfo = NULL; DWORD count; DWORD index; if (debug) std::wcout << L"Trying to enumerate terminal sessions" << '\n'; if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &count)) { std::wcout << L"Failed to enumerate terminal sessions" << '\n'; die(); if (pSessionInfo) WTSFreeMemory(pSessionInfo); return 3; } if (debug) std::wcout << L"Got all sessions (" << count << L"), traversing and counting active ones" << '\n'; for (index = 0; index < count; index++) { LPWSTR name; DWORD size; INT len; if (debug) std::wcout << L"Querrying session number " << index << '\n'; if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, pSessionInfo[index].SessionId, WTSUserName, &name, &size)) continue; if (debug) std::wcout << L"Found \"" << name << L"\". Checking whether it's a real session" << '\n'; len = lstrlenW(name); WTSFreeMemory(name); if (!len) continue; if (pSessionInfo[index].State == WTSActive || pSessionInfo[index].State == WTSDisconnected) { users++; if (debug) std::wcout << L"\"" << name << L"\" is a real session, counting it. Now " << users << '\n'; } } if (debug) std::wcout << "Finished coutning user sessions (" << users << "). Freeing memory and returning" << '\n'; WTSFreeMemory(pSessionInfo); printInfo.users = users; return -1; } icinga2-2.8.1/plugins/check_users.h000066400000000000000000000034171322762156600172050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CHECK_USERS_H #define CHECK_USERS_H #include "thresholds.h" #include struct printInfoStruct { threshold warn, crit; DOUBLE users; }; INT parseArguments(INT, WCHAR **, boost::program_options::variables_map&, printInfoStruct&); INT printOutput(printInfoStruct&); INT check_users(printInfoStruct&); #endif /* CHECK_USERS_H */ icinga2-2.8.1/plugins/thresholds.cpp000066400000000000000000000140451322762156600174200ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "thresholds.h" #include #include #include using namespace boost::algorithm; threshold::threshold() : set(false) {} threshold::threshold(CONST std::wstring& stri) { if (stri.empty()) throw std::invalid_argument("Threshold must not be empty"); std::wstring str = stri; //kill whitespace boost::algorithm::trim(str); bool low = (str.at(0) == L'!'); if (low) str = std::wstring(str.begin() + 1, str.end()); bool pc = false; if (str.at(0) == L'[' && str.at(str.length() - 1) == L']') {//is range str = std::wstring(str.begin() + 1, str.end() - 1); std::vector svec; boost::split(svec, str, boost::is_any_of(L"-")); if (svec.size() != 2) throw std::invalid_argument("Threshold range requires two arguments"); std::wstring str1 = svec.at(0), str2 = svec.at(1); if (str1.at(str1.length() - 1) == L'%' && str2.at(str2.length() - 1) == L'%') { pc = true; str1 = std::wstring(str1.begin(), str1.end() - 1); str2 = std::wstring(str2.begin(), str2.end() - 1); } try { boost::algorithm::trim(str1); lower = boost::lexical_cast(str1); boost::algorithm::trim(str2); upper = boost::lexical_cast(str2); legal = !low; perc = pc; set = true; } catch (CONST boost::bad_lexical_cast&) { throw std::invalid_argument("Unknown Threshold type"); } } else { //not range if (str.at(str.length() - 1) == L'%') { pc = true; str = std::wstring(str.begin(), str.end() - 1); } try { boost::algorithm::trim(str); lower = upper = boost::lexical_cast(str); legal = !low; perc = pc; set = true; } catch (CONST boost::bad_lexical_cast&) { throw std::invalid_argument("Unknown Threshold type"); } } } //return TRUE if the threshold is broken BOOL threshold::rend(CONST DOUBLE val, CONST DOUBLE max) { DOUBLE upperAbs = upper; DOUBLE lowerAbs = lower; if (perc) { upperAbs = upper / 100.0 * max; lowerAbs = lower / 100.0 * max; } if (!set) return set; if (lowerAbs == upperAbs) return val > upperAbs == legal; else return (val < lowerAbs || upperAbs < val) != legal; } //returns a printable string of the threshold std::wstring threshold::pString(CONST DOUBLE max) { if (!set) return L""; //transform percentages to abolute values DOUBLE lowerAbs = lower; DOUBLE upperAbs = upper; if (perc) { lowerAbs = lower / 100.0 * max; upperAbs = upper / 100.0 * max; } std::wstring s, lowerStr = removeZero(lowerAbs), upperStr = removeZero(upperAbs); if (lower != upper) { s.append(L"[").append(lowerStr).append(L"-") .append(upperStr).append(L"]"); } else s.append(lowerStr); return s; } std::wstring removeZero(DOUBLE val) { std::wstring ret = boost::lexical_cast(val); INT pos = ret.length(); if (ret.find_first_of(L".") == std::string::npos) return ret; for (std::wstring::reverse_iterator rit = ret.rbegin(); rit != ret.rend(); ++rit) { if (*rit == L'.') { return ret.substr(0, pos - 1); } if (*rit != L'0') { return ret.substr(0, pos); } pos--; } return L"0"; } std::vector splitMultiOptions(std::wstring str) { std::vector sVec; boost::split(sVec, str, boost::is_any_of(L",")); return sVec; } Bunit parseBUnit(CONST std::wstring& str) { std::wstring wstr = to_upper_copy(str); if (wstr == L"B") return BunitB; if (wstr == L"KB") return BunitkB; if (wstr == L"MB") return BunitMB; if (wstr == L"GB") return BunitGB; if (wstr == L"TB") return BunitTB; throw std::invalid_argument("Unknown unit type"); } std::wstring BunitStr(CONST Bunit& unit) { switch (unit) { case BunitB: return L"B"; case BunitkB: return L"kB"; case BunitMB: return L"MB"; case BunitGB: return L"GB"; case BunitTB: return L"TB"; } return NULL; } Tunit parseTUnit(CONST std::wstring& str) { std::wstring wstr = to_lower_copy(str); if (wstr == L"ms") return TunitMS; if (wstr == L"s") return TunitS; if (wstr == L"m") return TunitM; if (wstr == L"h") return TunitH; throw std::invalid_argument("Unknown unit type"); } std::wstring TunitStr(CONST Tunit& unit) { switch (unit) { case TunitMS: return L"ms"; case TunitS: return L"s"; case TunitM: return L"m"; case TunitH: return L"h"; } return NULL; } VOID die(DWORD err) { if (!err) err = GetLastError(); LPWSTR mBuf = NULL; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&mBuf, 0, NULL)) std::wcout << "Failed to format error message, last error was: " << err << '\n'; else std::wcout << mBuf << std::endl; } icinga2-2.8.1/plugins/thresholds.h000066400000000000000000000047311322762156600170660ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef THRESHOLDS_H #define THRESHOLDS_H #include #include #include enum Bunit { BunitB = 0, BunitkB = 1, BunitMB = 2, BunitGB = 3, BunitTB = 4 }; enum Tunit { TunitMS, TunitS, TunitM, TunitH }; enum state { OK = 0, WARNING = 1, CRITICAL = 2 }; class threshold { public: //DOUBLEs are always enough for ANY 64 bit value DOUBLE lower, upper; //TRUE means everything BELOW upper/outside [lower-upper] is fine BOOL legal, perc, set; threshold(); threshold(CONST DOUBLE v, CONST DOUBLE c, BOOL l = TRUE, BOOL p = FALSE); threshold(CONST std::wstring&); //return TRUE if the threshold is broken BOOL rend(CONST DOUBLE val, CONST DOUBLE max = 100.0); //returns a printable string of the threshold std::wstring pString(CONST DOUBLE max = 100.0); }; std::wstring removeZero(DOUBLE); std::vector splitMultiOptions(std::wstring); Bunit parseBUnit(CONST std::wstring&); std::wstring BunitStr(CONST Bunit&); Tunit parseTUnit(CONST std::wstring&); std::wstring TunitStr(CONST Tunit&); VOID die(DWORD err = 0); #endif /* THRESHOLDS_H */ icinga2-2.8.1/test/000077500000000000000000000000001322762156600140275ustar00rootroot00000000000000icinga2-2.8.1/test/CMakeLists.txt000066400000000000000000000114151322762156600165710ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. set(Boost_USE_STATIC_LIBS OFF) include(BoostTestTargets) set(base_test_SOURCES base-array.cpp base-base64.cpp base-convert.cpp base-dictionary.cpp base-fifo.cpp base-json.cpp base-match.cpp base-netstring.cpp base-object.cpp base-serialize.cpp base-shellescape.cpp base-stacktrace.cpp base-stream.cpp base-string.cpp base-timer.cpp base-type.cpp base-value.cpp config-ops.cpp icinga-checkresult.cpp icinga-macros.cpp icinga-notification.cpp icinga-perfdata.cpp remote-url.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(base test base_test_SOURCES) endif() add_boost_test(base SOURCES test-runner.cpp ${base_test_SOURCES} LIBRARIES base config icinga TESTS base_array/construct base_array/getset base_array/resize base_array/insert base_array/remove base_array/foreach base_array/clone base_array/json base_base64/base64 base_convert/tolong base_convert/todouble base_convert/tostring base_convert/tobool base_dictionary/construct base_dictionary/get1 base_dictionary/get2 base_dictionary/foreach base_dictionary/remove base_dictionary/clone base_dictionary/json base_fifo/construct base_fifo/io base_json/invalid1 base_match/tolong base_netstring/netstring base_object/construct base_object/getself base_serialize/scalar base_serialize/array base_serialize/dictionary base_serialize/object base_shellescape/escape_basic base_shellescape/escape_quoted base_stacktrace/stacktrace base_stream/readline_stdio base_string/construct base_string/equal base_string/clear base_string/append base_string/trim base_string/contains base_string/replace base_string/index base_string/find base_timer/construct base_timer/interval base_timer/invoke base_timer/scope base_type/gettype base_type/assign base_type/byname base_type/instantiate base_value/scalar base_value/convert base_value/format config_ops/simple config_ops/advanced icinga_checkresult/host_1attempt icinga_checkresult/host_2attempts icinga_checkresult/host_3attempts icinga_checkresult/service_1attempt icinga_checkresult/service_2attempts icinga_checkresult/service_3attempts icinga_checkresult/host_flapping_notification icinga_checkresult/service_flapping_notification icinga_notification/state_filter icinga_notification/type_filter icinga_macros/simple icinga_perfdata/empty icinga_perfdata/simple icinga_perfdata/quotes icinga_perfdata/multiple icinga_perfdata/uom icinga_perfdata/warncritminmax icinga_perfdata/ignore_invalid_warn_crit_min_max icinga_perfdata/invalid icinga_perfdata/multi remote_url/id_and_path remote_url/parameters remote_url/get_and_set remote_url/format remote_url/illegal_legal_strings ) if(ICINGA2_WITH_LIVESTATUS) set(livestatus_test_SOURCES livestatus.cpp ) if(ICINGA2_UNITY_BUILD) mkunity_target(livestatus test livestatus_test_SOURCES) endif() add_boost_test(livestatus SOURCES test-runner.cpp livestatus-fixture.cpp ${livestatus_test_SOURCES} LIBRARIES base config icinga livestatus DEPENDENCIES methods TESTS livestatus/hosts livestatus/services ) endif() set(icinga_checkable_test_SOURCES icinga-checkable-flapping.cpp ) add_boost_test(icinga_checkable SOURCES icinga-checkable-test.cpp ${icinga_checkable_test_SOURCES} LIBRARIES base config icinga cli TESTS icinga_checkable_flapping/host_not_flapping icinga_checkable_flapping/host_flapping icinga_checkable_flapping/host_flapping_recover icinga_checkable_flapping/host_flapping_docs_example ) icinga2-2.8.1/test/base-array.cpp000066400000000000000000000102311322762156600165560ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/array.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_array) BOOST_AUTO_TEST_CASE(construct) { Array::Ptr array = new Array(); BOOST_CHECK(array); BOOST_CHECK(array->GetLength() == 0); } BOOST_AUTO_TEST_CASE(getset) { Array::Ptr array = new Array(); array->Add(7); array->Add(2); array->Add(5); BOOST_CHECK(array->GetLength() == 3); BOOST_CHECK(array->Get(0) == 7); BOOST_CHECK(array->Get(1) == 2); BOOST_CHECK(array->Get(2) == 5); array->Set(1, 9); BOOST_CHECK(array->Get(1) == 9); array->Remove(1); BOOST_CHECK(array->GetLength() == 2); BOOST_CHECK(array->Get(1) == 5); } BOOST_AUTO_TEST_CASE(resize) { Array::Ptr array = new Array(); array->Resize(2); BOOST_CHECK(array->GetLength() == 2); BOOST_CHECK(array->Get(0) == Empty); BOOST_CHECK(array->Get(1) == Empty); } BOOST_AUTO_TEST_CASE(insert) { Array::Ptr array = new Array(); array->Insert(0, 11); array->Insert(1, 22); BOOST_CHECK(array->GetLength() == 2); BOOST_CHECK(array->Get(1) == 22); array->Insert(0, 33); BOOST_CHECK(array->GetLength() == 3); BOOST_CHECK(array->Get(0) == 33); BOOST_CHECK(array->Get(1) == 11); array->Insert(1, 44); BOOST_CHECK(array->GetLength() == 4); BOOST_CHECK(array->Get(0) == 33); BOOST_CHECK(array->Get(1) == 44); BOOST_CHECK(array->Get(2) == 11); } BOOST_AUTO_TEST_CASE(remove) { Array::Ptr array = new Array(); array->Add(7); array->Add(2); array->Add(5); { ObjectLock olock(array); Array::Iterator it = array->Begin(); array->Remove(it); } BOOST_CHECK(array->GetLength() == 2); BOOST_CHECK(array->Get(0) == 2); array->Clear(); BOOST_CHECK(array->GetLength() == 0); } BOOST_AUTO_TEST_CASE(foreach) { Array::Ptr array = new Array(); array->Add(7); array->Add(2); array->Add(5); ObjectLock olock(array); int n = 0; for (const Value& item : array) { BOOST_CHECK(n != 0 || item == 7); BOOST_CHECK(n != 1 || item == 2); BOOST_CHECK(n != 2 || item == 5); n++; } } BOOST_AUTO_TEST_CASE(clone) { Array::Ptr array = new Array(); array->Add(7); array->Add(2); array->Add(5); Array::Ptr clone = array->ShallowClone(); BOOST_CHECK(clone->GetLength() == 3); BOOST_CHECK(clone->Get(0) == 7); BOOST_CHECK(clone->Get(1) == 2); BOOST_CHECK(clone->Get(2) == 5); } BOOST_AUTO_TEST_CASE(json) { Array::Ptr array = new Array(); array->Add(7); array->Add(2); array->Add(5); String json = JsonEncode(array); BOOST_CHECK(json.GetLength() > 0); Array::Ptr deserialized = JsonDecode(json); BOOST_CHECK(deserialized); BOOST_CHECK(deserialized->GetLength() == 3); BOOST_CHECK(deserialized->Get(0) == 7); BOOST_CHECK(deserialized->Get(1) == 2); BOOST_CHECK(deserialized->Get(2) == 5); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-base64.cpp000066400000000000000000000061001322762156600165240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/base64.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_base64) BOOST_AUTO_TEST_CASE(base64) { std::vector clearText; clearText.push_back(""); clearText.push_back("1"); clearText.push_back("12"); clearText.push_back("123"); clearText.push_back("1234"); clearText.push_back( "VsowLvPqEiAeITDmo-5L_NB-k7fsT3sT2d3K9O4iC2uBk41hvCPAxrgGSxrdeX5s" "Zo0Z9b1kxDZlzf8GHQ9ARW6YLeGODMtiZo8cKkUzfSbxyZ_wlE9u6pCTTg9kODCM" "Ve-X_a3jWkOy89RoDkT5ahKBY-8S25L6wlvWt8ZyQ2bLxfplzEzuHgEknTMKKp2K" "jRlwI2p3gF4FYeQM7dx0E5O782Lh1P3IC6jPNqiZgTgWmsRYZbAN8oU2V626bQxD" "n8prQ0Xr_3aPdP7VIVgxNZMnF0NJrQvB_rzq1Dip1UM_xH_9nansbX25E64OQU-r" "q54EdO-vb_9FvyqdeVTJ3UTgXIP7OXtz4K8xlEHWdb1-hJChVvDc0KSnN5HVN2NJ" "yJrAofVyHBxXGRnGMdN8cOwvxzBFsz2Hih_lIqm1NVULm9_J9GoesY-aN8JzGocU" "U3hbhFQBiUlzliuodhwg4RXRcfmPHQRo7kWKaohpySkvqmWcXEAt2LPJ8nH70fW7" "vudgzwwWTnNcMlf0Wa-nKL4xXNNPQD0obDCfogN8uKuGqi0DltOUmFK62Zkkb0_d" "45grssnD5q89MjDGBkGMXuLY_JLOqc7Y9VV6H48vzoTNK1a2kOGV2TrAD8syuA5Z" "o8RLKjTqAYjKTUqEJjg0MflpiBnbDQvRqiSXs1cJuFNXRLpEC5GoqGqMd0zAGn4u" "5J3OurVd0SFp8_vkYUI6YwNUe00y8_Dn6DOBh_0KKADphZBgple82_8HrnQNreQn" "GkB2TpIsjwWud0yuhI-jQZEMNNlhEYMLwx7B-xTGhn0LFC1pLEXn_kZ2NOgDgUHd" "bdj906o3N2Jjo9Fb5GXkCrt-fNEYBjeXvIu73yeTGmsiAzfiICNHi_PmGkgq8fYQ" "O9lQgyRHCMic8zU7ffWuSoUPRgHsqztLHaCDbYIrNmgrn2taxcXSb57Xm_l-1xBH" "bZqdMvBziapJXaLJmhUg03lgdsIc_OuJmzt-sytDLVGIuNqpa4dETdhLsI7qis4B" ); // 1024 chars for (const String& str : clearText) { String enc = Base64::Encode(str); String dec = Base64::Decode(enc); BOOST_CHECK(str == dec); } } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-convert.cpp000066400000000000000000000057641322762156600171370ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/convert.hpp" #include "base/object.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_convert) BOOST_AUTO_TEST_CASE(tolong) { BOOST_CHECK_THROW(Convert::ToLong(" 7"), boost::exception); BOOST_CHECK(Convert::ToLong("-7") == -7); BOOST_CHECK_THROW(Convert::ToLong("7a"), boost::exception); BOOST_CHECK(Convert::ToLong(Value(-7)) == -7); } BOOST_AUTO_TEST_CASE(todouble) { BOOST_CHECK_THROW(Convert::ToDouble(" 7.3"), boost::exception); BOOST_CHECK(Convert::ToDouble("-7.3") == -7.3); BOOST_CHECK_THROW(Convert::ToDouble("7.3a"), boost::exception); BOOST_CHECK(Convert::ToDouble(Value(-7.3)) == -7.3); } BOOST_AUTO_TEST_CASE(tostring) { BOOST_CHECK(Convert::ToString(7) == "7"); BOOST_CHECK(Convert::ToString(7.5) == "7.500000"); BOOST_CHECK(Convert::ToString("hello") == "hello"); String str = "hello"; BOOST_CHECK(Convert::ToString(str) == "hello"); BOOST_CHECK(Convert::ToString(Value(7)) == "7"); BOOST_CHECK(Convert::ToString(Value(7.5)) == "7.500000"); BOOST_CHECK(Convert::ToString(Value("hello")) == "hello"); BOOST_CHECK(Convert::ToString(Value("hello hello")) == "hello hello"); } BOOST_AUTO_TEST_CASE(tobool) { BOOST_CHECK(Convert::ToBool("a") == true); BOOST_CHECK(Convert::ToBool("0") == true); BOOST_CHECK(Convert::ToBool("1") == true); BOOST_CHECK(Convert::ToBool("2") == true); BOOST_CHECK(Convert::ToBool(1) == true); BOOST_CHECK(Convert::ToBool(0) == false); BOOST_CHECK(Convert::ToBool(Value(true)) == true); BOOST_CHECK(Convert::ToBool(Value(false)) == false); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-dictionary.cpp000066400000000000000000000120311322762156600176050ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_dictionary) BOOST_AUTO_TEST_CASE(construct) { Dictionary::Ptr dictionary = new Dictionary(); BOOST_CHECK(dictionary); } BOOST_AUTO_TEST_CASE(get1) { Dictionary::Ptr dictionary = new Dictionary(); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); BOOST_CHECK(dictionary->GetLength() == 2); Value test1; test1 = dictionary->Get("test1"); BOOST_CHECK(test1 == 7); Value test2; test2 = dictionary->Get("test2"); BOOST_CHECK(test2 == "hello world"); String key3 = "test3"; Value test3; test3 = dictionary->Get(key3); BOOST_CHECK(test3.IsEmpty()); } BOOST_AUTO_TEST_CASE(get2) { Dictionary::Ptr dictionary = new Dictionary(); Dictionary::Ptr other = new Dictionary(); dictionary->Set("test1", other); BOOST_CHECK(dictionary->GetLength() == 1); Dictionary::Ptr test1 = dictionary->Get("test1"); BOOST_CHECK(other == test1); Dictionary::Ptr test2 = dictionary->Get("test2"); BOOST_CHECK(!test2); } BOOST_AUTO_TEST_CASE(foreach) { Dictionary::Ptr dictionary = new Dictionary(); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); ObjectLock olock(dictionary); bool seen_test1 = false, seen_test2 = false; for (const Dictionary::Pair& kv : dictionary) { BOOST_CHECK(kv.first == "test1" || kv.first == "test2"); if (kv.first == "test1") { BOOST_CHECK(!seen_test1); seen_test1 = true; BOOST_CHECK(kv.second == 7); continue; } else if (kv.first == "test2") { BOOST_CHECK(!seen_test2); seen_test2 = true; BOOST_CHECK(kv.second == "hello world"); } } BOOST_CHECK(seen_test1); BOOST_CHECK(seen_test2); } BOOST_AUTO_TEST_CASE(remove) { Dictionary::Ptr dictionary = new Dictionary(); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); BOOST_CHECK(dictionary->Contains("test1")); BOOST_CHECK(dictionary->GetLength() == 2); dictionary->Set("test1", Empty); BOOST_CHECK(dictionary->Contains("test1")); BOOST_CHECK(dictionary->GetLength() == 2); dictionary->Remove("test1"); BOOST_CHECK(!dictionary->Contains("test1")); BOOST_CHECK(dictionary->GetLength() == 1); dictionary->Remove("test2"); BOOST_CHECK(!dictionary->Contains("test2")); BOOST_CHECK(dictionary->GetLength() == 0); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); { ObjectLock olock(dictionary); Dictionary::Iterator it = dictionary->Begin(); dictionary->Remove(it); } BOOST_CHECK(dictionary->GetLength() == 1); } BOOST_AUTO_TEST_CASE(clone) { Dictionary::Ptr dictionary = new Dictionary(); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); Dictionary::Ptr clone = dictionary->ShallowClone(); BOOST_CHECK(dictionary != clone); BOOST_CHECK(clone->GetLength() == 2); BOOST_CHECK(clone->Get("test1") == 7); BOOST_CHECK(clone->Get("test2") == "hello world"); clone->Set("test3", 5); BOOST_CHECK(!dictionary->Contains("test3")); BOOST_CHECK(dictionary->GetLength() == 2); clone->Set("test2", "test"); BOOST_CHECK(dictionary->Get("test2") == "hello world"); } BOOST_AUTO_TEST_CASE(json) { Dictionary::Ptr dictionary = new Dictionary(); dictionary->Set("test1", 7); dictionary->Set("test2", "hello world"); String json = JsonEncode(dictionary); BOOST_CHECK(json.GetLength() > 0); Dictionary::Ptr deserialized = JsonDecode(json); BOOST_CHECK(deserialized->GetLength() == 2); BOOST_CHECK(deserialized->Get("test1") == 7); BOOST_CHECK(deserialized->Get("test2") == "hello world"); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-fifo.cpp000066400000000000000000000043361322762156600163740ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/fifo.hpp" #include "base/objectlock.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_fifo) BOOST_AUTO_TEST_CASE(construct) { FIFO::Ptr fifo = new FIFO(); BOOST_CHECK(fifo); BOOST_CHECK(fifo->GetAvailableBytes() == 0); fifo->Close(); } BOOST_AUTO_TEST_CASE(io) { FIFO::Ptr fifo = new FIFO(); fifo->Write("hello", 5); BOOST_CHECK(fifo->GetAvailableBytes() == 5); char buffer1[2]; fifo->Read(buffer1, 2, true); BOOST_CHECK(memcmp(buffer1, "he", 2) == 0); BOOST_CHECK(fifo->GetAvailableBytes() == 3); char buffer2[5]; size_t rc = fifo->Read(buffer2, 5, true); BOOST_CHECK(rc == 3); BOOST_CHECK(memcmp(buffer2, "llo", 3) == 0); BOOST_CHECK(fifo->GetAvailableBytes() == 0); BOOST_CHECK(!fifo->IsEof()); fifo->Close(); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-json.cpp000066400000000000000000000035721322762156600164230ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/dictionary.hpp" #include "base/objectlock.hpp" #include "base/json.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_json) BOOST_AUTO_TEST_CASE(invalid1) { BOOST_CHECK_THROW(JsonDecode("\"1.7"), std::exception); BOOST_CHECK_THROW(JsonDecode("{8: \"test\"}"), std::exception); BOOST_CHECK_THROW(JsonDecode("{\"test\": \"test\""), std::exception); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-match.cpp000066400000000000000000000042741322762156600165460ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/utility.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_match) BOOST_AUTO_TEST_CASE(tolong) { BOOST_CHECK(Utility::Match("*", "hello")); BOOST_CHECK(!Utility::Match("\\**", "hello")); BOOST_CHECK(Utility::Match("\\**", "*ello")); BOOST_CHECK(Utility::Match("?e*l?", "hello")); BOOST_CHECK(Utility::Match("?e*l?", "helo")); BOOST_CHECK(!Utility::Match("world", "hello")); BOOST_CHECK(!Utility::Match("hee*", "hello")); BOOST_CHECK(Utility::Match("he??o", "hello")); BOOST_CHECK(Utility::Match("he?", "hel")); BOOST_CHECK(Utility::Match("he*", "hello")); BOOST_CHECK(Utility::Match("he*o", "heo")); BOOST_CHECK(Utility::Match("he**o", "heo")); BOOST_CHECK(Utility::Match("he**o", "hello")); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-netstring.cpp000066400000000000000000000035551322762156600174700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/netstring.hpp" #include "base/fifo.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_netstring) BOOST_AUTO_TEST_CASE(netstring) { FIFO::Ptr fifo = new FIFO(); NetString::WriteStringToStream(fifo, "hello"); String s; StreamReadContext src; BOOST_CHECK(NetString::ReadStringFromStream(fifo, &s, src) == StatusNewItem); BOOST_CHECK(s == "hello"); fifo->Close(); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-object.cpp000066400000000000000000000041401322762156600167100ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/object.hpp" #include "base/value.hpp" #include using namespace icinga; class TestObject : public Object { public: DECLARE_PTR_TYPEDEFS(TestObject); TestObject::Ptr GetTestRef(void) { return this; } }; BOOST_AUTO_TEST_SUITE(base_object) BOOST_AUTO_TEST_CASE(construct) { Object::Ptr tobject = new TestObject(); BOOST_CHECK(tobject); } BOOST_AUTO_TEST_CASE(getself) { TestObject::Ptr tobject = new TestObject(); TestObject::Ptr tobject_self = tobject->GetTestRef(); BOOST_CHECK(tobject == tobject_self); Value vobject = tobject; BOOST_CHECK(!vobject.IsEmpty()); BOOST_CHECK(vobject.IsObjectType()); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-serialize.cpp000066400000000000000000000060461322762156600174400ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/perfdatavalue.hpp" #include "base/dictionary.hpp" #include "base/objectlock.hpp" #include "base/serializer.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_serialize) BOOST_AUTO_TEST_CASE(scalar) { BOOST_CHECK(Deserialize(Serialize(7)) == 7); BOOST_CHECK(Deserialize(Serialize(7.3)) == 7.3); BOOST_CHECK(Deserialize(Serialize(Empty)) == Empty); BOOST_CHECK(Deserialize(Serialize("hello")) == "hello"); } BOOST_AUTO_TEST_CASE(array) { Array::Ptr array = new Array(); array->Add(7); array->Add(7.3); array->Add(Empty); array->Add("hello"); Array::Ptr result = Deserialize(Serialize(array)); BOOST_CHECK(result->GetLength() == array->GetLength()); BOOST_CHECK(result->Get(0) == 7); BOOST_CHECK(result->Get(1) == 7.3); BOOST_CHECK(result->Get(2) == Empty); BOOST_CHECK(result->Get(3) == "hello"); } BOOST_AUTO_TEST_CASE(dictionary) { Dictionary::Ptr dict = new Dictionary(); dict->Set("k1", 7); dict->Set("k2", 7.3); dict->Set("k3", Empty); dict->Set("k4", "hello"); Dictionary::Ptr result = Deserialize(Serialize(dict)); BOOST_CHECK(result->GetLength() == dict->GetLength()); BOOST_CHECK(result->Get("k1") == 7); BOOST_CHECK(result->Get("k2") == 7.3); BOOST_CHECK(result->Get("k3") == Empty); BOOST_CHECK(result->Get("k4") == "hello"); } BOOST_AUTO_TEST_CASE(object) { PerfdataValue::Ptr pdv = new PerfdataValue("size", 100, true, "bytes"); PerfdataValue::Ptr result = Deserialize(Serialize(pdv)); BOOST_CHECK(result->GetValue() == pdv->GetValue()); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-shellescape.cpp000066400000000000000000000043221322762156600177340ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/utility.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_shellescape) BOOST_AUTO_TEST_CASE(escape_basic) { #ifdef _WIN32 BOOST_CHECK(Utility::EscapeShellCmd("%PATH%") == "^%PATH^%"); #else /* _WIN32 */ BOOST_CHECK(Utility::EscapeShellCmd("$PATH") == "\\$PATH"); BOOST_CHECK(Utility::EscapeShellCmd("\\$PATH") == "\\\\\\$PATH"); #endif /* _WIN32 */ } BOOST_AUTO_TEST_CASE(escape_quoted) { #ifdef _WIN32 BOOST_CHECK(Utility::EscapeShellCmd("'hello'") == "^'hello^'"); BOOST_CHECK(Utility::EscapeShellCmd("\"hello\"") == "^\"hello^\""); #else /* _WIN32 */ BOOST_CHECK(Utility::EscapeShellCmd("'hello'") == "'hello'"); BOOST_CHECK(Utility::EscapeShellCmd("'hello") == "\\'hello"); #endif /* _WIN32 */ } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-stacktrace.cpp000066400000000000000000000033041322762156600175670ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/stacktrace.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_stacktrace) BOOST_AUTO_TEST_CASE(stacktrace) { StackTrace st; std::ostringstream obuf; obuf << st; BOOST_CHECK(obuf.str().size() > 0); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-stream.cpp000066400000000000000000000044011322762156600167350ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/stdiostream.hpp" #include "base/string.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_stream) BOOST_AUTO_TEST_CASE(readline_stdio) { std::stringstream msgbuf; msgbuf << "Hello\nWorld\n\n"; StdioStream::Ptr stdstream = new StdioStream(&msgbuf, false); StreamReadContext rlc; String line; BOOST_CHECK(stdstream->ReadLine(&line, rlc) == StatusNewItem); BOOST_CHECK(line == "Hello"); BOOST_CHECK(stdstream->ReadLine(&line, rlc) == StatusNewItem); BOOST_CHECK(line == "World"); BOOST_CHECK(stdstream->ReadLine(&line, rlc) == StatusNewItem); BOOST_CHECK(line == ""); BOOST_CHECK(stdstream->ReadLine(&line, rlc) == StatusNewItem); BOOST_CHECK(line == ""); BOOST_CHECK(stdstream->ReadLine(&line, rlc) == StatusEof); stdstream->Close(); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-string.cpp000066400000000000000000000062571322762156600167630ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/string.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_string) BOOST_AUTO_TEST_CASE(construct) { BOOST_CHECK(String() == ""); BOOST_CHECK(String(5, 'n') == "nnnnn"); } BOOST_AUTO_TEST_CASE(equal) { BOOST_CHECK(String("hello") == String("hello")); BOOST_CHECK("hello" == String("hello")); BOOST_CHECK(String("hello") == String("hello")); BOOST_CHECK(String("hello") != String("helloworld")); BOOST_CHECK("hello" != String("helloworld")); BOOST_CHECK(String("hello") != "helloworld"); } BOOST_AUTO_TEST_CASE(clear) { String s = "hello"; s.Clear(); BOOST_CHECK(s == ""); BOOST_CHECK(s.IsEmpty()); } BOOST_AUTO_TEST_CASE(append) { String s; s += "he"; s += String("ll"); s += 'o'; BOOST_CHECK(s == "hello"); } BOOST_AUTO_TEST_CASE(trim) { String s1 = "hello"; BOOST_CHECK(s1.Trim() == "hello"); String s2 = " hello"; BOOST_CHECK(s2.Trim() == "hello"); String s3 = "hello "; BOOST_CHECK(s3.Trim() == "hello"); String s4 = " hello "; BOOST_CHECK(s4.Trim() == "hello"); } BOOST_AUTO_TEST_CASE(contains) { String s1 = "hello world"; String s2 = "hello"; BOOST_CHECK(s1.Contains(s2)); String s3 = " hello world "; String s4 = " hello"; BOOST_CHECK(s3.Contains(s4)); String s5 = " hello world "; String s6 = "world "; BOOST_CHECK(s5.Contains(s6)); } BOOST_AUTO_TEST_CASE(replace) { String s = "hello"; s.Replace(0, 2, "x"); BOOST_CHECK(s == "xllo"); } BOOST_AUTO_TEST_CASE(index) { String s = "hello"; BOOST_CHECK(s[0] == 'h'); s[0] = 'x'; BOOST_CHECK(s == "xello"); for (char& ch : s) { ch = 'y'; } BOOST_CHECK(s == "yyyyy"); } BOOST_AUTO_TEST_CASE(find) { String s = "hello"; BOOST_CHECK(s.Find("ll") == 2); BOOST_CHECK(s.FindFirstOf("xl") == 2); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-timer.cpp000066400000000000000000000047411322762156600165710ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/timer.hpp" #include "base/utility.hpp" #include "base/application.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_timer) BOOST_AUTO_TEST_CASE(construct) { Timer::Ptr timer = new Timer(); BOOST_CHECK(timer); } BOOST_AUTO_TEST_CASE(interval) { Timer::Ptr timer = new Timer(); timer->SetInterval(1.5); BOOST_CHECK(timer->GetInterval() == 1.5); } static void Callback(int *counter) { (*counter)++; } BOOST_AUTO_TEST_CASE(invoke) { int counter; Timer::Ptr timer = new Timer(); timer->OnTimerExpired.connect(boost::bind(&Callback, &counter)); timer->SetInterval(1); counter = 0; timer->Start(); Utility::Sleep(5.5); timer->Stop(); BOOST_CHECK(counter >= 4 && counter <= 6); } BOOST_AUTO_TEST_CASE(scope) { int counter; Timer::Ptr timer = new Timer(); timer->OnTimerExpired.connect(boost::bind(&Callback, &counter)); timer->SetInterval(1); counter = 0; timer->Start(); Utility::Sleep(5.5); timer.reset(); Utility::Sleep(5.5); BOOST_CHECK(counter >= 4 && counter <= 6); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-type.cpp000066400000000000000000000044751322762156600164360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/perfdatavalue.hpp" #include "base/dictionary.hpp" #include "base/objectlock.hpp" #include "base/application.hpp" #include "base/type.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_type) BOOST_AUTO_TEST_CASE(gettype) { Type::Ptr t = Type::GetByName("Application"); BOOST_CHECK(t); } BOOST_AUTO_TEST_CASE(assign) { Type::Ptr t1 = Type::GetByName("Application"); Type::Ptr t2 = Type::GetByName("ConfigObject"); BOOST_CHECK(t1->IsAssignableFrom(t1)); BOOST_CHECK(t2->IsAssignableFrom(t1)); BOOST_CHECK(!t1->IsAssignableFrom(t2)); } BOOST_AUTO_TEST_CASE(byname) { Type::Ptr t = Type::GetByName("Application"); BOOST_CHECK(t); } BOOST_AUTO_TEST_CASE(instantiate) { Type::Ptr t = Type::GetByName("PerfdataValue"); Object::Ptr p = t->Instantiate(std::vector()); BOOST_CHECK(p); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/base-value.cpp000066400000000000000000000042671322762156600165700ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/value.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(base_value) BOOST_AUTO_TEST_CASE(scalar) { Value v; v = 3; BOOST_CHECK(v.IsScalar()); v = "hello"; BOOST_CHECK(v.IsScalar()); v = Empty; BOOST_CHECK(!v.IsScalar()); } BOOST_AUTO_TEST_CASE(convert) { Value v; BOOST_CHECK(v.IsEmpty()); BOOST_CHECK(v == ""); BOOST_CHECK(static_cast(v) == 0); BOOST_CHECK(!v.IsScalar()); BOOST_CHECK(!v.IsObjectType()); BOOST_CHECK(v + "hello" == "hello"); BOOST_CHECK("hello" + v == "hello"); } BOOST_AUTO_TEST_CASE(format) { Value v = 3; std::ostringstream obuf; obuf << v; BOOST_CHECK(obuf.str() == "3"); std::istringstream ibuf("3"); ibuf >> v; BOOST_CHECK(v != 3); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/config-ops.cpp000066400000000000000000000264571322762156600166150ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configcompiler.hpp" #include "base/exception.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(config_ops) BOOST_AUTO_TEST_CASE(simple) { ScriptFrame frame; Expression *expr; Dictionary::Ptr dict; expr = ConfigCompiler::CompileText("", ""); BOOST_CHECK(expr->Evaluate(frame).GetValue() == Empty); delete expr; expr = ConfigCompiler::CompileText("", "\n3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "{ 3\n\n5 }"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "1 + 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 4); delete expr; expr = ConfigCompiler::CompileText("", "3 - 1"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 2); delete expr; expr = ConfigCompiler::CompileText("", "5m * 10"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3000); delete expr; expr = ConfigCompiler::CompileText("", "5m / 5"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 60); delete expr; expr = ConfigCompiler::CompileText("", "7 & 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "2 | 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "true && false"); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "true || false"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 < 5"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 > 5"); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 <= 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "3 >= 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "2 + 3 * 4"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 14); delete expr; expr = ConfigCompiler::CompileText("", "(2 + 3) * 4"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 20); delete expr; expr = ConfigCompiler::CompileText("", "2 * - 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == -6); delete expr; expr = ConfigCompiler::CompileText("", "-(2 + 3)"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == -5); delete expr; expr = ConfigCompiler::CompileText("", "- 2 * 2 - 2 * 3 - 4 * - 5"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 10); delete expr; expr = ConfigCompiler::CompileText("", "!0 == true"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "~0"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == (double)~(long)0); delete expr; expr = ConfigCompiler::CompileText("", "4 << 8"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 1024); delete expr; expr = ConfigCompiler::CompileText("", "1024 >> 4"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 64); delete expr; expr = ConfigCompiler::CompileText("", "2 << 3 << 4"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 256); delete expr; expr = ConfigCompiler::CompileText("", "256 >> 4 >> 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 2); delete expr; expr = ConfigCompiler::CompileText("", "\"hello\" == \"hello\""); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"hello\" != \"hello\""); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in [ \"foo\", \"bar\" ]"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in [ \"bar\", \"baz\" ]"); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in null"); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" in \"bar\""); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in [ \"bar\", \"baz\" ]"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in [ \"foo\", \"bar\" ]"); BOOST_CHECK(!expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in null"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"foo\" !in \"bar\""); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "{ a += 3 }"); dict = expr->Evaluate(frame).GetValue(); delete expr; BOOST_CHECK(dict->GetLength() == 1); BOOST_CHECK(dict->Get("a") == 3); expr = ConfigCompiler::CompileText("", "test"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "null + 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "3 + null"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "\"test\" + 3"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == "test3"); delete expr; expr = ConfigCompiler::CompileText("", "\"\\\"te\\\\st\""); BOOST_CHECK(expr->Evaluate(frame).GetValue() == "\"te\\st"); delete expr; expr = ConfigCompiler::CompileText("", "\"\\'test\""); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "({ a = 3\nb = 3 })"); BOOST_CHECK(expr->Evaluate(frame).GetValue().IsObjectType()); delete expr; } BOOST_AUTO_TEST_CASE(advanced) { ScriptFrame frame; Expression *expr; Function::Ptr func; expr = ConfigCompiler::CompileText("", "regex(\"^Hello\", \"Hello World\")"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "__boost_test()"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; Object::Ptr self = new Object(); ScriptFrame frame2(self); expr = ConfigCompiler::CompileText("", "this"); BOOST_CHECK(expr->Evaluate(frame2).GetValue() == Value(self)); delete expr; expr = ConfigCompiler::CompileText("", "var v = 7; v"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "{ a = 3 }.a"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "[ 2, 3 ][1]"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "var v = { a = 3}; v.a"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "a = 3 b = 3"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "function() { 3 }()"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "function() { return 3, 5 }()"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "typeof([]) == Array"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof({}) == Dictionary"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof(3) == Number"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "typeof(\"test\") == String"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 | 8) == 15"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 ^ 8) == 15"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 & 15) == 7"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "7 in [7] == true"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "7 !in [7] == false"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 | 8) > 14"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 ^ 8) > 14"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "(7 & 15) > 6"); BOOST_CHECK(expr->Evaluate(frame).GetValue()); delete expr; expr = ConfigCompiler::CompileText("", "\"a\" = 3"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "3 = 3"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "var e; e"); BOOST_CHECK(expr->Evaluate(frame).GetValue().IsEmpty()); delete expr; expr = ConfigCompiler::CompileText("", "var e = 3; e"); BOOST_CHECK(expr->Evaluate(frame).GetValue() == 3); delete expr; expr = ConfigCompiler::CompileText("", "Array.x"); BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "{{ 3 }}"); func = expr->Evaluate(frame).GetValue(); BOOST_CHECK(func->Invoke() == 3); delete expr; } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/config/000077500000000000000000000000001322762156600152745ustar00rootroot00000000000000icinga2-2.8.1/test/config/2742.conf000066400000000000000000000012671322762156600165470ustar00rootroot00000000000000 object CheckCommand "2742-macro-command" { command = "echo UPTIME: $icinga.uptime$ SERVICES warn: $icinga.num_services_warning$ crit: $icinga.num_services_critical$ unknown: $icinga.num_services_unknown$ ackd: $icinga.num_services_acknowledged$ HOST: down: $icinga.num_hosts_down$ unreachable: $icinga.num_hosts_unreachable$" } object HostGroup "2742-windows-servers"{ display_name = "2742-windows-servers" assign where match("2742-*", host.name) } apply Service "2742-macro-test" { import "test-generic-service" check_command = "2742-macro-command" assign where match("2742-*", host.name) } object Host "2742-server" { import "test-generic-host" address = "192.168.1.5", } icinga2-2.8.1/test/config/5872.conf000066400000000000000000000031631322762156600165530ustar00rootroot00000000000000 object HostGroup "5872-windows-servers"{ display_name = "5872-windows-servers" assign where match("5872-*", host.name) } apply Service "5872-ping4" { import "test-generic-service" check_command = "ping4" assign where match("5872-*", host.name) } object Host "5872-server" { import "test-generic-host" address = "192.168.1.5", } object Host "5872-pc" { import "test-generic-host" address = "192.168.1.101", } object Host "5872-router" { import "test-generic-host" address = "192.168.1.1", } object Host "5872-switch" { import "test-generic-host" address = "192.168.1.2", } apply Dependency "5872-host-switch" to Host { parent_host_name = "5872-router" disable_checks = true assign where host.name == "5872-switch" } apply Dependency "5872-host-pc" to Host { parent_host_name = "5872-switch" disable_checks = true assign where host.name == "5872-pc" } apply Dependency "5872-host-server" to Host { parent_host_name = "5872-switch" disable_checks = true assign where host.name == "5872-server" } apply Dependency "5872-service-switch" to Service { parent_host_name = "5872-router" parent_service_name = "5872-ping4" disable_checks = true assign where host.name == "5872-switch" } apply Dependency "5872-service-pc" to Service { parent_host_name = "5872-switch" parent_service_name = "5872-ping4" disable_checks = true assign where host.name == "5872-pc" } apply Dependency "5872-service-server" to Service { parent_host_name = "5872-switch" parent_service_name = "5872-ping4" states = [ Warning, Critical ] disable_checks = true assign where host.name == "5872-server" } icinga2-2.8.1/test/config/5912.conf.dis000066400000000000000000000004071322762156600173220ustar00rootroot00000000000000 apply Service "5912-ping4" { import "test-generic-service" check_command = "ping4" host_name = "foo" service_name = "bar" assign where match("5912-*", host.name) } object Host "5912-server" { import "test-generic-host" address = "192.168.1.5", } icinga2-2.8.1/test/config/5926.conf000066400000000000000000000011721322762156600165510ustar00rootroot00000000000000 object CheckCommand "5926-macro-test" { command = "echo \"address: $address$ address_service: $service.vars.address$ foo: $foo$ keks: $keks$ god: $god$\"" //command = "echo \"address: $address$ address_service: $service.vars.address$\"" } object Host "5926-macro-test-host" { import "test-generic-host" check_command = "5926-macro-test" address = "1.2.3.4" vars.god = "father" } apply Service "5926-macro-test-service" { import "test-generic-service" check_command = "5926-macro-test" vars.address = "5.6.7.8" vars.foo = "bar" vars.keks = "schaschlik" assign where host.name == "5926-macro-test-host" } icinga2-2.8.1/test/config/5927.conf000066400000000000000000000017061322762156600165550ustar00rootroot00000000000000 object EventCommand "5927-handle" { command = "echo \"event handler triggered.\"" } object NotificationCommand "5927-notification" { command = "echo \"notification triggered.\"" } object HostGroup "5927-bar" { assign where match("5927-keks*", host.name) } object Host "5927-keks" { import "test-generic-host" event_command = "5927-handle" address = "1.2.3.4" } apply Service "5927-foo" { import "test-generic-service" check_command = "ping4" event_command = "5927-handle" assign where "5927-bar" in host.groups } apply Notification "5927-host-notification" to Host { import "test-mail-host-notification" command = "5927-notification" assign where "5927-bar" in host.groups } apply Notification "5927-service-notification" to Service { import "test-mail-service-notification" command = "5927-notification" assign where "5927-bar" in host.groups } object ServiceGroup "5927-bar" { assign where service.name == "5927-foo" } icinga2-2.8.1/test/config/5980.conf000066400000000000000000000021521322762156600165500ustar00rootroot00000000000000 object Host "5980-host" { import "test-generic-host" address = "127.0.0.1" } object Service "5980-service1" { import "test-generic-service" host_name = "5980-host" check_command = "dummy" } object Service "5980-service2" { import "test-generic-service" host_name = "5980-host" check_command = "dummy" } template ScheduledDowntime "5980-test-downtime" { author = "icingaadmin" comment = "Scheduled downtime for tests" ranges = { monday = "02:00-03:00" tuesday = "02:00-03:00" wednesday = "02:00-03:00" thursday = "02:00-03:00" friday = "02:00-03:00" saturday = "02:00-03:00" sunday = "02:00-03:00" } } apply ScheduledDowntime "5980-test-service-downtime" to Host { import "5980-test-downtime" comment = "Scheduled host downtime for tests" ranges = { tuesday = "09:37-09:40" } assign where host.name == "5980-host" } apply ScheduledDowntime "5980-test-service-downtime" to Service { import "5980-test-downtime" comment = "Scheduled service downtime for tests" ranges = { tuesday = "09:37-09:40" } assign where host.name == "5980-host" } icinga2-2.8.1/test/config/6105.conf000066400000000000000000000006271322762156600165430ustar00rootroot00000000000000 object HostGroup "6105-bar" { assign where match("6105-keks*", host.name) vars.foo = "bar" } object Host "6105-keks" { import "test-generic-host" address = "12.3.4" } apply Service "6105-foo" { import "test-generic-service" check_command = "ping4" assign where "6105-bar" in host.groups } object ServiceGroup "6105-bar" { assign where service.name == "6105-foo" vars.bar = "foo" } icinga2-2.8.1/test/config/6479.conf000066400000000000000000000017061322762156600165600ustar00rootroot00000000000000 object EventCommand "6479-handle" { command = "echo \"event handler triggered.\"" } object NotificationCommand "6479-notification" { command = "echo \"notification triggered.\"" } object HostGroup "6479-bar" { assign where match("6479-keks*", host.name) } object Host "6479-keks" { import "test-generic-host" event_command = "6479-handle" address = "1.2.3.4" } apply Service "6479-foo" { import "test-generic-service" check_command = "ping4" event_command = "6479-handle" assign where "6479-bar" in host.groups } apply Notification "6479-host-notification" to Host { import "test-mail-host-notification" command = "6479-notification" assign where "6479-bar" in host.groups } apply Notification "6479-service-notification" to Service { import "test-mail-service-notification" command = "6479-notification" assign where "6479-bar" in host.groups } object ServiceGroup "6479-bar" { assign where service.name == "6479-foo" } icinga2-2.8.1/test/config/6608.conf000066400000000000000000000004411322762156600165450ustar00rootroot00000000000000 object Host "6608-host" { import "test-generic-host" vars.BUMSTI = "keks" vars.bumsti = "schaschlik" } object Service "6608-service" { import "test-generic-service" check_command = "dummy" host_name = "6608-host" vars.DINGDONG = "$BUMSTI$" vars.dingdong = "$bumsti$" } icinga2-2.8.1/test/config/6968.conf000066400000000000000000000010041322762156600165520ustar00rootroot00000000000000object Host "6968-server" { import "test-generic-host" address = "127.0.0.1" } object Service "6968-test" { import "test-generic-service" host_name = "6968-server" check_command = "6968-check_vmware" vars.vmware_check = "vCenter_License_Status" } object CheckCommand "6968-check_vmware" { command = [ PluginDir + "/check_vmware.pl" ] arguments = { "--server" = "$address$" "--username" = "***" "--password" = "***" "--check" = { set_if = "$vmware_check$" } } } icinga2-2.8.1/test/config/7560.conf000066400000000000000000000017621322762156600165520ustar00rootroot00000000000000object Host "7560-server" { import "test-generic-host" address = "127.0.0.1" check_command = "hostalive" vars.interfaces += { eth0 = { port = 1 vlan = "internal" address = "127.0.0.2" qos = "enabled" } eth1 = { port = 2 vlan = "mgmt" address = "127.0.1.2" } eth2 = { port = 3 vlan = "remote" address = "127.0.2.2" } } } apply Service "if-" for (if_name => config in host.vars.interfaces) { import "test-generic-service" check_command = "ping4" vars.qos = "disabled" vars += config display_name = "if-" + if_name + "-" + vars.vlan notes = "Interface check for Port " + string(vars.port) + " in VLAN " + vars.vlan + " on Address " + vars.address + " QoS " + vars.qos notes_url = "http://foreman.company.com/hosts/" + host.name action_url = "http://snmp.checker.company.com/" + host.name + "if-" + if_name assign where match("7560-*", host.name) && typeof(host.vars.interfaces) == typeof({}) } icinga2-2.8.1/test/config/7683.conf000066400000000000000000000007351322762156600165570ustar00rootroot00000000000000object Host "7683-parent" { check_command = "dummy" vars.dummy_state = 0 } object Host "7683-child1" { check_command = "dummy" vars.dummy_state = 0 } object Host "7683-child2" { check_command = "dummy" vars.dummy_state = 0 } object Service "7683-service" { check_command = "dummy" host_name = "7683-parent" vars.dummy_state = 0 } apply Dependency "test-host" to Host { parent_host_name = "7683-parent" assign where match("7683-child*", host.name) } icinga2-2.8.1/test/config/8063.conf000066400000000000000000000036171322762156600165520ustar00rootroot00000000000000object CheckCommand "8063-my-disk" { command = [ PluginDir + "/check_disk" ] arguments = { "-w" = { value = "$disk_wfree$" description = "Exit with WARNING status if less than INTEGER units of disk are free or Exit with WARNING status if less than PERCENT of disk space is free" required = true } "-c" = { value = "$disk_cfree$" description = "Exit with CRITICAL status if less than INTEGER units of disk are free or Exit with CRITCAL status if less than PERCENT of disk space is free" required = true } "-W" = { value = "$disk_inode_wfree$" description = "Exit with WARNING status if less than PERCENT of inode space is free" } "-K" = { value = "$disk_inode_cfree$" description = "Exit with CRITICAL status if less than PERCENT of inode space is free" } "-p" = { value = "$disk_partitions$" description = "Path or partition (may be repeated)" repeat_key = true order = 1 } "-x" = { value = "$disk_partitions_excluded$" description = "Ignore device (only works if -p unspecified)" } } vars.disk_wfree = "20%" vars.disk_cfree = "10%" } object Host "8063-my-server" { import "generic-host" address = "127.0.0.1" address6 = "::1" vars.local_disks["basic-partitions"] = { disk_partitions = [ "/", "/tmp", "/var", "/home", "/run/user/1000/gvfs" ] } } apply Service "8063-" for (disk => config in host.vars.local_disks) { import "generic-service" check_command = "8063-my-disk" check_interval = 5s retry_interval = 5s volatile = true vars.volatile_check = true vars += config vars.disk_wfree = "10%" vars.disk_cfree = "5%" assign where host.vars.local_disks } apply Notification "disk-notification" to Service { import "test-mail-service-notification" users = [ "test-icingaadmin" ] assign where service.vars.volatile_check == true } icinga2-2.8.1/test/config/README000066400000000000000000000001341322762156600161520ustar00rootroot00000000000000Contains various test configuration for fixed issues. May be used for regression tests too. icinga2-2.8.1/test/config/templates.conf000066400000000000000000000032541322762156600201450ustar00rootroot00000000000000/** * test templates */ template Service "test-generic-service" { max_check_attempts = 3 check_interval = 5m retry_interval = 1m } template Host "test-generic-host" { check_command = "hostalive" } template User "test-generic-user" { } template Notification "test-mail-host-notification" { command = "mail-host-notification" states = [ Up, Down ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] period = "test-24x7" user_groups = [ "test-icingaadmins" ] } /** * Provides default settings for service notifications. * By convention all service notifications should import * this template. */ template Notification "test-mail-service-notification" { command = "mail-service-notification" states = [ OK, Warning, Critical, Unknown ] types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart, FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ] period = "test-24x7" user_groups = [ "test-icingaadmins" ] } /* users */ object User "test-icingaadmin" { import "test-generic-user" display_name = "Test Icinga 2 Admin" groups = [ "test-icingaadmins" ] email = "icinga@localhost" } object UserGroup "test-icingaadmins" { display_name = "Test Icinga 2 Admin Group" } /* timeperiods */ object TimePeriod "test-24x7" { display_name = "Test Icinga 2 24x7 TimePeriod" ranges = { "monday" = "00:00-24:00" "tuesday" = "00:00-24:00" "wednesday" = "00:00-24:00" "thursday" = "00:00-24:00" "friday" = "00:00-24:00" "saturday" = "00:00-24:00" "sunday" = "00:00-24:00" } } icinga2-2.8.1/test/icinga-checkable-flapping.cpp000066400000000000000000000204431322762156600214650ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include "icinga/host.hpp" #include using namespace icinga; #ifdef I2_DEBUG static CheckResult::Ptr MakeCheckResult(ServiceState state) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); double now = Utility::GetTime(); cr->SetScheduleStart(now); cr->SetScheduleEnd(now); cr->SetExecutionStart(now); cr->SetExecutionEnd(now); Utility::IncrementTime(60); return cr; } static void LogFlapping(const Checkable::Ptr& obj) { std::bitset<20> stateChangeBuf = obj->GetFlappingBuffer(); int oldestIndex = (obj->GetFlappingBuffer() & 0xFF00000) >> 20; std::cout << "Flapping: " << obj->IsFlapping() << "\nHT: " << obj->GetFlappingThresholdHigh() << " LT: " << obj->GetFlappingThresholdLow() << "\nOur value: " << obj->GetFlappingCurrent() << "\nPtr: " << oldestIndex << " Buf: " << stateChangeBuf << '\n'; } static void LogHostStatus(const Host::Ptr &host) { std::cout << "Current status: state: " << host->GetState() << " state_type: " << host->GetStateType() << " check attempt: " << host->GetCheckAttempt() << "/" << host->GetMaxCheckAttempts() << std::endl; } #endif /* I2_DEBUG */ BOOST_AUTO_TEST_SUITE(icinga_checkable_flapping) BOOST_AUTO_TEST_CASE(host_not_flapping) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ std::cout << "Running test with a non-flapping host...\n"; Host::Ptr host = new Host(); host->SetName("test"); host->SetEnableFlapping(true); host->SetMaxCheckAttempts(5); // Host otherwise is soft down host->SetState(HostUp); host->SetStateType(StateTypeHard); Utility::SetTime(0); BOOST_CHECK(host->GetFlappingCurrent() == 0); LogFlapping(host); LogHostStatus(host); // watch the state being stable int i = 0; while (i++ < 10) { // For some reason, elusive to me, the first check is a state change host->ProcessCheckResult(MakeCheckResult(ServiceOK)); LogFlapping(host); LogHostStatus(host); BOOST_CHECK(host->GetState() == 0); BOOST_CHECK(host->GetCheckAttempt() == 1); BOOST_CHECK(host->GetStateType() == StateTypeHard); //Should not be flapping BOOST_CHECK(!host->IsFlapping()); BOOST_CHECK(host->GetFlappingCurrent() < 30.0); } #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(host_flapping) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ std::cout << "Running test with host changing state with every check...\n"; Host::Ptr host = new Host(); host->SetName("test"); host->SetEnableFlapping(true); host->SetMaxCheckAttempts(5); Utility::SetTime(0); int i = 0; while (i++ < 25) { if (i % 2) host->ProcessCheckResult(MakeCheckResult(ServiceOK)); else host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); LogFlapping(host); LogHostStatus(host); //30 Percent is our high Threshold if (i >= 6) { BOOST_CHECK(host->IsFlapping()); } else { BOOST_CHECK(!host->IsFlapping()); } } #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(host_flapping_recover) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ std::cout << "Running test with flapping recovery...\n"; Host::Ptr host = new Host(); host->SetName("test"); host->SetEnableFlapping(true); host->SetMaxCheckAttempts(5); // Host otherwise is soft down host->SetState(HostUp); host->SetStateType(StateTypeHard); Utility::SetTime(0); // A few warning host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); LogFlapping(host); LogHostStatus(host); for (int i = 0; i <= 7; i++) { if (i % 2) host->ProcessCheckResult(MakeCheckResult(ServiceOK)); else host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); } LogFlapping(host); LogHostStatus(host); // We should be flapping now BOOST_CHECK(host->GetFlappingCurrent() > 30.0); BOOST_CHECK(host->IsFlapping()); // Now recover from flapping int count = 0; while (host->IsFlapping()) { BOOST_CHECK(host->GetFlappingCurrent() > 25.0); BOOST_CHECK(host->IsFlapping()); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); LogFlapping(host); LogHostStatus(host); count++; } std::cout << "Recovered from flapping after " << count << " Warning results.\n"; BOOST_CHECK(host->GetFlappingCurrent() < 25.0); BOOST_CHECK(!host->IsFlapping()); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(host_flapping_docs_example) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ std::cout << "Simulating the documentation example...\n"; Host::Ptr host = new Host(); host->SetName("test"); host->SetEnableFlapping(true); host->SetMaxCheckAttempts(5); // Host otherwise is soft down host->SetState(HostUp); host->SetStateType(StateTypeHard); Utility::SetTime(0); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceOK)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); LogFlapping(host); LogHostStatus(host); BOOST_CHECK(host->GetFlappingCurrent() == 39.1); BOOST_CHECK(host->IsFlapping()); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); LogFlapping(host); LogHostStatus(host); BOOST_CHECK(host->GetFlappingCurrent() < 25.0); BOOST_CHECK(!host->IsFlapping()); #endif } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/icinga-checkable-test.cpp000066400000000000000000000047531322762156600206520ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #define BOOST_TEST_MAIN #define BOOST_TEST_MODULE icinga2_test #include "cli/daemonutility.hpp" #include "base/application.hpp" #include "base/loader.hpp" #include #include using namespace icinga; struct IcingaCheckableFixture { IcingaCheckableFixture(void) { BOOST_TEST_MESSAGE("setup running Icinga 2 core"); Application::InitializeBase(); /* start the Icinga application and load the configuration */ Application::DeclareSysconfDir("etc"); Application::DeclareLocalStateDir("var"); ActivationScope ascope; Loader::LoadExtensionLibrary("icinga"); Loader::LoadExtensionLibrary("methods"); //loaded by ITL std::vector configs; std::vector newItems; DaemonUtility::LoadConfigFiles(configs, newItems, "icinga2.debug", "icinga2.vars"); /* ignore config errors */ WorkQueue upq; ConfigItem::ActivateItems(upq, newItems); } ~IcingaCheckableFixture(void) { BOOST_TEST_MESSAGE("cleanup Icinga 2 core"); Application::UninitializeBase(); } }; BOOST_GLOBAL_FIXTURE(IcingaCheckableFixture); icinga2-2.8.1/test/icinga-checkresult.cpp000066400000000000000000000650631322762156600203110ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/host.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(icinga_checkresult) static CheckResult::Ptr MakeCheckResult(ServiceState state) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); double now = Utility::GetTime(); cr->SetScheduleStart(now); cr->SetScheduleEnd(now); cr->SetExecutionStart(now); cr->SetExecutionEnd(now); return cr; } static void NotificationHandler(const Checkable::Ptr& checkable, NotificationType type) { std::cout << "Notification triggered: " << Notification::NotificationTypeToString(type) << std::endl; checkable->SetExtension("requested_notifications", true); checkable->SetExtension("notification_type", type); } static void CheckNotification(const Checkable::Ptr& checkable, bool expected, NotificationType type = NotificationRecovery) { BOOST_CHECK((expected && checkable->GetExtension("requested_notifications").ToBool()) || (!expected && !checkable->GetExtension("requested_notifications").ToBool())); if (expected && checkable->GetExtension("requested_notifications").ToBool()) BOOST_CHECK(checkable->GetExtension("notification_type") == type); checkable->SetExtension("requested_notifications", false); } BOOST_AUTO_TEST_CASE(host_1attempt) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Host::Ptr host = new Host(); host->SetMaxCheckAttempts(1); host->Activate(); host->SetAuthority(true); host->SetStateRaw(ServiceOK); host->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationProblem); std::cout << "Second check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationRecovery); std::cout << "Third check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationRecovery); c.disconnect(); } BOOST_AUTO_TEST_CASE(host_2attempts) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Host::Ptr host = new Host(); host->SetMaxCheckAttempts(2); host->Activate(); host->SetAuthority(true); host->SetStateRaw(ServiceOK); host->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "Second check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationProblem); std::cout << "Third check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationRecovery); std::cout << "Fourth check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "Fifth check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); c.disconnect(); } BOOST_AUTO_TEST_CASE(host_3attempts) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Host::Ptr host = new Host(); host->SetMaxCheckAttempts(3); host->Activate(); host->SetAuthority(true); host->SetStateRaw(ServiceOK); host->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "Second check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 2); CheckNotification(host, false); std::cout << "Third check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, true, NotificationRecovery); std::cout << "Fifth check result (critical)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); std::cout << "Sixth check result (ok)" << std::endl; host->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); CheckNotification(host, false); c.disconnect(); } BOOST_AUTO_TEST_CASE(service_1attempt) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Service::Ptr service = new Service(); service->SetMaxCheckAttempts(1); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationProblem); std::cout << "Second check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationRecovery); std::cout << "Third check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationRecovery); c.disconnect(); } BOOST_AUTO_TEST_CASE(service_2attempts) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Service::Ptr service = new Service(); service->SetMaxCheckAttempts(2); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "Second check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationProblem); std::cout << "Third check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationRecovery); std::cout << "Fourth check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "Fifth check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); c.disconnect(); } BOOST_AUTO_TEST_CASE(service_3attempts) { boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); Service::Ptr service = new Service(); service->SetMaxCheckAttempts(3); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "Second check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 2); CheckNotification(service, false); std::cout << "Third check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, true, NotificationRecovery); std::cout << "Fifth check result (critical)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); std::cout << "Sixth check result (ok)" << std::endl; service->ProcessCheckResult(MakeCheckResult(ServiceOK)); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); CheckNotification(service, false); c.disconnect(); } BOOST_AUTO_TEST_CASE(host_flapping_notification) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); int timeStepInterval = 60; Host::Ptr host = new Host(); host->Activate(); host->SetAuthority(true); host->SetStateRaw(ServiceOK); host->SetStateType(StateTypeHard); host->SetEnableFlapping(true); /* Initialize start time */ Utility::SetTime(0); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); Utility::IncrementTime(timeStepInterval); std::cout << "Inserting flapping check results" << std::endl; for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); host->ProcessCheckResult(MakeCheckResult(state)); Utility::IncrementTime(timeStepInterval); } BOOST_CHECK(host->IsFlapping() == true); CheckNotification(host, true, NotificationFlappingStart); std::cout << "Now calm down..." << std::endl; for (int i = 0; i < 20; i++) { host->ProcessCheckResult(MakeCheckResult(ServiceOK)); Utility::IncrementTime(timeStepInterval); } CheckNotification(host, true, NotificationFlappingEnd); c.disconnect(); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(service_flapping_notification) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); int timeStepInterval = 60; Service::Ptr service = new Service(); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); service->SetEnableFlapping(true); /* Initialize start time */ Utility::SetTime(0); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); Utility::IncrementTime(timeStepInterval); std::cout << "Inserting flapping check results" << std::endl; for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); service->ProcessCheckResult(MakeCheckResult(state)); Utility::IncrementTime(timeStepInterval); } BOOST_CHECK(service->IsFlapping() == true); CheckNotification(service, true, NotificationFlappingStart); std::cout << "Now calm down..." << std::endl; for (int i = 0; i < 20; i++) { service->ProcessCheckResult(MakeCheckResult(ServiceOK)); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); c.disconnect(); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(service_flapping_problem_notifications) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); int timeStepInterval = 60; Service::Ptr service = new Service(); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); service->SetEnableFlapping(true); service->SetMaxCheckAttempts(3); /* Initialize start time */ Utility::SetTime(0); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); Utility::IncrementTime(timeStepInterval); std::cout << "Inserting flapping check results" << std::endl; for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); service->ProcessCheckResult(MakeCheckResult(state)); Utility::IncrementTime(timeStepInterval); } BOOST_CHECK(service->IsFlapping() == true); CheckNotification(service, true, NotificationFlappingStart); //Insert enough check results to get into hard problem state but staying flapping service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == true); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceCritical); CheckNotification(service, false, NotificationProblem); // Calm down while (service->IsFlapping()) { service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); /* Intended behaviour is a Problem notification being sent as well, but there are is a Problem: * We don't know whether the Object was Critical before we started flapping and sent out a Notification. * A notification will not be sent, no matter how many criticals follow. * * service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); * CheckNotification(service, true, NotificationProblem); * ^ This fails, no notification will be sent * * There is also a different issue, when we receive a OK check result, a Recovery Notification will be sent * since the service went from hard critical into soft ok. Yet there is no fitting critical notification. * This should not happen: * * service->ProcessCheckResult(MakeCheckResult(ServiceOK)); * CheckNotification(service, false, NotificationRecovery); * ^ This fails, recovery is sent */ BOOST_CHECK(service->IsFlapping() == false); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceCritical); // Known failure, see #5713 // CheckNotification(service, true, NotificationProblem); service->ProcessCheckResult(MakeCheckResult(ServiceOK)); Utility::IncrementTime(timeStepInterval); // Known failure, see #5713 // CheckNotification(service, true, NotificationRecovery); c.disconnect(); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(service_flapping_ok_into_bad) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); int timeStepInterval = 60; Service::Ptr service = new Service(); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); service->SetEnableFlapping(true); service->SetMaxCheckAttempts(3); /* Initialize start time */ Utility::SetTime(0); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); Utility::IncrementTime(timeStepInterval); std::cout << "Inserting flapping check results" << std::endl; for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); service->ProcessCheckResult(MakeCheckResult(state)); Utility::IncrementTime(timeStepInterval); } BOOST_CHECK(service->IsFlapping() == true); CheckNotification(service, true, NotificationFlappingStart); //Insert enough check results to get into hard problem state but staying flapping service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == true); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceCritical); CheckNotification(service, false, NotificationProblem); // Calm down while (service->IsFlapping()) { service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == false); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceCritical); // We expect a problem notification here // Known failure, see #5713 // CheckNotification(service, true, NotificationProblem); c.disconnect(); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_CASE(service_flapping_ok_over_bad_into_ok) { #ifndef I2_DEBUG BOOST_WARN_MESSAGE(false, "This test can only be run in a debug build!"); #else /* I2_DEBUG */ boost::signals2::connection c = Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationHandler, _1, _2)); int timeStepInterval = 60; Service::Ptr service = new Service(); service->Activate(); service->SetAuthority(true); service->SetStateRaw(ServiceOK); service->SetStateType(StateTypeHard); service->SetEnableFlapping(true); service->SetMaxCheckAttempts(3); /* Initialize start time */ Utility::SetTime(0); std::cout << "Before first check result (ok, hard)" << std::endl; BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); Utility::IncrementTime(timeStepInterval); std::cout << "Inserting flapping check results" << std::endl; for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); service->ProcessCheckResult(MakeCheckResult(state)); Utility::IncrementTime(timeStepInterval); } BOOST_CHECK(service->IsFlapping() == true); CheckNotification(service, true, NotificationFlappingStart); //Insert enough check results to get into hard problem state but staying flapping service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == true); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceCritical); CheckNotification(service, false, NotificationProblem); // Calm down while (service->IsFlapping()) { service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); service->ProcessCheckResult(MakeCheckResult(ServiceOK)); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == false); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetState() == ServiceOK); // There should be no recovery // Known failure, see #5713 // CheckNotification(service, false, NotificationRecovery); c.disconnect(); #endif /* I2_DEBUG */ } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/icinga-macros.cpp000066400000000000000000000057361322762156600172620ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/macroprocessor.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(icinga_macros) BOOST_AUTO_TEST_CASE(simple) { Dictionary::Ptr macrosA = new Dictionary(); macrosA->Set("testA", 7); macrosA->Set("testB", "hello"); Dictionary::Ptr macrosB = new Dictionary(); macrosB->Set("testA", 3); macrosB->Set("testC", "world"); Array::Ptr testD = new Array(); testD->Add(3); testD->Add("test"); macrosB->Set("testD", testD); MacroProcessor::ResolverList resolvers; resolvers.push_back(std::make_pair("macrosA", macrosA)); resolvers.push_back(std::make_pair("macrosB", macrosB)); BOOST_CHECK(MacroProcessor::ResolveMacros("$macrosA.testB$ $macrosB.testC$", resolvers) == "hello world"); BOOST_CHECK(MacroProcessor::ResolveMacros("$testA$", resolvers) == "7"); BOOST_CHECK(MacroProcessor::ResolveMacros("$testA$$testB$", resolvers) == "7hello"); Array::Ptr result = MacroProcessor::ResolveMacros("$testD$", resolvers); BOOST_CHECK(result->GetLength() == 2); /* verify the config validator macro checks */ BOOST_CHECK(MacroProcessor::ValidateMacroString("$host.address") == false); BOOST_CHECK(MacroProcessor::ValidateMacroString("host.vars.test$") == false); BOOST_CHECK(MacroProcessor::ValidateMacroString("host.vars.test$") == false); BOOST_CHECK(MacroProcessor::ValidateMacroString("$template::test$abc$") == false); BOOST_CHECK(MacroProcessor::ValidateMacroString("$$test $host.vars.test$") == true); BOOST_CHECK(MacroProcessor::ValidateMacroString("test $host.vars.test$") == true); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/icinga-notification.cpp000066400000000000000000000113721322762156600204550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/notification.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(icinga_notification) BOOST_AUTO_TEST_CASE(state_filter) { unsigned long fstate; Array::Ptr states = new Array(); states->Add("OK"); states->Add("Warning"); Notification::Ptr notification = new Notification(); notification->SetStateFilter(FilterArrayToInt(states, notification->GetStateFilterMap(), ~0)); notification->Activate(); notification->SetAuthority(true); /* Test passing notification state */ fstate = StateFilterWarning; std::cout << "#1 Notification state: " << fstate << " against " << notification->GetStateFilter() << " must pass. " << std::endl; BOOST_CHECK(notification->GetStateFilter() & fstate); /* Test filtered notification state */ fstate = StateFilterUnknown; std::cout << "#2 Notification state: " << fstate << " against " << notification->GetStateFilter() << " must fail." << std::endl; BOOST_CHECK(!(notification->GetStateFilter() & fstate)); /* Test unset states filter configuration */ notification->SetStateFilter(FilterArrayToInt(Array::Ptr(), notification->GetStateFilterMap(), ~0)); fstate = StateFilterOK; std::cout << "#3 Notification state: " << fstate << " against " << notification->GetStateFilter() << " must pass." << std::endl; BOOST_CHECK(notification->GetStateFilter() & fstate); /* Test empty states filter configuration */ states->Clear(); notification->SetStateFilter(FilterArrayToInt(states, notification->GetStateFilterMap(), ~0)); fstate = StateFilterCritical; std::cout << "#4 Notification state: " << fstate << " against " << notification->GetStateFilter() << " must fail." << std::endl; BOOST_CHECK(!(notification->GetStateFilter() & fstate)); } BOOST_AUTO_TEST_CASE(type_filter) { unsigned long ftype; Array::Ptr types = new Array(); types->Add("Problem"); types->Add("DowntimeStart"); types->Add("DowntimeEnd"); Notification::Ptr notification = new Notification(); notification->SetTypeFilter(FilterArrayToInt(types, notification->GetTypeFilterMap(), ~0)); notification->Activate(); notification->SetAuthority(true); /* Test passing notification type */ ftype = NotificationProblem; std::cout << "#1 Notification type: " << ftype << " against " << notification->GetTypeFilter() << " must pass." << std::endl; BOOST_CHECK(notification->GetTypeFilter() & ftype); /* Test filtered notification type */ ftype = NotificationCustom; std::cout << "#2 Notification type: " << ftype << " against " << notification->GetTypeFilter() << " must fail." << std::endl; BOOST_CHECK(!(notification->GetTypeFilter() & ftype)); /* Test unset types filter configuration */ notification->SetTypeFilter(FilterArrayToInt(Array::Ptr(), notification->GetTypeFilterMap(), ~0)); ftype = NotificationRecovery; std::cout << "#3 Notification type: " << ftype << " against " << notification->GetTypeFilter() << " must pass." << std::endl; BOOST_CHECK(notification->GetTypeFilter() & ftype); /* Test empty types filter configuration */ types->Clear(); notification->SetTypeFilter(FilterArrayToInt(types, notification->GetTypeFilterMap(), ~0)); ftype = NotificationProblem; std::cout << "#4 Notification type: " << ftype << " against " << notification->GetTypeFilter() << " must fail." << std::endl; BOOST_CHECK(!(notification->GetTypeFilter() & ftype)); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/icinga-perfdata.cpp000066400000000000000000000112731322762156600175550ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/perfdatavalue.hpp" #include "icinga/pluginutility.hpp" #include using namespace icinga; BOOST_AUTO_TEST_SUITE(icinga_perfdata) BOOST_AUTO_TEST_CASE(empty) { Array::Ptr pd = PluginUtility::SplitPerfdata(""); BOOST_CHECK(pd->GetLength() == 0); } BOOST_AUTO_TEST_CASE(simple) { PerfdataValue::Ptr pdv = PerfdataValue::Parse("test=123456"); BOOST_CHECK(pdv->GetLabel() == "test"); BOOST_CHECK(pdv->GetValue() == 123456); String str = pdv->Format(); BOOST_CHECK(str == "test=123456"); } BOOST_AUTO_TEST_CASE(quotes) { Array::Ptr pd = PluginUtility::SplitPerfdata("'hello world'=123456"); BOOST_CHECK(pd->GetLength() == 1); PerfdataValue::Ptr pdv = PerfdataValue::Parse("'hello world'=123456"); BOOST_CHECK(pdv->GetLabel() == "hello world"); BOOST_CHECK(pdv->GetValue() == 123456); } BOOST_AUTO_TEST_CASE(multiple) { Array::Ptr pd = PluginUtility::SplitPerfdata("testA=123456 testB=123456"); BOOST_CHECK(pd->GetLength() == 2); String str = PluginUtility::FormatPerfdata(pd); BOOST_CHECK(str == "testA=123456 testB=123456"); } BOOST_AUTO_TEST_CASE(uom) { PerfdataValue::Ptr pv = PerfdataValue::Parse("test=123456B"); BOOST_CHECK(pv); BOOST_CHECK(pv->GetValue() == 123456); BOOST_CHECK(!pv->GetCounter()); BOOST_CHECK(pv->GetUnit() == "bytes"); BOOST_CHECK(pv->GetCrit() == Empty); BOOST_CHECK(pv->GetWarn() == Empty); BOOST_CHECK(pv->GetMin() == Empty); BOOST_CHECK(pv->GetMax() == Empty); String str = pv->Format(); BOOST_CHECK(str == "test=123456B"); pv = PerfdataValue::Parse("test=1000ms;200;500"); BOOST_CHECK(pv); BOOST_CHECK(pv->GetValue() == 1); BOOST_CHECK(pv->GetUnit() == "seconds"); BOOST_CHECK(pv->GetWarn() == 0.2); BOOST_CHECK(pv->GetCrit() == 0.5); pv = PerfdataValue::Parse("test=1000ms"); BOOST_CHECK(pv); BOOST_CHECK(pv->GetValue() == 1); BOOST_CHECK(pv->GetUnit() == "seconds"); BOOST_CHECK(pv->GetCrit() == Empty); BOOST_CHECK(pv->GetWarn() == Empty); BOOST_CHECK(pv->GetMin() == Empty); BOOST_CHECK(pv->GetMax() == Empty); str = pv->Format(); BOOST_CHECK(str == "test=1s"); } BOOST_AUTO_TEST_CASE(warncritminmax) { PerfdataValue::Ptr pv = PerfdataValue::Parse("test=123456B;1000;2000;3000;4000"); BOOST_CHECK(pv); BOOST_CHECK(pv->GetValue() == 123456); BOOST_CHECK(!pv->GetCounter()); BOOST_CHECK(pv->GetUnit() == "bytes"); BOOST_CHECK(pv->GetWarn() == 1000); BOOST_CHECK(pv->GetCrit() == 2000); BOOST_CHECK(pv->GetMin() == 3000); BOOST_CHECK(pv->GetMax() == 4000); BOOST_CHECK(pv->Format() == "test=123456B;1000;2000;3000;4000"); } BOOST_AUTO_TEST_CASE(ignore_invalid_warn_crit_min_max) { PerfdataValue::Ptr pv = PerfdataValue::Parse("test=123456;1000:2000;0:3000;3000;4000"); BOOST_CHECK(pv); BOOST_CHECK(pv->GetValue() == 123456); BOOST_CHECK(pv->GetWarn() == Empty); BOOST_CHECK(pv->GetCrit() == Empty); BOOST_CHECK(pv->GetMin() == 3000); BOOST_CHECK(pv->GetMax() == 4000); BOOST_CHECK(pv->Format() == "test=123456"); } BOOST_AUTO_TEST_CASE(invalid) { BOOST_CHECK_THROW(PerfdataValue::Parse("123456"), boost::exception); BOOST_CHECK_THROW(PerfdataValue::Parse("test=1,23456"), boost::exception); } BOOST_AUTO_TEST_CASE(multi) { Array::Ptr pd = PluginUtility::SplitPerfdata("test::a=3 b=4"); BOOST_CHECK(pd->Get(0) == "test::a=3"); BOOST_CHECK(pd->Get(1) == "test::b=4"); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/jenkins/000077500000000000000000000000001322762156600154705ustar00rootroot00000000000000icinga2-2.8.1/test/jenkins/README000066400000000000000000000036051322762156600163540ustar00rootroot00000000000000Set of scripts to set up and test a virtual demo machine ======================================================== This directory contains a few scripts primarily used by build.icinga.com. * bootstrap-vm.sh Ensures that all required software is installed and its configuration is applied to the VM. (Usually not of interest for the typical user.) * run_tests.sh This is a wrapper script intended to be ran manually by a user. (Note that you need to start this project's vagrant box for this to work!) * run_tests.py The actual test-runner. Accepts two options (-C|--config, -O|--output) and expects one or more filenames or -patterns that should be run on the VM. * run_tests.conf The default configuration file for the test-runner. (Used when running the wrapper script or when no custom configuration file is passed to the test-runner.) Format: - commands: This section is mandatory and contains the commands to use. - settings: This section is mandatory and defines settings that are applied to all tests. - setups: This section is optional and contains setup routines that should be ran before (setup) and after (teardown) any matching test is executed. (Note that only one setup can be effective at a time.) Example: "^v[1-9]\.test$": { "setup": { "copy": ["source >> target"], // Files that should be copied. // Note that these files remain // if not removed explicitly "clean": ["target"], // Files to delete from the system "exec": ["cmd1", "cmd2"] // Commands to execute on the system }, "teardown": { // The same kind of instructions as above can be added here } } icinga2-2.8.1/test/jenkins/apache_state.test000077500000000000000000000002561322762156600210200ustar00rootroot00000000000000#!/bin/sh sudo service httpd status &> /dev/null if [ $? -gt 0 ]; then echo '[FAIL] httpd is not running' exit 1 else echo '[OK] httpd is running' exit 0 fi icinga2-2.8.1/test/jenkins/bootstrap-vm.sh000077500000000000000000000017651322762156600204750ustar00rootroot00000000000000#!/bin/sh if [ "$1" != "--force" ]; then echo 'This script is NOT intended to be ran by an individual user.' \ 'If you are not human, pass "--force" as the first option to it!' exit 1 fi if [ $# -lt 3 ]; then echo 'Too few arguments. You need to pass "--force "' \ 'to run this script.' exit 1 fi user=$2 host=$3 SSH_OPTIONS="-o PasswordAuthentication=no" SSH="ssh $SSH_OPTIONS $user@$host" $SSH "mkdir /vagrant" # TODO clone git and use the icinga2x puppet modules git clone git://git.icinga.com/icinga-vagrant.git scp -qr icinga-vagrant/icinga2x/.vagrant-puppet $user@$host:/vagrant rm -rf icinga-vagrant $SSH "useradd vagrant" $SSH "su -c 'mkdir -p -m 0700 ~/.ssh' vagrant" $SSH "su -c \"echo '`cat ~/.ssh/id_rsa.pub`' >> ~/.ssh/authorized_keys\" vagrant" $SSH "echo '10.10.27.1 packages.icinga.com' >> /etc/hosts" $SSH "puppet apply --modulepath=/vagrant/.vagrant-puppet/modules" \ " /vagrant/.vagrant-puppet/manifests/default.pp" exit 0 icinga2-2.8.1/test/jenkins/checkresult.test000077500000000000000000000057161322762156600207210ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import unicode_literals import os import sys import time import utils STATE_OK = 0 TYPE_PASSIVE_CHECK = 1 CHECK_INTERVAL = 300 # seconds CHECKRESULT_READ_INTERVAL = 5 # seconds CHECKRESULT_LOCATION = '/tmp/icinga2/checkresults' CHECKRESULT_TEMPLATE = """ host_name=%(hostname)s service_description=%(servicename)s check_type=%(check_type)s check_options=0 scheduled_check=0 reschedule_check=0 latency=0 start_time=%(start_time)s finish_time=%(finish_time)s early_timeout=0 exited_ok=%(excited_ok)s return_code=%(return_code)s output=%(output)s """ def main(): run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql') # We need to wait a bit first as Icinga processes a # checkresult only if its newer than the last check query = 'select unix_timestamp(s.last_check) as last_check ' \ 'from icinga_servicestatus as s ' \ 'inner join icinga_services as c ' \ 'on s.service_object_id = c.service_object_id ' \ "where c.display_name = 'PassiveService1'" state_time = float(next(iter(run_query(query)), {}).get('last_check', '0')) if state_time == 0: utils.Logger.fail('"PassiveService1" seems not' ' to have been checked yet\n') return 1 if (state_time + CHECK_INTERVAL) - time.time() < 30: time.sleep(45) # Now pass the checkresult in resultfile_path = os.path.join(CHECKRESULT_LOCATION, 'cfoobar') with open(resultfile_path, 'w') as f: f.write(CHECKRESULT_TEMPLATE % { 'hostname': 'nsca-ng', 'servicename': 'PassiveService1', 'check_type': TYPE_PASSIVE_CHECK, 'start_time': time.time(), 'finish_time': time.time(), 'excited_ok': '1', 'return_code': STATE_OK, 'output': 'Passing in CheckResult header files works!' }) utils.Logger.debug('Written file: {0}\n'.format(resultfile_path)) # And notfiy Icinga that the file has been completely written... resultfileok_path = os.path.join(CHECKRESULT_LOCATION, 'cfoobar.ok') with open(resultfileok_path, 'w') as f: pass utils.Logger.debug('Written file: {0}\n'.format(resultfileok_path)) # Lastly check whether the service changed its state time.sleep(CHECKRESULT_READ_INTERVAL * 2) query = 'select s.output ' \ 'from icinga_servicestatus as s ' \ 'inner join icinga_services as c ' \ 'on s.service_object_id = c.service_object_id ' \ "where c.display_name = 'PassiveService1'" output = next(iter(run_query(query)), {}).get('output', '') if output != 'Passing in CheckResult header files works!': utils.Logger.fail('Checkresult header files seem ' 'not to be processed properly\n') return 1 utils.Logger.ok('Checkresult header files are processed properly\n') return 0 if __name__ == '__main__': sys.exit(main()) icinga2-2.8.1/test/jenkins/eventhandler.test000077500000000000000000000233261322762156600210610ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import unicode_literals import os import sys import time import socket import utils LIVESTATUS_PATH = '/var/run/icinga2/cmd/livestatus' LS_HOST_COLUMNS = [ 'name', 'name', 'display_name', 'display_name', None, 'state', 'state_type', 'current_attempt', 'max_check_attempts', None, 'last_state', None, 'last_state_change', None, 'latency', 'execution_time', 'plugin_output', None, 'last_check', 'address', 'address6' ] LS_SVC_COLUMNS = [ 'description', 'display_name', 'display_name', None, 'state', 'state_type', 'current_attempt', 'max_check_attempts', None, 'last_state', None, 'last_state_change', None, 'latency', 'execution_time', 'plugin_output', 'perf_data', 'last_check', 'host_num_services', 'host_num_services_ok', 'host_num_services_warn', 'host_num_services_unknown', 'host_num_services_crit' ] STATE_MAP = { 'SOFT': 0, 'HARD': 1 } def send_command(command): try: return send_query('COMMAND [{0}] {1}'.format(int(time.time()), command)) except utils.LiveStatusError, error: sys.stderr.write('Failed to execute command: {0}\n\n{1}\n' ''.format(command, error)) def send_query(query): response = LIVESTATUS.query(query + '\nColumnHeaders: on') if response: header, result = response.pop(0), {} return [dict((header[i], v) for i, v in enumerate(r)) for r in response] return [] def get_one(query): return next(iter(send_query(query)), {}) def get_event_output(): try: with open('/tmp/test_event.out') as f: remove = True return f.read().rstrip().split('|') except (IOError, OSError): remove = False finally: if remove: os.system('sudo rm -f /tmp/test_event.out') def convert_output(value): try: return int(value) except ValueError: try: return float(value) except ValueError: return STATE_MAP.get(value, value) def validate_time_format(inputstr, formatstr): try: time.strptime(inputstr, formatstr) except ValueError: return False else: return True def main(): send_command('CHANGE_HOST_EVENT_HANDLER;localhost;test_event') host_info = get_one('GET hosts\nFilter: name = localhost' '\nColumns: event_handler') if host_info.get('event_handler') != 'test_event': utils.Logger.fail('Could not assign eventcommand "test_event"' ' to host "localhost"\n') return 1 utils.Logger.ok('Successfully assigned an eventcommand' ' to host "localhost"\n') send_command('PROCESS_HOST_CHECK_RESULT;localhost;1;A negative result to' ' trigger an eventhandler|some interesting perfdata!') event_output = get_event_output() if not event_output: send_command('CHANGE_HOST_EVENT_HANDLER;localhost;') utils.Logger.fail('Could not trigger the eventcommand\n') return 1 utils.Logger.ok('Successfully triggered the eventcommand\n') failure = False utils.Logger.info('Checking host macros...\n') host_info = get_one('GET hosts\nFilter: name = localhost\nColumns: {0}' ''.format(' '.join(c for c in LS_HOST_COLUMNS if c))) if event_output[0] != host_info['name']*2: failure = True utils.Logger.fail('Escaping environment variables ' 'seems not to properly working\n') utils.Logger.fail(' Expected: {0!r} Got: {1!r}\n' ''.format(host_info['name']*2, event_output[0])) else: utils.Logger.ok('Escaped environment variables' ' are properly processed\n') for i, column in enumerate(LS_HOST_COLUMNS[1:], 1): if column is not None: macro_name, _, macro_value = event_output[i].partition('=') output_value = convert_output(macro_value) if output_value != host_info[column]: failure = True utils.Logger.fail('Macro "{0}" returns an incorrect value. ' 'Expected "{2}" but got "{1}"\n' ''.format(macro_name, output_value, host_info[column])) else: utils.Logger.ok('Macro "{0}" returns the correct value\n' ''.format(macro_name)) utils.Logger.info('Checking service macros...\n') svc_info = get_one('GET services\nFilter: description = ping4\nColumns: {0}' ''.format(' '.join(c for c in LS_SVC_COLUMNS if c))) for i, column in enumerate(LS_SVC_COLUMNS, len(LS_HOST_COLUMNS)): if column is not None: macro_name, _, macro_value = event_output[i].partition('=') output_value = convert_output(macro_value) if output_value != svc_info[column]: failure = True utils.Logger.fail('Macro "{0}" returns an incorrect value. ' 'Expected "{2}" but got "{1}"\n' ''.format(macro_name, output_value, svc_info[column])) else: utils.Logger.ok('Macro "{0}" returns the correct value\n' ''.format(macro_name)) utils.Logger.info('Checking global macros...\n') timet = convert_output(event_output[-6].partition('=')[2]) if not isinstance(timet, int): failure = True utils.Logger.fail('Macro "TIMET" does not return a timestamp. ' 'Expected int but got: {0!r}\n'.format(timet)) else: utils.Logger.ok('Macro "TIMET" returns the correct value\n') longdatetime = event_output[-5].partition('=')[2] longdatetime_format = '%Y-%m-%d %H:%M:%S +0000' if not validate_time_format(longdatetime, longdatetime_format): failure = True utils.Logger.fail('Macro "LONGDATETIME" returns an incorrect value.' ' Expected value of format "{0}" but got "{1}"\n' ''.format(longdatetime_format, longdatetime)) else: utils.Logger.ok('Macro "LONGDATETIME" returns the correct value\n') shortdatetime = event_output[-4].partition('=')[2] shortdatetime_format = '%Y-%m-%d %H:%M:%S' if not validate_time_format(shortdatetime, shortdatetime_format): failure = True utils.Logger.fail('Macro "SHORTDATETIME" returns an incorrect value.' ' Expected value of format "{0}" but got "{1}"\n' ''.format(shortdatetime_format, shortdatetime)) else: utils.Logger.ok('Macro "SHORTDATETIME" returns the correct value\n') m_date = event_output[-3].partition('=')[2] m_date_format = '%Y-%m-%d' if not validate_time_format(m_date, m_date_format): failure = True utils.Logger.fail('Macro "DATE" returns an incorrect value. ' 'Expected value of format "{0}" but got "{1}"\n' ''.format(m_date_format, m_date)) else: utils.Logger.ok('Macro "DATE" returns the correct value\n') m_time = event_output[-2].partition('=')[2] m_time_format = '%H:%M:%S +0000' if not validate_time_format(m_time, m_time_format): failure = True utils.Logger.fail('Macro "TIME" returns an incorrect value. ' 'Expected value of format "{0}" but got "{1}"\n' ''.format(m_time_format, m_time)) else: utils.Logger.ok('Macro "TIME" returns the correct value\n') utils.Logger.info('Checking command macros...\n') if convert_output(event_output[-1].partition('=')[2]) != 1337: failure = True utils.Logger.fail('The command macro "custom_macro"' ' is not being substituted\n') else: utils.Logger.ok('The command macro "custom_macro"' ' is correctly substituted\n') send_command('DISABLE_HOST_EVENT_HANDLER;localhost') send_command('PROCESS_HOST_CHECK_RESULT;localhost;0;A positive result that' ' should not trigger an eventhandler') if get_event_output(): failure = True utils.Logger.fail('Could not disable the eventcommand\n') else: utils.Logger.ok('Successfully disabled the eventcommand\n') send_command('ENABLE_HOST_EVENT_HANDLER;localhost') host_info = get_one('GET hosts\nFilter: name = localhost' '\nColumns: event_handler_enabled') if host_info['event_handler_enabled'] != 1: failure = True utils.Logger.fail('Could not re-enable the eventcommand\n') else: utils.Logger.ok('Successfully re-enabled the eventcommand\n') send_command('CHANGE_HOST_EVENT_HANDLER;localhost;') host_info = get_one('GET hosts\nFilter: name = localhost' '\nColumns: event_handler') if host_info['event_handler']: failure = True utils.Logger.fail('Could not remove eventcommand "test_event"' ' assigned to host "localhost"\n') else: utils.Logger.ok('Successfully removed the eventcommand' ' assigned to host "localhost"\n') return 1 if failure else 0 if __name__ == '__main__': try: with utils.LiveStatusSocket(LIVESTATUS_PATH) as LIVESTATUS: sys.exit(main()) except (OSError, IOError, socket.error), e: utils.Logger.error('Could not connect to Livestatus socket: {0} ({1})' '\n'.format(LIVESTATUS_PATH, unicode(e))) icinga2-2.8.1/test/jenkins/external_commandpipe.test000077500000000000000000000004021322762156600225660ustar00rootroot00000000000000#!/bin/sh commandpipe_path="/var/run/icinga2/cmd/icinga2.cmd" if [ -e $commandpipe_path ]; then echo "[OK] Icinga2 commandpipe found ($commandpipe_path)" exit 0 else echo "[FAIL] Icinga2 commandpipe not found ($commandpipe_path)" exit 1 fi icinga2-2.8.1/test/jenkins/external_commands.test000077500000000000000000001775641322762156600221230ustar00rootroot00000000000000#!/usr/bin/env python # coding: utf-8 from __future__ import unicode_literals import os import sys import time import random import socket import subprocess try: from subprocess import DEVNULL except ImportError: from os import devnull DEVNULL = open(devnull, 'w') import utils ICINGA_UID = 'icinga' USERNAME = 'Icinga 2 Admin' MAX_CHECK_ATTEMPTS = 3 LIVESTATUS_PATH = '/var/run/icinga2/cmd/livestatus' def send_command(command, quiet=False): try: return send_query('COMMAND [{0}] {1}'.format(int(time.time()), command)) except utils.LiveStatusError, error: if not quiet: sys.stderr.write('Failed to execute command: {0}\n\n{1}'.format(command, error)) def send_query(query): response = LIVESTATUS.query(query + '\nColumnHeaders: on') if response: header, result = response.pop(0), {} return [dict((header[i], v) for i, v in enumerate(r)) for r in response] return [] def run_query(query, retries=3): tries = 0 while True: rs = next(iter(utils.run_mysql_query(query, b'/usr/bin/mysql')), {}) if tries == retries or any(True for v in rs.itervalues() if v is not None): return rs else: tries += 1 time.sleep(1) def get_one(query): return next(iter(send_query(query)), {}) def restart_icinga(): LIVESTATUS.close() subprocess.check_call('sudo service icinga2 restart', shell=True, stdout=DEVNULL) LIVESTATUS.reconnect() def success(msg): utils.Logger.ok(msg + '\n') return False def fail(msg): utils.Logger.fail(msg + '\n') return True def error(msg): utils.Logger.error(msg + '\n') return True def test_host_comments(hostname): comment = 'test{0:.4}'.format(random.random()) add_command = 'ADD_HOST_COMMENT;%s;{persistent};{author};{comment}' % hostname del_command = 'DEL_HOST_COMMENT;{id}' comment_query = '\n'.join(['GET comments', 'Filter: type = 1', 'Filter: comment = {comment}', 'Columns: id']) send_command(add_command.format(persistent=0, author=USERNAME, comment=comment)) comment_info = get_one(comment_query.format(comment=comment)) if comment_info: success('Successfully added comment to host "{0}"'.format(hostname)) send_command(del_command.format(id=comment_info['id'])) if get_one(comment_query.format(comment=comment)): return fail('Could not remove comment with id #{0} from host "{1}"' ''.format(comment_info['id'], hostname)) return success('Successfully removed comment from host "{0}"' ''.format(hostname)) return fail('Could not add comment to host "{0}"'.format(hostname)) def test_service_comments(hostname, servicename): comment = 'test{0:.4}'.format(random.random()) add_command = 'ADD_SVC_COMMENT;%s;%s;{persistent};{author}' \ ';{comment}' % (hostname, servicename) del_command = 'DEL_SVC_COMMENT;{id}' comment_query = '\n'.join(['GET comments', 'Filter: type = 2', 'Filter: comment = {comment}', 'Columns: id']) send_command(add_command.format(persistent=0, author=USERNAME, comment=comment)) comment_info = get_one(comment_query.format(comment=comment)) if comment_info: success('Successfully added comment to service "{0}" of host "{1}"' ''.format(servicename, hostname)) send_command(del_command.format(id=comment_info['id'])) if get_one(comment_query.format(comment=comment)): return fail('Could not remove comment with id #{0} from service "{1}"' ''.format(comment_info['id'], servicename)) return success('Successfully removed comment from service "{0}"' ''.format(servicename)) return fail('Could not add comment to service "{0}" of host "{1}"' ''.format(servicename, hostname)) def test_host_downtimes(hostname): comment = 'test{0:.4}'.format(random.random()) start, end = time.time() + 20, time.time() + 320 add_command = 'SCHEDULE_HOST_DOWNTIME;%s;{start};{end};1;0' \ ';0;{author};{comment}' % hostname del_command = 'DEL_HOST_DOWNTIME;{id}' downtime_query = '\n'.join(['GET downtimes', 'Filter: triggered_by = 0', 'Filter: duration = 0', 'Filter: fixed = 1', 'Filter: comment = {comment}', 'Columns: id']) send_command(add_command.format(start=start, end=end, author=USERNAME, comment=comment)) downtime_info = get_one(downtime_query.format(comment=comment)) if downtime_info: success('Successfully scheduled downtime for host "{0}"'.format(hostname)) send_command(del_command.format(id=downtime_info['id'])) if get_one(downtime_query.format(comment=comment)): return fail('Could not remove downtime for host "{0}"'.format(hostname)) return success('Successfully removed downtime for host "{0}"'.format(hostname)) return fail('Could not schedule downtime for host "{0}"'.format(hostname)) def test_service_downtimes(hostname, servicename): comment = 'test{0:.4}'.format(random.random()) start, end = time.time() + 20, time.time() + 320 add_command = 'SCHEDULE_SVC_DOWNTIME;%s;%s;{start};{end};1;0;0' \ ';{author};{comment}' % (hostname, servicename) del_command = 'DEL_SVC_DOWNTIME;{id}' downtime_query = '\n'.join(['GET downtimes', 'Filter: triggered_by = 0', 'Filter: duration = 0', 'Filter: fixed = 1', 'Filter: comment = {comment}', 'Columns: id']) send_command(add_command.format(start=start, end=end, author=USERNAME, comment=comment)) downtime_info = get_one(downtime_query.format(comment=comment)) if downtime_info: success('Successfully scheduled downtime for service "{0}" of host "{1}"' ''.format(servicename, hostname)) send_command(del_command.format(id=downtime_info['id'])) if get_one(downtime_query.format(comment=comment)): return fail('Could not remove downtime for service "{0}" of host "{1}"' ''.format(servicename, hostname)) return success('Successfully removed downtime for service "{0}" of host "{1}"' ''.format(servicename, hostname)) return fail('Could not schedule downtime for service "{0}" of host "{1}"' ''.format(servicename, hostname)) def test_host_problem_acknowledgements(hostname): comment = 'test{0:.4}'.format(random.random()) send_command('PROCESS_HOST_CHECK_RESULT;{0};1;fail'.format(hostname)) send_command('ACKNOWLEDGE_HOST_PROBLEM;{0};0;0;0;{1};{2}' ''.format(hostname, USERNAME, comment)) ack_info = get_one('GET comments\nFilter: comment = {0}' '\nFilter: entry_type = 4\nColumns: id'.format(comment)) if ack_info: success('Acknowledgement for host "{0}" has been processed'.format(hostname)) host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: acknowledged'.format(hostname)) if host_info['acknowledged'] != 1: return fail('Could not acknowledge problem on host "{0}"'.format(hostname)) else: return fail('Acknowledgement for host "{0}" has not been processed' ''.format(hostname)) success('Successfully acknowledged problem on host "{0}"'.format(hostname)) send_command('PROCESS_HOST_CHECK_RESULT;{0};0;ok'.format(hostname)) if get_one('GET comments\nFilter: id = {0}'.format(ack_info['id'])): return fail('Non sticky acknowledgements are not removed if their host recovers') success('Non sticky acknowledgements are removed if their host recovers') comment = 'test{0:.4}'.format(random.random()) send_command('PROCESS_HOST_CHECK_RESULT;{0};1;fail'.format(hostname)) send_command('ACKNOWLEDGE_HOST_PROBLEM;{0};1;0;0;{1};{2}' ''.format(hostname, USERNAME, comment)) ack_info = get_one('GET comments\nFilter: comment = {0}' '\nFilter: entry_type = 4\nColumns: id'.format(comment)) send_command('PROCESS_HOST_CHECK_RESULT;{0};0;ok'.format(hostname)) if not get_one('GET comments\nFilter: id = {0}'.format(ack_info['id'])): return fail('Sticky acknowledgements are removed if their host recovers') send_command('DEL_HOST_COMMENT;{0}'.format(ack_info['id'])) success('Sticky acknowledgements need to be manually' ' removed once their host has recovered') host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: acknowledged state' ''.format(hostname)) if host_info['state'] == 0 and host_info['acknowledged'] == 1: return fail('Host "{0}" is still acknowledged though it is not DOWN anymore' ''.format(hostname)) return success('Hosts are not acknowledged anymore once their state changes') def test_remove_host_acknowledgements(hostname): comment = 'test{0:.4}'.format(random.random()) send_command('PROCESS_HOST_CHECK_RESULT;{0};1;fail'.format(hostname)) send_command('ACKNOWLEDGE_HOST_PROBLEM;{0};0;0;0;{1};{2}' ''.format(hostname, USERNAME, comment)) ack_info = get_one('GET comments\nFilter: comment = {0}\nColumns: id' ''.format(comment)) if not ack_info: return fail('Acknowledgement for host "{0}" has not been processed' ''.format(hostname)) send_command('REMOVE_HOST_ACKNOWLEDGEMENT;{0}'.format(hostname)) if get_one('GET comments\nFilter: id = {0}'.format(ack_info['id'])): return fail('Acknowledgement related comments are not removed' ' when manually removing an acknowledgement') return success('Acknowledgement related comments are removed when' ' manually removing an acknowledgement') def test_expiring_host_acknowledgements(hostname): comment, expire_time = 'test{0:.4}'.format(random.random()), time.time() + 5 send_command('PROCESS_HOST_CHECK_RESULT;{0};1;fail'.format(hostname)) send_command('ACKNOWLEDGE_HOST_PROBLEM_EXPIRE;{0};0;0;0;{1};{2};{3}' ''.format(hostname, expire_time, USERNAME, comment)) time.sleep(expire_time - time.time()) host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: acknowledged' ''.format(hostname)) if host_info['acknowledged'] == 1: send_command('REMOVE_HOST_ACKNOWLEDGEMENT;{0}'.format(hostname)) return fail('Acknowledgements do not expire as desired') return success('Acknowledgements do expire as desired') def test_change_host_check_command(hostname, command): old_command = get_one('GET hosts\nFilter: name = {0}\nColumns: check_command' ''.format(hostname))['check_command'] send_command('CHANGE_HOST_CHECK_COMMAND;{0};{1}'.format(hostname, command)) host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: check_command' ''.format(hostname)) if host_info['check_command'] != command: return fail('Could not change the check command of host "{0}" to "{1}"' ''.format(hostname, command)) send_command('CHANGE_HOST_CHECK_COMMAND;{0};{1}'.format(hostname, old_command)) return success('Successfully changed check command of host "{0}" to "{1}"' ''.format(hostname, command)) def test_change_host_check_timeperiod(hostname, period): old_period = get_one('GET hosts\nFilter: name = {0}\nColumns: check_period' ''.format(hostname))['check_period'] send_command('CHANGE_HOST_CHECK_TIMEPERIOD;{0};{1}'.format(hostname, period)) host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: check_period' ''.format(hostname)) if host_info['check_period'] != period: return fail('Could not change the check period of host "{0}" to "{1}"' ''.format(hostname, period)) send_command('CHANGE_HOST_CHECK_TIMEPERIOD;{0};{1}'.format(hostname, period)) return success('Successfully changed check period of host "{0}" to "{1}"' ''.format(hostname, period)) def test_change_host_modified_attributes(hostname): send_command('CHANGE_MAX_HOST_CHECK_ATTEMPTS;{0};1337'.format(hostname)) restart_icinga() host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: max_check_attempts'.format(hostname)) if host_info['max_check_attempts'] != 1337: return fail('Modified attributes of host "{0}" seem not to be ' 'persisted between application restarts'.format(hostname)) else: success('Modified attributes are being persisted' ' between application restarts') send_command('CHANGE_HOST_MODATTR;{0};0'.format(hostname)) restart_icinga() host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: max_check_attempts'.format(hostname)) if host_info['max_check_attempts'] == 1337: return fail('Re-setting the "modified attributes" value does not' ' seem to invalidate any modified attributes') return success('Re-setting the "modified attributes" value seems to' ' invalidate the modified attributes') def test_change_host_max_check_attempts(hostname): old_value = get_one('GET hosts\nFilter: name = {0}' '\nColumns: max_check_attempts' ''.format(hostname))['max_check_attempts'] send_command('CHANGE_MAX_HOST_CHECK_ATTEMPTS;{0};1234'.format(hostname)) host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: max_check_attempts'.format(hostname)) if host_info['max_check_attempts'] != 1234: return fail('Could not change the maximum number of check' ' attempts for host "{0}"'.format(hostname)) send_command('CHANGE_MAX_HOST_CHECK_ATTEMPTS;{0};{1}'.format(hostname, old_value)) return success('Successfully changed maximum number of check' ' attempts for host "{0}"'.format(hostname)) def test_change_service_max_check_attempts(hostname, servicename): old_value = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: max_check_attempts' ''.format(hostname, servicename))['max_check_attempts'] send_command('CHANGE_MAX_SVC_CHECK_ATTEMPTS;{0};{1};1234' ''.format(hostname, servicename)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: max_check_attempts'.format(hostname, servicename)) if svc_info['max_check_attempts'] != 1234: return fail('Could not change the maximum number of check attempts for ' 'service "{0}" on host "{1}"'.format(servicename, hostname)) send_command('CHANGE_MAX_SVC_CHECK_ATTEMPTS;{0};{1};{2}' ''.format(hostname, servicename, old_value)) return success('Successfully changed maximum number of check attempts ' 'for service "{0}" on host "{1}"'.format(servicename, hostname)) def test_change_host_normal_check_interval(hostname): old_value = get_one('GET hosts\nFilter: name = {0}\nColumns: check_interval' ''.format(hostname))['check_interval'] send_command('CHANGE_NORMAL_HOST_CHECK_INTERVAL;{0};7200'.format(hostname)) host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: check_interval' ''.format(hostname)) if host_info['check_interval'] != 7200: return fail('Could not change the check interval of host "{0}"' ''.format(hostname)) send_command('CHANGE_NORMAL_HOST_CHECK_INTERVAL;{0};{1}'.format(hostname, old_value)) return success('Successfully changed check interval of host "{0}"' ''.format(hostname)) def test_change_service_normal_check_interval(hostname, servicename): old_value = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_interval' ''.format(hostname, servicename))['check_interval'] send_command('CHANGE_NORMAL_SVC_CHECK_INTERVAL;{0};{1};7200' ''.format(hostname, servicename)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_interval' ''.format(hostname, servicename)) if svc_info['check_interval'] != 7200: return fail('Could not change the check interval of service "{0}"' ' on host "{1}"'.format(servicename, hostname)) send_command('CHANGE_NORMAL_SVC_CHECK_INTERVAL;{0};{1};{2}' ''.format(hostname, servicename, old_value)) return success('Successfully changed check interval of service ' '"{0}" on host "{1}"'.format(servicename, hostname)) def test_change_host_retry_check_interval(hostname): old_value = get_one('GET hosts\nFilter: name = {0}\nColumns: retry_interval' ''.format(hostname))['retry_interval'] send_command('CHANGE_RETRY_HOST_CHECK_INTERVAL;{0};3600'.format(hostname)) host_info = get_one('GET hosts\nFilter: name = {0}\nColumns: retry_interval' ''.format(hostname)) if host_info['retry_interval'] != 3600: return fail('Could not change the retry interval of host "{0}"' ''.format(hostname)) send_command('CHANGE_RETRY_HOST_CHECK_INTERVAL;{0};{1}'.format(hostname, old_value)) return success('Successfully changed retry interval of host "{0}"' ''.format(hostname)) def test_change_service_retry_check_interval(hostname, servicename): old_value = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: retry_interval' ''.format(hostname, servicename))['retry_interval'] send_command('CHANGE_RETRY_SVC_CHECK_INTERVAL;{0};{1};3600' ''.format(hostname, servicename)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: retry_interval' ''.format(hostname, servicename)) if svc_info['retry_interval'] != 3600: return fail('Could not change retry interval of service "{0}"' ' on host "{1}"'.format(servicename, hostname)) send_command('CHANGE_RETRY_SVC_CHECK_INTERVAL;{0};{1};{2}' ''.format(hostname, servicename, old_value)) return success('Successfully changed retry interval of service "{0}"' ' on host "{1}"'.format(servicename, hostname)) def test_change_service_check_command(hostname, servicename, command): old_value = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_command' ''.format(hostname, servicename))['check_command'] send_command('CHANGE_SVC_CHECK_COMMAND;{0};{1};{2}' ''.format(hostname, servicename, command)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_command' ''.format(hostname, servicename)) if svc_info['check_command'] != command: return fail('Could not change the check command of service "{0}" on ' 'host "{1}" to "{2}"'.format(servicename, hostname, command)) send_command('CHANGE_SVC_CHECK_COMMAND;{0};{1};{2}' ''.format(hostname, servicename, old_value)) return success('Successfully changed check command of service "{0}" on' ' host "{1}"'.format(servicename, hostname)) def test_change_service_check_timeperiod(hostname, servicename, period): old_value = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_period' ''.format(hostname, servicename))['check_period'] send_command('CHANGE_SVC_CHECK_TIMEPERIOD;{0};{1};{2}' ''.format(hostname, servicename, period)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: check_period' ''.format(hostname, servicename)) if svc_info['check_period'] != period: return fail('Could not change the check period of service "{0}" on host' ' "{1}" to "{2}"'.format(servicename, hostname, period)) send_command('CHANGE_SVC_CHECK_TIMEPERIOD;{0};{1};{2}' ''.format(hostname, servicename, old_value)) return success('Successfully changed check period of service "{0}"' ' on host "{1}"'.format(servicename, hostname)) def test_delay_host_notification(hostname): # This test assumes that the notification interval # for the given host is set to 10 seconds send_command('DISABLE_HOST_CHECK;{0}'.format(hostname)) for _ in xrange(MAX_CHECK_ATTEMPTS): send_command('PROCESS_HOST_CHECK_RESULT;{0};1;down'.format(hostname)) state_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: state state_type last_hard_state_change' ''.format(hostname)) if state_info['state'] != 1 or state_info['state_type'] != 1: send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) return fail('Could not switch state of host "{0}"' ' to DOWN (HARD)'.format(hostname)) time.sleep(1) note_info1 = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification'.format(hostname)) if not -1 < (note_info1['last_notification'] - \ state_info['last_hard_state_change']) < 1: send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) return fail('Switching host "{0}" to state DOWN (HARD) does not ' 'cause a notification being sent out'.format(hostname)) send_command('DELAY_HOST_NOTIFICATION;{0};{1}' ''.format(hostname, note_info1['last_notification'] + 20)) time.sleep(5 + 10 - (time.time() - note_info1['last_notification'])) note_info2 = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification'.format(hostname)) if note_info2['last_notification'] != note_info1['last_notification']: send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) return fail('There were a notification being sent out for host ' '"{0}" before the time that it should be delayed to' ''.format(hostname)) time.sleep(5 + note_info1['last_notification'] + 20 - time.time()) send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) note_info3 = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification'.format(hostname)) if note_info3['last_notification'] < note_info1['last_notification'] + 20: return fail('Could not delay notification for' ' host "{0}"'.format(hostname)) return success('Successfully delayed notification' ' for host "{0}"'.format(hostname)) def test_delay_service_notification(hostname, servicename): # This test assumes that the notification interval # for the given service is set to 10 seconds send_command('DISABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) for _ in xrange(MAX_CHECK_ATTEMPTS): send_command('PROCESS_SERVICE_CHECK_RESULT;{0};{1};2;critical' ''.format(hostname, servicename)) state_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: state state_type last_hard_state_change' ''.format(hostname, servicename)) if state_info['state'] != 2 or state_info['state_type'] != 1: send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) return fail('Could not switch state of service "{0}" on host "{1}"' ' to CRITICAL (HARD)'.format(servicename, hostname)) time.sleep(1) note_info1 = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename)) if not -1 < (note_info1['last_notification'] - \ state_info['last_hard_state_change']) < 1: send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) return fail('Switching service "{0}" on host "{1}" to state CRITICAL ' '(HARD) does not cause a notification being sent out' ''.format(servicename, hostname)) send_command('DELAY_SVC_NOTIFICATION;{0};{1};{2}' ''.format(hostname, servicename, note_info1['last_notification'] + 20)) time.sleep(5 + 10 - (time.time() - note_info1['last_notification'])) note_info2 = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename)) if note_info2['last_notification'] != note_info1['last_notification']: send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) return fail('There were a notification being sent out for service "{0}" ' 'on host "{1}" before the time that it should be delayed to' ''.format(servicename, hostname)) time.sleep(5 + note_info1['last_notification'] + 20 - time.time()) send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) note_info3 = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename)) if note_info3['last_notification'] < note_info1['last_notification'] + 20: return fail('Could not delay notification for service "{0}"' ' on host "{0}"'.format(servicename, hostname)) return success('Successfully delayed notification for service "{0}"' ' on host "{0}"'.format(servicename, hostname)) def test_disabling_scheduling_host_checks(hostname): # This test assumes that icinga is writing the hostchecks db table (DbCatCheck) compare_time = lambda a, b: -2 < a - b < 2 start_time_query = ('SELECT UNIX_TIMESTAMP(MAX(start_time)) as start_time' ' FROM icinga_hostchecks AS c' ' INNER JOIN icinga_hosts AS h' ' ON h.host_object_id = c.host_object_id' ' WHERE h.alias = "{0}"' '').format(hostname) # Need to use a sql query here because prior to this test another one ran # which submitted a passive checkresult and with livestatus it is only # possible to access the execution of the last result, which in this case # is the passive one without a start and end time. execution_time = float(run_query('SELECT MAX(c.execution_time) AS e_time' ' FROM icinga_hostchecks AS c' ' INNER JOIN icinga_hosts AS h' ' ON h.host_object_id = c.host_object_id' ' WHERE h.alias = "{0}"' ''.format(hostname)).get('e_time', -1)) if execution_time == -1: return fail('Unable to fetch the maximum execution time of' ' host "{0}" from the IDO'.format(hostname)) send_command('DISABLE_HOST_CHECK;{0}'.format(hostname)) scheduled_check = time.time() + 4 send_command('SCHEDULE_HOST_CHECK;{0};{1}'.format(hostname, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if compare_time(last_check, scheduled_check + execution_time): send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) return fail('Could not disable active checks on host "{0}"' ''.format(hostname)) success('Successfully disabled active checks on host "{0}"'.format(hostname)) scheduled_check = time.time() + 4 send_command('SCHEDULE_FORCED_HOST_CHECK;{0};{1}' ''.format(hostname, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if not compare_time(last_check, scheduled_check + execution_time): send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) return fail('Could not schedule a forced check on host "{0}" while' ' active checks were disabled'.format(hostname)) success('Successfully scheduled a forced check on host "{0}" ' 'while active checks were disabled'.format(hostname)) send_command('ENABLE_HOST_CHECK;{0}'.format(hostname)) scheduled_check = time.time() + 4 send_command('SCHEDULE_HOST_CHECK;{0};{1}' ''.format(hostname, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if not compare_time(last_check, scheduled_check + execution_time): return fail('Could not schedule a check after re-enabling ' 'active checks for host "{0}"'.format(hostname)) return success('Successfully scheduled a check on host "{0}" after' ' re-enabling active checks'.format(hostname)) def test_disabling_scheduling_service_checks(hostname, servicename): # This test assumes that icinga is writing the servicechecks db table (DbCatCheck) start_time_query = ('SELECT UNIX_TIMESTAMP(MAX(start_time)) as start_time' ' FROM icinga_servicechecks AS c' ' INNER JOIN icinga_services AS s' ' ON s.service_object_id = c.service_object_id' ' INNER JOIN icinga_hosts as h' ' ON h.host_object_id = s.host_object_id' ' WHERE h.alias = "{0}" AND s.display_name = "{1}"' '').format(hostname, servicename) compare_time = lambda a, b: -2 < a - b < 2 execution_time = float(run_query('SELECT MAX(c.execution_time) AS e_time' ' FROM icinga_servicechecks AS c' ' INNER JOIN icinga_services AS s' ' ON s.service_object_id = c.service_object_id' ' INNER JOIN icinga_hosts as h' ' ON h.host_object_id = s.host_object_id' ' WHERE h.alias = "{0}" AND s.display_name = "{1}"' ''.format(hostname, servicename)).get('e_time', -1)) if execution_time == -1: return fail('Unable to fetch the maximum execution time of service "{0}"' ' on host "{1}" from the IDO'.format(hostname, servicename)) send_command('DISABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) scheduled_check = time.time() + 4 send_command('SCHEDULE_SVC_CHECK;{0};{1};{2}'.format(hostname, servicename, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if compare_time(last_check, scheduled_check + execution_time): send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) return fail('Could not disable active checks for service "{0}" on host' ' "{1}"'.format(servicename, hostname)) success('Successfully disabled active checks for service "{0}" on host' '"{1}"'.format(servicename, hostname)) scheduled_check = time.time() + 4 send_command('SCHEDULE_FORCED_SVC_CHECK;{0};{1};{2}' ''.format(hostname, servicename, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if not compare_time(last_check, scheduled_check + execution_time): send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) return fail('Could not schedule a forced check for service "{0}"' ' on host "{1}" while active checks were disabled' ''.format(servicename, hostname)) success('Successfully scheduled a forced check for service "{0}" ' 'on host "{1}" while active checks were disabled' ''.format(servicename, hostname)) send_command('ENABLE_SVC_CHECK;{0};{1}'.format(hostname, servicename)) scheduled_check = time.time() + 4 send_command('SCHEDULE_SVC_CHECK;{0};{1};{2}' ''.format(hostname, servicename, scheduled_check)) time.sleep(execution_time + 4 + 5) # +5 as this is the transaction interval last_check = float(run_query(start_time_query).get('start_time') or 0) if not compare_time(last_check, scheduled_check + execution_time): return fail('Could not schedule a check after re-enabling ' 'active checks for service "{0}" on host "{1}"' ''.format(servicename, hostname)) return success('Successfully scheduled a check for service "{0}" ' 'on host "{1}" after re-enabling active checks' ''.format(servicename, hostname)) def test_shutdown_restart_process(): get_pid = lambda: subprocess.Popen("ps ax | grep icinga[2] | awk '{print $1}'", shell=1, stdout=subprocess.PIPE).stdout.read() send_command('SHUTDOWN_PROCESS') time.sleep(2) if get_pid(): return fail('Could not stop the icinga2 process by using SHUTDOWN_PROCESS') success('Successfully stopped the icinga2 process with SHUTDOWN_PROCESS') restart_icinga() pid_before_restart = int(get_pid()) send_command('RESTART_PROCESS') LIVESTATUS.close() time.sleep(6) pid_after_restart = get_pid() if not pid_after_restart: restart_icinga() return fail('RESTART_PROCESS seems to just stop the process') if int(pid_after_restart) == pid_before_restart: return fail('RESTART_PROCESS does not restart the process at all') LIVESTATUS.reconnect() return success('Successfully restarted process by using RESTART_PROCESS') def test_passive_host_checkresult_processing(hostname): send_command('PROCESS_HOST_CHECK_RESULT;{0};1;blub'.format(hostname)) host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: state plugin_output'.format(hostname)) if host_info['state'] != 1: return fail('Could not submit a passive checkresult for host "{0}". Wrong' ' state: {1} != 1'.format(hostname, host_info['state'])) if host_info['plugin_output'] != 'blub': return fail('Could not submit a passive checkresult for host "{0}". Wrong' ' output: "{1}" != "blub"'.format(hostname, host_info['plugin_output'])) success('Successfully submitted a passive checkresult for host "{0}"' ''.format(hostname)) send_command('DISABLE_PASSIVE_HOST_CHECKS;{0}'.format(hostname)) send_command('PROCESS_HOST_CHECK_RESULT;{0};0;nope'.format(hostname), True) host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: state'.format(hostname)) if host_info['state'] == 0: send_command('ENABLE_PASSIVE_HOST_CHECKS;{0}'.format(hostname)) return fail('Submitted a passive checkresult for host "{0}" though the' ' submission of passive checkresults has been disabled' ''.format(hostname)) success('It is not possible to submit passive host checkresults' ' while their submission has been disabled') send_command('ENABLE_PASSIVE_HOST_CHECKS;{0}'.format(hostname)) send_command('PROCESS_HOST_CHECK_RESULT;{0};2;nope²'.format(hostname), True) host_info = get_one('GET hosts\nFilter: name = {0}' '\nColumns: plugin_output'.format(hostname)) if host_info['plugin_output'] == 'nope²': return fail('It is possible to submit a passive host checkresult' ' whose status code is 2 (UNREACHABLE)') return success('It is not possible to submit a passive host checkresult' ' whose status code is 2 (UNREACHABLE)') def test_passive_svc_checkresult_processing(hostname, servicename): send_command('PROCESS_SERVICE_CHECK_RESULT;{0};{1};1;blub' ''.format(hostname, servicename)) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: state plugin_output' ''.format(hostname, servicename)) if svc_info['state'] != 1: return fail('Could not submit a passive checkresult for service' ' "{0}" on host "{1}". Wrong state: {2} != 1' ''.format(servicename, hostname, svc_info['state'])) if svc_info['plugin_output'] != 'blub': return fail('Could not submit a passive checkresult for service' ' "{0}" on host "{1}". Wrong output: "{2}" != "blub"' ''.format(servicename, hostname, svc_info['plugin_output'])) success('Successfully submitted a passive checkresult for service' ' "{0}" on host "{1}"'.format(servicename, hostname)) send_command('DISABLE_PASSIVE_SVC_CHECKS;{0};{1}' ''.format(hostname, servicename)) send_command('PROCESS_SERVICE_CHECK_RESULT;{0};{1};0;nope' ''.format(hostname, servicename), True) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}\nColumns: state' ''.format(hostname, servicename)) if svc_info['state'] == 0: send_command('ENABLE_PASSIVE_SVC_CHECKS;{0};{1}' ''.format(hostname, servicename)) return fail('Submitted a passive checkresult for service "{0}" on host ' '"{1}" though the submission of passive checkresults has ' 'been disabled'.format(servicename, hostname)) success('It is not possible to submit passive service checkresults' ' while their submission has been disabled') send_command('ENABLE_PASSIVE_SVC_CHECKS;{0};{1}' ''.format(hostname, servicename)) send_command('PROCESS_SERVICE_CHECK_RESULT;{0};{1};0;yäh!' ''.format(hostname, servicename), True) svc_info = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}\nColumns: plugin_output' ''.format(hostname, servicename)) if svc_info['plugin_output'] != 'yäh!': return fail('It is not possible to submit a passive service checkresult' ' whose output data contains non-ascii characters') return success('It is possible to submit a passive service checkresult' ' whose output data contains non-ascii characters') def test_process_file(hostname): with open('/tmp/comments.txt', 'w') as f: f.write("""[{2}] ADD_HOST_COMMENT;{0};0;{1};TheFirst [{3}] ADD_HOST_COMMENT;{0};0;{1};TheSecond [{4}] ADD_HOST_COMMENT;{0};0;{1};TheThird [{5}] ADD_HOST_COMMENT;{0};0;{1};TheFourth [{6}] ADD_HOST_COMMENT;{0};0;{1};TheFifth """.format(hostname, USERNAME, *[time.time() + i for i in xrange(4, 9)])) os.system('sudo chown {0} /tmp/comments.txt'.format(ICINGA_UID)) send_command('PROCESS_FILE;{0};1'.format('/tmp/comments.txt')) try: with open('/tmp/comments.txt') as f: pass except IOError: success('Files processed by PROCESS_FILE are deleted if' ' the delete-option is set to a non-zero value') else: os.remove('/tmp/comments.txt') return fail('Files processed by PROCESS_FILE are not deleted if' ' the delete-option is set to an non-zero value') comments = send_query('GET comments\nColumns: id\nFilter: comment ~' ' ^The(First|Second|Third|Fourth|Fifth)$') for comment in comments: send_command('DEL_HOST_COMMENT;{0}'.format(comment['id'])) if len(comments) < 5: return fail('Not all commands were processed by PROCESS_FILE') return success('All commands were processed by PROCESS_FILE') def test_custom_host_notifications(hostname): check_time = lambda a, b: -1 < (a - b) < 1 send_command('DISABLE_HOST_NOTIFICATIONS;{0}'.format(hostname)) sent_at = time.time() send_command('SEND_CUSTOM_HOST_NOTIFICATION;{0};0;{1};test' ''.format(hostname, USERNAME)) last_notification = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification' ''.format(hostname))['last_notification'] if check_time(last_notification, sent_at): send_command('ENABLE_HOST_NOTIFICATIONS;{0}'.format(hostname)) return fail('Sent a custom host notification for host "{0}" while' ' notifications were disabled'.format(hostname)) success('It is not possible to send custom host notifications for host' ' "{0}" while notifications are disabled'.format(hostname)) sent_at = time.time() send_command('SEND_CUSTOM_HOST_NOTIFICATION;{0};2;{1};test' ''.format(hostname, USERNAME)) last_notification = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification' ''.format(hostname))['last_notification'] if not check_time(last_notification, sent_at): send_command('ENABLE_HOST_NOTIFICATIONS;{0}'.format(hostname)) return fail('Could not send a forced custom notification for host "{0}"' ' while notifications were disabled'.format(hostname)) success('Successfully sent a forced custom notification for host ' '"{0}" while notifications were disabled'.format(hostname)) send_command('ENABLE_HOST_NOTIFICATIONS;{0}'.format(hostname)) sent_at = time.time() send_command('SEND_CUSTOM_HOST_NOTIFICATION;{0};0;{1};test' ''.format(hostname, USERNAME)) last_notification = get_one('GET hosts\nFilter: name = {0}' '\nColumns: last_notification' ''.format(hostname))['last_notification'] if not check_time(last_notification, sent_at): return fail('Could not send a custom host notification for host "{0}"' ' after notifications were re-enabled'.format(hostname)) return success('Successfully sent a a custom host notification for host "{0}"' ' after notifications were re-enabled'.format(hostname)) def test_custom_svc_notifications(hostname, servicename): check_time = lambda a, b: -1 < (a - b) < 1 send_command('DISABLE_SVC_NOTIFICATIONS;{0};{1}'.format(hostname, servicename)) sent_at = time.time() send_command('SEND_CUSTOM_SVC_NOTIFICATION;{0};{1};0;{2};test' ''.format(hostname, servicename, USERNAME)) last_notification = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename))['last_notification'] if check_time(last_notification, sent_at): send_command('ENABLE_SVC_NOTIFICATIONS;{0};{1}'.format(hostname, servicename)) return fail('Sent a custom service notification for service "{0}" on host "{1}"' ' while notifications were disabled'.format(servicename, hostname)) success('It is not possible to send custom service notifications for service "{0}" on' ' host "{1}" while notifications are disabled'.format(servicename, hostname)) sent_at = time.time() send_command('SEND_CUSTOM_SVC_NOTIFICATION;{0};{1};2;{2};test' ''.format(hostname, servicename, USERNAME)) last_notification = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename))['last_notification'] if not check_time(last_notification, sent_at): send_command('ENABLE_SVC_NOTIFICATIONS;{0};{1}'.format(hostname, servicename)) return fail('Could not send a forced custom notification for service "{0}" on host ' '"{1}" while notifications were disabled'.format(servicename, hostname)) success('Successfully sent a forced custom notification for service "{0}" on host' ' "{0}" while notifications were disabled'.format(servicename, hostname)) send_command('ENABLE_SVC_NOTIFICATIONS;{0};{1}'.format(hostname, servicename)) sent_at = time.time() send_command('SEND_CUSTOM_SVC_NOTIFICATION;{0};{1};0;{2};test' ''.format(hostname, servicename, USERNAME)) last_notification = get_one('GET services\nFilter: host_name = {0}' '\nFilter: description = {1}' '\nColumns: last_notification' ''.format(hostname, servicename))['last_notification'] if not check_time(last_notification, sent_at): return fail('Could not send a custom service notification for service "{0}" on host ' '"{1}" after notifications were re-enabled'.format(servicename, hostname)) return success('Successfully sent a custom service notification for service "{0}" on host' ' "{1}" after notifications were re-enabled'.format(servicename, hostname)) def test_hostgroup_commands(): # This test requires the "files/configs/groups.conf" configuration file failure = False send_command('CHANGE_HOST_MODATTR;localhost;0') localhost_services = [d['description'] for d in send_query('GET services\nColumns: description' '\nFilter: host_name = localhost')] for svc_desc in localhost_services: send_command('CHANGE_SVC_MODATTR;localhost;{0};0'.format(svc_desc)) send_command('DISABLE_HOSTGROUP_HOST_CHECKS;linux-servers') send_command('DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS;linux-servers') send_command('DISABLE_HOSTGROUP_HOST_NOTIFICATIONS;linux-servers') host_info = get_one('GET hosts\nFilter: name = localhost') if host_info['active_checks_enabled'] != 0: fail('Could not disable active checks for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully disabled active checks for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) if host_info['accept_passive_checks'] != 0: fail('Could not disable passive checks for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully disabled passive checks for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) if host_info['notifications_enabled'] != 0: fail('Could not disable notifications for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully disabled notifications for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) send_command('ENABLE_HOSTGROUP_HOST_CHECKS;linux-servers') send_command('ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS;linux-servers') send_command('ENABLE_HOSTGROUP_HOST_NOTIFICATIONS;linux-servers') host_info = get_one('GET hosts\nFilter: name = localhost') if host_info['active_checks_enabled'] != 1: fail('Could not enable active checks for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully enabled active checks for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) if host_info['accept_passive_checks'] != 1: fail('Could not enable passive checks for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully enabled passive checks for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) if host_info['notifications_enabled'] != 1: fail('Could not enable notifications for host "{0}" that is part' ' of hostgroup "linux-servers"'.format(host_info['name'])) failure = True else: success('Successfully enabled notifications for host "{0}" that is ' 'part of hostgroup "linux-servers"'.format(host_info['name'])) send_command('DISABLE_HOSTGROUP_SVC_CHECKS;linux-servers') send_command('DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS;linux-servers') send_command('DISABLE_HOSTGROUP_SVC_NOTIFICATIONS;linux-servers') for svc_info in send_query('GET services\nFilter: host_name = localhost'): if svc_info['active_checks_enabled'] != 0: fail('Could not disable active checks for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully disabled active checks for service "{0}" ' 'on host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) if svc_info['accept_passive_checks'] != 0: fail('Could not disable passive checks for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully disabled passive checks for service "{0}" ' 'on host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) if svc_info['notifications_enabled'] != 0: fail('Could not disable notifications for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully disabled notifications for service "{0}" on' ' host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) send_command('ENABLE_HOSTGROUP_SVC_CHECKS;linux-servers') send_command('ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS;linux-servers') send_command('ENABLE_HOSTGROUP_SVC_NOTIFICATIONS;linux-servers') for svc_info in send_query('GET services\nFilter: host_name = localhost'): if svc_info['active_checks_enabled'] != 1: fail('Could not enable active checks for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully enabled active checks for service "{0}" ' 'on host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) if svc_info['accept_passive_checks'] != 1: fail('Could not enable passive checks for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully enabled passive checks for service "{0}" ' 'on host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) if svc_info['notifications_enabled'] != 1: fail('Could not enable notifications for service "{0}" on ' 'host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) failure = True else: success('Successfully enabled notifications for service "{0}" on' ' host "{1}" that is part of hostgroup "linux-servers"' ''.format(svc_info['description'], svc_info['host_name'])) return failure def test_servicegroup_commands(): # This test requires the "files/configs/groups.conf" configuration file failure = False send_command('CHANGE_HOST_MODATTR;localhost;0') aservicegroup_services = send_query('GET services\nColumns: description host_name' '\nFilter: groups >= aservicegroup') for svc_info in aservicegroup_services: send_command('CHANGE_SVC_MODATTR;{0};{1};0'.format(svc_info['host_name'], svc_info['description'])) send_command('DISABLE_SERVICEGROUP_HOST_CHECKS;aservicegroup') send_command('DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS;aservicegroup') send_command('DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS;aservicegroup') aservicegroup_hosts = send_query('GET hosts\nFilter: name = localhost') for host_info in aservicegroup_hosts: if host_info['active_checks_enabled'] != 0: fail('Could not disable active checks for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully disabled active checks for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) if host_info['accept_passive_checks'] != 0: fail('Could not disable passive checks for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully disabled passive checks for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) if host_info['notifications_enabled'] != 0: fail('Could not disable notifications for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully disabled notifications for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) send_command('ENABLE_SERVICEGROUP_HOST_CHECKS;aservicegroup') send_command('ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS;aservicegroup') send_command('ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS;aservicegroup') aservicegroup_hosts = send_query('GET hosts\nFilter: name = localhost') for host_info in aservicegroup_hosts: if host_info['active_checks_enabled'] != 1: fail('Could not enable active checks for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully enabled active checks for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) if host_info['accept_passive_checks'] != 1: fail('Could not enable passive checks for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully enabled passive checks for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) if host_info['notifications_enabled'] != 1: fail('Could not enable notifications for host "{0}" which has' ' services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) failure = True else: success('Successfully enabled notifications for host "{0}" which ' 'has services that are part of servicegroup "aservicegroup"' ''.format(host_info['name'])) send_command('DISABLE_SERVICEGROUP_SVC_CHECKS;aservicegroup') send_command('DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS;aservicegroup') send_command('DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS;aservicegroup') aservicegroup_services = send_query('GET services\nFilter: groups >= aservicegroup') for svc_info in aservicegroup_services: if svc_info['active_checks_enabled'] != 0: fail('Could not disable active checks for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully disabled active checks for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) if svc_info['accept_passive_checks'] != 0: fail('Could not disable passive checks for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully disabled passive checks for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) if svc_info['notifications_enabled'] != 0: fail('Could not disable notifications for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully disabled notifications for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) send_command('ENABLE_SERVICEGROUP_SVC_CHECKS;aservicegroup') send_command('ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS;aservicegroup') send_command('ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS;aservicegroup') aservicegroup_services = send_query('GET services\nFilter: groups >= aservicegroup') for svc_info in aservicegroup_services: if svc_info['active_checks_enabled'] != 1: fail('Could not enable active checks for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully enabled active checks for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) if svc_info['accept_passive_checks'] != 1: fail('Could not enable passive checks for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully enabled passive checks for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) if svc_info['notifications_enabled'] != 1: fail('Could not enable notifications for service "{0}"' ' that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) failure = True else: success('Successfully enabled notifications for service ' '"{0}" that is part of servicegroup "aservicegroup"' ''.format(svc_info['description'])) return failure def main(): failure = test_host_comments('localhost') #failure |= test_host_comments('nsca-ng') # Cannot work without a hostcheck! failure |= test_service_comments('localhost', 'disk') failure |= test_service_comments('nsca-ng', 'PassiveService1') failure |= test_host_downtimes('localhost') #failure |= test_host_downtimes('nsca-ng') failure |= test_service_downtimes('localhost', 'disk') failure |= test_service_downtimes('nsca-ng', 'PassiveService1') failure |= test_host_problem_acknowledgements('localhost') failure |= test_remove_host_acknowledgements('localhost') failure |= test_expiring_host_acknowledgements('localhost') failure |= test_change_host_check_command('localhost', 'disk') failure |= test_change_service_check_command('localhost', 'disk', 'ping4') failure |= test_change_host_check_timeperiod('localhost', 'none') failure |= test_change_service_check_timeperiod('localhost', 'disk', 'none') failure |= test_change_host_max_check_attempts('localhost') failure |= test_change_service_max_check_attempts('localhost', 'disk') failure |= test_change_host_normal_check_interval('localhost') failure |= test_change_service_normal_check_interval('localhost', 'disk') failure |= test_change_host_retry_check_interval('localhost') failure |= test_change_service_retry_check_interval('localhost', 'disk') failure |= test_change_host_modified_attributes('localhost') failure |= test_delay_service_notification('localhost', 'disk') failure |= test_delay_host_notification('localhost') failure |= test_disabling_scheduling_host_checks('localhost') failure |= test_disabling_scheduling_service_checks('localhost', 'disk') failure |= test_shutdown_restart_process() failure |= test_passive_host_checkresult_processing('localhost') failure |= test_passive_svc_checkresult_processing('localhost', 'disk') failure |= test_process_file('localhost') failure |= test_custom_host_notifications('localhost') failure |= test_custom_svc_notifications('localhost', 'disk') failure |= test_hostgroup_commands() failure |= test_servicegroup_commands() return 1 if failure else 0 if __name__ == '__main__': try: with utils.LiveStatusSocket(LIVESTATUS_PATH) as LIVESTATUS: sys.exit(main()) except (OSError, IOError, socket.error), e: error('Could not connect to Livestatus socket: {0} ({1})' ''.format(LIVESTATUS_PATH, unicode(e))) icinga2-2.8.1/test/jenkins/files/000077500000000000000000000000001322762156600165725ustar00rootroot00000000000000icinga2-2.8.1/test/jenkins/files/configs/000077500000000000000000000000001322762156600202225ustar00rootroot00000000000000icinga2-2.8.1/test/jenkins/files/configs/checkresult.conf000066400000000000000000000001441322762156600234040ustar00rootroot00000000000000library "compat" object CheckResultReader "reader" { spool_dir = "/tmp/icinga2/checkresults" } icinga2-2.8.1/test/jenkins/files/configs/eventhandler.conf000066400000000000000000000036251322762156600235560ustar00rootroot00000000000000object EventCommand "test_event" { import "plugin-event-command", command = {{{echo "\ $$HOSTNAME$HOSTNAME$\ |HOSTNAME=$HOSTNAME$\ |HOSTDISPLAYNAME=$HOSTDISPLAYNAME$\ |HOSTALIAS=$HOSTALIAS$\ |HOSTSTATE=$HOSTSTATE$\ |HOSTSTATEID=$HOSTSTATEID$\ |HOSTSTATETYPE=$HOSTSTATETYPE$\ |HOSTATTEMPT=$HOSTATTEMPT$\ |MAXHOSTATTEMPT=$MAXHOSTATTEMPT$\ |LASTHOSTSTATE=$LASTHOSTSTATE$\ |LASTEHOSTSTATEID=$LASTHOSTSTATEID$\ |LASTHOSTSTATETYPE=$LASTHOSTSTATETYPE$\ |LASTHOSTSTATECHANGE=$LASTHOSTSTATECHANGE$\ |HOSTDURATIONSEC=$HOSTDURATIONSEC$\ |HOSTLATENCY=$HOSTLATENCY$\ |HOSTEXECUTIONTIME=$HOSTEXECUTIONTIME$\ |HOSTOUTPUT=$HOSTOUTPUT$\ |HOSTPERFDATA=$HOSTPERFDATA$\ |LASTHOSTCHECK=$LASTHOSTCHECK$\ |HOSTADDRESS=$HOSTADDRESS$\ |HOSTADDRESS6=$HOSTADDRESS6$\ |SERVICEDESC=$SERVICEDESC$\ |SERVICEDISPLAYNAME=$SERVICEDISPLAYNAME$\ |SERVICECHECKCOMMAND=$SERVICECHECKCOMMAND$\ |SERVICESTATE=$SERVICESTATE$\ |SERVICESTATEID=$SERVICESTATEID$\ |SERVICESTATETYPE=$SERVICESTATETYPE$\ |SERVICEATTEMPT=$SERVICEATTEMPT$\ |MAXSERVICEATTEMPT=$MAXSERVICEATTEMPT$\ |LASTSERVICESTATE=$LASTSERVICESTATE$\ |LASTSERVICESTATEID=$LASTSERVICESTATEID$\ |LASTSERVICESTATETYPE=$LASTSERVICESTATETYPE$\ |LASTSERVICESTATECHANGE=$LASTSERVICESTATECHANGE$\ |SERVICEDURATIONSEC=$SERVICEDURATIONSEC$\ |SERVICELATENCY=$SERVICELATENCY$\ |SERVICEEXECUTIONTIME=$SERVICEEXECUTIONTIME$\ |SERVICEOUTPUT=$SERVICEOUTPUT$\ |SERVICEPERFDATA=$SERVICEPERFDATA$\ |LASTSERVICECHECK=$LASTSERVICECHECK$\ |TOTALHOSTSERVICES=$TOTALHOSTSERVICES$\ |TOTALHOSTSERVICESOK=$TOTALHOSTSERVICESOK$\ |TOTALHOSTSERVICESWARNING=$TOTALHOSTSERVICESWARNING$\ |TOTALHOSTSERVICESUNKNOWN=$TOTALHOSTSERVICESUNKNOWN$\ |TOTALHOSTSERVICESCRITICAL=$TOTALHOSTSERVICESCRITICAL$\ |TIMET=$TIMET$\ |LONGDATETIME=$LONGDATETIME$\ |SHORTDATETIME=$SHORTDATETIME$\ |DATE=$DATE$\ |TIME=$TIME$\ |custom_macro=$custom_macro$\ " > /tmp/test_event.out}}}, export_macros = ["HOSTNAME"], macros = { custom_macro = 1337 } } icinga2-2.8.1/test/jenkins/files/configs/groups.conf000066400000000000000000000014001322762156600224030ustar00rootroot00000000000000/** * A new service group required by external_commands.test::test_servicegroup_commands */ object ServiceGroup "aservicegroup" { display_name = "aServiceGroup" } /** * The two default hostgroups */ object HostGroup "linux-servers" { display_name = "Linux Servers" } object HostGroup "windows-servers" { display_name = "Windows Servers" } /** * This template is essentially the same as the default one but with a servicegroup added */ template Service "generic-service" { max_check_attempts = 3, check_interval = 5m, retry_interval = 1m, enable_perfdata = true, groups = ["aservicegroup"], notifications["mail-icingaadmin"] = { templates = [ "mail-notification" ], user_groups = [ "icingaadmins" ] } } icinga2-2.8.1/test/jenkins/files/configs/ido_checkresults.conf000066400000000000000000000010561322762156600244250ustar00rootroot00000000000000/** * This is a copy of the default configuration file "ido-mysql.conf" with the "categories" attribute added */ library "db_ido_mysql" object IdoMysqlConnection "ido-mysql" { user = "icinga", password = "icinga", host = "localhost", database = "icinga", categories = (DbCatCheck | DbCatConfig | DbCatState | DbCatAcknowledgement | DbCatComment | DbCatDowntime | DbCatEventHandler | DbCatExternalCommand | DbCatFlapping | DbCatLog | DbCatNotification | DbCatProgramStatus | DbCatRetention | DbCatStateHistory) } icinga2-2.8.1/test/jenkins/files/configs/notifications.conf000066400000000000000000000027251322762156600237500ustar00rootroot00000000000000/** * This template is essentially the same as the default one but with a customised notification_interval */ template Notification "mail-notification" { notification_command = "mail-service-notification", notification_state_filter = (StateFilterWarning | StateFilterCritical | StateFilterUnknown), notification_type_filter = (NotificationFilterProblem | NotificationFilterAcknowledgement | NotificationFilterRecovery | NotificationFilterCustom | NotificationFilterFlappingStart | NotificationFilterFlappingEnd | NotificationFilterDowntimeStart | NotificationFilterDowntimeEnd | NotificationFilterDowntimeRemoved), notification_period = "24x7", notification_interval = 10 } /** * 1:1 copy of the default command */ object NotificationCommand "mail-service-notification" { import "plugin-notification-command", command = [ (SysconfDir + "/icinga2/scripts/mail-notification.sh") ], export_macros = [ "NOTIFICATIONTYPE", "SERVICEDESC", "HOSTALIAS", "HOSTADDRESS", "SERVICESTATE", "LONGDATETIME", "SERVICEOUTPUT", "NOTIFICATIONAUTHORNAME", "NOTIFICATIONCOMMENT", "HOSTDISPLAYNAME", "SERVICEDISPLAYNAME", "USEREMAIL" ] } icinga2-2.8.1/test/jenkins/files/ido_tests.py000066400000000000000000000173401322762156600211460ustar00rootroot00000000000000from __future__ import unicode_literals import sys from datetime import datetime, timedelta import utils CHECK_INTERVAL = 10 # minutes; The actual interval is 5 minutes but as other # tests might restart Icinga we need to take any # rescheduling into account TABLE_PREFIX = 'icinga_' TABLES = [ # Central tables 'instances', 'objects', # Debugging tables 'conninfo', # Historical tables 'acknowledgements', 'commenthistory', 'contactnotifications', 'dbversion', 'downtimehistory', 'eventhandlers', 'externalcommands', 'flappinghistory', 'hostchecks', 'logentries', 'notifications', 'processevents', 'servicechecks', 'statehistory', 'systemcommands', # Current status tables 'comments', 'customvariablestatus', 'hoststatus', 'programstatus', 'runtimevariables', 'scheduleddowntime', 'servicestatus', 'contactstatus', # Configuration tables 'commands', 'configfiles', 'configfilevariables', 'contact_addresses', 'contact_notificationcommands', 'contactgroup_members', 'contactgroups', 'contactnotificationmethods', 'contacts', 'customvariables', 'host_contactgroups', 'host_contacts', 'host_parenthosts', 'hostdependencies', 'hostescalation_contactgroups', 'hostescalation_contacts', 'hostescalations', 'hostgroup_members', 'hostgroups', 'hosts', 'service_contactgroups', 'service_contacts', 'servicedependencies', 'serviceescalation_contactgroups', 'serviceescalation_contacts', 'serviceescalations', 'servicegroup_members', 'servicegroups', 'services', 'timeperiod_timeranges', 'timeperiods' ] EXAMPLE_CONFIG = { 'localhost': ['disk', 'http', 'icinga', 'load', 'ping4', 'ping6', 'procs', 'ssh', 'users'], 'nsca-ng': ['PassiveService1', 'PassiveService2'] } def validate_tables(tables): """ Return whether all tables of the IDO database scheme exist in the given table listing """ utils.Logger.info('Checking database scheme... (tables)\n') failures = False for table in (TABLE_PREFIX + n for n in TABLES): if table in tables: utils.Logger.ok('Found table "{0}" in database\n'.format(table)) else: utils.Logger.fail('Could not find table "{0}" in database\n' ''.format(table)) failures = True return not failures def verify_host_config(config_data): """ Return whether the example hosts exist in the given "hosts" table """ utils.Logger.info('Checking example host configuration...\n') failures = False for hostname in EXAMPLE_CONFIG: if not any(1 for e in config_data if e['alias'] == hostname): utils.Logger.fail('Could not find host "{0}"\n'.format(hostname)) failures = True else: utils.Logger.ok('Found host "{0}"\n'.format(hostname)) return not failures def verify_service_config(config_data): """ Return whether the example services exist in the given "services" table """ utils.Logger.info('Checking example service configuration...\n') failures = False for hostname, servicename in ((h, s) for h, ss in EXAMPLE_CONFIG.iteritems() for s in ss): if not any(1 for c in config_data if c['alias'] == hostname and c['display_name'] == servicename): utils.Logger.fail('Could not find service "{0}" on host "{1}"\n' ''.format(servicename, hostname)) failures = True else: utils.Logger.ok('Found service "{0}" on host "{1}"\n' ''.format(servicename, hostname)) return not failures def check_last_host_status_update(check_info): """ Return whether the example hosts are checked as scheduled """ utils.Logger.info('Checking last host status updates...\n') failures = False for host_info in check_info: if host_info['alias'] == 'localhost': last_check = datetime.fromtimestamp(float(host_info['last_check'])) if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL, seconds=10): utils.Logger.fail('The last status update of host "{0}" was' ' more than {1} minutes ago\n' ''.format(host_info['alias'], CHECK_INTERVAL)) failures = True else: utils.Logger.ok('Host "{0}" is being updated\n' ''.format(host_info['alias'])) elif host_info['alias'] == 'nsca-ng': if float(host_info['last_check']) > 0: utils.Logger.fail('The host "{0}" was checked even' ' though it has no check service' ''.format(host_info['alias'])) failures = True else: utils.Logger.ok('Host "{0}" is not being checked because ' 'there is no check service\n' ''.format(host_info['alias'])) else: utils.Logger.info('Skipping host "{0}"\n' ''.format(host_info['alias'])) return not failures def check_last_service_status_update(check_info): """ Return whether the example services are checked as scheduled """ utils.Logger.info('Checking last service status updates...\n') failures = False for svc_info in check_info: if svc_info['display_name'] in EXAMPLE_CONFIG.get(svc_info['alias'], []): last_check = datetime.fromtimestamp(float(svc_info['last_check'])) if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL, seconds=10): utils.Logger.fail('The last status update of service "{0}" on ' 'host "{1}" was more than {2} minutes ago\n' ''.format(svc_info['display_name'], svc_info['alias'], CHECK_INTERVAL)) failures = True else: utils.Logger.ok('Service "{0}" on host "{1}" is being updated\n' ''.format(svc_info['display_name'], svc_info['alias'])) else: utils.Logger.info('Skipping service "{0}" on host "{1}"\n' ''.format(svc_info['display_name'], svc_info['alias'])) return not failures def check_logentries(logentry_info): """ Return whether the given logentry originates from host "localhost" and refers to its very last hard status change """ utils.Logger.info('Checking status log for host "localhost"...\n') if logentry_info and logentry_info[0]['alias'] == 'localhost': entry_time = datetime.fromtimestamp(float(logentry_info[0]['entry_time'])) state_time = datetime.fromtimestamp(float(logentry_info[0]['state_time'])) if entry_time - state_time > timedelta(seconds=10): utils.Logger.fail('The last hard state of host "localhost"' ' seems not to have been logged\n') return False else: utils.Logger.fail('No logs found in the IDO for host "localhost"\n') return False utils.Logger.ok('The last hard state of host "localhost"' ' was properly logged\n') return True icinga2-2.8.1/test/jenkins/files/utils.py000066400000000000000000000203271322762156600203100ustar00rootroot00000000000000from __future__ import unicode_literals import os import sys import time import json import socket import subprocess __all__ = ['parse_statusdata', 'run_mysql_query', 'run_pgsql_query', 'LiveStatusSocket'] MYSQL_PARAMS = b"-t -D icinga -u icinga --password=icinga -e".split() MYSQL_SEPARATOR = '|' PGSQL_PARAMS = b"-nq -U icinga -d icinga -c".split() PGSQL_SEPARATOR = '|' PGSQL_ENVIRONMENT = { b'PGPASSWORD': b'icinga' } def parse_statusdata(data, intelligent_cast=True): parsed_data, data_type, type_data = {}, '', {} for line in (l for l in data.split(os.linesep) if l and not l.startswith('#')): if '{' in line: data_type = line.partition('{')[0].strip() elif '}' in line: parsed_data.setdefault(data_type, []).append(type_data) else: key, _, value = line.partition('=') if intelligent_cast: value = _cast_status_value(value) type_data[key.strip()] = value return parsed_data def _cast_status_value(value): try: return int(value) except ValueError: try: return float(value) except ValueError: return value def run_mysql_query(query, path): p = subprocess.Popen([path] + MYSQL_PARAMS + [query.encode('utf-8')], stdout=subprocess.PIPE) Logger.debug('Sent MYSQL query: {0!r}\n'.format(query)) resultset = [l.decode('utf-8') for l in p.stdout.readlines()] Logger.debug('Received MYSQL resultset: {0!r}\n' ''.format(''.join(resultset)), True) return _parse_mysql_result(resultset) def _parse_mysql_result(resultset): result, header = [], None for line in (l for l in resultset if MYSQL_SEPARATOR in l): columns = [c.strip() for c in line[1:-3].split(MYSQL_SEPARATOR)] if header is None: header = columns else: result.append(dict((header[i], v if v != 'NULL' else None) for i, v in enumerate(columns))) return result def run_pgsql_query(query, path): p = subprocess.Popen([path] + PGSQL_PARAMS + [query.encode('utf-8')], stdout=subprocess.PIPE, env=PGSQL_ENVIRONMENT) Logger.debug('Sent PostgreSQL query: {0!r}\n'.format(query)) resultset = [l.decode('utf-8') for l in p.stdout.readlines()] Logger.debug('Received PostgreSQL resultset: {0!r}\n' ''.format(''.join(resultset)), True) return _parse_pgsql_result(resultset) def _parse_pgsql_result(resultset): result, header = [], None for line in (l for l in resultset if PGSQL_SEPARATOR in l): columns = [c.strip() for c in line.split(PGSQL_SEPARATOR)] if header is None: header = columns else: result.append(dict((header[i], v) for i, v in enumerate(columns))) return result class LiveStatusError(Exception): pass class LiveStatusSocket(object): options = [ 'KeepAlive: on', 'OutputFormat: json', 'ResponseHeader: fixed16' ] def __init__(self, path): self.path = path self._connected = False def __enter__(self): self.connect() return self def __exit__(self, exc_type, exc_value, tb): self.close() def connect(self): self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) Logger.debug('Opened UNIX stream socket\n', True) self.sock.connect(self.path) Logger.debug('Connected to Livestatus socket: {0}\n'.format(self.path), True) self._connected = True def reconnect(self, timeout=30): Logger.debug('Reconnecting to Livestatus socket\n', True) start = time.time() while not self._connected and time.time() - start < timeout: try: self.connect() except socket.error, error: Logger.debug('Could not connect: {0}\n'.format(error), True) # Icinga2 does some "magic" with the socket during startup # which causes random errors being raised (EACCES, ENOENT, ..) # so we just ignore them until the timeout is reached time.sleep(1) if not self._connected: # Raise the very last exception once the timeout is reached raise def close(self): if self._connected: self.sock.shutdown(socket.SHUT_RDWR) Logger.debug('Shutted down Livestatus connection\n', True) self.sock.close() Logger.debug('Closed Livestatus socket\n', True) self._connected = False def query(self, command): self.send(command) statuscode, response = self.recv() if statuscode != 200: raise LiveStatusError(statuscode, response) return response def send(self, query): if not self._connected: raise RuntimeError('Tried to write to closed socket') full_query = '\n'.join([query] + self.options) self.sock.sendall((full_query + '\n\n').encode('utf-8')) Logger.debug('Sent Livestatus query: {0!r}\n'.format(full_query)) def recv(self): if not self._connected: raise RuntimeError('Tried to read from closed socket') response = b'' response_header = self.sock.recv(16) response_code = int(response_header[:3]) response_length = int(response_header[3:].strip()) if response_length > 0: while len(response) < response_length: response += self.sock.recv(response_length - len(response)) response = response.decode('utf-8') try: response = json.loads(response) except ValueError: pass Logger.debug('Received Livestatus response: {0!r} (Header was: {1!r})' '\n'.format(response, response_header), True) return response_code, response class Logger(object): INFO = 1 OK = 2 FAIL = 3 ERROR = 4 DEBUG_STD = 5 DEBUG_EXT = 6 VERBOSITY = None @classmethod def permitted(cls, severity): if cls.VERBOSITY is None: cls.VERBOSITY = next((int(sys.argv.pop(i).partition('=')[2]) for i, a in enumerate(sys.argv) if a.startswith('--verbosity=')), 1) return (severity == cls.INFO and cls.VERBOSITY >= 1) or \ (severity == cls.OK and cls.VERBOSITY >= 1) or \ (severity == cls.FAIL and cls.VERBOSITY >= 1) or \ (severity == cls.ERROR and cls.VERBOSITY >= 1) or \ (severity == cls.DEBUG_STD and cls.VERBOSITY >= 2) or \ (severity == cls.DEBUG_EXT and cls.VERBOSITY >= 3) @staticmethod def write(text, stderr=False): if stderr: sys.stderr.write(text) sys.stderr.flush() else: sys.stdout.write(text) sys.stdout.flush() @classmethod def log(cls, severity, text): if severity == cls.INFO and cls.permitted(cls.INFO): cls.write('\x00[INFO] {0}'.format(text)) elif severity == cls.ERROR and cls.permitted(cls.ERROR): cls.write('\x00[ERROR] {0}'.format(text)) elif severity == cls.FAIL and cls.permitted(cls.FAIL): cls.write('\x00[FAIL] {0}'.format(text)) elif severity == cls.OK and cls.permitted(cls.OK): cls.write('\x00[OK] {0}'.format(text)) elif severity == cls.DEBUG_STD and cls.permitted(cls.DEBUG_STD): cls.write('\x00\x00[DEBUG] {0}'.format(text)) elif severity == cls.DEBUG_EXT and cls.permitted(cls.DEBUG_EXT): cls.write('\x00\x00\x00\x00[DEBUG] {0}'.format(text)) else: return False return True @classmethod def info(cls, text): return cls.log(cls.INFO, text) @classmethod def error(cls, text): return cls.log(cls.ERROR, text) @classmethod def fail(cls, text): return cls.log(cls.FAIL, text) @classmethod def ok(cls, text): return cls.log(cls.OK, text) @classmethod def debug(cls, text, extended=False): return cls.log(cls.DEBUG_EXT if extended else cls.DEBUG_STD, text) icinga2-2.8.1/test/jenkins/files/wait_for_ido.sh000077500000000000000000000013231322762156600215750ustar00rootroot00000000000000#!/bin/sh TIMEOUT=30 case $1 in mysql) TYPE='MySQL' CMD='/usr/bin/mysql -t -D icinga -u icinga --password=icinga -e' ;; pgsql) TYPE='PostgreSQL' CMD='/usr/bin/psql -nq -U icinga -d icinga -c' export PGPASSWORD='icinga' ;; *) echo "No IDO type specifier given!" exit 1 ;; esac tries=1 while true do out="`$CMD 'select * from icinga_hosts'`" if [ $tries -lt $TIMEOUT ] && [ "$out" == "" ]; then sleep 1 tries=$(($tries + 1)) else if [ $tries -eq $TIMEOUT ]; then echo "IDO ($TYPE) does not have any hosts or is not responding" >&2 fi break fi done icinga2-2.8.1/test/jenkins/icinga2_state.test000077500000000000000000000002641322762156600211120ustar00rootroot00000000000000#!/bin/sh sudo service icinga2 status &> /dev/null if [ $? -gt 0 ]; then echo '[FAIL] icinga2 is not running' exit 1 else echo '[OK] icinga2 is running' exit 0 fi icinga2-2.8.1/test/jenkins/ido_mysql.test000077500000000000000000000045061322762156600204010ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import unicode_literals import sys import utils import ido_tests def main(): failures = False run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql') if not ido_tests.validate_tables([d['Tables_in_icinga'] for d in run_query('show tables')]): return 1 # Bail out as we cannot proceed without any data host_info = run_query('select * from icinga_hosts') if not ido_tests.verify_host_config(host_info): return 1 # Bail out as we cannot proceed without any data service_info = run_query( 'select c2.alias, c1.* from icinga_services as c1 ' 'inner join icinga_hosts as c2' ' on c1.host_object_id = c2.host_object_id' ) if not ido_tests.verify_service_config(service_info): return 1 # Bail out as we cannot proceed without any data hostchecks_data = run_query( 'select c.alias, unix_timestamp(s.last_check) as last_check' ' from icinga_hoststatus as s ' 'inner join icinga_hosts as c' ' on s.host_object_id = c.host_object_id' ) if not ido_tests.check_last_host_status_update(hostchecks_data): failures = True servicechecks_data = run_query( 'select c2.alias, c1.display_name, unix_timestamp(s.last_check) as last_check' ' from icinga_servicestatus as s ' 'inner join icinga_services as c1' ' on s.service_object_id = c1.service_object_id ' 'inner join icinga_hosts as c2' ' on c1.host_object_id = c2.host_object_id' ) if not ido_tests.check_last_service_status_update(servicechecks_data): failures = True logentry_info = run_query( 'select hosts.alias,' ' max(unix_timestamp(logs.entry_time)) as entry_time,' ' max(unix_timestamp(hist.state_time)) as state_time' ' from icinga_logentries as logs ' 'inner join icinga_hosts as hosts' ' on logs.object_id = hosts.host_object_id and hosts.alias = "localhost" ' 'inner join icinga_statehistory as hist' ' on hist.object_id = hosts.host_object_id and hist.state_type = 1' ) if not ido_tests.check_logentries(logentry_info): failures = True return 1 if failures else 0 if __name__ == '__main__': sys.exit(main()) icinga2-2.8.1/test/jenkins/ido_pgsql.test000077500000000000000000000046011322762156600203560ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import unicode_literals import sys import utils import ido_tests def main(): failures = False run_query = lambda q: utils.run_pgsql_query(q, b'/usr/bin/psql') if not ido_tests.validate_tables([d['Name'] for d in run_query('\\dt') if d['Type'] == 'table']): return 1 # Bail out as we cannot proceed without any data host_info = run_query('select * from icinga_hosts') if not ido_tests.verify_host_config(host_info): return 1 # Bail out as we cannot proceed without any data service_info = run_query( 'select c2.alias, c1.* from icinga_services as c1 ' 'inner join icinga_hosts as c2' ' on c1.host_object_id = c2.host_object_id' ) if not ido_tests.verify_service_config(service_info): return 1 # Bail out as we cannot proceed without any data hostchecks_data = run_query( 'select c.alias, unix_timestamp(s.last_check) as last_check' ' from icinga_hoststatus as s ' 'inner join icinga_hosts as c' ' on s.host_object_id = c.host_object_id' ) if not ido_tests.check_last_host_status_update(hostchecks_data): failures = True servicechecks_data = run_query( 'select c2.alias, c1.display_name, unix_timestamp(s.last_check) as last_check' ' from icinga_servicestatus as s ' 'inner join icinga_services as c1' ' on s.service_object_id = c1.service_object_id ' 'inner join icinga_hosts as c2' ' on c1.host_object_id = c2.host_object_id' ) if not ido_tests.check_last_service_status_update(servicechecks_data): failures = True logentry_info = run_query( 'select hosts.alias,' ' max(unix_timestamp(logs.entry_time)) as entry_time,' ' max(unix_timestamp(hist.state_time)) as state_time' ' from icinga_logentries as logs ' 'inner join icinga_hosts as hosts' ' on logs.object_id = hosts.host_object_id ' 'inner join icinga_statehistory as hist' ' on hist.object_id = hosts.host_object_id ' "where hosts.alias = 'localhost' and hist.state_type = 1 " 'group by hosts.alias' ) if not ido_tests.check_logentries(logentry_info): failures = True return 1 if failures else 0 if __name__ == '__main__': sys.exit(main()) icinga2-2.8.1/test/jenkins/livestatus_socket.test000077500000000000000000000006541322762156600221540ustar00rootroot00000000000000#!/bin/sh livestatus_path="/var/run/icinga2/cmd/livestatus" if [ ! -e $livestatus_path ]; then sudo icinga2 feature enable livestatus 1> /dev/null sudo service icinga2 restart 1> /dev/null sleep 1 if [ ! -e $livestatus_path ]; then echo "[FAIL] Icinga2 Livestatus socket not found ($livestatus_path)" exit 1 fi fi echo "[OK] Icinga2 Livestatus socket found ($livestatus_path)" exit 0 icinga2-2.8.1/test/jenkins/logfile.test000077500000000000000000000003561322762156600200210ustar00rootroot00000000000000#!/bin/sh logfile_path="/var/log/icinga2/icinga2.log" if sudo test -f $logfile_path; then echo "[OK] Icinga2 log file found ($logfile_path)" exit 0 else echo "[FAIL] Icinga2 log file not found ($logfile_path)" exit 1 fi icinga2-2.8.1/test/jenkins/mysql_state.test000077500000000000000000000002611322762156600207400ustar00rootroot00000000000000#!/bin/sh sudo service mysqld status &> /dev/null if [ $? -gt 0 ]; then echo '[FAIL] mysqld is not running' exit 1 else echo '[OK] mysqld is running' exit 0 fi icinga2-2.8.1/test/jenkins/nsca-ng.test000077500000000000000000000017221322762156600177240ustar00rootroot00000000000000#!/bin/sh pid_before_restart=`ps -U icinga | grep icinga2 | awk '{print $1}'` echo 'RESTART_PROCESS' | sudo send_nsca -C sleep 3 pid_after_restart=`ps -U icinga | grep icinga2 | awk '{print $1}'` if [ $pid_after_restart -eq $pid_before_restart ]; then echo "[FAIL] Failed to send 'RESTART_PROCESS' to icinga2" exit 1 else echo "[OK] Successfully sent 'RESTART_PROCESS' to icinga2" fi printf "localhost\t0\tA passive result returning OK\n" | sudo send_nsca if [ $? -gt 0 ]; then echo "[FAIL] Failed to send passive check result for host 'localhost'" exit 1 else echo "[OK] Successfully sent a passive check result for host 'localhost'" fi printf "localhost\tdisk\t2\tA passive result not returning OK\n" | sudo send_nsca if [ $? -gt 0 ]; then echo "[FAIL] Failed to send passive check result for service 'disk' on host 'localhost'" exit 1 else echo "[OK] Successfully sent a passive check result for service 'disk' on host 'localhost'" fi icinga2-2.8.1/test/jenkins/pgsql_state.test000077500000000000000000000002751322762156600207260ustar00rootroot00000000000000#!/bin/sh sudo service postgresql status &> /dev/null if [ $? -gt 0 ]; then echo '[FAIL] postgresql is not running' exit 1 else echo '[OK] postgresql is running' exit 0 fi icinga2-2.8.1/test/jenkins/pidfile.test000077500000000000000000000003461322762156600200130ustar00rootroot00000000000000#!/bin/sh pidfile_path="/var/run/icinga2/icinga2.pid" if [ -f $pidfile_path ]; then echo "[OK] Icinga2 pidfile found ($pidfile_path)" exit 0 else echo "[FAIL] Icinga2 pidfile not found ($pidfile_path)" exit 1 fi icinga2-2.8.1/test/jenkins/run_tests.conf000077500000000000000000000101271322762156600203710ustar00rootroot00000000000000{ "commands": { "copy": "scp -qF ssh_config {0} default:{1}", "exec": "ssh -F ssh_config default '{0}'", "clean": "ssh -F ssh_config default 'rm -f {0}'" }, "settings": { "test_root": "/tmp" }, "setups": { "^ido_[a-z]{2}sql.test$": { "setup": { "copy": [ "files/ido_tests.py >> /tmp/ido_tests.py", "files/utils.py >> /tmp/utils.py" ] }, "teardown": { "clean": [ "/tmp/ido_tests.py*", "/tmp/utils.py*" ] } }, "checkresult.test": { "setup": { "copy": [ "files/configs/checkresult.conf >> /tmp/checkresult.conf", "files/wait_for_ido.sh >> /tmp/wait_for_ido.sh", "files/utils.py >> /tmp/utils.py" ], "exec": [ "sudo mv /tmp/checkresult.conf /etc/icinga2/conf.d/", "mkdir -p -m 0777 /tmp/icinga2/checkresults", "sudo service icinga2 restart", "/tmp/wait_for_ido.sh mysql" ] }, "teardown": { "clean": ["/tmp/utils.py*"], "exec": [ "sudo rm /etc/icinga2/conf.d/checkresult.conf", "sudo service icinga2 restart", "rmdir /tmp/icinga2/checkresults", "/tmp/wait_for_ido.sh mysql", "/tmp/wait_for_ido.sh pgsql && rm /tmp/wait_for_ido.sh" ] } }, "external_commands.test": { "setup": { "copy": [ "files/utils.py >> /tmp/utils.py", "files/configs/notifications.conf >> /tmp/notifications.conf", "files/configs/ido_checkresults.conf >> /tmp/ido_checkresults.conf", "files/configs/groups.conf >> /tmp/groups.conf" ], "exec": [ "sudo mv /etc/icinga2/conf.d/generic-service.conf /etc/icinga2/conf.d/generic-service.conf.bak", "sudo mv /etc/icinga2/conf.d/notifications.conf /etc/icinga2/conf.d/notifications.conf.bak", "sudo mv /etc/icinga2/conf.d/groups.conf /etc/icinga2/conf.d/groups.conf.bak", "sudo mv /tmp/groups.conf /etc/icinga2/conf.d/", "sudo mv /tmp/ido_checkresults.conf /etc/icinga2/conf.d/", "sudo mv /tmp/notifications.conf /etc/icinga2/conf.d/", "sudo service icinga2 restart" ] }, "teardown": { "clean": ["/tmp/utils.py*"], "exec": [ "sudo rm /etc/icinga2/conf.d/groups.conf", "sudo mv /etc/icinga2/conf.d/groups.conf.bak /etc/icinga2/conf.d/groups.conf", "sudo mv /etc/icinga2/conf.d/generic-service.conf.bak /etc/icinga2/conf.d/generic-service.conf", "sudo rm /etc/icinga2/conf.d/ido_checkresults.conf", "sudo rm /etc/icinga2/conf.d/notifications.conf", "sudo mv /etc/icinga2/conf.d/notifications.conf.bak /etc/icinga2/conf.d/notifications.conf", "sudo service icinga2 restart" ] } }, "eventhandler.test": { "setup": { "copy": [ "files/utils.py >> /tmp/utils.py", "files/configs/eventhandler.conf >> /tmp/eventhandler.conf" ], "exec": [ "sudo mv /tmp/eventhandler.conf /etc/icinga2/conf.d/", "sudo service icinga2 restart" ] }, "teardown": { "clean": ["/tmp/utils.py*"], "exec": [ "sudo rm /etc/icinga2/conf.d/eventhandler.conf", "sudo service icinga2 restart" ] } } } } icinga2-2.8.1/test/jenkins/run_tests.py000077500000000000000000000234461322762156600201040ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import unicode_literals import os import re import sys import json import glob import subprocess from optparse import OptionParser from xml.dom.minidom import getDOMImplementation try: from subprocess import DEVNULL except ImportError: DEVNULL = open(os.devnull, 'w') class Logger(object): INFO = 1 OK = 2 FAIL = 3 ERROR = 4 DEBUG_STD = 5 DEBUG_EXT = 6 VERBOSITY = 0 OUTPUT_LENGTH = 1024 @staticmethod def write(text, stderr=False): if stderr: sys.stderr.write(text.encode('utf-8')) sys.stderr.flush() else: sys.stdout.write(text.encode('utf-8')) sys.stdout.flush() @classmethod def set_verbosity(cls, verbosity): cls.VERBOSITY = verbosity @classmethod def log(cls, severity, text): if severity == cls.INFO and cls.VERBOSITY >= 1: cls.write('\033[1;94m[INFO]\033[1;0m {0}'.format(text)) elif severity == cls.ERROR and cls.VERBOSITY >= 1: cls.write('\033[1;33m[ERROR]\033[1;0m {0}'.format(text), True) elif severity == cls.FAIL and cls.VERBOSITY >= 1: cls.write('\033[1;31m[FAIL] {0}\033[1;0m'.format(text)) elif severity == cls.OK and cls.VERBOSITY >= 1: cls.write('\033[1;32m[OK]\033[1;0m {0}'.format(text)) elif severity == cls.DEBUG_STD and cls.VERBOSITY >= 2: cls.write('\033[1;90m[DEBUG]\033[1;0m {0}'.format(text)) elif severity == cls.DEBUG_EXT and cls.VERBOSITY >= 3: if cls.VERBOSITY < 4 and len(text) > cls.OUTPUT_LENGTH: suffix = '... (Truncated to {0} bytes)\n' \ ''.format(cls.OUTPUT_LENGTH) text = text[:cls.OUTPUT_LENGTH] + suffix cls.write('\033[1;90m[DEBUG]\033[1;0m {0}'.format(text)) else: return False return True @classmethod def info(cls, text): return cls.log(cls.INFO, text) @classmethod def error(cls, text): return cls.log(cls.ERROR, text) @classmethod def fail(cls, text): return cls.log(cls.FAIL, text) @classmethod def ok(cls, text): return cls.log(cls.OK, text) @classmethod def debug(cls, text, extended=False): return cls.log(cls.DEBUG_EXT if extended else cls.DEBUG_STD, text) class TestSuite(object): def __init__(self, configpath): self._tests = [] self._results = {} self.load_config(configpath) def add_test(self, filepath): self._tests.append(filepath) def load_config(self, filepath): with open(filepath) as f: self._config = json.load(f) def get_report(self): dom = getDOMImplementation() document = dom.createDocument(None, 'testsuite', None) xml_root = document.documentElement for name, info in self._results.iteritems(): testresult = document.createElement('testcase') testresult.setAttribute('classname', 'vm') testresult.setAttribute('name', name) totaltests = document.createElement('tests') totaltests.appendChild(document.createTextNode(str(info['total']))) testresult.appendChild(totaltests) failedtests = document.createElement('failures') failedtests.appendChild(document.createTextNode(str(info['failures']))) testresult.appendChild(failedtests) systemout = document.createElement('system-out') systemout.appendChild(document.createTextNode(info['stdout'])) testresult.appendChild(systemout) systemerr = document.createElement('system-err') systemerr.appendChild(document.createTextNode(info['stderr'])) testresult.appendChild(systemerr) if info['returncode'] != 0: failure = document.createElement('failure') failure.setAttribute('type', 'returncode') failure.appendChild(document.createTextNode( 'code: {0}'.format(info['returncode']))) testresult.appendChild(failure) xml_root.appendChild(testresult) return document.toxml() def run(self): for path in self._tests: test_name = os.path.basename(path) Logger.debug('Copying test "{0}" to remote machine\n'.format(test_name)) self._copy_test(path) self._apply_setup_routines(test_name, 'setup') note_printed = Logger.info('Running test "{0}"...\n'.format(test_name)) result = self._run_test(path) Logger.info('Test "{0}" has finished (Total tests: {1}, Failures: {2})\n' ''.format(test_name, result['total'], result['failures'])) self._apply_setup_routines(test_name, 'teardown') Logger.debug('Removing test "{0}" from remote machine\n'.format(test_name)) self._remove_test(test_name) self._results[test_name] = result if note_printed: Logger.write('\n') def _apply_setup_routines(self, test_name, context): instructions = next((t[1].get(context) for t in self._config.get('setups', {}).iteritems() if re.match(t[0], test_name)), None) if instructions is not None: note_printed = Logger.info('Applying {0} routines for test "{1}" .. ' ''.format(context, test_name)) for instruction in instructions.get('copy', []): source, _, destination = instruction.partition('>>') self._copy_file(source.strip(), destination.strip()) for filepath in instructions.get('clean', []): self._remove_file(filepath) for command in instructions.get('exec', []): self._exec_command(command) if note_printed: Logger.write('Done\n') def _remove_file(self, path): command = self._config['commands']['clean'].format(path) rc = subprocess.call(command, stdout=DEVNULL, shell=True) if rc != 0: Logger.error('Cannot remove file "{0}" ({1})\n'.format(path, rc)) def _exec_command(self, command): command = self._config['commands']['exec'].format(command) rc = subprocess.call(command, stdout=DEVNULL, shell=True) if rc != 0: Logger.error('Command "{0}" exited with exit code "{1}"\n' \ ''.format(command, rc)) def _copy_file(self, source, destination): command = self._config['commands']['copy'].format(source, destination) rc = subprocess.call(command, stdout=DEVNULL, shell=True) if rc != 0: Logger.error('Cannot copy file "{0}" to "{1}" ({2})\n' \ ''.format(source, destination, rc)) def _copy_test(self, path): self._copy_file(path, os.path.join(self._config['settings']['test_root'], os.path.basename(path))) def _remove_test(self, test_name): test_root = self._config['settings']['test_root'] self._remove_file(os.path.join(test_root, test_name)) def _run_test(self, path): command = self._config['commands']['exec'] target = os.path.join(self._config['settings']['test_root'], os.path.basename(path)) options = ['--verbosity={0}'.format(Logger.VERBOSITY)] p = subprocess.Popen(command.format(' '.join([target] + options)), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) output, test_count, failed_tests = self._watch_output(p.stdout) return { 'total': test_count, 'failures': failed_tests, 'stdout': output, 'stderr': p.stderr.read().decode('utf-8'), 'returncode': p.wait() } def _watch_output(self, pipe): output, total, failures = '', 0, 0 while True: line = pipe.readline().decode('utf-8') if not line: break verbosity_level = line.count('\x00') line = line[verbosity_level:] if line.startswith('[ERROR] '): Logger.error(line[8:]) elif line.startswith('[DEBUG] '): Logger.debug(line[8:], verbosity_level == 4) elif line.startswith('[FAIL] '): Logger.fail(line[7:]) failures += 1 total += 1 elif line.startswith('[OK] '): Logger.ok(line[5:]) total += 1 else: Logger.info(line.replace('[INFO] ', '')) output += line return (output, total, failures) def parse_commandline(): parser = OptionParser(version='0.5') parser.add_option('-C', '--config', default="run_tests.conf", help='The path to the config file to use [%default]') parser.add_option('-R', '--results', help='The file where to store the test results') parser.add_option('-v', '--verbose', action='count', default=1, help='Be more verbose (Maximum output: -vvv)') parser.add_option('-q', '--quiet', action='count', default=0, help='Be less verbose') return parser.parse_args() def main(): options, arguments = parse_commandline() suite = TestSuite(options.config) for path in (p for a in arguments for p in glob.glob(a)): suite.add_test(path) Logger.set_verbosity(options.verbose - options.quiet) suite.run() if options.results is not None: with open(options.results, 'w') as f: f.write(suite.get_report().encode('utf-8')) return 0 if __name__ == '__main__': sys.exit(main()) icinga2-2.8.1/test/jenkins/run_tests.sh000077500000000000000000000001251322762156600200530ustar00rootroot00000000000000#!/bin/sh vagrant ssh-config > ssh_config ./run_tests.py $@ *.test rm -f ssh_config icinga2-2.8.1/test/jenkins/statusdata.test000077500000000000000000000023361322762156600205550ustar00rootroot00000000000000#!/bin/bash statusdata_path="/var/cache/icinga2/status.dat" objectscache_path="/var/cache/icinga2/objects.cache" if [ ! -f $statusdata_path ]; then sudo icinga2 feature enable statusdata 1> /dev/null sudo service icinga2 restart 1> /dev/null n=0 while [ $n -lt 3 ] do sleep 15 if [ -f $statusdata_path ]; then break fi n=$(( $n + 1)) done if [ $n -eq 3 ]; then echo "[FAIL] Icinga2 status.dat not found ($statusdata_path)" exit 1 fi fi echo "[OK] Icinga2 status.dat found ($statusdata_path)" if [ -f $objectscache_path ]; then echo "[OK] Icinga2 objects.cache found ($objectscache_path)" else echo "[FAIL] Icinga2 objects.cache not found ($objectscache_path)" exit 1 fi status_time=$(stat --format="%Y" $statusdata_path) now=$(date +"%s") sleep $(((15 + 5) - ($now - $status_time))) new_status_time=$(stat --format="%Y" $statusdata_path) if [ $new_status_time -eq $status_time ]; then echo "[FAIL] Icinga2 status.dat is not being updated (Last update: $(date -r $statusdata_path '+%x %X'))" exit 1 else echo "[OK] Icinga2 status.dat is being updated (Last update: $(date -r $statusdata_path '+%x %X'))" fi icinga2-2.8.1/test/livestatus-fixture.cpp000066400000000000000000000046131322762156600204260ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "config/configcompiler.hpp" #include "config/configitem.hpp" #include "base/application.hpp" #include "base/loader.hpp" #include using namespace icinga; struct LivestatusFixture { LivestatusFixture(void) { BOOST_TEST_MESSAGE("Preparing config objects..."); ConfigItem::RunWithActivationContext(new Function("CreateTestObjects", WrapFunction(CreateTestObjects))); } static void CreateTestObjects(void) { String config = R"CONFIG( object CheckCommand "dummy" { command = "/bin/echo" } object Host "test-01" { address = "127.0.0.1" check_command = "dummy" } object Host "test-02" { address = "127.0.0.2" check_command = "dummy" } apply Service "livestatus" { check_command = "dummy" notes = "test livestatus" assign where match("test-*", host.name) } )CONFIG"; Expression *expr = ConfigCompiler::CompileText("", config); expr->Evaluate(*ScriptFrame::GetCurrentFrame()); } }; BOOST_GLOBAL_FIXTURE(LivestatusFixture); icinga2-2.8.1/test/livestatus.cpp000066400000000000000000000103331322762156600167360ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "livestatus/livestatusquery.hpp" #include "base/application.hpp" #include "base/stdiostream.hpp" #include "base/json.hpp" #include using namespace icinga; String LivestatusQueryHelper(const std::vector& lines) { LivestatusQuery::Ptr query = new LivestatusQuery(lines, ""); std::stringstream stream; StdioStream::Ptr sstream = new StdioStream(&stream, false); query->Execute(sstream); String output; String result; StreamReadContext src; for (;;) { StreamReadStatus srs = sstream->ReadLine(&result, src); if (srs == StatusEof) break; if (srs != StatusNewItem) continue; if (result.GetLength() > 0) output += result + "\n"; else break; } BOOST_TEST_MESSAGE("Query Result: " + output); return output; } //____________________________________________________________________________// BOOST_AUTO_TEST_SUITE(livestatus) BOOST_AUTO_TEST_CASE(hosts) { BOOST_TEST_MESSAGE( "Querying Livestatus..."); std::vector lines; lines.push_back("GET hosts"); lines.push_back("Columns: host_name address check_command"); lines.push_back("OutputFormat: json"); lines.push_back("\n"); /* use our query helper */ String output = LivestatusQueryHelper(lines); Array::Ptr query_result = JsonDecode(output); /* the outer elements */ BOOST_CHECK(query_result->GetLength() > 1); Array::Ptr res1 = query_result->Get(0); Array::Ptr res2 = query_result->Get(1); /* results are non-deterministic and not sorted by livestatus */ BOOST_CHECK(res1->Contains("test-01") || res2->Contains("test-01")); BOOST_CHECK(res1->Contains("test-02") || res2->Contains("test-02")); BOOST_CHECK(res1->Contains("127.0.0.1") || res2->Contains("127.0.0.1")); BOOST_CHECK(res1->Contains("127.0.0.2") || res2->Contains("127.0.0.2")); BOOST_TEST_MESSAGE("Done with testing livestatus hosts..."); } BOOST_AUTO_TEST_CASE(services) { BOOST_TEST_MESSAGE( "Querying Livestatus..."); std::vector lines; lines.push_back("GET services"); lines.push_back("Columns: host_name service_description check_command notes"); lines.push_back("OutputFormat: json"); lines.push_back("\n"); /* use our query helper */ String output = LivestatusQueryHelper(lines); Array::Ptr query_result = JsonDecode(output); /* the outer elements */ BOOST_CHECK(query_result->GetLength() > 1); Array::Ptr res1 = query_result->Get(0); Array::Ptr res2 = query_result->Get(1); /* results are non-deterministic and not sorted by livestatus */ BOOST_CHECK(res1->Contains("livestatus") || res2->Contains("livestatus")); //service_description BOOST_CHECK(res1->Contains("test livestatus") || res2->Contains("test livestatus")); //notes BOOST_TEST_MESSAGE("Done with testing livestatus services..."); } //____________________________________________________________________________// BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/livestatus/000077500000000000000000000000001322762156600162325ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/README000066400000000000000000000003111322762156600171050ustar00rootroot00000000000000Compat Livestatus Component Query Tests ======================================= Collection of queries used for execution on the livestatus socket. $ ./run_queries host/services or $ ./run_queries icinga2-2.8.1/test/livestatus/queries/000077500000000000000000000000001322762156600177075ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/commands/000077500000000000000000000000001322762156600215105ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/commands/command000066400000000000000000000001121322762156600230430ustar00rootroot00000000000000GET commands Columns: name line custom_variables ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/commands/modattr000066400000000000000000000001411322762156600231010ustar00rootroot00000000000000GET commands Columns: name modified_attributes modified_attributes_list ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/comments/000077500000000000000000000000001322762156600215345ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/comments/comment000066400000000000000000000000461322762156600231210ustar00rootroot00000000000000GET comments ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/comments/comment_short000066400000000000000000000001601322762156600243350ustar00rootroot00000000000000GET comments Columns: id type is_service host_name service_description author comment ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/contacts/000077500000000000000000000000001322762156600215255ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/contacts/contacts000066400000000000000000000000461322762156600232660ustar00rootroot00000000000000GET contacts ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/contacts/group000066400000000000000000000000531322762156600226020ustar00rootroot00000000000000GET contactgroups ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/contacts/modattr000066400000000000000000000001411322762156600231160ustar00rootroot00000000000000GET contacts Columns: name modified_attributes modified_attributes_list ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/custom/000077500000000000000000000000001322762156600212215ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/custom/scrambled000066400000000000000000000000031322762156600230710ustar00rootroot00000000000000D icinga2-2.8.1/test/livestatus/queries/custom/thruk_alert_history000066400000000000000000000010111322762156600252420ustar00rootroot00000000000000GET log Columns: class time type state host_name service_description plugin_output message options state_type contact_name Filter: time >= 1383692400 Filter: time <= 1383778800 Filter: type = SERVICE ALERT And: 1 Filter: type = HOST ALERT And: 1 Filter: type = SERVICE FLAPPING ALERT Filter: type = HOST FLAPPING ALERT Filter: type = SERVICE DOWNTIME ALERT Filter: type = HOST DOWNTIME ALERT Filter: message ~ starting\.\.\. Filter: message ~ shutting\ down\.\.\. Or: 8 And: 3 OutputFormat: json ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/custom/thruk_comments000066400000000000000000000003711322762156600242070ustar00rootroot00000000000000GET comments Columns: author comment entry_time entry_type expires expire_time host_name id persistent service_description source type Filter: host_name = localhost Filter: service_description = processes OutputFormat: json ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/downtimes/000077500000000000000000000000001322762156600217205ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/downtimes/downtime000066400000000000000000000000471322762156600234720ustar00rootroot00000000000000GET downtimes ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/downtimes/downtime_short000066400000000000000000000002041322762156600247040ustar00rootroot00000000000000GET downtimes Columns: id type is_service host_name service_description author comment start_time end_time ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/endpoints/000077500000000000000000000000001322762156600217125ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/endpoints/endpoints000066400000000000000000000000471322762156600236410ustar00rootroot00000000000000GET endpoints ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/000077500000000000000000000000001322762156600210475ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/hosts/bygroup000066400000000000000000000001141322762156600224550ustar00rootroot00000000000000GET hostsbygroup Columns: hostgroup_name host_name ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/check000066400000000000000000000001141322762156600220430ustar00rootroot00000000000000GET hosts Columns: name plugin_output check_source ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/command000066400000000000000000000001211322762156600224020ustar00rootroot00000000000000GET hosts Columns: check_command check_command_expanded ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/comment000066400000000000000000000001411322762156600224300ustar00rootroot00000000000000GET hosts Columns: comments comments_with_info comments_with_extra_info ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/contact000066400000000000000000000001041322762156600224200ustar00rootroot00000000000000GET hosts Columns: contacts contact_groups ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/customvar000066400000000000000000000001721322762156600230150ustar00rootroot00000000000000GET hosts Columns: name custom_variable_names custom_variable_values custom_variables cv_is_json ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/downtime000066400000000000000000000001121322762156600226120ustar00rootroot00000000000000GET hosts Columns: downtimes downtimes_with_info ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/extra000066400000000000000000000003021322762156600221100ustar00rootroot00000000000000GET hosts Columns: name address notes notes_expanded notes_url notes_url_expanded action_url action_url_expanded icon_image icon_image_expanded icon_image_alt x_2d y_2d ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/group000066400000000000000000000000501322762156600221210ustar00rootroot00000000000000GET hostgroups ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/host000066400000000000000000000001001322762156600217360ustar00rootroot00000000000000GET hosts Columns: name parents childs ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/host_nagvis000066400000000000000000000001411322762156600233120ustar00rootroot00000000000000GET hosts Columns: name alias host_name OutputFormat:json KeepAlive: on ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/legacy000066400000000000000000000001461322762156600222370ustar00rootroot00000000000000GET hosts Columns: name notes notes_url action_url icon_image icon_image_alt ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/modattr000066400000000000000000000001631322762156600224440ustar00rootroot00000000000000GET hosts Columns: name modified_attributes modified_attributes_list original_attributes ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/notification000066400000000000000000000003071322762156600234600ustar00rootroot00000000000000GET hosts Columns: name current_notification_number notification_period notification_interval notifications_enabled no_more_notifications last_notification next_notification ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/services000066400000000000000000000005261322762156600226200ustar00rootroot00000000000000GET hosts Columns: name num_services worst_service_state num_services_ok num_services_warn num_services_crit num_services_unknown num_services_pending worst_service_hard_state num_services_hard_ok num_services_hard_warn num_services_hard_crit num_services_hard_unknown services services_with_state services_with_info ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/state000066400000000000000000000002431322762156600221110ustar00rootroot00000000000000GET hosts Columns: name last_state_change last_hard_state_change last_time_up last_time_down last_time_unreachable staleness is_reachable ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/hosts/stats_sum000066400000000000000000000001111322762156600230050ustar00rootroot00000000000000GET hosts ResponseHeader: fixed16 Stats: latency = 3 Stats: sum latency icinga2-2.8.1/test/livestatus/queries/log/000077500000000000000000000000001322762156600204705ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/log/alerts000066400000000000000000000003331322762156600217040ustar00rootroot00000000000000GET log Columns: host_name service_description time lineno class type options plugin_output state state_type comment contact_name command_name Filter: time >= 1348657741 Filter: message ~ ALERT ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/avail000066400000000000000000000004271322762156600215120ustar00rootroot00000000000000GET log Columns: time type message class Filter: type = HOST ALERT Filter: state_type = HARD Filter: type = INITIAL HOST STATE Filter: state_type = HARD Filter: type = CURRENT HOST STATE Filter: state_type = HARD Filter: type = HOST DOWNTIME ALERT Or: 7 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/avail_svc000066400000000000000000000005061322762156600223630ustar00rootroot00000000000000GET log Columns: time type message class Filter: type = HOST DOWNTIME ALERT Filter: type = SERVICE ALERT Filter: state_type = HARD Filter: type = INITIAL SERVICE STATE Filter: state_type = HARD Filter: type = CURRENT SERVICE STATE Filter: state_type = HARD Filter: type = SERVICE DOWNTIME ALERT Or: 8 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/class000066400000000000000000000001161322762156600215160ustar00rootroot00000000000000GET log Filter: time >= 1348657741 Filter: class = 1 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/localhost_disk000066400000000000000000000004041322762156600234130ustar00rootroot00000000000000GET log Columns: host_name service_description time lineno class type options plugin_output state state_type comment contact_name command_name Filter: time >= 1348657741 Filter: host_name = localhost Filter: service_description = disk ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/log000066400000000000000000000000741322762156600211750ustar00rootroot00000000000000GET log Filter: time >= 1348657741 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/minimal000066400000000000000000000003031322762156600220350ustar00rootroot00000000000000GET log Columns: host_name service_description time lineno class type options plugin_output state state_type comment contact_name command_name Filter: time >= 1348657741 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/log/trend000066400000000000000000000011241322762156600215250ustar00rootroot00000000000000GET log Columns: time type message Filter: host_name = localhost Filter: type = HOST ALERT Filter: state_type = HARD Filter: type = INITIAL HOST STATE Filter: state_type = HARD Filter: type = CURRENT HOST STATE Filter: state_type = HARD Filter: type = HOST DOWNTIME ALERT Or: 7 And: 2 Filter: host_name = localhost Filter: type = SERVICE ALERT Filter: state_type = HARD Filter: type = INITIAL SERVICE STATE Filter: state_type = HARD Filter: type = CURRENT SERVICE STATE Filter: state_type = HARD Filter: type = SERVICE DOWNTIME ALERT Or: 7 And: 2 Filter: class = 2 Or: 3 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/000077500000000000000000000000001322762156600215325ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/services/bygroup000066400000000000000000000001461322762156600231450ustar00rootroot00000000000000GET servicesbygroup Columns: servicegroup_name host_name service_description ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/byhostgroup000066400000000000000000000001471322762156600240440ustar00rootroot00000000000000GET servicesbyhostgroup Columns: hostgroup_name host_name service_description ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/check000066400000000000000000000001401322762156600225250ustar00rootroot00000000000000GET services Columns: description host_name plugin_output check_source ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/command000066400000000000000000000001241322762156600230700ustar00rootroot00000000000000GET services Columns: check_command check_command_expanded ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/comment000066400000000000000000000001441322762156600231160ustar00rootroot00000000000000GET services Columns: comments comments_with_info comments_with_extra_info ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/contact000066400000000000000000000001071322762156600231060ustar00rootroot00000000000000GET services Columns: contacts contact_groups ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/customvar000066400000000000000000000001511322762156600234750ustar00rootroot00000000000000GET services Columns: host_name service_description custom_variables cv_is_json ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/downtime000066400000000000000000000001151322762156600233000ustar00rootroot00000000000000GET services Columns: downtimes downtimes_with_info ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/extra000066400000000000000000000003211322762156600225740ustar00rootroot00000000000000GET services Columns: description host_name host_address notes notes_expanded notes_url notes_url_expanded action_url action_url_expanded icon_image icon_image_expanded icon_image_alt ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/group000066400000000000000000000000531322762156600226070ustar00rootroot00000000000000GET servicegroups ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/legacy000066400000000000000000000001721322762156600227210ustar00rootroot00000000000000GET services Columns: host_name description notes notes_url action_url icon_image icon_image_alt ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/modattr000066400000000000000000000001741322762156600231310ustar00rootroot00000000000000GET services Columns: description modified_attributes modified_attributes_list original_attributes ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/notification000066400000000000000000000003211322762156600241370ustar00rootroot00000000000000GET services Columns: description current_notification_number notification_period notification_interval notifications_enabled no_more_notifications last_notification next_notification ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/services000066400000000000000000000000461322762156600233000ustar00rootroot00000000000000GET services ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/services/state000066400000000000000000000003111322762156600225700ustar00rootroot00000000000000GET services Columns: description host_name last_state_change last_hard_state_change last_time_ok last_time_warning last_time_critical last_time_unknown staleness is_reachable ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/special/000077500000000000000000000000001322762156600213275ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/special/services000066400000000000000000000001441322762156600230740ustar00rootroot00000000000000GET services Separators: 10 32 35 95 Columns: description custom_variables ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/statehist/000077500000000000000000000000001322762156600217175ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/statehist/duration000066400000000000000000000003041322762156600234640ustar00rootroot00000000000000GET statehist Columns: host_name service_description state duration_ok duration_warning duration_critical duration_unknown duration_unmonitored Filter: time >= 1348657741 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/statehist/statehist000066400000000000000000000003071322762156600236520ustar00rootroot00000000000000GET statehist Columns: host_name service_description state duration duration_part in_downtime in_host_downtime in_notification_period is_flapping Filter: time >= 1348657741 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/statehist/statehist_disk000066400000000000000000000003511322762156600246630ustar00rootroot00000000000000GET statehist Columns: host_name service_description state duration duration_part in_downtime in_host_downtime in_notification_period is_flapping Filter: service_description = disk Filter: time >= 1348657741 ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/statehist/sum000066400000000000000000000003641322762156600224510ustar00rootroot00000000000000GET statehist Columns: host_name service_description state duration duration_part Filter: host_name = localhost Filter: service_description = disk Filter: time >= 1348657741 Stats: sum duration Stats: sum duration_part ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/status/000077500000000000000000000000001322762156600212325ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/status/checks000066400000000000000000000002211322762156600224100ustar00rootroot00000000000000GET status Columns: accept_passive_host_checks accept_passive_service_checks execute_host_checks execute_service_checks ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/status/custom000066400000000000000000000000761322762156600224720ustar00rootroot00000000000000GET status Columns: custom_variables ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/status/livestatus000066400000000000000000000002221322762156600233540ustar00rootroot00000000000000GET status Columns: connections connections_rate external_commands external_commands_rate livestatus_active_connections ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/status/program000066400000000000000000000001551322762156600226250ustar00rootroot00000000000000GET status Columns: nagios_pid program_start num_hosts num_services program_version ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/status/status000066400000000000000000000000441322762156600224760ustar00rootroot00000000000000GET status ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/queries/timeperiods/000077500000000000000000000000001322762156600222335ustar00rootroot00000000000000icinga2-2.8.1/test/livestatus/queries/timeperiods/timeperiod000066400000000000000000000000511322762156600243130ustar00rootroot00000000000000GET timeperiods ResponseHeader: fixed16 icinga2-2.8.1/test/livestatus/run_queries000077500000000000000000000011671322762156600205260ustar00rootroot00000000000000#!/bin/bash NC=`which nc` LOCALSTATEDIR=`icinga2 variable get LocalStateDir` LIVESTATUSSOCKET="$LOCALSTATEDIR/run/icinga2/cmd/livestatus" LIVESTATUSHOST="127.0.0.1" LIVESTATUSPORT="6558" LIVESTATUSQUERIES="./queries" LIVESTATUSTABLE=$1 echo -e "Querying Livestatus socket: $LIVESTATUSSOCKET" if [ -n "$LIVESTATUSTABLE" ]; then cat "$LIVESTATUSTABLE" (cat "$LIVESTATUSTABLE"; sleep 1) | $NC -U $LIVESTATUSSOCKET else echo -e "Looking into $LIVESTATUSQUERIES\n" for q in $(find $LIVESTATUSQUERIES -type f) do cat $q (cat $q; sleep 1) | $NC -U $LIVESTATUSSOCKET echo -e "================================\n\n" done fi icinga2-2.8.1/test/remote-url.cpp000066400000000000000000000110631322762156600166270ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "base/array.hpp" #include "remote/url.hpp" #include #include using namespace icinga; BOOST_AUTO_TEST_SUITE(remote_url) BOOST_AUTO_TEST_CASE(id_and_path) { Url::Ptr url = new Url("http://icinga.com/foo/bar/baz?hurr=durr"); BOOST_CHECK(url->GetScheme() == "http"); BOOST_CHECK(url->GetAuthority() == "icinga.com"); std::vector PathCorrect; PathCorrect.push_back("foo"); PathCorrect.push_back("bar"); PathCorrect.push_back("baz"); BOOST_CHECK(url->GetPath() == PathCorrect); } BOOST_AUTO_TEST_CASE(get_and_set) { Url::Ptr url = new Url(); url->SetScheme("ftp"); url->SetUsername("Horst"); url->SetPassword("Seehofer"); url->SetHost("koenigreich.bayern"); url->SetPort("1918"); std::vector p = boost::assign::list_of("path")("to")("münchen"); url->SetPath(p); BOOST_CHECK(url->Format(false, true) == "ftp://Horst:Seehofer@koenigreich.bayern:1918/path/to/m%C3%BCnchen"); std::map > m; std::vector v1 = boost::assign::list_of("hip")("hip")("hurra"); std::vector v2 = boost::assign::list_of("äü^ä+#ül-"); std::vector v3 = boost::assign::list_of("1")("2"); m.insert(std::pair >("shout", v1)); m.insert(std::pair >("sonderzeichen", v2)); url->SetQuery(m); url->SetQueryElements("count", v3); url->AddQueryElement("count", "3"); std::map > mn = url->GetQuery(); BOOST_CHECK(mn["shout"][0] == v1[0]); BOOST_CHECK(mn["sonderzeichen"][0] == v2[0]); BOOST_CHECK(mn["count"][2] == "3"); } BOOST_AUTO_TEST_CASE(parameters) { Url::Ptr url = new Url("https://icinga.com/hya/?rain=karl&rair=robert&foo[]=bar"); BOOST_CHECK(url->GetQueryElement("rair") == "robert"); BOOST_CHECK(url->GetQueryElement("rain") == "karl"); std::vector test = url->GetQueryElements("foo"); BOOST_CHECK(test.size() == 1); BOOST_CHECK(test[0] == "bar"); } BOOST_AUTO_TEST_CASE(format) { Url::Ptr url = new Url("http://foo.bar/baz/?hop=top&flop=sop#iLIKEtrains"); BOOST_CHECK(new Url(url->Format(false, false))); url = new Url("//main.args/////////?k[]=one&k[]=two#three"); BOOST_CHECK(new Url(url->Format(false, false))); url = new Url("/foo/bar/index.php?blaka"); BOOST_CHECK(new Url(url->Format(false, false))); BOOST_CHECK(url->Format(false, false) == "/foo/bar/index.php?blaka"); url = new Url("/"); BOOST_CHECK(url->Format(false, false) == "/"); } BOOST_AUTO_TEST_CASE(illegal_legal_strings) { BOOST_CHECK(new Url("/?foo=barr&foo[]=bazz")); BOOST_CHECK_THROW(new Url("/?]=gar"), std::invalid_argument); BOOST_CHECK_THROW(new Url("/#?[]"), std::invalid_argument); BOOST_CHECK(new Url("/?foo=bar&foo=ba")); BOOST_CHECK_THROW(new Url("/?foo=bar&[]=d"), std::invalid_argument); BOOST_CHECK(new Url("/?fo=&bar=garOA")); BOOST_CHECK(new Url("https://127.0.0.1:5665/demo?type=Service&filter=service.state%3E0")); BOOST_CHECK(new Url("/?foo=baz??&\?\?=/?")); BOOST_CHECK(new Url("/")); BOOST_CHECK(new Url("///////")); BOOST_CHECK(new Url("/??[]=?#?=?")); BOOST_CHECK(new Url("http://foo/#bar")); BOOST_CHECK(new Url("//foo/")); } BOOST_AUTO_TEST_SUITE_END() icinga2-2.8.1/test/test-runner.cpp000066400000000000000000000036131322762156600170240ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "icinga/icingaapplication.hpp" #include "base/application.hpp" #include using namespace icinga; static bool init_unit_test(void) { return true; } int main(int argc, char *argv[]) { Application::InitializeBase(); IcingaApplication::Ptr appInst; appInst = new IcingaApplication(); static_pointer_cast(appInst)->OnConfigLoaded(); int rc = boost::unit_test::unit_test_main(&init_unit_test, argc, argv); appInst.reset(); Application::Exit(rc); } icinga2-2.8.1/third-party/000077500000000000000000000000001322762156600153175ustar00rootroot00000000000000icinga2-2.8.1/third-party/CMakeLists.txt000066400000000000000000000016711322762156600200640ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_subdirectory(mmatch) if(NOT YAJL_FOUND) add_subdirectory(yajl) endif() if(UNIX OR CYGWIN) add_subdirectory(execvpe) endif() add_subdirectory(socketpair) icinga2-2.8.1/third-party/cmake/000077500000000000000000000000001322762156600163775ustar00rootroot00000000000000icinga2-2.8.1/third-party/cmake/BoostTestTargets.cmake000066400000000000000000000200301322762156600226540ustar00rootroot00000000000000# - Add tests using boost::test # # Add this line to your test files in place of including a basic boost test header: # #include # # If you cannot do that and must use the included form for a given test, # include the line # // OVERRIDE_BOOST_TEST_INCLUDED_WARNING # in the same file with the boost test include. # # include(BoostTestTargets) # add_boost_test( SOURCES [] # [FAIL_REGULAR_EXPRESSION ] # [LAUNCHER ] # [LIBRARIES [...]] # [RESOURCES [...]] # [TESTS [...]] # [DEPENDENCIES [...]]) # # If for some reason you need access to the executable target created, # it can be found in ${${testdriver_name}_TARGET_NAME} as specified when # you called add_boost_test # # Requires CMake 2.6 or newer (uses the 'function' command) # # Requires: # GetForceIncludeDefinitions # CopyResourcesToBuildTree # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__add_boost_test) return() endif() set(__add_boost_test YES) set(BOOST_TEST_TARGET_PREFIX "boosttest") if(NOT Boost_FOUND) find_package(Boost 1.34.0 QUIET) endif() if("${Boost_VERSION}0" LESS "1034000") set(_shared_msg "NOTE: boost::test-based targets and tests cannot " "be added: boost >= 1.34.0 required but not found. " "(found: '${Boost_VERSION}'; want >=103400) ") if(BUILD_TESTING) message(FATAL_ERROR ${_shared_msg} "You may disable BUILD_TESTING to continue without the " "tests.") else() message(STATUS ${_shared_msg} "BUILD_TESTING disabled, so continuing anyway.") endif() endif() include(GetForceIncludeDefinitions) include(CopyResourcesToBuildTree) if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000") set(_boosttesttargets_libs) set(_boostConfig "BoostTestTargetsIncluded.h") if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework) endif() if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY) set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}") if(Boost_USE_STATIC_LIBS) set(_boostConfig "BoostTestTargetsStatic.h") else() set(_boostConfig "BoostTestTargetsDynamic.h") endif() endif() get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH) configure_file("${_moddir}/${_boostConfig}" "${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h" COPYONLY) include_directories("${CMAKE_CURRENT_BINARY_DIR}") endif() function(add_boost_test _name) if(NOT BUILD_TESTING) return() endif() if("${CMAKE_VERSION}" VERSION_LESS "2.8.0") if(NOT "${_boost_test_cmakever_pestered}x" EQUAL "${CMAKE_VERSION}x") message(STATUS "Not adding boost::test targets - CMake 2.8.0 or newer required, using ${CMAKE_VERSION}") set(_boost_test_cmakever_pestered "${CMAKE_VERSION}" CACHE INTERNAL "" FORCE) endif() return() endif() # parse arguments set(_nowhere) set(_curdest _nowhere) set(_val_args SOURCES FAIL_REGULAR_EXPRESSION LAUNCHER LIBRARIES RESOURCES TESTS DEPENDENCIES) set(_bool_args USE_COMPILED_LIBRARY) foreach(_arg ${_val_args} ${_bool_args}) set(${_arg}) endforeach() foreach(_element ${ARGN}) list(FIND _val_args "${_element}" _val_arg_find) list(FIND _bool_args "${_element}" _bool_arg_find) if("${_val_arg_find}" GREATER "-1") set(_curdest "${_element}") elseif("${_bool_arg_find}" GREATER "-1") set("${_element}" ON) set(_curdest _nowhere) else() list(APPEND ${_curdest} "${_element}") endif() endforeach() if(_nowhere) message(FATAL_ERROR "Syntax error in use of add_boost_test!") endif() if(NOT SOURCES) message(FATAL_ERROR "Syntax error in use of add_boost_test: at least one source file required!") endif() if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000") include_directories(${Boost_INCLUDE_DIRS}) set(includeType) foreach(src ${SOURCES}) file(READ ${src} thefile) if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*") set(includeType CONFIGURED) set(includeFileLoc ${src}) break() elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*") set(includeType INCLUDED) set(includeFileLoc ${src}) set(_boosttesttargets_libs) # clear this out - linking would be a bad idea if(NOT "${thefile}" MATCHES ".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*") message("Please replace the include line in ${src} with this alternate include line instead:") message(" \#include ") message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") endif() break() endif() endforeach() if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}") if("${includeType}" STREQUAL "CONFIGURED") message(STATUS "Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})") elseif("${includeType}" STREQUAL "INCLUDED") message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.") else() message("In test '${_name}': Didn't detect the CMake-configurable boost test include.") message("Please replace your existing boost test include in that test with the following:") message(" \#include ") message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") endif() endif() set(_boostTestTargetsNagged${_name} "${includeType}" CACHE INTERNAL "" FORCE) if(RESOURCES) list(APPEND SOURCES ${RESOURCES}) endif() # Generate a unique target name, using the relative binary dir # and provided name. (transform all / into _ and remove all other # non-alphabet characters) file(RELATIVE_PATH targetpath "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}") string(REPLACE "/" "_" targetpath "${targetpath}") set(_target_name ${BOOST_TEST_TARGET_PREFIX}-${targetpath}-${_name}) set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE) # Build the test. add_executable(${_target_name} ${SOURCES}) list(APPEND LIBRARIES ${_boosttesttargets_libs}) if(LIBRARIES) target_link_libraries(${_target_name} ${LIBRARIES}) endif() if(RESOURCES) set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES}) copy_resources_to_build_tree(${_target_name}) endif() if(NOT Boost_TEST_FLAGS) # set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML) set(Boost_TEST_FLAGS --catch_system_error=yes) endif() # TODO: Figure out why only recent boost handles individual test running properly if(LAUNCHER) set(_test_command ${LAUNCHER} "\$") else() set(_test_command ${_target_name}) endif() if(TESTS AND "${Boost_VERSION}" VERSION_GREATER "103799") foreach(_test ${TESTS}) add_test(NAME ${_name}-${_test} COMMAND ${_test_command} --run_test=${_test} ${Boost_TEST_FLAGS}) if(FAIL_REGULAR_EXPRESSION) set_tests_properties(${_name}-${_test} PROPERTIES FAIL_REGULAR_EXPRESSION "${FAIL_REGULAR_EXPRESSION}") endif() endforeach() else() add_test(NAME ${_name}-boost_test COMMAND ${_test_command} ${Boost_TEST_FLAGS}) if(FAIL_REGULAR_EXPRESSION) set_tests_properties(${_name}-${_test} PROPERTIES FAIL_REGULAR_EXPRESSION "${FAIL_REGULAR_EXPRESSION}") endif() endif() if (DEPENDENCIES) add_dependencies(${_target_name} ${DEPENDENCIES}) endif() # CppCheck the test if we can. if(COMMAND add_cppcheck) add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS) endif() endif() endfunction() icinga2-2.8.1/third-party/cmake/BoostTestTargetsDynamic.h000066400000000000000000000004031322762156600233320ustar00rootroot00000000000000// Small header computed by CMake to set up boost test. // include AFTER #define BOOST_TEST_MODULE whatever // but before any other boost test includes. // Using the Boost UTF dynamic library #define BOOST_TEST_DYN_LINK #include icinga2-2.8.1/third-party/cmake/BoostTestTargetsIncluded.h000066400000000000000000000003621322762156600235010ustar00rootroot00000000000000// Small header computed by CMake to set up boost test. // include AFTER #define BOOST_TEST_MODULE whatever // but before any other boost test includes. // Using the Boost UTF included framework #include icinga2-2.8.1/third-party/cmake/BoostTestTargetsStatic.h000066400000000000000000000003451322762156600232020ustar00rootroot00000000000000// Small header computed by CMake to set up boost test. // include AFTER #define BOOST_TEST_MODULE whatever // but before any other boost test includes. // Using the Boost UTF static library #include icinga2-2.8.1/third-party/cmake/CopyResourcesToBuildTree.cmake000066400000000000000000000046631322762156600243220ustar00rootroot00000000000000# - Copy the resources your app needs to the build tree. # # copy_resources_to_build_tree() # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__copy_resources_to_build_tree) return() endif() set(__copy_resources_to_build_tree YES) function(copy_resources_to_build_tree _target) get_target_property(_resources ${_target} RESOURCE) if(NOT _resources) # Bail if no resources message(STATUS "Told to copy resources for target ${_target}, but " "no resources are set!") return() endif() get_target_property(_path ${_target} LOCATION) get_filename_component(_path "${_path}" PATH) if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles") foreach(_config ${CMAKE_CONFIGURATION_TYPES}) get_target_property(_path${_config} ${_target} LOCATION_${_config}) get_filename_component(_path${_config} "${_path${_config}}" PATH) add_custom_command(TARGET ${_target} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E make_directory "${_path${_config}}/" COMMENT "Creating directory ${_path${_config}}/") endforeach() endif() foreach(_res ${_resources}) if(NOT IS_ABSOLUTE "${_res}") get_filename_component(_res "${_res}" ABSOLUTE) endif() get_filename_component(_name "${_res}" NAME) if(MSVC) # Working dir is solution file dir, not exe file dir. add_custom_command(TARGET ${_target} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy "${_res}" "${CMAKE_BINARY_DIR}/" COMMENT "Copying ${_name} to ${CMAKE_BINARY_DIR}/ for MSVC") else() if("${CMAKE_GENERATOR}" MATCHES "Makefiles") add_custom_command(TARGET ${_target} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy "${_res}" "${_path}/" COMMENT "Copying ${_name} to ${_path}/") else() foreach(_config ${CMAKE_CONFIGURATION_TYPES}) add_custom_command(TARGET ${_target} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy "${_res}" "${_path${_config}}" COMMENT "Copying ${_name} to ${_path${_config}}") endforeach() endif() endif() endforeach() endfunction() icinga2-2.8.1/third-party/cmake/FindBISON.cmake000066400000000000000000000222141322762156600210550ustar00rootroot00000000000000# - Find bison executable and provides macros to generate custom build rules # The module defines the following variables: # # BISON_EXECUTABLE - path to the bison program # BISON_VERSION - version of bison # BISON_FOUND - true if the program was found # # If bison is found, the module defines the macros: # BISON_TARGET( [VERBOSE ] # [COMPILE_FLAGS ] [HEADER ]) # which will create a custom rule to generate a parser. is # the path to a yacc file. is the name of the source file # generated by bison. A header file containing the token list is also # generated according to bison's -d option by default or if the HEADER # option is used, the argument is passed to bison's --defines option to # specify output file. If COMPILE_FLAGS option is specified, the next # parameter is added in the bison command line. if VERBOSE option is # specified, is created and contains verbose descriptions of the # grammar and parser. The macro defines a set of variables: # BISON_${Name}_DEFINED - true is the macro ran successfully # BISON_${Name}_INPUT - The input source file, an alias for # BISON_${Name}_OUTPUT_SOURCE - The source file generated by bison # BISON_${Name}_OUTPUT_HEADER - The header file generated by bison # BISON_${Name}_OUTPUTS - The sources files generated by bison # BISON_${Name}_COMPILE_FLAGS - Options used in the bison command line # # ==================================================================== # Example: # # find_package(BISON) # BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp) # add_executable(Foo main.cpp ${BISON_MyParser_OUTPUTS}) # ==================================================================== #============================================================================= # Copyright 2009 Kitware, Inc. # Copyright 2006 Tristan Carel # Modified 2010 by Jon Siwek, adding HEADER option # # Distributed under the OSI-approved BSD License (the "License"): # CMake - Cross Platform Makefile Generator # Copyright 2000-2009 Kitware, Inc., Insight Software Consortium # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= FIND_PROGRAM(BISON_EXECUTABLE bison DOC "path to the bison executable") MARK_AS_ADVANCED(BISON_EXECUTABLE) IF(BISON_EXECUTABLE) EXECUTE_PROCESS(COMMAND ${BISON_EXECUTABLE} --version OUTPUT_VARIABLE BISON_version_output ERROR_VARIABLE BISON_version_error RESULT_VARIABLE BISON_version_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${BISON_version_result} EQUAL 0) MESSAGE(SEND_ERROR "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n${BISON_version_error}") ELSE() STRING(REGEX REPLACE "^bison \\(GNU Bison\\) ([^\n]+)\n.*" "\\1" BISON_VERSION "${BISON_version_output}") ENDIF() # internal macro MACRO(BISON_TARGET_option_verbose Name BisonOutput filename) LIST(APPEND BISON_TARGET_cmdopt "--verbose") GET_FILENAME_COMPONENT(BISON_TARGET_output_path "${BisonOutput}" PATH) GET_FILENAME_COMPONENT(BISON_TARGET_output_name "${BisonOutput}" NAME_WE) ADD_CUSTOM_COMMAND(OUTPUT ${filename} COMMAND ${CMAKE_COMMAND} ARGS -E copy "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output" "${filename}" DEPENDS "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output" COMMENT "[BISON][${Name}] Copying bison verbose table to ${filename}" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) SET(BISON_${Name}_VERBOSE_FILE ${filename}) LIST(APPEND BISON_TARGET_extraoutputs "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output") ENDMACRO(BISON_TARGET_option_verbose) # internal macro MACRO(BISON_TARGET_option_extraopts Options) SET(BISON_TARGET_extraopts "${Options}") SEPARATE_ARGUMENTS(BISON_TARGET_extraopts) LIST(APPEND BISON_TARGET_cmdopt ${BISON_TARGET_extraopts}) ENDMACRO(BISON_TARGET_option_extraopts) #============================================================ # BISON_TARGET (public macro) #============================================================ # MACRO(BISON_TARGET Name BisonInput BisonOutput) SET(BISON_TARGET_output_header "") #SET(BISON_TARGET_command_opt "") SET(BISON_TARGET_cmdopt "") SET(BISON_TARGET_outputs "${BisonOutput}") IF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7 AND NOT ${ARGC} EQUAL 9) MESSAGE(SEND_ERROR "Usage") ELSE() # Parsing parameters IF(${ARGC} GREATER 5 OR ${ARGC} EQUAL 5) IF("${ARGV3}" STREQUAL "VERBOSE") BISON_TARGET_option_verbose(${Name} ${BisonOutput} "${ARGV4}") ENDIF() IF("${ARGV3}" STREQUAL "COMPILE_FLAGS") BISON_TARGET_option_extraopts("${ARGV4}") ENDIF() IF("${ARGV3}" STREQUAL "HEADER") set(BISON_TARGET_output_header "${ARGV4}") ENDIF() ENDIF() IF(${ARGC} GREATER 7 OR ${ARGC} EQUAL 7) IF("${ARGV5}" STREQUAL "VERBOSE") BISON_TARGET_option_verbose(${Name} ${BisonOutput} "${ARGV6}") ENDIF() IF("${ARGV5}" STREQUAL "COMPILE_FLAGS") BISON_TARGET_option_extraopts("${ARGV6}") ENDIF() IF("${ARGV5}" STREQUAL "HEADER") set(BISON_TARGET_output_header "${ARGV6}") ENDIF() ENDIF() IF(${ARGC} EQUAL 9) IF("${ARGV7}" STREQUAL "VERBOSE") BISON_TARGET_option_verbose(${Name} ${BisonOutput} "${ARGV8}") ENDIF() IF("${ARGV7}" STREQUAL "COMPILE_FLAGS") BISON_TARGET_option_extraopts("${ARGV8}") ENDIF() IF("${ARGV7}" STREQUAL "HEADER") set(BISON_TARGET_output_header "${ARGV8}") ENDIF() ENDIF() IF(BISON_TARGET_output_header) # Header's name passed in as argument to be used in --defines option LIST(APPEND BISON_TARGET_cmdopt "--defines=${BISON_TARGET_output_header}") set(BISON_${Name}_OUTPUT_HEADER ${BISON_TARGET_output_header}) ELSE() # Header's name generated by bison (see option -d) LIST(APPEND BISON_TARGET_cmdopt "-d") STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${ARGV2}") STRING(REPLACE "c" "h" _fileext ${_fileext}) STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}" BISON_${Name}_OUTPUT_HEADER "${ARGV2}") ENDIF() LIST(APPEND BISON_TARGET_outputs "${BISON_${Name}_OUTPUT_HEADER}") ADD_CUSTOM_COMMAND(OUTPUT ${BISON_TARGET_outputs} ${BISON_TARGET_extraoutputs} COMMAND ${BISON_EXECUTABLE} ARGS ${BISON_TARGET_cmdopt} -o ${ARGV2} ${ARGV1} DEPENDS ${ARGV1} COMMENT "[BISON][${Name}] Building parser with bison ${BISON_VERSION}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) # define target variables SET(BISON_${Name}_DEFINED TRUE) SET(BISON_${Name}_INPUT ${ARGV1}) SET(BISON_${Name}_OUTPUTS ${BISON_TARGET_outputs}) SET(BISON_${Name}_COMPILE_FLAGS ${BISON_TARGET_cmdopt}) SET(BISON_${Name}_OUTPUT_SOURCE "${BisonOutput}") ENDIF(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5 AND NOT ${ARGC} EQUAL 7 AND NOT ${ARGC} EQUAL 9) ENDMACRO(BISON_TARGET) # #============================================================ ENDIF(BISON_EXECUTABLE) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON DEFAULT_MSG BISON_EXECUTABLE) # FindBISON.cmake ends hereicinga2-2.8.1/third-party/cmake/FindEditline.cmake000066400000000000000000000067031322762156600217450ustar00rootroot00000000000000# Copyright (c) 2014, Matthias Vallentin # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # Tries to find editline headers and libraries # # Usage of this module as follows: # # find_package(Editline) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # EDITLINE_ROOT_DIR Set this variable to the root installation of # editline if the module has problems finding # the proper installation path. # # Variables defined by this module: # # EDITLINE_FOUND System has Editline libs/headers # EDITLINE_LIBRARIES The Editline libraries # EDITLINE_INCLUDE_DIR The location of Editline headers # EDITLINE_VERSION The full version of Editline # EDITLINE_VERSION_MAJOR The version major of Editline # EDITLINE_VERSION_MINOR The version minor of Editline find_path(EDITLINE_INCLUDE_DIR NAMES histedit.h HINTS ${EDITLINE_ROOT_DIR}/include) if (EDITLINE_INCLUDE_DIR) file(STRINGS ${EDITLINE_INCLUDE_DIR}/histedit.h editline_header REGEX "^#define.LIBEDIT_[A-Z]+.*$") string(REGEX REPLACE ".*#define.LIBEDIT_MAJOR[ \t]+([0-9]+).*" "\\1" EDITLINE_VERSION_MAJOR "${editline_header}") string(REGEX REPLACE ".*#define.LIBEDIT_MINOR[ \t]+([0-9]+).*" "\\1" EDITLINE_VERSION_MINOR "${editline_header}") set(EDITLINE_VERSION_MAJOR ${EDITLINE_VERSION_MAJOR} CACHE STRING "" FORCE) set(EDITLINE_VERSION_MINOR ${EDITLINE_VERSION_MINOR} CACHE STRING "" FORCE) set(EDITLINE_VERSION ${EDITLINE_VERSION_MAJOR}.${EDITLINE_VERSION_MINOR} CACHE STRING "" FORCE) endif () find_library(EDITLINE_LIBRARIES NAMES edit HINTS ${EDITLINE_ROOT_DIR}/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( Editline DEFAULT_MSG EDITLINE_LIBRARIES EDITLINE_INCLUDE_DIR) mark_as_advanced( EDITLINE_ROOT_DIR EDITLINE_LIBRARIES EDITLINE_INCLUDE_DIR EDITLINE_VERSION EDITLINE_VERSION_MAJOR EDITLINE_VERSION_MINOR ) icinga2-2.8.1/third-party/cmake/FindFLEX.cmake000066400000000000000000000170511322762156600207440ustar00rootroot00000000000000# - Find flex executable and provides a macro to generate custom build rules # # The module defines the following variables: # FLEX_FOUND - true is flex executable is found # FLEX_EXECUTABLE - the path to the flex executable # FLEX_VERSION - the version of flex # FLEX_LIBRARIES - The flex libraries # # The minimum required version of flex can be specified using the # standard syntax, e.g. FIND_PACKAGE(FLEX 2.5.13) # # # If flex is found on the system, the module provides the macro: # FLEX_TARGET(Name FlexInput FlexOutput [COMPILE_FLAGS ]) # which creates a custom command to generate the file from # the file. If COMPILE_FLAGS option is specified, the next # parameter is added to the flex command line. Name is an alias used to # get details of this custom command. Indeed the macro defines the # following variables: # FLEX_${Name}_DEFINED - true is the macro ran successfully # FLEX_${Name}_OUTPUTS - the source file generated by the custom rule, an # alias for FlexOutput # FLEX_${Name}_INPUT - the flex source file, an alias for ${FlexInput} # # Flex scanners oftenly use tokens defined by Bison: the code generated # by Flex depends of the header generated by Bison. This module also # defines a macro: # ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget) # which adds the required dependency between a scanner and a parser # where and are the first parameters of # respectively FLEX_TARGET and BISON_TARGET macros. # # ==================================================================== # Example: # # find_package(BISON) # find_package(FLEX) # # BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp # FLEX_TARGET(MyScanner lexer.l ${CMAKE_CURRENT_BIANRY_DIR}/lexer.cpp) # ADD_FLEX_BISON_DEPENDENCY(MyScanner MyParser) # # include_directories(${CMAKE_CURRENT_BINARY_DIR}) # add_executable(Foo # Foo.cc # ${BISON_MyParser_OUTPUTS} # ${FLEX_MyScanner_OUTPUTS} # ) # ==================================================================== #============================================================================= # Copyright 2009 Kitware, Inc. # Copyright 2006 Tristan Carel # Modified 2010 by Jon Siwek, backporting for CMake 2.6 compat # # Distributed under the OSI-approved BSD License (the "License"): # CMake - Cross Platform Makefile Generator # Copyright 2000-2009 Kitware, Inc., Insight Software Consortium # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= FIND_PROGRAM(FLEX_EXECUTABLE flex DOC "path to the flex executable") MARK_AS_ADVANCED(FLEX_EXECUTABLE) FIND_LIBRARY(FL_LIBRARY NAMES fl DOC "path to the fl library") MARK_AS_ADVANCED(FL_LIBRARY) SET(FLEX_LIBRARIES ${FL_LIBRARY}) IF(FLEX_EXECUTABLE) GET_FILENAME_COMPONENT(FLEX_EXECUTABLE_NAME ${FLEX_EXECUTABLE} NAME) EXECUTE_PROCESS(COMMAND ${FLEX_EXECUTABLE} --version OUTPUT_VARIABLE FLEX_version_output ERROR_VARIABLE FLEX_version_error RESULT_VARIABLE FLEX_version_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${FLEX_version_result} EQUAL 0) IF(FLEX_FIND_REQUIRED) MESSAGE(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}") ELSE() MESSAGE("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available") ENDIF() ELSE() STRING(REGEX REPLACE "^${FLEX_EXECUTABLE_NAME}[^ ]* (.*)$" "\\1" FLEX_VERSION "${FLEX_version_output}") ENDIF() IF(FLEX_FIND_VERSION) IF("${FLEX_VERSION}" VERSION_LESS "${FLEX_FIND_VERSION}") MESSAGE(SEND_ERROR "Your version of flex is too old. You can specify an alternative path using -DFLEX_EXECUTABLE=/path/to/flex") ENDIF() ENDIF() #============================================================ # FLEX_TARGET (public macro) #============================================================ # MACRO(FLEX_TARGET Name Input Output) SET(FLEX_TARGET_usage "FLEX_TARGET( [COMPILE_FLAGS ]") IF(${ARGC} GREATER 3) IF(${ARGC} EQUAL 5) IF("${ARGV3}" STREQUAL "COMPILE_FLAGS") SET(FLEX_EXECUTABLE_opts "${ARGV4}") SEPARATE_ARGUMENTS(FLEX_EXECUTABLE_opts) ELSE() MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) ENDIF() ELSE() MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) ENDIF() ENDIF() ADD_CUSTOM_COMMAND(OUTPUT ${Output} COMMAND ${FLEX_EXECUTABLE} ARGS ${FLEX_EXECUTABLE_opts} -o${Output} ${Input} DEPENDS ${Input} COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) SET(FLEX_${Name}_DEFINED TRUE) SET(FLEX_${Name}_OUTPUTS ${Output}) SET(FLEX_${Name}_INPUT ${Input}) SET(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts}) ENDMACRO(FLEX_TARGET) #============================================================ #============================================================ # ADD_FLEX_BISON_DEPENDENCY (public macro) #============================================================ # MACRO(ADD_FLEX_BISON_DEPENDENCY FlexTarget BisonTarget) IF(NOT FLEX_${FlexTarget}_OUTPUTS) MESSAGE(SEND_ERROR "Flex target `${FlexTarget}' does not exists.") ENDIF() IF(NOT BISON_${BisonTarget}_OUTPUT_HEADER) MESSAGE(SEND_ERROR "Bison target `${BisonTarget}' does not exists.") ENDIF() SET_SOURCE_FILES_PROPERTIES(${FLEX_${FlexTarget}_OUTPUTS} PROPERTIES OBJECT_DEPENDS ${BISON_${BisonTarget}_OUTPUT_HEADER}) ENDMACRO(ADD_FLEX_BISON_DEPENDENCY) #============================================================ ENDIF(FLEX_EXECUTABLE) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX FLEX_EXECUTABLE FLEX_VERSION) # FindFLEX.cmake ends here icinga2-2.8.1/third-party/cmake/FindGit.cmake000066400000000000000000000040171322762156600207270ustar00rootroot00000000000000#.rst: # FindGit # ------- # # # # The module defines the following variables: # # :: # # GIT_EXECUTABLE - path to git command line client # GIT_FOUND - true if the command line client was found # GIT_VERSION_STRING - the version of git found (since CMake 2.8.8) # # Example usage: # # :: # # find_package(Git) # if(GIT_FOUND) # message("git found: ${GIT_EXECUTABLE}") # endif() #============================================================================= # Copyright 2010 Kitware, Inc. # Copyright 2012 Rolf Eike Beer # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) # Look for 'git' or 'eg' (easy git) # set(git_names git eg) # Prefer .cmd variants on Windows unless running in a Makefile # in the MSYS shell. # if(WIN32) if(NOT CMAKE_GENERATOR MATCHES "MSYS") set(git_names git.cmd git eg.cmd eg) endif() endif() find_program(GIT_EXECUTABLE NAMES ${git_names} PATH_SUFFIXES Git/cmd Git/bin DOC "git command line client" ) mark_as_advanced(GIT_EXECUTABLE) if(GIT_EXECUTABLE) execute_process(COMMAND ${GIT_EXECUTABLE} --version OUTPUT_VARIABLE git_version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (git_version MATCHES "^git version [0-9]") string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}") endif() endif() # Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Git GIT_EXECUTABLE GIT_VERSION_STRING) icinga2-2.8.1/third-party/cmake/FindMySQL.cmake000066400000000000000000000102101322762156600211410ustar00rootroot00000000000000#-------------------------------------------------------- # Copyright (C) 1995-2007 MySQL AB # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # There are special exceptions to the terms and conditions of the GPL # as it is applied to this software. View the full text of the exception # in file LICENSE.exceptions in the top-level directory of this software # distribution. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # The MySQL Connector/ODBC is licensed under the terms of the # GPL, like most MySQL Connectors. There are special exceptions # to the terms and conditions of the GPL as it is applied to # this software, see the FLOSS License Exception available on # mysql.com. ########################################################################## #-------------- FIND MYSQL_INCLUDE_DIR ------------------ FIND_PATH(MYSQL_INCLUDE_DIR mysql.h $ENV{MYSQL_INCLUDE_DIR} $ENV{MYSQL_DIR}/include /usr/include/mysql /usr/local/include/mysql /opt/mysql/mysql/include /opt/mysql/mysql/include/mysql /opt/mysql/include /opt/local/include/mysql5 /usr/local/mysql/include /usr/local/mysql/include/mysql $ENV{ProgramFiles}/MySQL/*/include $ENV{SystemDrive}/MySQL/*/include) #----------------- FIND MYSQL_LIB_DIR ------------------- IF (WIN32) SET(MYSQL_CLIENT_LIBS libmysql) # Set lib path suffixes # dist = for mysql binary distributions # build = for custom built tree IF (CMAKE_BUILD_TYPE STREQUAL Debug) SET(libsuffixDist debug) SET(libsuffixBuild Debug) ELSE (CMAKE_BUILD_TYPE STREQUAL Debug) SET(libsuffixDist opt) SET(libsuffixBuild Release) ADD_DEFINITIONS(-DDBUG_OFF) ENDIF (CMAKE_BUILD_TYPE STREQUAL Debug) FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient PATHS $ENV{MYSQL_DIR}/lib/${libsuffixDist} $ENV{MYSQL_DIR}/libmysql $ENV{MYSQL_DIR}/libmysql/${libsuffixBuild} $ENV{MYSQL_DIR}/client/${libsuffixBuild} $ENV{MYSQL_DIR}/libmysql/${libsuffixBuild} $ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist} $ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist}) ELSE (WIN32) SET(MYSQL_CLIENT_LIBS mysqlclient) FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient PATHS $ENV{MYSQL_DIR}/libmysql_r/.libs $ENV{MYSQL_DIR}/lib $ENV{MYSQL_DIR}/lib/mysql /usr/lib/mysql /usr/local/lib/mysql /usr/local/mysql/lib /usr/local/mysql/lib/mysql /opt/local/mysql5/lib /opt/local/lib/mysql5/mysql /opt/mysql/mysql/lib/mysql /opt/mysql/lib/mysql) ENDIF (WIN32) IF(MYSQL_LIB) GET_FILENAME_COMPONENT(MYSQL_LIB_DIR ${MYSQL_LIB} PATH) ENDIF(MYSQL_LIB) IF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR) SET(MYSQL_FOUND TRUE) INCLUDE_DIRECTORIES(${MYSQL_INCLUDE_DIR}) LINK_DIRECTORIES(${MYSQL_LIB_DIR}) FIND_LIBRARY(MYSQL_ZLIB zlib PATHS ${MYSQL_LIB_DIR}) FIND_LIBRARY(MYSQL_YASSL yassl PATHS ${MYSQL_LIB_DIR}) FIND_LIBRARY(MYSQL_TAOCRYPT taocrypt PATHS ${MYSQL_LIB_DIR}) IF (MYSQL_ZLIB) SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} zlib) ENDIF (MYSQL_ZLIB) IF (MYSQL_YASSL) SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} yassl) ENDIF (MYSQL_YASSL) IF (MYSQL_TAOCRYPT) SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} taocrypt) ENDIF (MYSQL_TAOCRYPT) # Added needed mysqlclient dependencies on Windows IF (WIN32) SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} ws2_32) ENDIF (WIN32) MESSAGE(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}") MESSAGE(STATUS "MySQL client libraries: ${MYSQL_CLIENT_LIBS}") ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR) MESSAGE(STATUS "Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}") SET(MYSQL_FOUND FALSE) ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR) icinga2-2.8.1/third-party/cmake/FindPostgreSQL.cmake000066400000000000000000000177371322762156600222240ustar00rootroot00000000000000#.rst: # FindPostgreSQL # -------------- # # Find the PostgreSQL installation. # # In Windows, we make the assumption that, if the PostgreSQL files are # installed, the default directory will be C:\Program Files\PostgreSQL. # # This module defines # # :: # # PostgreSQL_LIBRARIES - the PostgreSQL libraries needed for linking # PostgreSQL_INCLUDE_DIRS - the directories of the PostgreSQL headers #============================================================================= # Copyright 2004-2009 Kitware, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # ---------------------------------------------------------------------------- # History: # This module is derived from the module originally found in the VTK source tree. # # ---------------------------------------------------------------------------- # Note: # PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the # version mumber of the implementation of PostgreSQL. # In Windows the default installation of PostgreSQL uses that as part of the path. # E.g C:\Program Files\PostgreSQL\8.4. # Currently, the following version numbers are known to this module: # "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" # # To use this variable just do something like this: # set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4") # before calling find_package(PostgreSQL) in your CMakeLists.txt file. # This will mean that the versions you set here will be found first in the order # specified before the default ones are searched. # # ---------------------------------------------------------------------------- # You may need to manually set: # PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are. # PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are. # If FindPostgreSQL.cmake cannot find the include files or the library files. # # ---------------------------------------------------------------------------- # The following variables are set if PostgreSQL is found: # PostgreSQL_FOUND - Set to true when PostgreSQL is found. # PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL # PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries # PostgreSQL_LIBRARIES - The PostgreSQL libraries. # # ---------------------------------------------------------------------------- # If you have installed PostgreSQL in a non-standard location. # (Please note that in the following comments, it is assumed that # points to the root directory of the include directory of PostgreSQL.) # Then you have three options. # 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to /include and # PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is # 2) Use CMAKE_INCLUDE_PATH to set a path to /PostgreSQL<-version>. This will allow find_path() # to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file # set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/include") # 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have # installed PostgreSQL, e.g. . # # ---------------------------------------------------------------------------- set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include") set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}") set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.") set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}") set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4") set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS} "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") # Define additional search paths for root directories. if ( WIN32 ) foreach (suffix ${PostgreSQL_KNOWN_VERSIONS} ) set(PostgreSQL_ADDITIONAL_SEARCH_PATHS ${PostgreSQL_ADDITIONAL_SEARCH_PATHS} "C:/Program Files/PostgreSQL/${suffix}" ) endforeach() endif() set( PostgreSQL_ROOT_DIRECTORIES ENV PostgreSQL_ROOT ${PostgreSQL_ROOT} ${PostgreSQL_ADDITIONAL_SEARCH_PATHS} ) # # Look for an installation. # find_path(PostgreSQL_INCLUDE_DIR NAMES libpq-fe.h PATHS # Look in other places. ${PostgreSQL_ROOT_DIRECTORIES} PATH_SUFFIXES pgsql postgresql include # Help the user find it if we cannot. DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" ) # The PostgreSQL library. set (PostgreSQL_LIBRARY_TO_FIND pq) # Setting some more prefixes for the library set (PostgreSQL_LIB_PREFIX "") if ( WIN32 ) set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib") set ( PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND}) endif() find_library( PostgreSQL_LIBRARY NAMES ${PostgreSQL_LIBRARY_TO_FIND} PATHS ${PostgreSQL_ROOT_DIRECTORIES} PATH_SUFFIXES lib ) get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH) if (PostgreSQL_INCLUDE_DIR AND EXISTS "${PostgreSQL_INCLUDE_DIR}/pg_config.h") file(STRINGS "${PostgreSQL_INCLUDE_DIR}/pg_config.h" pgsql_version_str REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"") string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}") set(pgsql_version_str "") endif() # Did we find anything? include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PostgreSQL DEFAULT_MSG PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR) set( PostgreSQL_FOUND ${POSTGRESQL_FOUND}) # Now try to get the include and library path. if(PostgreSQL_FOUND) set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ) set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} ) set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY_TO_FIND}) #message("Final PostgreSQL include dir: ${PostgreSQL_INCLUDE_DIRS}") #message("Final PostgreSQL library dir: ${PostgreSQL_LIBRARY_DIRS}") #message("Final PostgreSQL libraries: ${PostgreSQL_LIBRARIES}") endif() mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_LIBRARY ) icinga2-2.8.1/third-party/cmake/FindTermcap.cmake000066400000000000000000000051101322762156600215720ustar00rootroot00000000000000# Copyright (c) 2014, Matthias Vallentin # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # Tries to find termcap headers and libraries # # Usage of this module as follows: # # find_package(Termcap) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # TERMCAP_ROOT_DIR Set this variable to the root installation of # termcap if the module has problems finding # the proper installation path. # # Variables defined by this module: # # TERMCAP_FOUND System has Termcap libs/headers # TERMCAP_LIBRARIES The Termcap libraries # TERMCAP_INCLUDE_DIR The location of Termcap headers find_path(TERMCAP_INCLUDE_DIR NAMES termcap.h HINTS ${TERMCAP_ROOT_DIR}/include) find_library(TERMCAP_LIBRARIES NAMES termcap ncurses HINTS ${TERMCAP_ROOT_DIR}/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( Termcap DEFAULT_MSG TERMCAP_LIBRARIES TERMCAP_INCLUDE_DIR) mark_as_advanced( TERMCAP_ROOT_DIR TERMCAP_LIBRARIES TERMCAP_INCLUDE_DIR ) icinga2-2.8.1/third-party/cmake/GNUInstallDirs.cmake000066400000000000000000000221221322762156600222020ustar00rootroot00000000000000#.rst: # GNUInstallDirs # -------------- # # Define GNU standard installation directories # # Provides install directory variables as defined for GNU software: # # :: # # http://www.gnu.org/prep/standards/html_node/Directory-Variables.html # # Inclusion of this module defines the following variables: # # :: # # CMAKE_INSTALL_ - destination for files of a given type # CMAKE_INSTALL_FULL_ - corresponding absolute path # # where is one of: # # :: # # BINDIR - user executables (bin) # SBINDIR - system admin executables (sbin) # LIBEXECDIR - program executables (libexec) # SYSCONFDIR - read-only single-machine data (etc) # SHAREDSTATEDIR - modifiable architecture-independent data (com) # LOCALSTATEDIR - modifiable single-machine data (var) # LIBDIR - object code libraries (lib or lib64 or lib/ on Debian) # INCLUDEDIR - C header files (include) # OLDINCLUDEDIR - C header files for non-gcc (/usr/include) # DATAROOTDIR - read-only architecture-independent data root (share) # DATADIR - read-only architecture-independent data (DATAROOTDIR) # INFODIR - info documentation (DATAROOTDIR/info) # LOCALEDIR - locale-dependent data (DATAROOTDIR/locale) # MANDIR - man documentation (DATAROOTDIR/man) # DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME) # # Each CMAKE_INSTALL_ value may be passed to the DESTINATION # options of install() commands for the corresponding file type. If the # includer does not define a value the above-shown default will be used # and the value will appear in the cache for editing by the user. Each # CMAKE_INSTALL_FULL_ value contains an absolute path constructed # from the corresponding destination by prepending (if necessary) the # value of CMAKE_INSTALL_PREFIX. #============================================================================= # Copyright 2011 Nikita Krupen'ko # Copyright 2011 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) # Installation directories # if(NOT DEFINED CMAKE_INSTALL_BINDIR) set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)") endif() if(NOT DEFINED CMAKE_INSTALL_SBINDIR) set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)") endif() if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR) set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)") endif() if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR) set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)") endif() if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR) set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)") endif() if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR) set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)") endif() if(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(_LIBDIR_DEFAULT "lib") # Override this default 'lib' with 'lib64' iff: # - we are on Linux system but NOT cross-compiling # - we are NOT on debian # - we are on a 64 bits system # reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu" # and CMAKE_INSTALL_PREFIX is "/usr" # See http://wiki.debian.org/Multiarch if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX) set(__LAST_LIBDIR_DEFAULT "lib") # __LAST_LIBDIR_DEFAULT is the default value that we compute from # _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX, not a cache entry for # the value that was last used as the default. # This value is used to figure out whether the user changed the # CMAKE_INSTALL_LIBDIR value manually, or if the value was the # default one. When CMAKE_INSTALL_PREFIX changes, the value is # updated to the new default, unless the user explicitly changed it. endif() if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING) if (EXISTS "/etc/debian_version") # is this a debian system ? if(CMAKE_LIBRARY_ARCHITECTURE) if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$") set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}") endif() if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX AND "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$") set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}") endif() endif() else() # not debian, rely on CMAKE_SIZEOF_VOID_P: if(NOT DEFINED CMAKE_SIZEOF_VOID_P) message(AUTHOR_WARNING "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. " "Please enable at least one language before including GNUInstallDirs.") else() if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") set(_LIBDIR_DEFAULT "lib64") if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX) set(__LAST_LIBDIR_DEFAULT "lib64") endif() endif() endif() endif() endif() if(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})") elseif(DEFINED __LAST_LIBDIR_DEFAULT AND "${__LAST_LIBDIR_DEFAULT}" STREQUAL "${CMAKE_INSTALL_LIBDIR}") set_property(CACHE CMAKE_INSTALL_LIBDIR PROPERTY VALUE "${_LIBDIR_DEFAULT}") endif() endif() # Save for next run set(_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "CMAKE_INSTALL_PREFIX during last run") if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)") endif() if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR) set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)") endif() if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR) set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)") endif() #----------------------------------------------------------------------------- # Values whose defaults are relative to DATAROOTDIR. Store empty values in # the cache and store the defaults in local variables if the cache values are # not set explicitly. This auto-updates the defaults as DATAROOTDIR changes. if(NOT CMAKE_INSTALL_DATADIR) set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)") set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}") endif() if(CMAKE_SYSTEM_NAME MATCHES "(DragonFly|FreeBSD|OpenBSD|NetBSD)") if(NOT CMAKE_INSTALL_INFODIR) set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (info)") set(CMAKE_INSTALL_INFODIR "info") endif() if(NOT CMAKE_INSTALL_MANDDIR) set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (man)") set(CMAKE_INSTALL_MANDIR "man") endif() else() if(NOT CMAKE_INSTALL_INFODIR) set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)") set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info") endif() if(NOT CMAKE_INSTALL_MANDDIR) set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)") set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man") endif() endif() if(NOT CMAKE_INSTALL_LOCALEDIR) set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)") set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale") endif() if(NOT CMAKE_INSTALL_DOCDIR) set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)") set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}") endif() #----------------------------------------------------------------------------- mark_as_advanced( CMAKE_INSTALL_BINDIR CMAKE_INSTALL_SBINDIR CMAKE_INSTALL_LIBEXECDIR CMAKE_INSTALL_SYSCONFDIR CMAKE_INSTALL_SHAREDSTATEDIR CMAKE_INSTALL_LOCALSTATEDIR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_OLDINCLUDEDIR CMAKE_INSTALL_DATAROOTDIR CMAKE_INSTALL_DATADIR CMAKE_INSTALL_INFODIR CMAKE_INSTALL_LOCALEDIR CMAKE_INSTALL_MANDIR CMAKE_INSTALL_DOCDIR ) # Result directories # foreach(dir BINDIR SBINDIR LIBEXECDIR SYSCONFDIR SHAREDSTATEDIR LOCALSTATEDIR LIBDIR INCLUDEDIR OLDINCLUDEDIR DATAROOTDIR DATADIR INFODIR LOCALEDIR MANDIR DOCDIR ) if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}}) set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}") else() set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}") endif() endforeach() icinga2-2.8.1/third-party/cmake/GetForceIncludeDefinitions.cmake000066400000000000000000000027071322762156600246050ustar00rootroot00000000000000# - Get the platform-appropriate flags to add to force inclusion of a file # # The most common use of this is to use a generated config.h-type file # placed out of the source tree in all files. # # get_force_include_definitions(var forcedincludefiles...) - # where var is the name of your desired output variable, and everything # else is a source file to forcibly include. # a list item to be filtered. # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__get_force_include_definitions) return() endif() set(__get_force_include_definitions YES) function(get_force_include_definitions var) set(_flagprefix) if(CMAKE_COMPILER_IS_GNUCXX) set(_flag "-include") elseif(MSVC) set(_flag "/FI") else() message(SEND_ERROR "You don't seem to be using MSVC or GCC, but") message(SEND_ERROR "the project called get_force_include_definitions.") message(SEND_ERROR "Contact this project with the name of your") message(FATAL_ERROR "compiler and preferably the flag to force includes") endif() set(_out) foreach(_item ${ARGN}) list(APPEND _out "${_flag} \"${_item}\"") endforeach() set(${var} "${_out}" PARENT_SCOPE) endfunction() icinga2-2.8.1/third-party/cmake/GetGitRevisionDescription.cmake000066400000000000000000000073141322762156600245140ustar00rootroot00000000000000# - Returns a version string from Git # # These functions force a re-configure on each git commit so that you can # trust the values of the variables in your build system. # # get_git_head_revision( [ ...]) # # Returns the refspec and sha hash of the current head revision # # git_describe( [ ...]) # # Returns the results of git describe on the source tree, and adjusting # the output so that it tests false if an error occurs. # # git_get_exact_tag( [ ...]) # # Returns the results of git describe --exact-match on the source tree, # and adjusting the output so that it tests false if there was no exact # matching tag. # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__get_git_revision_description) return() endif() set(__get_git_revision_description YES) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) function(get_git_head_revision _refspecvar _hashvar) set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}") set(GIT_DIR "${GIT_PARENT_DIR}/.git") while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) # We have reached the root directory, we are not in git set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) return() endif() set(GIT_DIR "${GIT_PARENT_DIR}/.git") endwhile() set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") if(NOT EXISTS "${GIT_DATA}") file(MAKE_DIRECTORY "${GIT_DATA}") endif() if(NOT EXISTS "${GIT_DIR}/HEAD") return() endif() set(HEAD_FILE "${GIT_DATA}/HEAD") configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY) include("${GIT_DATA}/grabRef.cmake") set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) endfunction() function(git_describe _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() get_git_head_revision(refspec hash) if(NOT GIT_FOUND) set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() if(NOT hash) set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) return() endif() # TODO sanitize #if((${ARGN}" MATCHES "&&") OR # (ARGN MATCHES "||") OR # (ARGN MATCHES "\\;")) # message("Please report the following error to the project!") # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") #endif() #message(STATUS "Arguments to execute_process: ${ARGN}") execute_process(COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT res EQUAL 0) set(out "${out}-${res}-NOTFOUND") endif() set(${_var} "${out}" PARENT_SCOPE) endfunction() function(git_get_exact_tag _var) git_describe(out --exact-match ${ARGN}) set(${_var} "${out}" PARENT_SCOPE) endfunction() icinga2-2.8.1/third-party/cmake/GetGitRevisionDescription.cmake.in000066400000000000000000000022621322762156600251160ustar00rootroot00000000000000# # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) set(HEAD_HASH) file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) if(HEAD_CONTENTS MATCHES "ref") # named branch string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) set(HEAD_HASH "${HEAD_REF}") endif() else() # detached HEAD configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) endif() if(NOT HEAD_HASH) file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) string(STRIP "${HEAD_HASH}" HEAD_HASH) endif() icinga2-2.8.1/third-party/execvpe/000077500000000000000000000000001322762156600167565ustar00rootroot00000000000000icinga2-2.8.1/third-party/execvpe/CMakeLists.txt000066400000000000000000000023011322762156600215120ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_library(execvpe SHARED execvpe.c execvpe.h) set_target_properties ( execvpe PROPERTIES DEFINE_SYMBOL I2_EXECVPE_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS execvpe RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS execvpe LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() icinga2-2.8.1/third-party/execvpe/execvpe.c000066400000000000000000000130341322762156600205620ustar00rootroot00000000000000/* Copyright (C) 1991,92, 1995-99, 2002, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) #include #endif /* !__FreeBSD__ && !__OpenBSD__ && !__NetBSD__ */ #include #include #include #include #include #include #include "execvpe.h" #if !defined(_MSC_VER) && !defined(HAVE_EXECVPE) /* The file is accessible but it is not an executable file. Invoke the shell to interpret it as a script. */ static void scripts_argv (const char *file, char *const argv[], int argc, char **new_argv) { /* Construct an argument list for the shell. */ new_argv[0] = (char *) "/bin/sh"; new_argv[1] = (char *) file; while (argc > 1) { new_argv[argc] = argv[argc - 1]; --argc; } } /* Execute FILE, searching in the `PATH' environment variable if it contains no slashes, with arguments ARGV and environment from ENVP. */ int icinga2_execvpe (file, argv, envp) const char *file; char *const argv[]; char *const envp[]; { if (*file == '\0') { /* We check the simple case first. */ errno = ENOENT; return -1; } if (strchr (file, '/') != NULL) { /* Don't search when it contains a slash. */ execve (file, argv, envp); if (errno == ENOEXEC) { /* Count the arguments. */ int argc = 0; while (argv[argc++]) ; size_t len = (argc + 1) * sizeof (char *); char **script_argv; void *ptr = NULL; script_argv = alloca (len); if (script_argv != NULL) { scripts_argv (file, argv, argc, script_argv); execve (script_argv[0], script_argv, envp); free (ptr); } } } else { size_t pathlen; size_t alloclen = 0; char *path = getenv ("PATH"); if (path == NULL) { pathlen = confstr (_CS_PATH, (char *) NULL, 0); alloclen = pathlen + 1; } else pathlen = strlen (path); size_t len = strlen (file) + 1; alloclen += pathlen + len + 1; char *name; name = alloca (alloclen); if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ path = name + pathlen + len + 1; path[0] = ':'; (void) confstr (_CS_PATH, path + 1, pathlen); } /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; char **script_argv = NULL; bool got_eacces = false; char *p = path; do { char *startp; path = p; p = strchr (path, ':'); if (!p) p = path + strlen(path); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ startp = name + 1; else startp = (char *) memcpy (name - (p - path), path, p - path); /* Try to execute this name. If it works, execve will not return. */ execve (startp, argv, envp); if (errno == ENOEXEC) { if (script_argv == NULL) { /* Count the arguments. */ int argc = 0; while (argv[argc++]) ; size_t arglen = (argc + 1) * sizeof (char *); script_argv = alloca (arglen); if (script_argv == NULL) { /* A possible EACCES error is not as important as the ENOMEM. */ got_eacces = false; break; } scripts_argv (startp, argv, argc, script_argv); } execve (script_argv[0], script_argv, envp); } switch (errno) { case EACCES: /* Record the we got a `Permission denied' error. If we end up finding no executable we can use, we want to diagnose that we did find one but were denied access. */ got_eacces = true; case ENOENT: case ESTALE: case ENOTDIR: /* Those errors indicate the file is missing or not executable by us, in which case we want to just try the next path directory. */ case ENODEV: case ETIMEDOUT: /* Some strange filesystems like AFS return even stranger error numbers. They cannot reasonably mean anything else so ignore those, too. */ break; default: /* Some other error means we found an executable file, but something went wrong executing it; return the error to our caller. */ return -1; } } while (*p++ != '\0'); /* We tried every element and none of them worked. */ if (got_eacces) /* At least one failure was due to permissions, so report that error. */ errno = EACCES; } /* Return the error from the last attempt (probably ENOENT). */ return -1; } #endif /* !defined(_MSC_VER) && !defined(HAVE_EXECVPE) */ icinga2-2.8.1/third-party/execvpe/execvpe.h000066400000000000000000000035561322762156600205770ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef EXECVPE_H #define EXECVPE_H #include "base/visibility.hpp" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef I2_EXECVPE_BUILD # define I2_EXECVPE_API I2_EXPORT #else # define I2_EXECVPE_API I2_IMPORT #endif /* I2_EXECVPE_BUILD */ #ifndef _MSC_VER I2_EXECVPE_API int icinga2_execvpe(const char *file, char *const argv[], char *const envp[]); #endif /* _MSC_VER */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* EXECVPE_H */ icinga2-2.8.1/third-party/mmatch/000077500000000000000000000000001322762156600165705ustar00rootroot00000000000000icinga2-2.8.1/third-party/mmatch/CMakeLists.txt000066400000000000000000000022711322762156600213320ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_library(mmatch SHARED mmatch.c mmatch.h) set_target_properties( mmatch PROPERTIES DEFINE_SYMBOL I2_MMATCH_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) install( TARGETS mmatch RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS mmatch LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() icinga2-2.8.1/third-party/mmatch/mmatch.c000066400000000000000000000165111322762156600202110ustar00rootroot00000000000000/* * IRC - Internet Relay Chat, common/match.c * Copyright (C) 1990 Jarkko Oikarinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: Match.cpp,v 1.2 2005/08/15 10:08:50 shroud23 Exp $ */ #include #include "mmatch.h" #define ToLower tolower /* * mmatch() * * Written by Run (carlo@runaway.xs4all.nl), 25-10-96 * * * From: Carlo Wood * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl> * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem) * To: coder-com@mail.undernet.org (coder committee) * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST) * * We need a new function `mmatch(const char *old_mask, const char *new_mask)' * which returns `true' likewise the current `match' (start with copying it), * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !) * as follows: a '*' in `new_mask' does not match a '?' in `old_mask' and * a '?' in `new_mask' does not match a '\?' in `old_mask'. * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'... * And last but not least, '\?' and '\*' in `new_mask' now become one character. */ #if 0 int mmatch(const char *old_mask, const char *new_mask) { const char *m = old_mask; const char *n = new_mask; const char *ma = m; const char *na = n; int wild = 0; int mq = 0, nq = 0; while (1) { if (*m == '*') { while (*m == '*') m++; wild = 1; ma = m; na = n; } if (!*m) { if (!*n) return 0; for (m--; (m > old_mask) && (*m == '?'); m--) ; if ((*m == '*') && (m > old_mask) && (m[-1] != '\\')) return 0; if (!wild) return 1; m = ma; /* Added to `mmatch' : Because '\?' and '\*' now is one character: */ if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?'))) ++na; n = ++na; } else if (!*n) { while (*m == '*') m++; return (*m != 0); } if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) { m++; mq = 1; } else mq = 0; /* Added to `mmatch' : Because '\?' and '\*' now is one character: */ if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?'))) { n++; nq = 1; } else nq = 0; /* * This `if' has been changed compared to match() to do the following: * Match when: * old (m) new (n) boolean expression * * any (*m == '*' && !mq) || * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) || * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) && * ToLower(*m) == ToLower(*n) && * !((mq && !nq) || (!mq && nq))) * * Here `any' also includes \* and \? ! * * After reworking the boolean expressions, we get: * (Optimized to use boolean shortcircuits, with most frequently occuring * cases upfront (which took 2 hours!)). */ if ((*m == '*' && !mq) || ((!mq || nq) && ToLower(*m) == ToLower(*n)) || (*m == '?' && !mq && (*n != '*' || nq))) { if (*m) m++; if (*n) n++; } else { if (!wild) return 1; m = ma; /* Added to `mmatch' : Because '\?' and '\*' now is one character: */ if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?'))) ++na; n = ++na; } } } #endif /* * Compare if a given string (name) matches the given * mask (which can contain wild cards: '*' - match any * number of chars, '?' - match any single character. * * return 0, if match * 1, if no match */ /* * match * * Rewritten by Andrea Cocito (Nemesi), November 1998. * */ /****************** Nemesi's match() ***************/ int match(const char *mask, const char *str) { const char *m = mask, *s = str; char ch; const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */ /* Process the "head" of the mask, if any */ while ((ch = *m++) && (ch != '*')) switch (ch) { case '\\': if (*m == '?' || *m == '*') ch = *m++; default: if (ToLower(*s) != ToLower(ch)) return 1; case '?': if (!*s++) return 1; }; if (!ch) return *s; /* We got a star: quickly find if/where we match the next char */ got_star: bm = m; /* Next try rollback here */ while ((ch = *m++)) switch (ch) { case '?': if (!*s++) return 1; case '*': bm = m; continue; /* while */ case '\\': if (*m == '?' || *m == '*') ch = *m++; default: goto break_while; /* C is structured ? */ }; break_while: if (!ch) return 0; /* mask ends with '*', we got it */ ch = ToLower(ch); if (!*s) /* String is already empty, don't continue */ return 1; /* This fixes the #quakenet access denied bug */ while (ToLower(*s++) != ch) if (!*s) return 1; bs = s; /* Next try start from here */ /* Check the rest of the "chunk" */ while ((ch = *m++)) { switch (ch) { case '*': goto got_star; case '\\': if (*m == '?' || *m == '*') ch = *m++; default: if (ToLower(*s) != ToLower(ch)) { /* If we've run out of string, give up */ if (!*bs) return 1; m = bm; s = bs; goto got_star; }; case '?': if (!*s++) return 1; }; }; if (*s) { m = bm; s = bs; goto got_star; }; return 0; } /* * collapse() * Collapse a pattern string into minimal components. * This particular version is "in place", so that it changes the pattern * which is to be reduced to a "minimal" size. * * (C) Carlo Wood - 6 Oct 1998 * Speedup rewrite by Andrea Cocito, December 1998. * Note that this new optimized alghoritm can *only* work in place. */ #if 0 char *collapse(char *pattern) { int star = 0; char *m = pattern; char *b; if (m) { do { if ((*m == '*') && ((m[1] == '*') || (m[1] == '?'))) { b = m; do { if (*m == '*') star = 1; else { if (star && (*m != '?')) { *b++ = '*'; star = 0; }; *b++ = *m; if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) *b++ = *++m; }; } while (*m++); break; } else { if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) m++; }; } while (*m++); }; return pattern; } #endif icinga2-2.8.1/third-party/mmatch/mmatch.h000066400000000000000000000007571322762156600202230ustar00rootroot00000000000000#ifndef MMATCH_H #define MMATCH_H #include "base/visibility.hpp" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef I2_MMATCH_BUILD # define I2_MMATCH_API I2_EXPORT #else # define I2_MMATCH_API I2_IMPORT #endif /* I2_MMATCH_BUILD */ I2_MMATCH_API int mmatch(const char *old_mask, const char *new_mask); I2_MMATCH_API int match(const char *mask, const char *str); I2_MMATCH_API char *collapse(char *pattern); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* MMATCH_H */ icinga2-2.8.1/third-party/socketpair/000077500000000000000000000000001322762156600174635ustar00rootroot00000000000000icinga2-2.8.1/third-party/socketpair/CMakeLists.txt000066400000000000000000000024241322762156600222250ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_library(socketpair SHARED socketpair.c socketpair.h) set_target_properties ( socketpair PROPERTIES DEFINE_SYMBOL I2_SOCKETPAIR_BUILD FOLDER Lib VERSION ${SPEC_VERSION} ) if(WIN32) target_link_libraries(socketpair ws2_32) endif() install( TARGETS socketpair RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2 ) if(APPLE) install( TARGETS socketpair LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() icinga2-2.8.1/third-party/socketpair/socketpair.c000066400000000000000000000122751322762156600220020ustar00rootroot00000000000000/* socketpair.c Copyright 2007, 2010 by Nathan C. Myers Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The name of the author must not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Changes: * 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements * git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54 * github.com/GerHobbelt/selectable-socketpair * always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64 * and UNIX/other platforms * 2013-07-18: Change to BSD 3-clause license * 2010-03-31: * set addr to 127.0.0.1 because win32 getsockname does not always set it. * 2010-02-25: * set SO_REUSEADDR option to avoid leaking some windows resource. * Windows System Error 10049, "Event ID 4226 TCP/IP has reached * the security limit imposed on the number of concurrent TCP connect * attempts." Bleah. * 2007-04-25: * preserve value of WSAGetLastError() on all error returns. * 2007-04-22: (Thanks to Matthew Gregan ) * s/EINVAL/WSAEINVAL/ fix trivial compile failure * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout * of a child process. * add argument make_overlapped */ #include #ifdef WIN32 # include /* socklen_t, et al (MSVC20xx) */ # include # include #else # include # include # include #endif #include "socketpair.h" #ifdef WIN32 /* dumb_socketpair: * If make_overlapped is nonzero, both sockets created will be usable for * "overlapped" operations via WSASend etc. If make_overlapped is zero, * socks[0] (only) will be usable with regular ReadFile etc., and thus * suitable for use as stdin or stdout of a child process. Note that the * sockets must be closed with closesocket() regardless. */ int dumb_socketpair(SOCKET socks[2], int make_overlapped) { union { struct sockaddr_in inaddr; struct sockaddr addr; } a; SOCKET listener; int e; socklen_t addrlen = sizeof(a.inaddr); DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); int reuse = 1; if (socks == 0) { WSASetLastError(WSAEINVAL); return SOCKET_ERROR; } socks[0] = socks[1] = -1; listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listener == -1) return SOCKET_ERROR; memset(&a, 0, sizeof(a)); a.inaddr.sin_family = AF_INET; a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.inaddr.sin_port = 0; for (;;) { if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) break; if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) break; memset(&a, 0, sizeof(a)); if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) break; // win32 getsockname may only set the port number, p=0.0005. // ( http://msdn.microsoft.com/library/ms738543.aspx ): a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.inaddr.sin_family = AF_INET; if (listen(listener, 1) == SOCKET_ERROR) break; socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); if (socks[0] == -1) break; if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) break; socks[1] = accept(listener, NULL, NULL); if (socks[1] == -1) break; closesocket(listener); return 0; } e = WSAGetLastError(); closesocket(listener); closesocket(socks[0]); closesocket(socks[1]); WSASetLastError(e); socks[0] = socks[1] = -1; return SOCKET_ERROR; } #else int dumb_socketpair(int socks[2], int dummy) { if (socks == 0) { errno = EINVAL; return -1; } dummy = socketpair(AF_UNIX, SOCK_STREAM, 0, socks); if (dummy) socks[0] = socks[1] = -1; return dummy; } #endif icinga2-2.8.1/third-party/socketpair/socketpair.h000066400000000000000000000037451322762156600220110ustar00rootroot00000000000000/* socketpair.h Copyright 2007, 2010 by Nathan C. Myers Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The name of the author must not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SOCKETPAIR_H #define SOCKETPAIR_H #include "base/visibility.hpp" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef I2_SOCKETPAIR_BUILD # define I2_SOCKETPAIR_API I2_EXPORT #else # define I2_SOCKETPAIR_API I2_IMPORT #endif /* I2_SOCKETPAIR_BUILD */ #ifdef _WIN32 I2_SOCKETPAIR_API int dumb_socketpair(SOCKET socks[2], int make_overlapped); #else /* _WIN32 */ I2_SOCKETPAIR_API int dumb_socketpair(int socks[2], int dummy); #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* SOCKETPAIR_H */ icinga2-2.8.1/third-party/yajl/000077500000000000000000000000001322762156600162565ustar00rootroot00000000000000icinga2-2.8.1/third-party/yajl/.gitignore000066400000000000000000000000331322762156600202420ustar00rootroot00000000000000.DS_Store Makefile /build/ icinga2-2.8.1/third-party/yajl/BUILDING000066400000000000000000000007401322762156600173770ustar00rootroot00000000000000Short story (If you already have ruby and cmake): ./configure && make install When things go wrong: attain CMake (http://www.cmake.org) and ruby (http://ruby-lang.org) and try again. OR, attain CMake and build by hand: 1. mkdir build 2. cd build 3. cmake .. 4. make 5. build output left in yajl-X.Y.Z NOTE: for 64-bit systems where lib64 is used you can pass the cmake variable LIB_SUFFIX to cause installation into the system's 'lib64' directory. best, lloyd icinga2-2.8.1/third-party/yajl/BUILDING.win32000066400000000000000000000020021322762156600203310ustar00rootroot00000000000000YAJL has been successfully built using Visual Studio 8. CMake, a build file generator, is used to build the software. CMake supports several different build environments, so you may either build YAJL using the IDE via the following steps: 1. acquire cmake (http://www.cmake.org) 2. mkdir build 3. cd build 4. cmake .. 5. devenv YetAnotherJSONParser.sln /project ALL_BUILD /build Release 6. build output is left in build/yajl-X.Y.Z Or you can build from the command line using nmake: 1. Click Start > Programs > Microsoft Visual Studio > Visual Studio Tools > Visual Studio Command Prompt -- for your version of Visual Studio, which will open a command prompt. You may verify that the compiler is in your path by typing "cl /?" at the prompt. 2. cd C:\path\to\yajl\source\ 3. mkdir build 4. cd build 5. cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. 6. nmake 7. nmake install Earlier versions of visual studio and other build generators haven't been thoroughly tested, but should work without any major issues. icinga2-2.8.1/third-party/yajl/CMakeLists.txt000066400000000000000000000036041322762156600210210ustar00rootroot00000000000000# Copyright (c) 2007-2014, Lloyd Hilaiel # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(YetAnotherJSONParser C) SET (YAJL_MAJOR 2) SET (YAJL_MINOR 1) SET (YAJL_MICRO 0) IF (WIN32) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") ADD_DEFINITIONS(-DWIN32) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996 /wd4255 /wd4130 /wd4100 /wd4711") SET(CMAKE_C_FLAGS_DEBUG "/D DEBUG /Od /Z7") SET(CMAKE_C_FLAGS_RELEASE "/D NDEBUG /O2") ELSE (WIN32) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") IF(CMAKE_COMPILER_IS_GNUCC) INCLUDE(CheckCCompilerFlag) CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_GCC_VISIBILITY) IF(HAVE_GCC_VISIBILITY) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") ENDIF(HAVE_GCC_VISIBILITY) ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pedantic -Wpointer-arith -Wno-format-y2k -Wstrict-prototypes -Wmissing-declarations -Wnested-externs -Wextra -Wundef -Wwrite-strings -Wold-style-definition -Wredundant-decls -Wno-unused-parameter -Wno-sign-compare -Wmissing-prototypes") SET(CMAKE_C_FLAGS_DEBUG "-DDEBUG") SET(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -Wuninitialized") ENDIF (WIN32) ADD_SUBDIRECTORY(src) icinga2-2.8.1/third-party/yajl/COPYING000066400000000000000000000013571322762156600173170ustar00rootroot00000000000000Copyright (c) 2007-2014, Lloyd Hilaiel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. icinga2-2.8.1/third-party/yajl/ChangeLog000066400000000000000000000167561322762156600200470ustar00rootroot000000000000002.1.0 * @nonodename, @patperry - fixed some compiler warnings * @yep, @emaste - documentation improvements * @sgravrock - build fix for NetBSD (and whenever sh != bash) * @rotty, @brimstone3, @lloyd - allow client to reset generator * @sgravrock - remove bash dependencies * @lloyd - add api tests * @rflynn - remove ruby dependency * @cloderic - nmake install works on windows * @shahbag - build fix for qnx * @breese - debugging improvements * @lloyd - json_verify supports -s flag for stream processing * @lloyd - json_reformat supports -s flag for stream processing 2.0.4 * @jcekstrom - additional checking in integer parsing * @jcekstrom - fix a bug in yajl_tree that would cause valid json integersto fail to parse * @plaguemorin - fix a memory leak in yajl_tree (error strings were being leaked) * @7AC - reset errno * @ConradIrwin - include flags to reformatter to allow toggling of escape solidus option 2.0.3 * John Stamp generation of a pkgconfig file at build time. * @robzuber bugfix in yajl_tree_get() * @lloyd - fix for compilation on 64 bit windows 2.0.2 * lth fix typos in yajl_tree.h macros YAJL_IS_INTEGER and YAJL_IS_DOUBLE, contributed by Artem S Vybornov. * lth add #ifdef __cplusplus wrappers to yajl_tree to allow proper usage from many populer C++ compilers. 2.0.1 * lth generator flag to allow client to specify they want escaped solidi '/'. issue #28 * lth crash fix when yajl_parse() is never called. issue #27 2.0.0 * lth YAJL is now ISC licensed: http://en.wikipedia.org/wiki/ISC_license * lth 20-35% (osx and linux respectively) parsing performance improvement attained by tweaking string scanning (idea: @michaelrhanson). * Florian Forster & lth - yajl_tree interface introduced as a higher level interface to the parser (eats JSON, poops a memory representation) * lth require a C99 compiler * lth integers are now represented with long long (64bit+) on all platforms. * lth size_t now used throughout to represent buffer lengths, so you can safely manage buffers greater than 4GB. * gno semantic improvements to yajl's API regarding partial value parsing and trailing garbage * lth new configuration mechanism for yajl, see yajl_config() and yajl_gen_config() * gno more allocation checking in more places * gno remove usage of strtol, replace with custom implementation that cares not about your locale. * lth yajl_parse_complete renamed to yajl_complete_parse. * lth add a switch to validate utf8 strings as they are generated. * lth tests are a lot quieter in their output. * lth addition of a little in tree performance benchmark, `perftest` in perf/perftest.c 1.0.12 * Conrad Irwin - Parse null bytes correctly * Mirek Rusin - fix LLVM warnings * gno - Don't generate numbers for keys. closes #13 * lth - various win32 fixes, including build documentation improvements * John Stamp - Don't export private symbols. * John Stamp - Install yajl_version.h, not the template. * John Stamp - Don't use -fPIC for static lib. Cmake will automatically add it for the shared. * lth 0 fix paths embedded in dylib upon installation on osx. closes #11 1.0.11 * lth remove -Wno-missing-field-initializers for greater gcc compat (3.4.6) 1.0.10 * Brian Maher - yajl is now buildable without a c++ compiler present * Brian Maher - fix header installation on OSX with cmake 2.8.0 installed * lth & vitali - allow builder to specify alternate lib directory for installation (i.e. lib64) * Vitali Lovich - yajl version number now programatically accessible * lth - prevent cmake from embedding rpaths in binaries. Static linking makes this unneccesary. 1.0.9 * lth - fix inverted logic causing yajl_gen_double() to always fail on win32 (thanks to Fredrik Kihlander for the report) 1.0.8 * Randall E. Barker - move dllexport defnitions so dlls with proper exports can again be generated on windows * lth - add yajl_get_bytes_consumed() which allows the client to determine the offset as an error, as well as determine how many bytes of an input buffer were consumed. * lth - fixes to keep "error offset" up to date (like when the client callback returns 0) * Brian Maher - allow client to specify a printing function in generation 1.0.7 * lth fix win32 build (isinf and isnan) 1.0.6 * lth fix several compiler warnings * lth fix generation of invalid json from yajl_gen_double (NaN is not JSON) * jstamp support for combining short options in tools * jstamp exit properly on errors from tools * octo test success no longer depends on integer size * max fix configure --prefix 1.0.5 * lth several performance improvements related to function inlinin' 1.0.4 * lth fix broken utf8 validation for three & four byte represenations. thanks to http://github.com/brianmario and http://github.com/technoweenie 1.0.3 * lth fix syntax error in cplusplus extern "C" statements for wider compiler support 1.0.2 * lth update doxygen documentation with new sample code, passing NULL for allocation functions added in 1.0.0 1.0.1 * lth resolve crash in json_reformatter due to incorrectly ordered parameters. 1.0.0 * lth add 'make install' rules, thaks to Andrei Soroker for the contribution. * lth client may override allocation routines at generator or parser allocation time * tjw add yajl_parse_complete routine to allow client to explicitly specify end-of-input, solving the "lonely number" case, where json text consists only of an element with no explicit syntactic end. * tjw many new test cases * tjw cleanup of code for symmetry and ease of reading * lth integration of patches from Robert Varga which cleanup compilation warnings on 64 bit linux 0.4.0 * lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to Eric Bergstrome * lth yajl_number callback to allow passthrough of arbitrary precision numbers to client. Thanks to Hatem Nassrat. * lth yajl_integer now deals in long, instead of long long. This combined with yajl_number improves compiler compatibility while maintaining precision. * lth better ./configure && make experience (still requires cmake and ruby) * lth fix handling of special characters hex 0F and 1F in yajl_encode (thanks to Robert Geiger) * lth allow leading zeros in exponents (thanks to Hatem Nassrat) 0.3.0 * lth doxygen documentation (html & man) generated as part of the build * lth many documentation updates. * lth fix to work with older versions of cmake (don't use LOOSE_LOOP constructs) * lth work around different behavior of freebsd 4 scanf. initialize parameter to scanf to zero. * lth all tests run 32x with ranging buffer sizes to stress stream parsing * lth yajl_test accepts -b option to allow read buffer size to be set * lth option to validate UTF8 added to parser (argument in yajl_parser_cfg) * lth fix buffer overrun when chunk ends inside \u escaped text * lth support client cancelation 0.2.2 * lth on windows build debug with C7 symbols and no pdb files. 0.2.1 * fix yajl_reformat and yajl_verify to work on arbitrarily sized inputs. * fix win32 build break, clean up all errors and warnings. * fix optimized build flags. 0.2.0 * optionally support comments in input text 0.1.0 * Initial release icinga2-2.8.1/third-party/yajl/README000066400000000000000000000053611322762156600171430ustar00rootroot00000000000000********************************************************************** This is YAJL 2. For the legacy version of YAJL see https://github.com/lloyd/yajl/tree/1.x ********************************************************************** Welcome to Yet Another JSON Library (YAJL) ## Why does the world need another C library for parsing JSON? Good question. In a review of current C JSON parsing libraries I was unable to find one that satisfies my requirements. Those are, 0. written in C 1. portable 2. robust -- as close to "crash proof" as possible 3. data representation independent 4. fast 5. generates verbose, useful error messages including context of where the error occurs in the input text. 6. can parse JSON data off a stream, incrementally 7. simple to use 8. tiny Numbers 3, 5, 6, and 7 were particularly hard to find, and were what caused me to ultimately create YAJL. This document is a tour of some of the more important aspects of YAJL. ## YAJL is Free. Permissive licensing means you can use it in open source and commercial products alike without any fees. My request beyond the licensing is that if you find bugs drop me a email, or better yet, fork and fix. Porting YAJL should be trivial, the implementation is ANSI C. If you port to new systems I'd love to hear of it and integrate your patches. ## YAJL is data representation independent. BYODR! Many JSON libraries impose a structure based data representation on you. This is a benefit in some cases and a drawback in others. YAJL uses callbacks to remain agnostic of the in-memory representation. So if you wish to build up an in-memory representation, you may do so using YAJL, but you must bring the code that defines and populates the in memory structure. This also means that YAJL can be used by other (higher level) JSON libraries if so desired. ## YAJL supports stream parsing This means you do not need to hold the whole JSON representation in textual form in memory. This makes YAJL ideal for filtering projects, where you're converting YAJL from one form to another (i.e. XML). The included JSON pretty printer is an example of such a filter program. ## YAJL is fast Minimal memory copying is performed. YAJL, when possible, returns pointers into the client provided text (i.e. for strings that have no embedded escape chars, hopefully the common case). I've put a lot of effort into profiling and tuning performance, but I have ignored a couple possible performance improvements to keep the interface clean, small, and flexible. My hope is that YAJL will perform comparably to the fastest JSON parser out there. YAJL should impose both minimal CPU and memory requirements on your application. ## YAJL is tiny. Fat free. No whip. enjoy, Lloyd - July, 2007 icinga2-2.8.1/third-party/yajl/TODO000066400000000000000000000005141322762156600167460ustar00rootroot00000000000000* add a test for 0x1F bug * numeric overflow in integers and double * line and char offsets in the lexer and in error messages * testing: a. the permuter b. some performance comparison against json_checker. * investigate pull instead of push parsing * Handle memory allocation failures gracefully * cygwin/msys support on win32 icinga2-2.8.1/third-party/yajl/src/000077500000000000000000000000001322762156600170455ustar00rootroot00000000000000icinga2-2.8.1/third-party/yajl/src/CMakeLists.txt000066400000000000000000000047341322762156600216150ustar00rootroot00000000000000# Copyright (c) 2007-2014, Lloyd Hilaiel # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c yajl_encode.c yajl_gen.c yajl_alloc.c yajl_tree.c yajl_version.c ) SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h yajl_alloc.h) SET (PUB_HDRS api/yajl_parse.h api/yajl_gen.h api/yajl_common.h api/yajl_tree.h) # useful when fixing lexer bugs. #ADD_DEFINITIONS(-DYAJL_LEXER_DEBUG) # Ensure defined when building YAJL (as opposed to using it from # another project). Used to ensure correct function export when # building win32 DLL. ADD_DEFINITIONS(-DYAJL_BUILD) # set up some paths SET (incDir ${CMAKE_CURRENT_BINARY_DIR}/../include/yajl) ADD_LIBRARY(yajl SHARED ${SRCS} ${HDRS} ${PUB_HDRS}) #### setup shared library version number SET_TARGET_PROPERTIES(yajl PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2 DEFINE_SYMBOL YAJL_SHARED SOVERSION ${YAJL_MAJOR} VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO} FOLDER Lib) #### build up an sdk as a post build step # create some directories FILE(MAKE_DIRECTORY ${incDir}) # generate build-time source CONFIGURE_FILE(api/yajl_version.h.cmake ${incDir}/yajl_version.h) # copy public headers to output directory FOREACH (header ${PUB_HDRS}) SET (header "${CMAKE_CURRENT_SOURCE_DIR}/${header}") EXEC_PROGRAM(${CMAKE_COMMAND} ARGS -E copy_if_different \"${header}\" \"${incDir}\") ENDFOREACH (header ${PUB_HDRS}) INCLUDE_DIRECTORIES(${incDir}/..) INSTALL(TARGETS yajl RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2) if(APPLE) install( TARGETS yajl LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents ) endif() icinga2-2.8.1/third-party/yajl/src/api/000077500000000000000000000000001322762156600176165ustar00rootroot00000000000000icinga2-2.8.1/third-party/yajl/src/api/yajl_common.h000066400000000000000000000050141322762156600222760ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __YAJL_COMMON_H__ #define __YAJL_COMMON_H__ #include #ifdef __cplusplus extern "C" { #endif #define YAJL_MAX_DEPTH 128 /* msft dll export gunk. To build a DLL on windows, you * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared * DLL, you must define YAJL_SHARED and WIN32 */ #if (defined(_WIN32) || defined(WIN32)) && defined(YAJL_SHARED) # ifdef YAJL_BUILD # define YAJL_API __declspec(dllexport) # else # define YAJL_API __declspec(dllimport) # endif #else # if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 # define YAJL_API __attribute__ ((visibility("default"))) # else # define YAJL_API # endif #endif /** pointer to a malloc function, supporting client overriding memory * allocation routines */ typedef void * (*yajl_malloc_func)(void *ctx, size_t sz); /** pointer to a free function, supporting client overriding memory * allocation routines */ typedef void (*yajl_free_func)(void *ctx, void * ptr); /** pointer to a realloc function which can resize an allocation. */ typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz); /** A structure which can be passed to yajl_*_alloc routines to allow the * client to specify memory allocation functions to be used. */ typedef struct { /** pointer to a function that can allocate uninitialized memory */ yajl_malloc_func malloc; /** pointer to a function that can resize memory allocations */ yajl_realloc_func realloc; /** pointer to a function that can free memory allocated using * reallocFunction or mallocFunction */ yajl_free_func free; /** a context pointer that will be passed to above allocation routines */ void * ctx; } yajl_alloc_funcs; #ifdef __cplusplus } #endif #endif icinga2-2.8.1/third-party/yajl/src/api/yajl_gen.h000066400000000000000000000156241322762156600215670ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file yajl_gen.h * Interface to YAJL's JSON generation facilities. */ #include #ifndef __YAJL_GEN_H__ #define __YAJL_GEN_H__ #include #ifdef __cplusplus extern "C" { #endif /** generator status codes */ typedef enum { /** no error */ yajl_gen_status_ok = 0, /** at a point where a map key is generated, a function other than * yajl_gen_string was called */ yajl_gen_keys_must_be_strings, /** YAJL's maximum generation depth was exceeded. see * YAJL_MAX_DEPTH */ yajl_max_depth_exceeded, /** A generator function (yajl_gen_XXX) was called while in an error * state */ yajl_gen_in_error_state, /** A complete JSON document has been generated */ yajl_gen_generation_complete, /** yajl_gen_double was passed an invalid floating point value * (infinity or NaN). */ yajl_gen_invalid_number, /** A print callback was passed in, so there is no internal * buffer to get from */ yajl_gen_no_buf, /** returned from yajl_gen_string() when the yajl_gen_validate_utf8 * option is enabled and an invalid was passed by client code. */ yajl_gen_invalid_string } yajl_gen_status; /** an opaque handle to a generator */ typedef struct yajl_gen_t * yajl_gen; /** a callback used for "printing" the results. */ typedef void (*yajl_print_t)(void * ctx, const char * str, size_t len); /** configuration parameters for the parser, these may be passed to * yajl_gen_config() along with option specific argument(s). In general, * all configuration parameters default to *off*. */ typedef enum { /** generate indented (beautiful) output */ yajl_gen_beautify = 0x01, /** * Set an indent string which is used when yajl_gen_beautify * is enabled. Maybe something like \\t or some number of * spaces. The default is four spaces ' '. */ yajl_gen_indent_string = 0x02, /** * Set a function and context argument that should be used to * output generated json. the function should conform to the * yajl_print_t prototype while the context argument is a * void * of your choosing. * * example: * yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr); */ yajl_gen_print_callback = 0x04, /** * Normally the generator does not validate that strings you * pass to it via yajl_gen_string() are valid UTF8. Enabling * this option will cause it to do so. */ yajl_gen_validate_utf8 = 0x08, /** * the forward solidus (slash or '/' in human) is not required to be * escaped in json text. By default, YAJL will not escape it in the * iterest of saving bytes. Setting this flag will cause YAJL to * always escape '/' in generated JSON strings. */ yajl_gen_escape_solidus = 0x10 } yajl_gen_option; /** allow the modification of generator options subsequent to handle * allocation (via yajl_alloc) * \returns zero in case of errors, non-zero otherwise */ YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...); /** allocate a generator handle * \param allocFuncs an optional pointer to a structure which allows * the client to overide the memory allocation * used by yajl. May be NULL, in which case * malloc/free/realloc will be used. * * \returns an allocated handle on success, NULL on failure (bad params) */ YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs); /** free a generator handle */ YAJL_API void yajl_gen_free(yajl_gen handle); YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number); /** generate a floating point number. number may not be infinity or * NaN, as these have no representation in JSON. In these cases the * generator will return 'yajl_gen_invalid_number' */ YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, const char * num, size_t len); YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, const unsigned char * str, size_t len); YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand); /** access the null terminated generator buffer. If incrementally * outputing JSON, one should call yajl_gen_clear to clear the * buffer. This allows stream generation. */ YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand, const unsigned char ** buf, size_t * len); /** clear yajl's output buffer, but maintain all internal generation * state. This function will not "reset" the generator state, and is * intended to enable incremental JSON outputing. */ YAJL_API void yajl_gen_clear(yajl_gen hand); /** Reset the generator state. Allows a client to generate multiple * json entities in a stream. The "sep" string will be inserted to * separate the previously generated entity from the current, * NULL means *no separation* of entites (clients beware, generating * multiple JSON numbers, for instance, will result in inscrutable * output) */ YAJL_API void yajl_gen_reset(yajl_gen hand, const char * sep); #ifdef __cplusplus } #endif #endif icinga2-2.8.1/third-party/yajl/src/api/yajl_parse.h000066400000000000000000000231351322762156600221240ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file yajl_parse.h * Interface to YAJL's JSON stream parsing facilities. */ #include #ifndef __YAJL_PARSE_H__ #define __YAJL_PARSE_H__ #include #ifdef __cplusplus extern "C" { #endif /** error codes returned from this interface */ typedef enum { /** no error was encountered */ yajl_status_ok, /** a client callback returned zero, stopping the parse */ yajl_status_client_canceled, /** An error occured during the parse. Call yajl_get_error for * more information about the encountered error */ yajl_status_error } yajl_status; /** attain a human readable, english, string for an error */ YAJL_API const char * yajl_status_to_string(yajl_status code); /** an opaque handle to a parser */ typedef struct yajl_handle_t * yajl_handle; /** yajl is an event driven parser. this means as json elements are * parsed, you are called back to do something with the data. The * functions in this table indicate the various events for which * you will be called back. Each callback accepts a "context" * pointer, this is a void * that is passed into the yajl_parse * function which the client code may use to pass around context. * * All callbacks return an integer. If non-zero, the parse will * continue. If zero, the parse will be canceled and * yajl_status_client_canceled will be returned from the parse. * * \attention { * A note about the handling of numbers: * * yajl will only convert numbers that can be represented in a * double or a 64 bit (long long) int. All other numbers will * be passed to the client in string form using the yajl_number * callback. Furthermore, if yajl_number is not NULL, it will * always be used to return numbers, that is yajl_integer and * yajl_double will be ignored. If yajl_number is NULL but one * of yajl_integer or yajl_double are defined, parsing of a * number larger than is representable in a double or 64 bit * integer will result in a parse error. * } */ typedef struct { int (* yajl_null)(void * ctx); int (* yajl_boolean)(void * ctx, int boolVal); int (* yajl_integer)(void * ctx, long long integerVal); int (* yajl_double)(void * ctx, double doubleVal); /** A callback which passes the string representation of the number * back to the client. Will be used for all numbers when present */ int (* yajl_number)(void * ctx, const char * numberVal, size_t numberLen); /** strings are returned as pointers into the JSON text when, * possible, as a result, they are _not_ null padded */ int (* yajl_string)(void * ctx, const unsigned char * stringVal, size_t stringLen); int (* yajl_start_map)(void * ctx); int (* yajl_map_key)(void * ctx, const unsigned char * key, size_t stringLen); int (* yajl_end_map)(void * ctx); int (* yajl_start_array)(void * ctx); int (* yajl_end_array)(void * ctx); } yajl_callbacks; /** allocate a parser handle * \param callbacks a yajl callbacks structure specifying the * functions to call when different JSON entities * are encountered in the input text. May be NULL, * which is only useful for validation. * \param afs memory allocation functions, may be NULL for to use * C runtime library routines (malloc and friends) * \param ctx a context pointer that will be passed to callbacks. */ YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks, yajl_alloc_funcs * afs, void * ctx); /** configuration parameters for the parser, these may be passed to * yajl_config() along with option specific argument(s). In general, * all configuration parameters default to *off*. */ typedef enum { /** Ignore javascript style comments present in * JSON input. Non-standard, but rather fun * arguments: toggled off with integer zero, on otherwise. * * example: * yajl_config(h, yajl_allow_comments, 1); // turn comment support on */ yajl_allow_comments = 0x01, /** * When set the parser will verify that all strings in JSON input are * valid UTF8 and will emit a parse error if this is not so. When set, * this option makes parsing slightly more expensive (~7% depending * on processor and compiler in use) * * example: * yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking */ yajl_dont_validate_strings = 0x02, /** * By default, upon calls to yajl_complete_parse(), yajl will * ensure the entire input text was consumed and will raise an error * otherwise. Enabling this flag will cause yajl to disable this * check. This can be useful when parsing json out of a that contains more * than a single JSON document. */ yajl_allow_trailing_garbage = 0x04, /** * Allow multiple values to be parsed by a single handle. The * entire text must be valid JSON, and values can be seperated * by any kind of whitespace. This flag will change the * behavior of the parser, and cause it continue parsing after * a value is parsed, rather than transitioning into a * complete state. This option can be useful when parsing multiple * values from an input stream. */ yajl_allow_multiple_values = 0x08, /** * When yajl_complete_parse() is called the parser will * check that the top level value was completely consumed. I.E., * if called whilst in the middle of parsing a value * yajl will enter an error state (premature EOF). Setting this * flag suppresses that check and the corresponding error. */ yajl_allow_partial_values = 0x10 } yajl_option; /** allow the modification of parser options subsequent to handle * allocation (via yajl_alloc) * \returns zero in case of errors, non-zero otherwise */ YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...); /** free a parser handle */ YAJL_API void yajl_free(yajl_handle handle); /** Parse some json! * \param hand - a handle to the json parser allocated with yajl_alloc * \param jsonText - a pointer to the UTF8 json text to be parsed * \param jsonTextLength - the length, in bytes, of input text */ YAJL_API yajl_status yajl_parse(yajl_handle hand, const unsigned char * jsonText, size_t jsonTextLength); /** Parse any remaining buffered json. * Since yajl is a stream-based parser, without an explicit end of * input, yajl sometimes can't decide if content at the end of the * stream is valid or not. For example, if "1" has been fed in, * yajl can't know whether another digit is next or some character * that would terminate the integer token. * * \param hand - a handle to the json parser allocated with yajl_alloc */ YAJL_API yajl_status yajl_complete_parse(yajl_handle hand); /** get an error string describing the state of the * parse. * * If verbose is non-zero, the message will include the JSON * text where the error occured, along with an arrow pointing to * the specific char. * * \returns A dynamically allocated string will be returned which should * be freed with yajl_free_error */ YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, const unsigned char * jsonText, size_t jsonTextLength); /** * get the amount of data consumed from the last chunk passed to YAJL. * * In the case of a successful parse this can help you understand if * the entire buffer was consumed (which will allow you to handle * "junk at end of input"). * * In the event an error is encountered during parsing, this function * affords the client a way to get the offset into the most recent * chunk where the error occured. 0 will be returned if no error * was encountered. */ YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand); /** free an error returned from yajl_get_error */ YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); #ifdef __cplusplus } #endif #endif icinga2-2.8.1/third-party/yajl/src/api/yajl_tree.h000066400000000000000000000160031322762156600217450ustar00rootroot00000000000000/* * Copyright (c) 2010-2011 Florian Forster * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file yajl_tree.h * * Parses JSON data and returns the data in tree form. * * \author Florian Forster * \date August 2010 * * This interface makes quick parsing and extraction of * smallish JSON docs trivial: * * \include example/parse_config.c */ #ifndef YAJL_TREE_H #define YAJL_TREE_H 1 #include #ifdef __cplusplus extern "C" { #endif /** possible data types that a yajl_val_s can hold */ typedef enum { yajl_t_string = 1, yajl_t_number = 2, yajl_t_object = 3, yajl_t_array = 4, yajl_t_true = 5, yajl_t_false = 6, yajl_t_null = 7, /** The any type isn't valid for yajl_val_s.type, but can be * used as an argument to routines like yajl_tree_get(). */ yajl_t_any = 8 } yajl_type; #define YAJL_NUMBER_INT_VALID 0x01 #define YAJL_NUMBER_DOUBLE_VALID 0x02 /** A pointer to a node in the parse tree */ typedef struct yajl_val_s * yajl_val; /** * A JSON value representation capable of holding one of the seven * types above. For "string", "number", "object", and "array" * additional data is available in the union. The "YAJL_IS_*" * and "YAJL_GET_*" macros below allow type checking and convenient * value extraction. */ struct yajl_val_s { /** Type of the value contained. Use the "YAJL_IS_*" macros to check for a * specific type. */ yajl_type type; /** Type-specific data. You may use the "YAJL_GET_*" macros to access these * members. */ union { char * string; struct { long long i; /*< integer value, if representable. */ double d; /*< double value, if representable. */ char *r; /*< unparsed number in string form. */ /** Signals whether the \em i and \em d members are * valid. See \c YAJL_NUMBER_INT_VALID and * \c YAJL_NUMBER_DOUBLE_VALID. */ unsigned int flags; } number; struct { const char **keys; /*< Array of keys */ yajl_val *values; /*< Array of values. */ size_t len; /*< Number of key-value-pairs. */ } object; struct { yajl_val *values; /*< Array of elements. */ size_t len; /*< Number of elements. */ } array; } u; }; /** * Parse a string. * * Parses an null-terminated string containing JSON data and returns a pointer * to the top-level value (root of the parse tree). * * \param input Pointer to a null-terminated utf8 string containing * JSON data. * \param error_buffer Pointer to a buffer in which an error message will * be stored if \em yajl_tree_parse fails, or * \c NULL. The buffer will be initialized before * parsing, so its content will be destroyed even if * \em yajl_tree_parse succeeds. * \param error_buffer_size Size of the memory area pointed to by * \em error_buffer_size. If \em error_buffer_size is * \c NULL, this argument is ignored. * * \returns Pointer to the top-level value or \c NULL on error. The memory * pointed to must be freed using \em yajl_tree_free. In case of an error, a * null terminated message describing the error in more detail is stored in * \em error_buffer if it is not \c NULL. */ YAJL_API yajl_val yajl_tree_parse (const char *input, char *error_buffer, size_t error_buffer_size); /** * Free a parse tree returned by "yajl_tree_parse". * * \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL * is valid and results in a no-op. */ YAJL_API void yajl_tree_free (yajl_val v); /** * Access a nested value inside a tree. * * \param parent the node under which you'd like to extract values. * \param path A null terminated array of strings, each the name of an object key * \param type the yajl_type of the object you seek, or yajl_t_any if any will do. * * \returns a pointer to the found value, or NULL if we came up empty. * * Future Ideas: it'd be nice to move path to a string and implement support for * a teeny tiny micro language here, so you can extract array elements, do things * like .first and .last, even .length. Inspiration from JSONPath and css selectors? * No it wouldn't be fast, but that's not what this API is about. */ YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type); /* Various convenience macros to check the type of a `yajl_val` */ #define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string)) #define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number)) #define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_INT_VALID)) #define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)) #define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object)) #define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array )) #define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true )) #define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false )) #define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null )) /** Given a yajl_val_string return a ptr to the bare string it contains, * or NULL if the value is not a string. */ #define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL) /** Get the string representation of a number. You should check type first, * perhaps using YAJL_IS_NUMBER */ #define YAJL_GET_NUMBER(v) ((v)->u.number.r) /** Get the double representation of a number. You should check type first, * perhaps using YAJL_IS_DOUBLE */ #define YAJL_GET_DOUBLE(v) ((v)->u.number.d) /** Get the 64bit (long long) integer representation of a number. You should * check type first, perhaps using YAJL_IS_INTEGER */ #define YAJL_GET_INTEGER(v) ((v)->u.number.i) /** Get a pointer to a yajl_val_object or NULL if the value is not an object. */ #define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL) /** Get a pointer to a yajl_val_array or NULL if the value is not an object. */ #define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL) #ifdef __cplusplus } #endif #endif /* YAJL_TREE_H */ icinga2-2.8.1/third-party/yajl/src/api/yajl_version.h.cmake000066400000000000000000000006171322762156600235560ustar00rootroot00000000000000#ifndef YAJL_VERSION_H_ #define YAJL_VERSION_H_ #include #define YAJL_MAJOR ${YAJL_MAJOR} #define YAJL_MINOR ${YAJL_MINOR} #define YAJL_MICRO ${YAJL_MICRO} #define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO) #ifdef __cplusplus extern "C" { #endif extern int YAJL_API yajl_version(void); #ifdef __cplusplus } #endif #endif /* YAJL_VERSION_H_ */ icinga2-2.8.1/third-party/yajl/src/yajl.c000066400000000000000000000115241322762156600201530ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "api/yajl_parse.h" #include "yajl_lex.h" #include "yajl_parser.h" #include "yajl_alloc.h" #include #include #include #include const char * yajl_status_to_string(yajl_status stat) { const char * statStr = "unknown"; switch (stat) { case yajl_status_ok: statStr = "ok, no error"; break; case yajl_status_client_canceled: statStr = "client canceled parse"; break; case yajl_status_error: statStr = "parse error"; break; } return statStr; } yajl_handle yajl_alloc(const yajl_callbacks * callbacks, yajl_alloc_funcs * afs, void * ctx) { yajl_handle hand = NULL; yajl_alloc_funcs afsBuffer; /* first order of business is to set up memory allocation routines */ if (afs != NULL) { if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) { return NULL; } } else { yajl_set_default_alloc_funcs(&afsBuffer); afs = &afsBuffer; } hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); /* copy in pointers to allocation routines */ memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); hand->callbacks = callbacks; hand->ctx = ctx; hand->lexer = NULL; hand->bytesConsumed = 0; hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); hand->flags = 0; yajl_bs_init(hand->stateStack, &(hand->alloc)); yajl_bs_push(hand->stateStack, yajl_state_start); return hand; } int yajl_config(yajl_handle h, yajl_option opt, ...) { int rv = 1; va_list ap; va_start(ap, opt); switch(opt) { case yajl_allow_comments: case yajl_dont_validate_strings: case yajl_allow_trailing_garbage: case yajl_allow_multiple_values: case yajl_allow_partial_values: if (va_arg(ap, int)) h->flags |= opt; else h->flags &= ~opt; break; default: rv = 0; } va_end(ap); return rv; } void yajl_free(yajl_handle handle) { yajl_bs_free(handle->stateStack); yajl_buf_free(handle->decodeBuf); if (handle->lexer) { yajl_lex_free(handle->lexer); handle->lexer = NULL; } YA_FREE(&(handle->alloc), handle); } yajl_status yajl_parse(yajl_handle hand, const unsigned char * jsonText, size_t jsonTextLen) { yajl_status status; /* lazy allocation of the lexer */ if (hand->lexer == NULL) { hand->lexer = yajl_lex_alloc(&(hand->alloc), hand->flags & yajl_allow_comments, !(hand->flags & yajl_dont_validate_strings)); } status = yajl_do_parse(hand, jsonText, jsonTextLen); return status; } yajl_status yajl_complete_parse(yajl_handle hand) { /* The lexer is lazy allocated in the first call to parse. if parse is * never called, then no data was provided to parse at all. This is a * "premature EOF" error unless yajl_allow_partial_values is specified. * allocating the lexer now is the simplest possible way to handle this * case while preserving all the other semantics of the parser * (multiple values, partial values, etc). */ if (hand->lexer == NULL) { hand->lexer = yajl_lex_alloc(&(hand->alloc), hand->flags & yajl_allow_comments, !(hand->flags & yajl_dont_validate_strings)); } return yajl_do_finish(hand); } unsigned char * yajl_get_error(yajl_handle hand, int verbose, const unsigned char * jsonText, size_t jsonTextLen) { return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); } size_t yajl_get_bytes_consumed(yajl_handle hand) { if (!hand) return 0; else return hand->bytesConsumed; } void yajl_free_error(yajl_handle hand, unsigned char * str) { /* use memory allocation functions if set */ YA_FREE(&(hand->alloc), str); } /* XXX: add utility routines to parse from file */ icinga2-2.8.1/third-party/yajl/src/yajl_alloc.c000066400000000000000000000027501322762156600213260ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file yajl_alloc.h * default memory allocation routines for yajl which use malloc/realloc and * free */ #include "yajl_alloc.h" #include static void * yajl_internal_malloc(void *ctx, size_t sz) { (void)ctx; return malloc(sz); } static void * yajl_internal_realloc(void *ctx, void * previous, size_t sz) { (void)ctx; return realloc(previous, sz); } static void yajl_internal_free(void *ctx, void * ptr) { (void)ctx; free(ptr); } void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) { yaf->malloc = yajl_internal_malloc; yaf->free = yajl_internal_free; yaf->realloc = yajl_internal_realloc; yaf->ctx = NULL; } icinga2-2.8.1/third-party/yajl/src/yajl_alloc.h000066400000000000000000000023411322762156600213270ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * \file yajl_alloc.h * default memory allocation routines for yajl which use malloc/realloc and * free */ #ifndef __YAJL_ALLOC_H__ #define __YAJL_ALLOC_H__ #include "api/yajl_common.h" #define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) #define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) #define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); #endif icinga2-2.8.1/third-party/yajl/src/yajl_buf.c000066400000000000000000000047321322762156600210120ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "yajl_buf.h" #include #include #include #define YAJL_BUF_INIT_SIZE 2048 struct yajl_buf_t { size_t len; size_t used; unsigned char * data; yajl_alloc_funcs * alloc; }; static void yajl_buf_ensure_available(yajl_buf buf, size_t want) { size_t need; assert(buf != NULL); /* first call */ if (buf->data == NULL) { buf->len = YAJL_BUF_INIT_SIZE; buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); buf->data[0] = 0; } need = buf->len; while (want >= (need - buf->used)) need <<= 1; if (need != buf->len) { buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); buf->len = need; } } yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) { yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); memset((void *) b, 0, sizeof(struct yajl_buf_t)); b->alloc = alloc; return b; } void yajl_buf_free(yajl_buf buf) { assert(buf != NULL); if (buf->data) YA_FREE(buf->alloc, buf->data); YA_FREE(buf->alloc, buf); } void yajl_buf_append(yajl_buf buf, const void * data, size_t len) { yajl_buf_ensure_available(buf, len); if (len > 0) { assert(data != NULL); memcpy(buf->data + buf->used, data, len); buf->used += len; buf->data[buf->used] = 0; } } void yajl_buf_clear(yajl_buf buf) { buf->used = 0; if (buf->data) buf->data[buf->used] = 0; } const unsigned char * yajl_buf_data(yajl_buf buf) { return buf->data; } size_t yajl_buf_len(yajl_buf buf) { return buf->used; } void yajl_buf_truncate(yajl_buf buf, size_t len) { assert(len <= buf->used); buf->used = len; } icinga2-2.8.1/third-party/yajl/src/yajl_buf.h000066400000000000000000000035031322762156600210120ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __YAJL_BUF_H__ #define __YAJL_BUF_H__ #include "api/yajl_common.h" #include "yajl_alloc.h" /* * Implementation/performance notes. If this were moved to a header * only implementation using #define's where possible we might be * able to sqeeze a little performance out of the guy by killing function * call overhead. YMMV. */ /** * yajl_buf is a buffer with exponential growth. the buffer ensures that * you are always null padded. */ typedef struct yajl_buf_t * yajl_buf; /* allocate a new buffer */ yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); /* free the buffer */ void yajl_buf_free(yajl_buf buf); /* append a number of bytes to the buffer */ void yajl_buf_append(yajl_buf buf, const void * data, size_t len); /* empty the buffer */ void yajl_buf_clear(yajl_buf buf); /* get a pointer to the beginning of the buffer */ const unsigned char * yajl_buf_data(yajl_buf buf); /* get the length of the buffer */ size_t yajl_buf_len(yajl_buf buf); /* truncate the buffer */ void yajl_buf_truncate(yajl_buf buf, size_t len); #endif icinga2-2.8.1/third-party/yajl/src/yajl_bytestack.h000066400000000000000000000045131322762156600222310ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A header only implementation of a simple stack of bytes, used in YAJL * to maintain parse state. */ #ifndef __YAJL_BYTESTACK_H__ #define __YAJL_BYTESTACK_H__ #include "api/yajl_common.h" #define YAJL_BS_INC 128 typedef struct yajl_bytestack_t { unsigned char * stack; size_t size; size_t used; yajl_alloc_funcs * yaf; } yajl_bytestack; /* initialize a bytestack */ #define yajl_bs_init(obs, _yaf) { \ (obs).stack = NULL; \ (obs).size = 0; \ (obs).used = 0; \ (obs).yaf = (_yaf); \ } \ /* initialize a bytestack */ #define yajl_bs_free(obs) \ if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); #define yajl_bs_current(obs) \ (assert((obs).used > 0), (obs).stack[(obs).used - 1]) #define yajl_bs_push(obs, byte) { \ if (((obs).size - (obs).used) == 0) { \ (obs).size += YAJL_BS_INC; \ (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\ (void *) (obs).stack, (obs).size);\ } \ (obs).stack[((obs).used)++] = (byte); \ } /* removes the top item of the stack, returns nothing */ #define yajl_bs_pop(obs) { ((obs).used)--; } #define yajl_bs_set(obs, byte) \ (obs).stack[((obs).used) - 1] = (byte); #endif icinga2-2.8.1/third-party/yajl/src/yajl_encode.c000066400000000000000000000161501322762156600214700ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "yajl_encode.h" #include #include #include #include static void CharToHex(unsigned char c, char * hexBuf) { const char * hexchar = "0123456789ABCDEF"; hexBuf[0] = hexchar[c >> 4]; hexBuf[1] = hexchar[c & 0x0F]; } void yajl_string_encode(const yajl_print_t print, void * ctx, const unsigned char * str, size_t len, int escape_solidus) { size_t beg = 0; size_t end = 0; char hexBuf[7]; hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; hexBuf[6] = 0; while (end < len) { const char * escaped = NULL; switch (str[end]) { case '\r': escaped = "\\r"; break; case '\n': escaped = "\\n"; break; case '\\': escaped = "\\\\"; break; /* it is not required to escape a solidus in JSON: * read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt * specifically, this production from the grammar: * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF */ case '/': if (escape_solidus) escaped = "\\/"; break; case '"': escaped = "\\\""; break; case '\f': escaped = "\\f"; break; case '\b': escaped = "\\b"; break; case '\t': escaped = "\\t"; break; default: if ((unsigned char) str[end] < 32) { CharToHex(str[end], hexBuf + 4); escaped = hexBuf; } break; } if (escaped != NULL) { print(ctx, (const char *) (str + beg), end - beg); print(ctx, escaped, (unsigned int)strlen(escaped)); beg = ++end; } else { ++end; } } print(ctx, (const char *) (str + beg), end - beg); } static void hexToDigit(unsigned int * val, const unsigned char * hex) { unsigned int i; for (i=0;i<4;i++) { unsigned char c = hex[i]; if (c >= 'A') c = (c & ~0x20) - 7; c -= '0'; assert(!(c & 0xF0)); *val = (*val << 4) | c; } } static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) { if (codepoint < 0x80) { utf8Buf[0] = (char) codepoint; utf8Buf[1] = 0; } else if (codepoint < 0x0800) { utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); utf8Buf[2] = 0; } else if (codepoint < 0x10000) { utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); utf8Buf[3] = 0; } else if (codepoint < 0x200000) { utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); utf8Buf[4] = 0; } else { utf8Buf[0] = '?'; utf8Buf[1] = 0; } } void yajl_string_decode(yajl_buf buf, const unsigned char * str, size_t len) { size_t beg = 0; size_t end = 0; while (end < len) { if (str[end] == '\\') { char utf8Buf[5]; const char * unescaped = "?"; yajl_buf_append(buf, str + beg, end - beg); switch (str[++end]) { case 'r': unescaped = "\r"; break; case 'n': unescaped = "\n"; break; case '\\': unescaped = "\\"; break; case '/': unescaped = "/"; break; case '"': unescaped = "\""; break; case 'f': unescaped = "\f"; break; case 'b': unescaped = "\b"; break; case 't': unescaped = "\t"; break; case 'u': { unsigned int codepoint = 0; hexToDigit(&codepoint, str + ++end); end+=3; /* check if this is a surrogate */ if ((codepoint & 0xFC00) == 0xD800) { end++; if (str[end] == '\\' && str[end + 1] == 'u') { unsigned int surrogate = 0; hexToDigit(&surrogate, str + end + 2); codepoint = (((codepoint & 0x3F) << 10) | ((((codepoint >> 6) & 0xF) + 1) << 16) | (surrogate & 0x3FF)); end += 5; } else { unescaped = "?"; break; } } Utf32toUtf8(codepoint, utf8Buf); unescaped = utf8Buf; if (codepoint == 0) { yajl_buf_append(buf, unescaped, 1); beg = ++end; continue; } break; } default: assert("this should never happen" == NULL); } yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped)); beg = ++end; } else { end++; } } yajl_buf_append(buf, str + beg, end - beg); } #define ADV_PTR s++; if (!(len--)) return 0; int yajl_string_validate_utf8(const unsigned char * s, size_t len) { if (!len) return 1; if (!s) return 0; while (len--) { /* single byte */ if (*s <= 0x7f) { /* noop */ } /* two byte */ else if ((*s >> 5) == 0x6) { ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; } /* three byte */ else if ((*s >> 4) == 0x0e) { ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; } /* four byte */ else if ((*s >> 3) == 0x1e) { ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; ADV_PTR; if (!((*s >> 6) == 0x2)) return 0; } else { return 0; } s++; } return 1; } icinga2-2.8.1/third-party/yajl/src/yajl_encode.h000066400000000000000000000024301322762156600214710ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __YAJL_ENCODE_H__ #define __YAJL_ENCODE_H__ #include "yajl_buf.h" #include "api/yajl_gen.h" void yajl_string_encode(const yajl_print_t printer, void * ctx, const unsigned char * str, size_t length, int escape_solidus); void yajl_string_decode(yajl_buf buf, const unsigned char * str, size_t length); int yajl_string_validate_utf8(const unsigned char * s, size_t len); #endif icinga2-2.8.1/third-party/yajl/src/yajl_gen.c000066400000000000000000000253471322762156600210140ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "api/yajl_gen.h" #include "yajl_buf.h" #include "yajl_encode.h" #include #include #include #include #include typedef enum { yajl_gen_start, yajl_gen_map_start, yajl_gen_map_key, yajl_gen_map_val, yajl_gen_array_start, yajl_gen_in_array, yajl_gen_complete, yajl_gen_error } yajl_gen_state; struct yajl_gen_t { unsigned int flags; unsigned int depth; const char * indentString; yajl_gen_state state[YAJL_MAX_DEPTH]; yajl_print_t print; void * ctx; /* yajl_buf */ /* memory allocation routines */ yajl_alloc_funcs alloc; }; int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...) { int rv = 1; va_list ap; va_start(ap, opt); switch(opt) { case yajl_gen_beautify: case yajl_gen_validate_utf8: case yajl_gen_escape_solidus: if (va_arg(ap, int)) g->flags |= opt; else g->flags &= ~opt; break; case yajl_gen_indent_string: { const char *indent = va_arg(ap, const char *); g->indentString = indent; for (; *indent; indent++) { if (*indent != '\n' && *indent != '\v' && *indent != '\f' && *indent != '\t' && *indent != '\r' && *indent != ' ') { g->indentString = NULL; rv = 0; } } break; } case yajl_gen_print_callback: yajl_buf_free(g->ctx); g->print = va_arg(ap, const yajl_print_t); g->ctx = va_arg(ap, void *); break; default: rv = 0; } va_end(ap); return rv; } yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * afs) { yajl_gen g = NULL; yajl_alloc_funcs afsBuffer; /* first order of business is to set up memory allocation routines */ if (afs != NULL) { if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) { return NULL; } } else { yajl_set_default_alloc_funcs(&afsBuffer); afs = &afsBuffer; } g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); if (!g) return NULL; memset((void *) g, 0, sizeof(struct yajl_gen_t)); /* copy in pointers to allocation routines */ memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); g->print = (yajl_print_t)&yajl_buf_append; g->ctx = yajl_buf_alloc(&(g->alloc)); g->indentString = " "; return g; } void yajl_gen_reset(yajl_gen g, const char * sep) { g->depth = 0; memset((void *) &(g->state), 0, sizeof(g->state)); if (sep != NULL) g->print(g->ctx, sep, strlen(sep)); } void yajl_gen_free(yajl_gen g) { if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); YA_FREE(&(g->alloc), g); } #define INSERT_SEP \ if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_in_array) { \ g->print(g->ctx, ",", 1); \ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \ } else if (g->state[g->depth] == yajl_gen_map_val) { \ g->print(g->ctx, ":", 1); \ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \ } #define INSERT_WHITESPACE \ if ((g->flags & yajl_gen_beautify)) { \ if (g->state[g->depth] != yajl_gen_map_val) { \ unsigned int _i; \ for (_i=0;_idepth;_i++) \ g->print(g->ctx, \ g->indentString, \ (unsigned int)strlen(g->indentString)); \ } \ } #define ENSURE_NOT_KEY \ if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_map_start) { \ return yajl_gen_keys_must_be_strings; \ } \ /* check that we're not complete, or in error state. in a valid state * to be generating */ #define ENSURE_VALID_STATE \ if (g->state[g->depth] == yajl_gen_error) { \ return yajl_gen_in_error_state;\ } else if (g->state[g->depth] == yajl_gen_complete) { \ return yajl_gen_generation_complete; \ } #define INCREMENT_DEPTH \ if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded; #define DECREMENT_DEPTH \ if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_generation_complete; #define APPENDED_ATOM \ switch (g->state[g->depth]) { \ case yajl_gen_start: \ g->state[g->depth] = yajl_gen_complete; \ break; \ case yajl_gen_map_start: \ case yajl_gen_map_key: \ g->state[g->depth] = yajl_gen_map_val; \ break; \ case yajl_gen_array_start: \ g->state[g->depth] = yajl_gen_in_array; \ break; \ case yajl_gen_map_val: \ g->state[g->depth] = yajl_gen_map_key; \ break; \ default: \ break; \ } \ #define FINAL_NEWLINE \ if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \ g->print(g->ctx, "\n", 1); yajl_gen_status yajl_gen_integer(yajl_gen g, long long int number) { char i[32]; ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; sprintf(i, "%lld", number); g->print(g->ctx, i, (unsigned int)strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } #if defined(_WIN32) || defined(WIN32) #include #define isnan _isnan #define isinf !_finite #endif yajl_gen_status yajl_gen_double(yajl_gen g, double number) { char i[32]; ENSURE_VALID_STATE; ENSURE_NOT_KEY; if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; INSERT_SEP; INSERT_WHITESPACE; sprintf(i, "%.20g", number); if (strspn(i, "0123456789-") == strlen(i)) { strcat(i, ".0"); } g->print(g->ctx, i, (unsigned int)strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_number(yajl_gen g, const char * s, size_t l) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, s, l); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_string(yajl_gen g, const unsigned char * str, size_t len) { // if validation is enabled, check that the string is valid utf8 // XXX: This checking could be done a little faster, in the same pass as // the string encoding if (g->flags & yajl_gen_validate_utf8) { if (!yajl_string_validate_utf8(str, len)) { return yajl_gen_invalid_string; } } ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, "\"", 1); yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus); g->print(g->ctx, "\"", 1); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_null(yajl_gen g) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, "null", strlen("null")); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_bool(yajl_gen g, int boolean) { const char * val = boolean ? "true" : "false"; ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, val, (unsigned int)strlen(val)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_map_open(yajl_gen g) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; INCREMENT_DEPTH; g->state[g->depth] = yajl_gen_map_start; g->print(g->ctx, "{", 1); if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_map_close(yajl_gen g) { ENSURE_VALID_STATE; DECREMENT_DEPTH; if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "}", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_array_open(yajl_gen g) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; INCREMENT_DEPTH; g->state[g->depth] = yajl_gen_array_start; g->print(g->ctx, "[", 1); if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_array_close(yajl_gen g) { ENSURE_VALID_STATE; DECREMENT_DEPTH; if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "]", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, size_t * len) { if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; *buf = yajl_buf_data((yajl_buf)g->ctx); *len = yajl_buf_len((yajl_buf)g->ctx); return yajl_gen_status_ok; } void yajl_gen_clear(yajl_gen g) { if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); } icinga2-2.8.1/third-party/yajl/src/yajl_lex.c000066400000000000000000000631301322762156600210230ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "yajl_lex.h" #include "yajl_buf.h" #include #include #include #include #ifdef YAJL_LEXER_DEBUG static const char * tokToStr(yajl_tok tok) { switch (tok) { case yajl_tok_bool: return "bool"; case yajl_tok_colon: return "colon"; case yajl_tok_comma: return "comma"; case yajl_tok_eof: return "eof"; case yajl_tok_error: return "error"; case yajl_tok_left_brace: return "brace"; case yajl_tok_left_bracket: return "bracket"; case yajl_tok_null: return "null"; case yajl_tok_integer: return "integer"; case yajl_tok_double: return "double"; case yajl_tok_right_brace: return "brace"; case yajl_tok_right_bracket: return "bracket"; case yajl_tok_string: return "string"; case yajl_tok_string_with_escapes: return "string_with_escapes"; } return "unknown"; } #endif /* Impact of the stream parsing feature on the lexer: * * YAJL support stream parsing. That is, the ability to parse the first * bits of a chunk of JSON before the last bits are available (still on * the network or disk). This makes the lexer more complex. The * responsibility of the lexer is to handle transparently the case where * a chunk boundary falls in the middle of a token. This is * accomplished is via a buffer and a character reading abstraction. * * Overview of implementation * * When we lex to end of input string before end of token is hit, we * copy all of the input text composing the token into our lexBuf. * * Every time we read a character, we do so through the readChar function. * readChar's responsibility is to handle pulling all chars from the buffer * before pulling chars from input text */ struct yajl_lexer_t { /* the overal line and char offset into the data */ size_t lineOff; size_t charOff; /* error */ yajl_lex_error error; /* a input buffer to handle the case where a token is spread over * multiple chunks */ yajl_buf buf; /* in the case where we have data in the lexBuf, bufOff holds * the current offset into the lexBuf. */ size_t bufOff; /* are we using the lex buf? */ unsigned int bufInUse; /* shall we allow comments? */ unsigned int allowComments; /* shall we validate utf8 inside strings? */ unsigned int validateUTF8; yajl_alloc_funcs * alloc; }; #define readChar(lxr, txt, off) \ (((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \ (*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \ ((txt)[(*(off))++])) #define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--)) yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, unsigned int allowComments, unsigned int validateUTF8) { yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t)); memset((void *) lxr, 0, sizeof(struct yajl_lexer_t)); lxr->buf = yajl_buf_alloc(alloc); lxr->allowComments = allowComments; lxr->validateUTF8 = validateUTF8; lxr->alloc = alloc; return lxr; } void yajl_lex_free(yajl_lexer lxr) { yajl_buf_free(lxr->buf); YA_FREE(lxr->alloc, lxr); return; } /* a lookup table which lets us quickly determine three things: * VEC - valid escaped control char * note. the solidus '/' may be escaped or not. * IJC - invalid json char * VHC - valid hex char * NFP - needs further processing (from a string scanning perspective) * NUC - needs utf8 checking when enabled (from a string scanning perspective) */ #define VEC 0x01 #define IJC 0x02 #define VHC 0x04 #define NFP 0x08 #define NUC 0x10 static const char charLookupTable[256] = { /*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , /*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , /*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , /*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , /*20*/ 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , 0 , 0 , /*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC , /*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC , /*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 , /*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 , /*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /*58*/ 0 , 0 , 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , /*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 , /*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 , /*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 , /*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC }; /** process a variable length utf8 encoded codepoint. * * returns: * yajl_tok_string - if valid utf8 char was parsed and offset was * advanced * yajl_tok_eof - if end of input was hit before validation could * complete * yajl_tok_error - if invalid utf8 was encountered * * NOTE: on error the offset will point to the first char of the * invalid utf8 */ #define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; } static yajl_tok yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset, unsigned char curChar) { if (curChar <= 0x7f) { /* single byte */ return yajl_tok_string; } else if ((curChar >> 5) == 0x6) { /* two byte */ UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) return yajl_tok_string; } else if ((curChar >> 4) == 0x0e) { /* three byte */ UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) { UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) return yajl_tok_string; } } else if ((curChar >> 3) == 0x1e) { /* four byte */ UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) { UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) { UTF8_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if ((curChar >> 6) == 0x2) return yajl_tok_string; } } } return yajl_tok_error; } /* lex a string. input is the lexer, pointer to beginning of * json text, and start of string (offset). * a token is returned which has the following meanings: * yajl_tok_string: lex of string was successful. offset points to * terminating '"'. * yajl_tok_eof: end of text was encountered before we could complete * the lex. * yajl_tok_error: embedded in the string were unallowable chars. offset * points to the offending char */ #define STR_CHECK_EOF \ if (*offset >= jsonTextLen) { \ tok = yajl_tok_eof; \ goto finish_string_lex; \ } /** scan a string for interesting characters that might need further * review. return the number of chars that are uninteresting and can * be skipped. * (lth) hi world, any thoughts on how to make this routine faster? */ static size_t yajl_string_scan(const unsigned char * buf, size_t len, int utf8check) { unsigned char mask = IJC|NFP|(utf8check ? NUC : 0); size_t skip = 0; while (skip < len && !(charLookupTable[*buf] & mask)) { skip++; buf++; } return skip; } static yajl_tok yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset) { yajl_tok tok = yajl_tok_error; int hasEscapes = 0; for (;;) { unsigned char curChar; /* now jump into a faster scanning routine to skip as much * of the buffers as possible */ { const unsigned char * p; size_t len; if ((lexer->bufInUse && yajl_buf_len(lexer->buf) && lexer->bufOff < yajl_buf_len(lexer->buf))) { p = ((const unsigned char *) yajl_buf_data(lexer->buf) + (lexer->bufOff)); len = yajl_buf_len(lexer->buf) - lexer->bufOff; lexer->bufOff += yajl_string_scan(p, len, lexer->validateUTF8); } else if (*offset < jsonTextLen) { p = jsonText + *offset; len = jsonTextLen - *offset; *offset += yajl_string_scan(p, len, lexer->validateUTF8); } } STR_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); /* quote terminates */ if (curChar == '"') { tok = yajl_tok_string; break; } /* backslash escapes a set of control chars, */ else if (curChar == '\\') { hasEscapes = 1; STR_CHECK_EOF; /* special case \u */ curChar = readChar(lexer, jsonText, offset); if (curChar == 'u') { unsigned int i = 0; for (i=0;i<4;i++) { STR_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); if (!(charLookupTable[curChar] & VHC)) { /* back up to offending char */ unreadChar(lexer, offset); lexer->error = yajl_lex_string_invalid_hex_char; goto finish_string_lex; } } } else if (!(charLookupTable[curChar] & VEC)) { /* back up to offending char */ unreadChar(lexer, offset); lexer->error = yajl_lex_string_invalid_escaped_char; goto finish_string_lex; } } /* when not validating UTF8 it's a simple table lookup to determine * if the present character is invalid */ else if(charLookupTable[curChar] & IJC) { /* back up to offending char */ unreadChar(lexer, offset); lexer->error = yajl_lex_string_invalid_json_char; goto finish_string_lex; } /* when in validate UTF8 mode we need to do some extra work */ else if (lexer->validateUTF8) { yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen, offset, curChar); if (t == yajl_tok_eof) { tok = yajl_tok_eof; goto finish_string_lex; } else if (t == yajl_tok_error) { lexer->error = yajl_lex_string_invalid_utf8; goto finish_string_lex; } } /* accept it, and move on */ } finish_string_lex: /* tell our buddy, the parser, wether he needs to process this string * again */ if (hasEscapes && tok == yajl_tok_string) { tok = yajl_tok_string_with_escapes; } return tok; } #define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof; static yajl_tok yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset) { /** XXX: numbers are the only entities in json that we must lex * _beyond_ in order to know that they are complete. There * is an ambiguous case for integers at EOF. */ unsigned char c; yajl_tok tok = yajl_tok_integer; RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); /* optional leading minus */ if (c == '-') { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } /* a single zero, or a series of integers */ if (c == '0') { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } else if (c >= '1' && c <= '9') { do { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } while (c >= '0' && c <= '9'); } else { unreadChar(lexer, offset); lexer->error = yajl_lex_missing_integer_after_minus; return yajl_tok_error; } /* optional fraction (indicates this is floating point) */ if (c == '.') { int numRd = 0; RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); while (c >= '0' && c <= '9') { numRd++; RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } if (!numRd) { unreadChar(lexer, offset); lexer->error = yajl_lex_missing_integer_after_decimal; return yajl_tok_error; } tok = yajl_tok_double; } /* optional exponent (indicates this is floating point) */ if (c == 'e' || c == 'E') { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); /* optional sign */ if (c == '+' || c == '-') { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } if (c >= '0' && c <= '9') { do { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } while (c >= '0' && c <= '9'); } else { unreadChar(lexer, offset); lexer->error = yajl_lex_missing_integer_after_exponent; return yajl_tok_error; } tok = yajl_tok_double; } /* we always go "one too far" */ unreadChar(lexer, offset); return tok; } static yajl_tok yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset) { unsigned char c; yajl_tok tok = yajl_tok_comment; RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); /* either slash or star expected */ if (c == '/') { /* now we throw away until end of line */ do { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); } while (c != '\n'); } else if (c == '*') { /* now we throw away until end of comment */ for (;;) { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); if (c == '*') { RETURN_IF_EOF; c = readChar(lexer, jsonText, offset); if (c == '/') { break; } else { unreadChar(lexer, offset); } } } } else { lexer->error = yajl_lex_invalid_char; tok = yajl_tok_error; } return tok; } yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset, const unsigned char ** outBuf, size_t * outLen) { yajl_tok tok = yajl_tok_error; unsigned char c; size_t startOffset = *offset; *outBuf = NULL; *outLen = 0; for (;;) { assert(*offset <= jsonTextLen); if (*offset >= jsonTextLen) { tok = yajl_tok_eof; goto lexed; } c = readChar(lexer, jsonText, offset); switch (c) { case '{': tok = yajl_tok_left_bracket; goto lexed; case '}': tok = yajl_tok_right_bracket; goto lexed; case '[': tok = yajl_tok_left_brace; goto lexed; case ']': tok = yajl_tok_right_brace; goto lexed; case ',': tok = yajl_tok_comma; goto lexed; case ':': tok = yajl_tok_colon; goto lexed; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': startOffset++; break; case 't': { const char * want = "rue"; do { if (*offset >= jsonTextLen) { tok = yajl_tok_eof; goto lexed; } c = readChar(lexer, jsonText, offset); if (c != *want) { unreadChar(lexer, offset); lexer->error = yajl_lex_invalid_string; tok = yajl_tok_error; goto lexed; } } while (*(++want)); tok = yajl_tok_bool; goto lexed; } case 'f': { const char * want = "alse"; do { if (*offset >= jsonTextLen) { tok = yajl_tok_eof; goto lexed; } c = readChar(lexer, jsonText, offset); if (c != *want) { unreadChar(lexer, offset); lexer->error = yajl_lex_invalid_string; tok = yajl_tok_error; goto lexed; } } while (*(++want)); tok = yajl_tok_bool; goto lexed; } case 'n': { const char * want = "ull"; do { if (*offset >= jsonTextLen) { tok = yajl_tok_eof; goto lexed; } c = readChar(lexer, jsonText, offset); if (c != *want) { unreadChar(lexer, offset); lexer->error = yajl_lex_invalid_string; tok = yajl_tok_error; goto lexed; } } while (*(++want)); tok = yajl_tok_null; goto lexed; } case '"': { tok = yajl_lex_string(lexer, (const unsigned char *) jsonText, jsonTextLen, offset); goto lexed; } case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* integer parsing wants to start from the beginning */ unreadChar(lexer, offset); tok = yajl_lex_number(lexer, (const unsigned char *) jsonText, jsonTextLen, offset); goto lexed; } case '/': /* hey, look, a probable comment! If comments are disabled * it's an error. */ if (!lexer->allowComments) { unreadChar(lexer, offset); lexer->error = yajl_lex_unallowed_comment; tok = yajl_tok_error; goto lexed; } /* if comments are enabled, then we should try to lex * the thing. possible outcomes are * - successful lex (tok_comment, which means continue), * - malformed comment opening (slash not followed by * '*' or '/') (tok_error) * - eof hit. (tok_eof) */ tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText, jsonTextLen, offset); if (tok == yajl_tok_comment) { /* "error" is silly, but that's the initial * state of tok. guilty until proven innocent. */ tok = yajl_tok_error; yajl_buf_clear(lexer->buf); lexer->bufInUse = 0; startOffset = *offset; break; } /* hit error or eof, bail */ goto lexed; default: lexer->error = yajl_lex_invalid_char; tok = yajl_tok_error; goto lexed; } } lexed: /* need to append to buffer if the buffer is in use or * if it's an EOF token */ if (tok == yajl_tok_eof || lexer->bufInUse) { if (!lexer->bufInUse) yajl_buf_clear(lexer->buf); lexer->bufInUse = 1; yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset); lexer->bufOff = 0; if (tok != yajl_tok_eof) { *outBuf = yajl_buf_data(lexer->buf); *outLen = yajl_buf_len(lexer->buf); lexer->bufInUse = 0; } } else if (tok != yajl_tok_error) { *outBuf = jsonText + startOffset; *outLen = *offset - startOffset; } /* special case for strings. skip the quotes. */ if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes) { assert(*outLen >= 2); (*outBuf)++; *outLen -= 2; } #ifdef YAJL_LEXER_DEBUG if (tok == yajl_tok_error) { printf("lexical error: %s\n", yajl_lex_error_to_string(yajl_lex_get_error(lexer))); } else if (tok == yajl_tok_eof) { printf("EOF hit\n"); } else { printf("lexed %s: '", tokToStr(tok)); fwrite(*outBuf, 1, *outLen, stdout); printf("'\n"); } #endif return tok; } const char * yajl_lex_error_to_string(yajl_lex_error error) { switch (error) { case yajl_lex_e_ok: return "ok, no error"; case yajl_lex_string_invalid_utf8: return "invalid bytes in UTF8 string."; case yajl_lex_string_invalid_escaped_char: return "inside a string, '\\' occurs before a character " "which it may not."; case yajl_lex_string_invalid_json_char: return "invalid character inside string."; case yajl_lex_string_invalid_hex_char: return "invalid (non-hex) character occurs after '\\u' inside " "string."; case yajl_lex_invalid_char: return "invalid char in json text."; case yajl_lex_invalid_string: return "invalid string in json text."; case yajl_lex_missing_integer_after_exponent: return "malformed number, a digit is required after the exponent."; case yajl_lex_missing_integer_after_decimal: return "malformed number, a digit is required after the " "decimal point."; case yajl_lex_missing_integer_after_minus: return "malformed number, a digit is required after the " "minus sign."; case yajl_lex_unallowed_comment: return "probable comment found in input text, comments are " "not enabled."; } return "unknown error code"; } /** allows access to more specific information about the lexical * error when yajl_lex_lex returns yajl_tok_error. */ yajl_lex_error yajl_lex_get_error(yajl_lexer lexer) { if (lexer == NULL) return (yajl_lex_error) -1; return lexer->error; } size_t yajl_lex_current_line(yajl_lexer lexer) { return lexer->lineOff; } size_t yajl_lex_current_char(yajl_lexer lexer) { return lexer->charOff; } yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t offset) { const unsigned char * outBuf; size_t outLen; size_t bufLen = yajl_buf_len(lexer->buf); size_t bufOff = lexer->bufOff; unsigned int bufInUse = lexer->bufInUse; yajl_tok tok; tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset, &outBuf, &outLen); lexer->bufOff = bufOff; lexer->bufInUse = bufInUse; yajl_buf_truncate(lexer->buf, bufLen); return tok; } icinga2-2.8.1/third-party/yajl/src/yajl_lex.h000066400000000000000000000101261322762156600210250ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __YAJL_LEX_H__ #define __YAJL_LEX_H__ #include "api/yajl_common.h" typedef enum { yajl_tok_bool, yajl_tok_colon, yajl_tok_comma, yajl_tok_eof, yajl_tok_error, yajl_tok_left_brace, yajl_tok_left_bracket, yajl_tok_null, yajl_tok_right_brace, yajl_tok_right_bracket, /* we differentiate between integers and doubles to allow the * parser to interpret the number without re-scanning */ yajl_tok_integer, yajl_tok_double, /* we differentiate between strings which require further processing, * and strings that do not */ yajl_tok_string, yajl_tok_string_with_escapes, /* comment tokens are not currently returned to the parser, ever */ yajl_tok_comment } yajl_tok; typedef struct yajl_lexer_t * yajl_lexer; yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, unsigned int allowComments, unsigned int validateUTF8); void yajl_lex_free(yajl_lexer lexer); /** * run/continue a lex. "offset" is an input/output parameter. * It should be initialized to zero for a * new chunk of target text, and upon subsetquent calls with the same * target text should passed with the value of the previous invocation. * * the client may be interested in the value of offset when an error is * returned from the lexer. This allows the client to render useful * error messages. * * When you pass the next chunk of data, context should be reinitialized * to zero. * * Finally, the output buffer is usually just a pointer into the jsonText, * however in cases where the entity being lexed spans multiple chunks, * the lexer will buffer the entity and the data returned will be * a pointer into that buffer. * * This behavior is abstracted from client code except for the performance * implications which require that the client choose a reasonable chunk * size to get adequate performance. */ yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t * offset, const unsigned char ** outBuf, size_t * outLen); /** have a peek at the next token, but don't move the lexer forward */ yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, size_t jsonTextLen, size_t offset); typedef enum { yajl_lex_e_ok = 0, yajl_lex_string_invalid_utf8, yajl_lex_string_invalid_escaped_char, yajl_lex_string_invalid_json_char, yajl_lex_string_invalid_hex_char, yajl_lex_invalid_char, yajl_lex_invalid_string, yajl_lex_missing_integer_after_decimal, yajl_lex_missing_integer_after_exponent, yajl_lex_missing_integer_after_minus, yajl_lex_unallowed_comment } yajl_lex_error; const char * yajl_lex_error_to_string(yajl_lex_error error); /** allows access to more specific information about the lexical * error when yajl_lex_lex returns yajl_tok_error. */ yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); /** get the current offset into the most recently lexed json string. */ size_t yajl_lex_current_offset(yajl_lexer lexer); /** get the number of lines lexed by this lexer instance */ size_t yajl_lex_current_line(yajl_lexer lexer); /** get the number of chars lexed by this lexer instance since the last * \n or \r */ size_t yajl_lex_current_char(yajl_lexer lexer); #endif icinga2-2.8.1/third-party/yajl/src/yajl_parser.c000066400000000000000000000502171322762156600215310ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "api/yajl_parse.h" #include "yajl_lex.h" #include "yajl_parser.h" #include "yajl_encode.h" #include "yajl_bytestack.h" #include #include #include #include #include #include #include #include #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10)) /* same semantics as strtol */ long long yajl_parse_integer(const unsigned char *number, unsigned int length) { long long ret = 0; long sign = 1; const unsigned char *pos = number; if (*pos == '-') { pos++; sign = -1; } if (*pos == '+') { pos++; } while (pos < number + length) { if ( ret > MAX_VALUE_TO_MULTIPLY ) { errno = ERANGE; return sign == 1 ? LLONG_MAX : LLONG_MIN; } ret *= 10; if (LLONG_MAX - ret < (*pos - '0')) { errno = ERANGE; return sign == 1 ? LLONG_MAX : LLONG_MIN; } if (*pos < '0' || *pos > '9') { errno = ERANGE; return sign == 1 ? LLONG_MAX : LLONG_MIN; } ret += (*pos++ - '0'); } return sign * ret; } unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, size_t jsonTextLen, int verbose) { size_t offset = hand->bytesConsumed; unsigned char * str; const char * errorType = NULL; const char * errorText = NULL; char text[72]; const char * arrow = " (right here) ------^\n"; if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { errorType = "parse"; errorText = hand->parseError; } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) { errorType = "lexical"; errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer)); } else { errorType = "unknown"; } { size_t memneeded = 0; memneeded += strlen(errorType); memneeded += strlen(" error"); if (errorText != NULL) { memneeded += strlen(": "); memneeded += strlen(errorText); } str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); if (!str) return NULL; str[0] = 0; strcat((char *) str, errorType); strcat((char *) str, " error"); if (errorText != NULL) { strcat((char *) str, ": "); strcat((char *) str, errorText); } strcat((char *) str, "\n"); } /* now we append as many spaces as needed to make sure the error * falls at char 41, if verbose was specified */ if (verbose) { size_t start, end, i; size_t spacesNeeded; spacesNeeded = (offset < 30 ? 40 - offset : 10); start = (offset >= 30 ? offset - 30 : 0); end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); for (i=0;ialloc), (unsigned int)(strlen((char *) str) + strlen((char *) text) + strlen(arrow) + 1)); if (newStr) { newStr[0] = 0; strcat((char *) newStr, (char *) str); strcat((char *) newStr, text); strcat((char *) newStr, arrow); } YA_FREE(&(hand->alloc), str); str = (unsigned char *) newStr; } } return str; } /* check for client cancelation */ #define _CC_CHK(x) \ if (!(x)) { \ yajl_bs_set(hand->stateStack, yajl_state_parse_error); \ hand->parseError = \ "client cancelled parse via callback return value"; \ return yajl_status_client_canceled; \ } yajl_status yajl_do_finish(yajl_handle hand) { yajl_status stat; stat = yajl_do_parse(hand,(const unsigned char *) " ",1); if (stat != yajl_status_ok) return stat; switch(yajl_bs_current(hand->stateStack)) { case yajl_state_parse_error: case yajl_state_lexical_error: return yajl_status_error; case yajl_state_got_value: case yajl_state_parse_complete: return yajl_status_ok; default: if (!(hand->flags & yajl_allow_partial_values)) { yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "premature EOF"; return yajl_status_error; } return yajl_status_ok; } } yajl_status yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, size_t jsonTextLen) { yajl_tok tok; const unsigned char * buf; size_t bufLen; size_t * offset = &(hand->bytesConsumed); *offset = 0; around_again: switch (yajl_bs_current(hand->stateStack)) { case yajl_state_parse_complete: if (hand->flags & yajl_allow_multiple_values) { yajl_bs_set(hand->stateStack, yajl_state_got_value); goto around_again; } if (!(hand->flags & yajl_allow_trailing_garbage)) { if (*offset != jsonTextLen) { tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); if (tok != yajl_tok_eof) { yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "trailing garbage"; } goto around_again; } } return yajl_status_ok; case yajl_state_lexical_error: case yajl_state_parse_error: return yajl_status_error; case yajl_state_start: case yajl_state_got_value: case yajl_state_map_need_val: case yajl_state_array_need_val: case yajl_state_array_start: { /* for arrays and maps, we advance the state for this * depth, then push the state of the next depth. * If an error occurs during the parsing of the nesting * enitity, the state at this level will not matter. * a state that needs pushing will be anything other * than state_start */ yajl_state stateToPush = yajl_state_start; tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { case yajl_tok_eof: return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; case yajl_tok_string: if (hand->callbacks && hand->callbacks->yajl_string) { _CC_CHK(hand->callbacks->yajl_string(hand->ctx, buf, bufLen)); } break; case yajl_tok_string_with_escapes: if (hand->callbacks && hand->callbacks->yajl_string) { yajl_buf_clear(hand->decodeBuf); yajl_string_decode(hand->decodeBuf, buf, bufLen); _CC_CHK(hand->callbacks->yajl_string( hand->ctx, yajl_buf_data(hand->decodeBuf), yajl_buf_len(hand->decodeBuf))); } break; case yajl_tok_bool: if (hand->callbacks && hand->callbacks->yajl_boolean) { _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, *buf == 't')); } break; case yajl_tok_null: if (hand->callbacks && hand->callbacks->yajl_null) { _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); } break; case yajl_tok_left_bracket: if (hand->callbacks && hand->callbacks->yajl_start_map) { _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); } stateToPush = yajl_state_map_start; break; case yajl_tok_left_brace: if (hand->callbacks && hand->callbacks->yajl_start_array) { _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); } stateToPush = yajl_state_array_start; break; case yajl_tok_integer: if (hand->callbacks) { if (hand->callbacks->yajl_number) { _CC_CHK(hand->callbacks->yajl_number( hand->ctx,(const char *) buf, bufLen)); } else if (hand->callbacks->yajl_integer) { long long int i = 0; errno = 0; i = yajl_parse_integer(buf, bufLen); if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) { yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "integer overflow" ; /* try to restore error offset */ if (*offset >= bufLen) *offset -= bufLen; else *offset = 0; goto around_again; } _CC_CHK(hand->callbacks->yajl_integer(hand->ctx, i)); } } break; case yajl_tok_double: if (hand->callbacks) { if (hand->callbacks->yajl_number) { _CC_CHK(hand->callbacks->yajl_number( hand->ctx, (const char *) buf, bufLen)); } else if (hand->callbacks->yajl_double) { double d = 0.0; yajl_buf_clear(hand->decodeBuf); yajl_buf_append(hand->decodeBuf, buf, bufLen); buf = yajl_buf_data(hand->decodeBuf); errno = 0; d = strtod((char *) buf, NULL); if ((d == HUGE_VAL || d == -HUGE_VAL) && errno == ERANGE) { yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "numeric (floating point) " "overflow"; /* try to restore error offset */ if (*offset >= bufLen) *offset -= bufLen; else *offset = 0; goto around_again; } _CC_CHK(hand->callbacks->yajl_double(hand->ctx, d)); } } break; case yajl_tok_right_brace: { if (yajl_bs_current(hand->stateStack) == yajl_state_array_start) { if (hand->callbacks && hand->callbacks->yajl_end_array) { _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); } yajl_bs_pop(hand->stateStack); goto around_again; } /* intentional fall-through */ } case yajl_tok_colon: case yajl_tok_comma: case yajl_tok_right_bracket: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "unallowed token at this point in JSON text"; goto around_again; default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "invalid token, internal error"; goto around_again; } /* got a value. transition depends on the state we're in. */ { yajl_state s = yajl_bs_current(hand->stateStack); if (s == yajl_state_start || s == yajl_state_got_value) { yajl_bs_set(hand->stateStack, yajl_state_parse_complete); } else if (s == yajl_state_map_need_val) { yajl_bs_set(hand->stateStack, yajl_state_map_got_val); } else { yajl_bs_set(hand->stateStack, yajl_state_array_got_val); } } if (stateToPush != yajl_state_start) { yajl_bs_push(hand->stateStack, stateToPush); } goto around_again; } case yajl_state_map_start: case yajl_state_map_need_key: { /* only difference between these two states is that in * start '}' is valid, whereas in need_key, we've parsed * a comma, and a string key _must_ follow */ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { case yajl_tok_eof: return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; case yajl_tok_string_with_escapes: if (hand->callbacks && hand->callbacks->yajl_map_key) { yajl_buf_clear(hand->decodeBuf); yajl_string_decode(hand->decodeBuf, buf, bufLen); buf = yajl_buf_data(hand->decodeBuf); bufLen = yajl_buf_len(hand->decodeBuf); } /* intentional fall-through */ case yajl_tok_string: if (hand->callbacks && hand->callbacks->yajl_map_key) { _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf, bufLen)); } yajl_bs_set(hand->stateStack, yajl_state_map_sep); goto around_again; case yajl_tok_right_bracket: if (yajl_bs_current(hand->stateStack) == yajl_state_map_start) { if (hand->callbacks && hand->callbacks->yajl_end_map) { _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); } yajl_bs_pop(hand->stateStack); goto around_again; } default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "invalid object key (must be a string)"; goto around_again; } } case yajl_state_map_sep: { tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { case yajl_tok_colon: yajl_bs_set(hand->stateStack, yajl_state_map_need_val); goto around_again; case yajl_tok_eof: return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "object key and value must " "be separated by a colon (':')"; goto around_again; } } case yajl_state_map_got_val: { tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { case yajl_tok_right_bracket: if (hand->callbacks && hand->callbacks->yajl_end_map) { _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); } yajl_bs_pop(hand->stateStack); goto around_again; case yajl_tok_comma: yajl_bs_set(hand->stateStack, yajl_state_map_need_key); goto around_again; case yajl_tok_eof: return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "after key and value, inside map, " "I expect ',' or '}'"; /* try to restore error offset */ if (*offset >= bufLen) *offset -= bufLen; else *offset = 0; goto around_again; } } case yajl_state_array_got_val: { tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { case yajl_tok_right_brace: if (hand->callbacks && hand->callbacks->yajl_end_array) { _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); } yajl_bs_pop(hand->stateStack); goto around_again; case yajl_tok_comma: yajl_bs_set(hand->stateStack, yajl_state_array_need_val); goto around_again; case yajl_tok_eof: return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "after array element, I expect ',' or ']'"; goto around_again; } } } abort(); return yajl_status_error; } icinga2-2.8.1/third-party/yajl/src/yajl_parser.h000066400000000000000000000047001322762156600215320ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __YAJL_PARSER_H__ #define __YAJL_PARSER_H__ #include "api/yajl_parse.h" #include "yajl_bytestack.h" #include "yajl_buf.h" #include "yajl_lex.h" typedef enum { yajl_state_start = 0, yajl_state_parse_complete, yajl_state_parse_error, yajl_state_lexical_error, yajl_state_map_start, yajl_state_map_sep, yajl_state_map_need_val, yajl_state_map_got_val, yajl_state_map_need_key, yajl_state_array_start, yajl_state_array_got_val, yajl_state_array_need_val, yajl_state_got_value, } yajl_state; struct yajl_handle_t { const yajl_callbacks * callbacks; void * ctx; yajl_lexer lexer; const char * parseError; /* the number of bytes consumed from the last client buffer, * in the case of an error this will be an error offset, in the * case of an error this can be used as the error offset */ size_t bytesConsumed; /* temporary storage for decoded strings */ yajl_buf decodeBuf; /* a stack of states. access with yajl_state_XXX routines */ yajl_bytestack stateStack; /* memory allocation routines */ yajl_alloc_funcs alloc; /* bitfield */ unsigned int flags; }; yajl_status yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, size_t jsonTextLen); yajl_status yajl_do_finish(yajl_handle handle); unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, size_t jsonTextLen, int verbose); /* A little built in integer parsing routine with the same semantics as strtol * that's unaffected by LOCALE. */ long long yajl_parse_integer(const unsigned char *number, unsigned int length); #endif icinga2-2.8.1/third-party/yajl/src/yajl_tree.c000066400000000000000000000325771322762156600212050ustar00rootroot00000000000000/* * Copyright (c) 2010-2011 Florian Forster * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "api/yajl_tree.h" #include "api/yajl_parse.h" #include "yajl_parser.h" #if defined(_WIN32) || defined(WIN32) #define snprintf sprintf_s #endif #define STATUS_CONTINUE 1 #define STATUS_ABORT 0 struct stack_elem_s; typedef struct stack_elem_s stack_elem_t; struct stack_elem_s { char * key; yajl_val value; stack_elem_t *next; }; struct context_s { stack_elem_t *stack; yajl_val root; char *errbuf; size_t errbuf_size; }; typedef struct context_s context_t; #define RETURN_ERROR(ctx,retval,...) { \ if ((ctx)->errbuf != NULL) \ snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \ return (retval); \ } static yajl_val value_alloc (yajl_type type) { yajl_val v; v = malloc (sizeof (*v)); if (v == NULL) return (NULL); memset (v, 0, sizeof (*v)); v->type = type; return (v); } static void yajl_object_free (yajl_val v) { size_t i; if (!YAJL_IS_OBJECT(v)) return; for (i = 0; i < v->u.object.len; i++) { free((char *) v->u.object.keys[i]); v->u.object.keys[i] = NULL; yajl_tree_free (v->u.object.values[i]); v->u.object.values[i] = NULL; } free((void*) v->u.object.keys); free(v->u.object.values); free(v); } static void yajl_array_free (yajl_val v) { size_t i; if (!YAJL_IS_ARRAY(v)) return; for (i = 0; i < v->u.array.len; i++) { yajl_tree_free (v->u.array.values[i]); v->u.array.values[i] = NULL; } free(v->u.array.values); free(v); } /* * Parsing nested objects and arrays is implemented using a stack. When a new * object or array starts (a curly or a square opening bracket is read), an * appropriate value is pushed on the stack. When the end of the object is * reached (an appropriate closing bracket has been read), the value is popped * off the stack and added to the enclosing object using "context_add_value". */ static int context_push(context_t *ctx, yajl_val v) { stack_elem_t *stack; stack = malloc (sizeof (*stack)); if (stack == NULL) RETURN_ERROR (ctx, ENOMEM, "Out of memory"); memset (stack, 0, sizeof (*stack)); assert ((ctx->stack == NULL) || YAJL_IS_OBJECT (v) || YAJL_IS_ARRAY (v)); stack->value = v; stack->next = ctx->stack; ctx->stack = stack; return (0); } static yajl_val context_pop(context_t *ctx) { stack_elem_t *stack; yajl_val v; if (ctx->stack == NULL) RETURN_ERROR (ctx, NULL, "context_pop: " "Bottom of stack reached prematurely"); stack = ctx->stack; ctx->stack = stack->next; v = stack->value; free (stack); return (v); } static int object_add_keyval(context_t *ctx, yajl_val obj, char *key, yajl_val value) { const char **tmpk; yajl_val *tmpv; /* We're checking for NULL in "context_add_value" or its callers. */ assert (ctx != NULL); assert (obj != NULL); assert (key != NULL); assert (value != NULL); /* We're assuring that "obj" is an object in "context_add_value". */ assert(YAJL_IS_OBJECT(obj)); tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1)); if (tmpk == NULL) RETURN_ERROR(ctx, ENOMEM, "Out of memory"); obj->u.object.keys = tmpk; tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1)); if (tmpv == NULL) RETURN_ERROR(ctx, ENOMEM, "Out of memory"); obj->u.object.values = tmpv; obj->u.object.keys[obj->u.object.len] = key; obj->u.object.values[obj->u.object.len] = value; obj->u.object.len++; return (0); } static int array_add_value (context_t *ctx, yajl_val array, yajl_val value) { yajl_val *tmp; /* We're checking for NULL pointers in "context_add_value" or its * callers. */ assert (ctx != NULL); assert (array != NULL); assert (value != NULL); /* "context_add_value" will only call us with array values. */ assert(YAJL_IS_ARRAY(array)); tmp = realloc(array->u.array.values, sizeof(*(array->u.array.values)) * (array->u.array.len + 1)); if (tmp == NULL) RETURN_ERROR(ctx, ENOMEM, "Out of memory"); array->u.array.values = tmp; array->u.array.values[array->u.array.len] = value; array->u.array.len++; return 0; } /* * Add a value to the value on top of the stack or the "root" member in the * context if the end of the parsing process is reached. */ static int context_add_value (context_t *ctx, yajl_val v) { /* We're checking for NULL values in all the calling functions. */ assert (ctx != NULL); assert (v != NULL); /* * There are three valid states in which this function may be called: * - There is no value on the stack => This is the only value. This is the * last step done when parsing a document. We assign the value to the * "root" member and return. * - The value on the stack is an object. In this case store the key on the * stack or, if the key has already been read, add key and value to the * object. * - The value on the stack is an array. In this case simply add the value * and return. */ if (ctx->stack == NULL) { assert (ctx->root == NULL); ctx->root = v; return (0); } else if (YAJL_IS_OBJECT (ctx->stack->value)) { if (ctx->stack->key == NULL) { if (!YAJL_IS_STRING (v)) RETURN_ERROR (ctx, EINVAL, "context_add_value: " "Object key is not a string (%#04x)", v->type); ctx->stack->key = v->u.string; v->u.string = NULL; free(v); return (0); } else /* if (ctx->key != NULL) */ { char * key; key = ctx->stack->key; ctx->stack->key = NULL; return (object_add_keyval (ctx, ctx->stack->value, key, v)); } } else if (YAJL_IS_ARRAY (ctx->stack->value)) { return (array_add_value (ctx, ctx->stack->value, v)); } else { RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to " "a value of type %#04x (not a composite type)", ctx->stack->value->type); } } static int handle_string (void *ctx, const unsigned char *string, size_t string_length) { yajl_val v; v = value_alloc (yajl_t_string); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); v->u.string = malloc (string_length + 1); if (v->u.string == NULL) { free (v); RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); } memcpy(v->u.string, string, string_length); v->u.string[string_length] = 0; return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_number (void *ctx, const char *string, size_t string_length) { yajl_val v; char *endptr; v = value_alloc(yajl_t_number); if (v == NULL) RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); v->u.number.r = malloc(string_length + 1); if (v->u.number.r == NULL) { free(v); RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); } memcpy(v->u.number.r, string, string_length); v->u.number.r[string_length] = 0; v->u.number.flags = 0; errno = 0; v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r, strlen(v->u.number.r)); if (errno == 0) v->u.number.flags |= YAJL_NUMBER_INT_VALID; endptr = NULL; errno = 0; v->u.number.d = strtod(v->u.number.r, &endptr); if ((errno == 0) && (endptr != NULL) && (*endptr == 0)) v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID; return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_start_map (void *ctx) { yajl_val v; v = value_alloc(yajl_t_object); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); v->u.object.keys = NULL; v->u.object.values = NULL; v->u.object.len = 0; return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_end_map (void *ctx) { yajl_val v; v = context_pop (ctx); if (v == NULL) return (STATUS_ABORT); return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_start_array (void *ctx) { yajl_val v; v = value_alloc(yajl_t_array); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); v->u.array.values = NULL; v->u.array.len = 0; return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_end_array (void *ctx) { yajl_val v; v = context_pop (ctx); if (v == NULL) return (STATUS_ABORT); return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_boolean (void *ctx, int boolean_value) { yajl_val v; v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_null (void *ctx) { yajl_val v; v = value_alloc (yajl_t_null); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } /* * Public functions */ yajl_val yajl_tree_parse (const char *input, char *error_buffer, size_t error_buffer_size) { static const yajl_callbacks callbacks = { /* null = */ handle_null, /* boolean = */ handle_boolean, /* integer = */ NULL, /* double = */ NULL, /* number = */ handle_number, /* string = */ handle_string, /* start map = */ handle_start_map, /* map key = */ handle_string, /* end map = */ handle_end_map, /* start array = */ handle_start_array, /* end array = */ handle_end_array }; yajl_handle handle; yajl_status status; char * internal_err_str; context_t ctx = { NULL, NULL, NULL, 0 }; ctx.errbuf = error_buffer; ctx.errbuf_size = error_buffer_size; if (error_buffer != NULL) memset (error_buffer, 0, error_buffer_size); handle = yajl_alloc (&callbacks, NULL, &ctx); yajl_config(handle, yajl_allow_comments, 1); status = yajl_parse(handle, (unsigned char *) input, strlen (input)); status = yajl_complete_parse (handle); if (status != yajl_status_ok) { if (error_buffer != NULL && error_buffer_size > 0) { internal_err_str = (char *) yajl_get_error(handle, 1, (const unsigned char *) input, strlen(input)); snprintf(error_buffer, error_buffer_size, "%s", internal_err_str); YA_FREE(&(handle->alloc), internal_err_str); } yajl_free (handle); return NULL; } yajl_free (handle); return (ctx.root); } yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type) { if (!path) return NULL; while (n && *path) { size_t i; size_t len; if (n->type != yajl_t_object) return NULL; len = n->u.object.len; for (i = 0; i < len; i++) { if (!strcmp(*path, n->u.object.keys[i])) { n = n->u.object.values[i]; break; } } if (i == len) return NULL; path++; } if (n && type != yajl_t_any && type != n->type) n = NULL; return n; } void yajl_tree_free (yajl_val v) { if (v == NULL) return; if (YAJL_IS_STRING(v)) { free(v->u.string); free(v); } else if (YAJL_IS_NUMBER(v)) { free(v->u.number.r); free(v); } else if (YAJL_GET_OBJECT(v)) { yajl_object_free(v); } else if (YAJL_GET_ARRAY(v)) { yajl_array_free(v); } else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */ { free(v); } } icinga2-2.8.1/third-party/yajl/src/yajl_version.c000066400000000000000000000001221322762156600217100ustar00rootroot00000000000000#include int yajl_version(void) { return YAJL_VERSION; } icinga2-2.8.1/tools/000077500000000000000000000000001322762156600142105ustar00rootroot00000000000000icinga2-2.8.1/tools/CMakeLists.txt000066400000000000000000000015521322762156600167530ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_subdirectory(mkclass) add_subdirectory(mkembedconfig) add_subdirectory(mkunity) icinga2-2.8.1/tools/debug/000077500000000000000000000000001322762156600152765ustar00rootroot00000000000000icinga2-2.8.1/tools/debug/gdb/000077500000000000000000000000001322762156600160325ustar00rootroot00000000000000icinga2-2.8.1/tools/debug/gdb/.gitignore000066400000000000000000000000161322762156600200170ustar00rootroot00000000000000icingadbg.pyc icinga2-2.8.1/tools/debug/gdb/README.md000066400000000000000000000025311322762156600173120ustar00rootroot00000000000000# Pretty Printer Installation Requirements: * icinga2 debug symbols * boost, gcc, etc debug symbols Install the `boost`, `python` and `icinga2` pretty printers. Absolute paths are required, so please make sure to update the installation paths accordingly (`pwd`). Boost Pretty Printers: $ mkdir ~/.gdb_printers && cd ~/.gdb_printers $ git clone https://github.com/ruediger/Boost-Pretty-Printer.git && cd Boost-Pretty-Printer $ pwd /home/michi/.gdb_printers/Boost-Pretty-Printer Python Pretty Printers: $ cd ~/.gdb_printers $ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python Icinga 2 Pretty Printers: $ mkdir -p ~/.gdb_printers/icinga2 && ~/.gdb_printers/icinga2 $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/icingadbg.py Now you'll need to modify/setup your `~/.gdbinit` configuration file. You can download the one from Icinga 2 and modify all paths. > **Note** > > The path to the `pthread` library varies on distributions. Use > `find /usr/lib* -type f -name '*libpthread.so*'` to get the proper > path. $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/gdbinit -O ~/.gdbinit $ vim ~/.gdbinit More details in the [troubleshooting debug documentation](https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/troubleshooting#debug). icinga2-2.8.1/tools/debug/gdb/gdbinit000066400000000000000000000010301322762156600173670ustar00rootroot00000000000000set print pretty on python import sys sys.path.insert(0, '/home/gbeutner/icinga2/tools/debug/gdb') from icingadbg import register_icinga_printers register_icinga_printers() end python import sys sys.path.insert(0, '/home/gbeutner/gdb_printers/python') from libstdcxx.v6.printers import register_libstdcxx_printers try: register_libstdcxx_printers(None) except: pass end python import sys sys.path.insert(0, '/home/gbeutner/Boost-Pretty-Printer') from boost.printers import register_printer_gen register_printer_gen(None) end icinga2-2.8.1/tools/debug/gdb/icingadbg.py000066400000000000000000000036271322762156600203230ustar00rootroot00000000000000import gdb import re class IcingaStringPrinter: def __init__(self, val): self.val = val def to_string(self): return '"' + self.val['m_Data']['_M_dataplus']['_M_p'].string() + '"' class IcingaValuePrinter: def __init__(self, val): self.val = val def to_string(self): which = self.val['m_Value']['which_'] if which == 0: return 'Empty' elif which == 1: return self.val['m_Value']['storage_']['data_']['buf'].cast(gdb.lookup_type('double').pointer()).dereference() elif which == 2: return self.val['m_Value']['storage_']['data_']['buf'].cast(gdb.lookup_type('bool').pointer()).dereference() elif which == 3: return self.val['m_Value']['storage_']['data_']['buf'].cast(gdb.lookup_type('icinga::String').pointer()).dereference() elif which == 4: return self.val['m_Value']['storage_']['data_']['buf'].cast(gdb.lookup_type('icinga::Object').pointer()).dereference() else: return '' class IcingaSignalPrinter: def __init__(self, val): self.val = val def to_string(self): return '' class IcingaMutexPrinter: def __init__(self, val): self.val = val def to_string(self): owner = self.val['__data']['__owner'] if owner == 0: return '' else: return '' def lookup_icinga_type(val): t = val.type.unqualified() if str(t) == 'icinga::String': return IcingaStringPrinter(val) elif str(t) == 'icinga::Value': return IcingaValuePrinter(val) elif re.match('^boost::signals2::signal.*<.*>$', str(t)): return IcingaSignalPrinter(val) elif str(t) == 'pthread_mutex_t': return IcingaMutexPrinter(val) return None def register_icinga_printers(): gdb.pretty_printers.append(lookup_icinga_type) icinga2-2.8.1/tools/debug/natvis/000077500000000000000000000000001322762156600166025ustar00rootroot00000000000000icinga2-2.8.1/tools/debug/natvis/Visualizers/000077500000000000000000000000001322762156600211225ustar00rootroot00000000000000icinga2-2.8.1/tools/debug/natvis/Visualizers/icinga2.natstepfilter000066400000000000000000000011771322762156600252520ustar00rootroot00000000000000 icinga::String::.*NoStepInto icinga::Value::.*NoStepInto icinga::Array::.*NoStepInto icinga::Dictionary::.*NoStepInto icinga::Object::.*NoStepInto icinga::ObjectImpl<.*NoStepInto icinga2-2.8.1/tools/debug/natvis/Visualizers/icinga2.natvis000066400000000000000000000022761322762156600236730ustar00rootroot00000000000000 {m_Data} Empty {*(double *)m_Value.storage_.data_.buf} {*(double *)m_Value.storage_.data_.buf} {*(icinga::String *)m_Value.storage_.data_.buf} {*(boost::intrusive_ptr<icinga::Object> *)m_Value.storage_.data_.buf} {m_Data} m_Data {m_Data} m_Data {m_Lock} icinga2-2.8.1/tools/debug/natvis/[Content_Types].xml000066400000000000000000000005111322762156600224070ustar00rootroot00000000000000icinga2-2.8.1/tools/debug/natvis/extension.vsixmanifest000066400000000000000000000020221322762156600232540ustar00rootroot00000000000000 Icinga 2 Debugger Visualizers for Visual Studio Icinga 2 Debugger Visualizers icinga2-2.8.1/tools/docker/000077500000000000000000000000001322762156600154575ustar00rootroot00000000000000icinga2-2.8.1/tools/docker/.gitignore000066400000000000000000000000161322762156600174440ustar00rootroot00000000000000.build config icinga2-2.8.1/tools/docker/README000066400000000000000000000002101322762156600163300ustar00rootroot00000000000000Icinga 2 Development Environment ================================ The `build' script in this directory builds Icinga 2 in a Docker VM. icinga2-2.8.1/tools/docker/clean000077500000000000000000000000651322762156600164700ustar00rootroot00000000000000#!/bin/sh cd `dirname -- $0` || exit 1 rm -Rf .build icinga2-2.8.1/tools/docker/docker/000077500000000000000000000000001322762156600167265ustar00rootroot00000000000000icinga2-2.8.1/tools/docker/docker/build000077500000000000000000000012531322762156600177540ustar00rootroot00000000000000#!/bin/sh if [ ! -e /.dockerenv ]; then echo "This script should only be run in the Docker VM environment." exit 1 fi cd cp icinga2/tools/debug/gdb/gdbinit .gdbinit sed -i 's/home\/gbeutner/home\/icinga/' .gdbinit cd icinga2-build || exit 1 CCACHE_SLOPPINESS="include_file_mtime" export CCACHE_SLOPPINESS if [ ! -e Makefile ]; then CC="ccache clang" CXX="ccache clang++" cmake ../icinga2 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$HOME/icinga2-install -DCMAKE_INSTALL_SYSCONFDIR=$HOME/icinga2-config fi make -j 4 && make install && cgdb -ex set scheduler-locking step -ex r --args ../icinga2-install/sbin/icinga2 -c ../icinga2-config/icinga2/icinga2.conf -DUseVfork=0 icinga2-2.8.1/tools/docker/run000077500000000000000000000017331322762156600162150ustar00rootroot00000000000000#!/bin/sh cd `dirname -- $0` DIR=`pwd` cd docker cat > Dockerfile <path = yyextra->GetPath(); \ yylloc->first_line = yylineno; \ yylloc->first_column = yycolumn; \ yylloc->last_line = yylineno; \ yylloc->last_column = yycolumn + yyleng - 1; \ yycolumn += yyleng; \ } while (0); #define YY_INPUT(buf, result, max_size) \ do { \ result = yyextra->ReadInput(buf, max_size); \ } while (0) struct lex_buf { char *buf; size_t size; }; static void lb_init(lex_buf *lb) { lb->buf = NULL; lb->size = 0; } /*static void lb_cleanup(lex_buf *lb) { free(lb->buf); }*/ static void lb_append_char(lex_buf *lb, char new_char) { const size_t block_size = 64; size_t old_blocks = (lb->size + (block_size - 1)) / block_size; size_t new_blocks = ((lb->size + 1) + (block_size - 1)) / block_size; if (old_blocks != new_blocks) { char *new_buf = (char *)realloc(lb->buf, new_blocks * block_size); if (new_buf == NULL && new_blocks > 0) throw std::bad_alloc(); lb->buf = new_buf; } lb->size++; lb->buf[lb->size - 1] = new_char; } static char *lb_steal(lex_buf *lb) { lb_append_char(lb, '\0'); char *buf = lb->buf; lb->buf = NULL; lb->size = 0; return buf; } %} %option reentrant noyywrap yylineno %option bison-bridge bison-locations %option never-interactive nounistd %option noinput nounput %x HEREDOC %x C_COMMENT %% lex_buf string_buf; \{\{\{ { lb_init(&string_buf); BEGIN(HEREDOC); } \}\}\} { BEGIN(INITIAL); lb_append_char(&string_buf, '\0'); yylval->text = lb_steal(&string_buf); return T_STRING; } (.|\n) { lb_append_char(&string_buf, yytext[0]); } "/*" { BEGIN(C_COMMENT); } { "*/" { BEGIN(INITIAL); } [^*] /* ignore comment */ "*" /* ignore star */ } <> { fprintf(stderr, "End-of-file while in comment.\n"); yyterminate(); } \/\/[^\n]* /* ignore C++-style comments */ [ \t\r\n] /* ignore whitespace */ #include { return T_INCLUDE; } #impl_include { return T_IMPL_INCLUDE; } class { return T_CLASS; } namespace { return T_NAMESPACE; } code { return T_CODE; } load_after { return T_LOAD_AFTER; } library { return T_LIBRARY; } abstract { yylval->num = TAAbstract; return T_CLASS_ATTRIBUTE; } vararg_constructor { yylval->num = TAVarArgConstructor; return T_CLASS_ATTRIBUTE; } config { yylval->num = FAConfig; return T_FIELD_ATTRIBUTE; } state { yylval->num = FAState; return T_FIELD_ATTRIBUTE; } enum { yylval->num = FAEnum; return T_FIELD_ATTRIBUTE; } get_protected { yylval->num = FAGetProtected; return T_FIELD_ATTRIBUTE; } set_protected { yylval->num = FASetProtected; return T_FIELD_ATTRIBUTE; } protected { yylval->num = FAGetProtected | FASetProtected; return T_FIELD_ATTRIBUTE; } no_storage { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; } no_user_modify { yylval->num = FANoUserModify; return T_FIELD_ATTRIBUTE; } no_user_view { yylval->num = FANoUserView; return T_FIELD_ATTRIBUTE; } deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; } navigation { return T_NAVIGATION; } validator { return T_VALIDATOR; } required { return T_REQUIRED; } name { return T_NAME; } array { return T_ARRAY; } default { yylval->num = FTDefault; return T_FIELD_ACCESSOR_TYPE; } get { yylval->num = FTGet; return T_FIELD_ACCESSOR_TYPE; } set { yylval->num = FTSet; return T_FIELD_ACCESSOR_TYPE; } track { yylval->num = FTTrack; return T_FIELD_ACCESSOR_TYPE; } navigate { yylval->num = FTNavigate; return T_FIELD_ACCESSOR_TYPE; } \"[^\"]+\" { yylval->text = strdup(yytext + 1); yylval->text[strlen(yylval->text) - 1] = '\0'; return T_STRING; } \<[^ \>]*\> { yylval->text = strdup(yytext + 1); yylval->text[strlen(yylval->text) - 1] = '\0'; return T_ANGLE_STRING; } [a-zA-Z_][:a-zA-Z0-9\-_]* { yylval->text = strdup(yytext); return T_IDENTIFIER; } . return yytext[0]; %% void ClassCompiler::InitializeScanner(void) { yylex_init(&m_Scanner); yyset_extra(this, m_Scanner); } void ClassCompiler::DestroyScanner(void) { yylex_destroy(m_Scanner); } icinga2-2.8.1/tools/mkclass/class_parser.yy000066400000000000000000000251631322762156600207200ustar00rootroot00000000000000%{ /****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "classcompiler.hpp" #include #include #include using std::malloc; using std::free; using std::exit; using namespace icinga; #define YYLTYPE icinga::ClassDebugInfo %} %pure-parser %locations %defines %error-verbose %parse-param { ClassCompiler *context } %lex-param { void *scanner } %union { char *text; int num; FieldType *type; Field *field; std::vector *fields; Klass *klass; FieldAccessor *fieldaccessor; std::vector *fieldaccessors; Rule *rule; std::vector *rules; Validator *validator; } %token T_INCLUDE "#include (T_INCLUDE)" %token T_IMPL_INCLUDE "#impl_include (T_IMPL_INCLUDE)" %token T_CLASS "class (T_CLASS)" %token T_CODE "code (T_CODE)" %token T_LOAD_AFTER "load_after (T_LOAD_AFTER)" %token T_LIBRARY "library (T_LIBRARY)" %token T_NAMESPACE "namespace (T_NAMESPACE)" %token T_VALIDATOR "validator (T_VALIDATOR)" %token T_REQUIRED "required (T_REQUIRED)" %token T_NAVIGATION "navigation (T_NAVIGATION)" %token T_NAME "name (T_NAME)" %token T_ARRAY "array (T_ARRAY)" %token T_STRING "string (T_STRING)" %token T_ANGLE_STRING "angle_string (T_ANGLE_STRING)" %token T_FIELD_ATTRIBUTE "field_attribute (T_FIELD_ATTRIBUTE)" %token T_CLASS_ATTRIBUTE "class_attribute (T_CLASS_ATTRIBUTE)" %token T_IDENTIFIER "identifier (T_IDENTIFIER)" %token T_GET "get (T_GET)" %token T_SET "set (T_SET)" %token T_DEFAULT "default (T_DEFAULT)" %token T_FIELD_ACCESSOR_TYPE "field_accessor_type (T_FIELD_ACCESSOR_TYPE)" %type T_IDENTIFIER %type T_STRING %type T_ANGLE_STRING %type identifier %type alternative_name_specifier %type inherits_specifier %type type_base_specifier %type include %type angle_include %type impl_include %type angle_impl_include %type code %type T_FIELD_ATTRIBUTE %type field_attribute %type field_attributes %type field_attribute_list %type T_FIELD_ACCESSOR_TYPE %type T_CLASS_ATTRIBUTE %type class_attribute_list %type field_type %type class_field %type class_fields %type class %type field_accessor_list %type field_accessors %type field_accessor %type validator_rule %type validator_rules %type validator %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); void yyerror(YYLTYPE *locp, ClassCompiler *, const char *err) { std::cerr << "in " << locp->path << " at " << locp->first_line << ":" << locp->first_column << "-" << locp->last_line << ":" << locp->last_column << ": " << err << std::endl; std::exit(1); } int yyparse(ClassCompiler *context); void ClassCompiler::Compile(void) { try { yyparse(this); } catch (const std::exception& ex) { std::cerr << "Exception: " << ex.what(); } HandleMissingValidators(); } #define scanner (context->GetScanner()) %} %% statements: /* empty */ | statements statement ; statement: include { context->HandleInclude($1, yylloc); std::free($1); } | angle_include { context->HandleAngleInclude($1, yylloc); std::free($1); } | impl_include { context->HandleImplInclude($1, yylloc); std::free($1); } | angle_impl_include { context->HandleAngleImplInclude($1, yylloc); std::free($1); } | class { context->HandleClass(*$1, yylloc); delete $1; } | validator { context->HandleValidator(*$1, yylloc); delete $1; } | namespace | code { context->HandleCode($1, yylloc); std::free($1); } | library ; include: T_INCLUDE T_STRING { $$ = $2; } ; angle_include: T_INCLUDE T_ANGLE_STRING { $$ = $2; } ; impl_include: T_IMPL_INCLUDE T_STRING { $$ = $2; } ; angle_impl_include: T_IMPL_INCLUDE T_ANGLE_STRING { $$ = $2; } ; namespace: T_NAMESPACE identifier '{' { context->HandleNamespaceBegin($2, yylloc); std::free($2); } statements '}' { context->HandleNamespaceEnd(yylloc); } ; code: T_CODE T_STRING { $$ = $2; } ; library: T_LIBRARY T_IDENTIFIER ';' { context->HandleLibrary($2, yylloc); free($2); } ; class: class_attribute_list T_CLASS T_IDENTIFIER inherits_specifier type_base_specifier '{' class_fields '}' ';' { $$ = new Klass(); $$->Name = $3; std::free($3); if ($4) { $$->Parent = $4; std::free($4); } if ($5) { $$->TypeBase = $5; std::free($5); } $$->Attributes = $1; for (const Field& field : *$7) { if (field.Attributes & FALoadDependency) { $$->LoadDependencies.push_back(field.Name); } else $$->Fields.push_back(field); } delete $7; ClassCompiler::OptimizeStructLayout($$->Fields); } ; class_attribute_list: /* empty */ { $$ = 0; } | T_CLASS_ATTRIBUTE { $$ = $1; } | class_attribute_list T_CLASS_ATTRIBUTE { $$ = $1 | $2; } inherits_specifier: /* empty */ { $$ = NULL; } | ':' identifier { $$ = $2; } ; type_base_specifier: /* empty */ { $$ = NULL; } | '<' identifier { $$ = $2; } ; class_fields: /* empty */ { $$ = new std::vector(); } | class_fields class_field { $$->push_back(*$2); delete $2; } ; field_type: identifier { $$ = new FieldType(); $$->IsName = false; $$->TypeName = $1; free($1); } | T_NAME '(' identifier ')' { $$ = new FieldType(); $$->IsName = true; $$->TypeName = $3; $$->ArrayRank = 0; free($3); } | T_ARRAY '(' field_type ')' { $$ = $3; $$->ArrayRank++; } ; class_field: field_attribute_list field_type identifier alternative_name_specifier field_accessor_list ';' { Field *field = $1; if ((field->Attributes & (FAConfig | FAState)) == 0) field->Attributes |= FAEphemeral; field->Type = *$2; delete $2; field->Name = $3; std::free($3); if ($4) { field->AlternativeName = $4; std::free($4); } std::vector::const_iterator it; for (it = $5->begin(); it != $5->end(); it++) { switch (it->Type) { case FTGet: field->GetAccessor = it->Accessor; field->PureGetAccessor = it->Pure; break; case FTSet: field->SetAccessor = it->Accessor; field->PureSetAccessor = it->Pure; break; case FTDefault: field->DefaultAccessor = it->Accessor; break; case FTTrack: field->TrackAccessor = it->Accessor; break; case FTNavigate: field->NavigateAccessor = it->Accessor; field->PureNavigateAccessor = it->Pure; break; } } delete $5; $$ = field; } | T_LOAD_AFTER identifier ';' { Field *field = new Field(); field->Attributes = FALoadDependency; field->Name = $2; std::free($2); $$ = field; } ; alternative_name_specifier: /* empty */ { $$ = NULL; } | '(' identifier ')' { $$ = $2; } ; field_attribute_list: /* empty */ { $$ = new Field(); } | '[' field_attributes ']' { $$ = $2; } ; field_attribute: T_FIELD_ATTRIBUTE { $$ = new Field(); $$->Attributes = $1; } | T_REQUIRED { $$ = new Field(); $$->Attributes = FARequired; } | T_NAVIGATION '(' identifier ')' { $$ = new Field(); $$->Attributes = FANavigation; $$->NavigationName = $3; std::free($3); } | T_NAVIGATION { $$ = new Field(); $$->Attributes = FANavigation; } ; field_attributes: /* empty */ { $$ = new Field(); } | field_attributes ',' field_attribute { $$ = $1; $$->Attributes |= $3->Attributes; if (!$3->NavigationName.empty()) $$->NavigationName = $3->NavigationName; delete $3; } | field_attribute { $$ = $1; } ; field_accessor_list: /* empty */ { $$ = new std::vector(); } | '{' field_accessors '}' { $$ = $2; } ; field_accessors: /* empty */ { $$ = new std::vector(); } | field_accessors field_accessor { $$ = $1; $$->push_back(*$2); delete $2; } ; field_accessor: T_FIELD_ACCESSOR_TYPE T_STRING { $$ = new FieldAccessor(static_cast($1), $2, false); std::free($2); } | T_FIELD_ACCESSOR_TYPE ';' { $$ = new FieldAccessor(static_cast($1), "", true); } ; validator_rules: /* empty */ { $$ = new std::vector(); } | validator_rules validator_rule { $$->push_back(*$2); delete $2; } ; validator_rule: T_NAME '(' T_IDENTIFIER ')' identifier ';' { $$ = new Rule(); $$->Attributes = 0; $$->IsName = true; $$->Type = $3; std::free($3); $$->Pattern = $5; std::free($5); } | T_IDENTIFIER identifier ';' { $$ = new Rule(); $$->Attributes = 0; $$->IsName = false; $$->Type = $1; std::free($1); $$->Pattern = $2; std::free($2); } | T_NAME '(' T_IDENTIFIER ')' identifier '{' validator_rules '}' ';' { $$ = new Rule(); $$->Attributes = 0; $$->IsName = true; $$->Type = $3; std::free($3); $$->Pattern = $5; std::free($5); $$->Rules = *$7; delete $7; } | T_IDENTIFIER identifier '{' validator_rules '}' ';' { $$ = new Rule(); $$->Attributes = 0; $$->IsName = false; $$->Type = $1; std::free($1); $$->Pattern = $2; std::free($2); $$->Rules = *$4; delete $4; } | T_REQUIRED identifier ';' { $$ = new Rule(); $$->Attributes = RARequired; $$->IsName = false; $$->Type = ""; $$->Pattern = $2; std::free($2); } ; validator: T_VALIDATOR T_IDENTIFIER '{' validator_rules '}' ';' { $$ = new Validator(); $$->Name = $2; std::free($2); $$->Rules = *$4; delete $4; } ; identifier: T_IDENTIFIER | T_STRING { $$ = $1; } ; icinga2-2.8.1/tools/mkclass/classcompiler.cpp000066400000000000000000001436571322762156600212310ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "classcompiler.hpp" #include #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #else /* _WIN32 */ #include #endif /* _WIN32 */ using namespace icinga; ClassCompiler::ClassCompiler(const std::string& path, std::istream& input, std::ostream& oimpl, std::ostream& oheader) : m_Path(path), m_Input(input), m_Impl(oimpl), m_Header(oheader) { InitializeScanner(); } ClassCompiler::~ClassCompiler(void) { DestroyScanner(); } std::string ClassCompiler::GetPath(void) const { return m_Path; } void *ClassCompiler::GetScanner(void) { return m_Scanner; } size_t ClassCompiler::ReadInput(char *buffer, size_t max_size) { m_Input.read(buffer, max_size); return static_cast(m_Input.gcount()); } void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo&) { m_Header << "#include \"" << path << "\"" << std::endl << std::endl; } void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo&) { m_Header << "#include <" << path << ">" << std::endl << std::endl; } void ClassCompiler::HandleImplInclude(const std::string& path, const ClassDebugInfo&) { m_Impl << "#include \"" << path << "\"" << std::endl << std::endl; } void ClassCompiler::HandleAngleImplInclude(const std::string& path, const ClassDebugInfo&) { m_Impl << "#include <" << path << ">" << std::endl << std::endl; } void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo&) { m_Header << "namespace " << name << std::endl << "{" << std::endl << std::endl; m_Impl << "namespace " << name << std::endl << "{" << std::endl << std::endl; } void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo&) { HandleMissingValidators(); m_Header << "}" << std::endl; m_Impl << "}" << std::endl; } void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo&) { m_Header << code << std::endl; } void ClassCompiler::HandleLibrary(const std::string& library, const ClassDebugInfo&) { m_Library = library; std::string libName = m_Library; std::locale locale; for (auto& ch : libName) ch = std::toupper(ch, locale); m_Header << "#ifndef I2_" << libName << "_API" << std::endl << "# ifdef I2_" << libName << "_BUILD" << std::endl << "# define I2_" << libName << "_API I2_EXPORT" << std::endl << "# else /* I2_" << libName << "_BUILD */" << std::endl << "# define I2_" << libName << "_API I2_IMPORT" << std::endl << "# endif /* I2_" << libName << "_BUILD */" << std::endl << "#endif /* I2_" << libName << "_API */" << std::endl << std::endl; } unsigned long ClassCompiler::SDBM(const std::string& str, size_t len = std::string::npos) { unsigned long hash = 0; size_t current = 0; for (const char& ch : str) { if (current >= len) break; hash = ch + (hash << 6) + (hash << 16) - hash; current++; } return hash; } static int TypePreference(const std::string& type) { if (type == "Value") return 0; else if (type == "String") return 1; else if (type == "double") return 2; else if (type.find("::Ptr") != std::string::npos) return 3; else if (type == "int") return 4; else return 5; } static bool FieldLayoutCmp(const Field& a, const Field& b) { return TypePreference(a.Type.GetRealType()) < TypePreference(b.Type.GetRealType()); } static bool FieldTypeCmp(const Field& a, const Field& b) { return a.Type.GetRealType() < b.Type.GetRealType(); } static std::string FieldTypeToIcingaName(const Field& field, bool inner) { std::string ftype = field.Type.TypeName; if (!inner && field.Type.ArrayRank > 0) return "Array"; if (field.Type.IsName) return "String"; if (field.Attributes & FAEnum) return "Number"; if (ftype == "bool" || ftype == "int" || ftype == "double") return "Number"; if (ftype == "int" || ftype == "double") return "Number"; else if (ftype == "bool") return "Boolean"; if (ftype.find("::Ptr") != std::string::npos) return ftype.substr(0, ftype.size() - strlen("::Ptr")); return ftype; } void ClassCompiler::OptimizeStructLayout(std::vector& fields) { std::sort(fields.begin(), fields.end(), FieldTypeCmp); std::stable_sort(fields.begin(), fields.end(), FieldLayoutCmp); } void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) { std::string apiMacro; if (!m_Library.empty()) { std::string libName = m_Library; std::locale locale; for (auto& ch : libName) ch = std::toupper(ch, locale); apiMacro = "I2_" + libName + "_API "; } /* forward declaration */ if (klass.Name.find_first_of(':') == std::string::npos) m_Header << "class " << klass.Name << ";" << std::endl << std::endl; /* TypeHelper */ if (klass.Attributes & TAAbstract) { m_Header << "template<>" << std::endl << "struct TypeHelper<" << klass.Name << ", " << ((klass.Attributes & TAVarArgConstructor) ? "true" : "false") << ">" << std::endl << "{" << std::endl << "\t" << "static ObjectFactory GetFactory(void)" << std::endl << "\t" << "{" << std::endl << "\t\t" << "return NULL;" << std::endl << "\t" << "}" << std::endl << "};" << std::endl << std::endl; } /* TypeImpl */ m_Header << "template<>" << std::endl << "class " << apiMacro << "TypeImpl<" << klass.Name << ">" << " : public Type"; if (!klass.Parent.empty()) m_Header << "Impl<" << klass.Parent << ">"; if (!klass.TypeBase.empty()) m_Header << ", public " + klass.TypeBase; m_Header << std::endl << "{" << std::endl << "public:" << std::endl << "\t" << "DECLARE_PTR_TYPEDEFS(TypeImpl<" << klass.Name << ">);" << std::endl << std::endl; /* GetName */ m_Header << "\t" << "virtual String GetName(void) const;" << std::endl; m_Impl << "String TypeImpl<" << klass.Name << ">::GetName(void) const" << std::endl << "{" << std::endl << "\t" << "return \"" << klass.Name << "\";" << std::endl << "}" << std::endl << std::endl; /* GetAttributes */ m_Header << "\t" << "virtual int GetAttributes(void) const;" << std::endl; m_Impl << "int TypeImpl<" << klass.Name << ">::GetAttributes(void) const" << std::endl << "{" << std::endl << "\t" << "return " << klass.Attributes << ";" << std::endl << "}" << std::endl << std::endl; /* GetBaseType */ m_Header << "\t" << "virtual Type::Ptr GetBaseType(void) const;" << std::endl; m_Impl << "Type::Ptr TypeImpl<" << klass.Name << ">::GetBaseType(void) const" << std::endl << "{" << std::endl << "\t" << "return "; if (!klass.Parent.empty()) m_Impl << klass.Parent << "::TypeInstance"; else m_Impl << "Object::TypeInstance"; m_Impl << ";" << std::endl << "}" << std::endl << std::endl; /* GetFieldId */ m_Header << "\t" << "virtual int GetFieldId(const String& name) const;" << std::endl; m_Impl << "int TypeImpl<" << klass.Name << ">::GetFieldId(const String& name) const" << std::endl << "{" << std::endl; if (!klass.Fields.empty()) { m_Impl << "\t" << "int offset = "; if (!klass.Parent.empty()) m_Impl << klass.Parent << "::TypeInstance->GetFieldCount()"; else m_Impl << "0"; m_Impl << ";" << std::endl << std::endl; } std::map > > jumptable; int hlen = 0, collisions = 0; do { int num = 0; hlen++; jumptable.clear(); collisions = 0; for (const Field& field : klass.Fields) { int hash = static_cast(SDBM(field.Name, hlen)); jumptable[hash].push_back(std::make_pair(num, field.Name)); num++; if (jumptable[hash].size() > 1) collisions++; } } while (collisions >= 5 && hlen < 8); if (!klass.Fields.empty()) { m_Impl << "\tswitch (static_cast(Utility::SDBM(name, " << hlen << "))) {" << std::endl; for (const auto& itj : jumptable) { m_Impl << "\t\tcase " << itj.first << ":" << std::endl; for (const auto& itf : itj.second) { m_Impl << "\t\t\t" << "if (name == \"" << itf.second << "\")" << std::endl << "\t\t\t\t" << "return offset + " << itf.first << ";" << std::endl; } m_Impl << std::endl << "\t\t\t\tbreak;" << std::endl; } m_Impl << "\t}" << std::endl; } m_Impl << std::endl << "\t" << "return "; if (!klass.Parent.empty()) m_Impl << klass.Parent << "::TypeInstance->GetFieldId(name)"; else m_Impl << "-1"; m_Impl << ";" << std::endl << "}" << std::endl << std::endl; /* GetFieldInfo */ m_Header << "\t" << "virtual Field GetFieldInfo(int id) const;" << std::endl; m_Impl << "Field TypeImpl<" << klass.Name << ">::GetFieldInfo(int id) const" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount();" << std::endl << "\t" << "if (real_id < 0) { return " << klass.Parent << "::TypeInstance->GetFieldInfo(id); }" << std::endl; if (klass.Fields.size() > 0) { m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; size_t num = 0; for (const Field& field : klass.Fields) { std::string ftype = FieldTypeToIcingaName(field, false); std::string nameref; if (field.Type.IsName) nameref = "\"" + field.Type.TypeName + "\""; else nameref = "NULL"; m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "return Field(" << num << ", \"" << ftype << "\", \"" << field.Name << "\", \"" << (field.NavigationName.empty() ? field.Name : field.NavigationName) << "\", " << nameref << ", " << field.Attributes << ", " << field.Type.ArrayRank << ");" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t"; } m_Impl << "\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl; if (klass.Fields.size() > 0) m_Impl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* GetFieldCount */ m_Header << "\t" << "virtual int GetFieldCount(void) const;" << std::endl; m_Impl << "int TypeImpl<" << klass.Name << ">::GetFieldCount(void) const" << std::endl << "{" << std::endl << "\t" << "return " << klass.Fields.size(); if (!klass.Parent.empty()) m_Impl << " + " << klass.Parent << "::TypeInstance->GetFieldCount()"; m_Impl << ";" << std::endl << "}" << std::endl << std::endl; /* GetFactory */ m_Header << "\t" << "virtual ObjectFactory GetFactory(void) const;" << std::endl; m_Impl << "ObjectFactory TypeImpl<" << klass.Name << ">::GetFactory(void) const" << std::endl << "{" << std::endl << "\t" << "return TypeHelper<" << klass.Name << ", " << ((klass.Attributes & TAVarArgConstructor) ? "true" : "false") << ">::GetFactory();" << std::endl << "}" << std::endl << std::endl; /* GetLoadDependencies */ m_Header << "\t" << "virtual std::vector GetLoadDependencies(void) const;" << std::endl; m_Impl << "std::vector TypeImpl<" << klass.Name << ">::GetLoadDependencies(void) const" << std::endl << "{" << std::endl << "\t" << "std::vector deps;" << std::endl; for (const std::string& dep : klass.LoadDependencies) m_Impl << "\t" << "deps.push_back(\"" << dep << "\");" << std::endl; m_Impl << "\t" << "return deps;" << std::endl << "}" << std::endl << std::endl; /* RegisterAttributeHandler */ m_Header << "public:" << std::endl << "\t" << "virtual void RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback);" << std::endl; m_Impl << "void TypeImpl<" << klass.Name << ">::RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback)" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = fieldId - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { " << klass.Parent << "::TypeInstance->RegisterAttributeHandler(fieldId, callback); return; }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "fieldId"; m_Impl << ") {" << std::endl; int num = 0; for (const Field& field : klass.Fields) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "ObjectImpl<" << klass.Name << ">::On" << field.GetFriendlyName() << "Changed.connect(callback);" << std::endl << "\t\t\t" << "break;" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; m_Header << "};" << std::endl << std::endl; m_Header << std::endl; /* ObjectImpl */ m_Header << "template<>" << std::endl << "class " << apiMacro << "ObjectImpl<" << klass.Name << ">" << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl << "{" << std::endl << "public:" << std::endl << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl; /* Validate */ m_Header << "\t" << "virtual void Validate(int types, const ValidationUtils& utils) override;" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::Validate(int types, const ValidationUtils& utils)" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << klass.Parent << "::Validate(types, utils);" << std::endl << std::endl; for (const Field& field : klass.Fields) { m_Impl << "\t" << "if (" << (field.Attributes & (FAEphemeral|FAConfig|FAState)) << " & types)" << std::endl << "\t\t" << "Validate" << field.GetFriendlyName() << "(Get" << field.GetFriendlyName() << "(), utils);" << std::endl; } m_Impl << "}" << std::endl << std::endl; for (const Field& field : klass.Fields) { std::string argName; if (field.Type.ArrayRank > 0) argName = "avalue"; else argName = "value"; m_Header << "\t" << "void SimpleValidate" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " " << argName << ", const ValidationUtils& utils);" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::SimpleValidate" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " " << argName << ", const ValidationUtils& utils)" << std::endl << "{" << std::endl; if (field.Attributes & FARequired) { if (field.Type.GetRealType().find("::Ptr") != std::string::npos) m_Impl << "\t" << "if (!" << argName << ")" << std::endl; else m_Impl << "\t" << "if (" << argName << ".IsEmpty())" << std::endl; m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl; } if (field.Attributes & FADeprecated) { if (field.Type.GetRealType().find("::Ptr") != std::string::npos) m_Impl << "\t" << "if (" << argName << ")" << std::endl; else m_Impl << "\t" << "if (" << argName << " != GetDefault" << field.GetFriendlyName() << "())" << std::endl; m_Impl << "\t\t" << "Log(LogWarning, \"" << klass.Name << "\") << \"Attribute '" << field.Name << "' for object '\" << dynamic_cast(this)->GetName() << \"' of type '\" << dynamic_cast(this)->GetReflectionType()->GetName() << \"' is deprecated and should not be used.\";" << std::endl; } if (field.Type.ArrayRank > 0) { m_Impl << "\t" << "if (avalue) {" << std::endl << "\t\t" << "ObjectLock olock(avalue);" << std::endl << "\t\t" << "for (const Value& value : avalue) {" << std::endl; } std::string ftype = FieldTypeToIcingaName(field, true); if (ftype == "Value") { m_Impl << "\t" << "if (value.IsObjectType()) {" << std::endl << "\t\t" << "Function::Ptr func = value;" << std::endl << "\t\t" << "if (func->IsDeprecated())" << std::endl << "\t\t\t" << "Log(LogWarning, \"" << klass.Name << "\") << \"Attribute '" << field.Name << "' for object '\" << dynamic_cast(this)->GetName() << \"' of type '\" << dynamic_cast(this)->GetReflectionType()->GetName() << \"' is set to a deprecated function: \" << func->GetName();" << std::endl << "\t" << "}" << std::endl << std::endl; } if (field.Type.IsName) { m_Impl << "\t" << "if ("; if (field.Type.ArrayRank > 0) m_Impl << "value.IsEmpty() || "; else m_Impl << "!value.IsEmpty() && "; m_Impl << "!utils.ValidateName(\"" << field.Type.TypeName << "\", value))" << std::endl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), boost::assign::list_of(\"" << field.Name << "\"), \"Object '\" + value + \"' of type '" << field.Type.TypeName << "' does not exist.\"));" << std::endl; } else if (field.Type.ArrayRank > 0 && (ftype == "Number" || ftype == "Boolean")) { m_Impl << "\t" << "try {" << std::endl << "\t\t" << "Convert::ToDouble(value);" << std::endl << "\t" << "} catch (const std::invalid_argument&) {" << std::endl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), boost::assign::list_of(\"" << field.Name << "\"), \"Array element '\" + value + \"' of type '\" + value.GetReflectionType()->GetName() + \"' is not valid here; expected type '" << ftype << "'.\"));" << std::endl << "\t" << "}" << std::endl; } if (field.Type.ArrayRank > 0) { m_Impl << "\t\t" << "}" << std::endl << "\t" << "}" << std::endl; } m_Impl << "}" << std::endl << std::endl; } if (!klass.Fields.empty()) { /* constructor */ m_Header << "public:" << std::endl << "\t" << "ObjectImpl<" << klass.Name << ">(void);" << std::endl; m_Impl << "ObjectImpl<" << klass.Name << ">::ObjectImpl(void)" << std::endl << "{" << std::endl; for (const Field& field : klass.Fields) { m_Impl << "\t" << "Set" << field.GetFriendlyName() << "(" << "GetDefault" << field.GetFriendlyName() << "(), true);" << std::endl; } m_Impl << "}" << std::endl << std::endl; /* destructor */ m_Header << "public:" << std::endl << "\t" << "~ObjectImpl<" << klass.Name << ">(void);" << std::endl; m_Impl << "ObjectImpl<" << klass.Name << ">::~ObjectImpl(void)" << std::endl << "{ }" << std::endl << std::endl; /* SetField */ m_Header << "public:" << std::endl << "\t" << "virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty) override;" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value, suppress_events, cookie); return; }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; size_t num = 0; for (const Field& field : klass.Fields) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "Set" << field.GetFriendlyName() << "("; if (field.Attributes & FAEnum) m_Impl << "static_cast<" << field.Type.GetRealType() << ">(static_cast("; m_Impl << "value"; if (field.Attributes & FAEnum) m_Impl << "))"; m_Impl << ", suppress_events, cookie);" << std::endl << "\t\t\t" << "break;" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* GetField */ m_Header << "public:" << std::endl << "\t" << "virtual Value GetField(int id) const override;" << std::endl; m_Impl << "Value ObjectImpl<" << klass.Name << ">::GetField(int id) const" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; num = 0; for (const Field& field : klass.Fields) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "return Get" << field.GetFriendlyName() << "();" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* ValidateField */ m_Header << "public:" << std::endl << "\t" << "virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils) override;" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::ValidateField(int id, const Value& value, const ValidationUtils& utils)" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { " << klass.Parent << "::ValidateField(id, value, utils); return; }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; num = 0; for (const Field& field : klass.Fields) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "Validate" << field.GetFriendlyName() << "("; if (field.Attributes & FAEnum) m_Impl << "static_cast<" << field.Type.GetRealType() << ">(static_cast("; m_Impl << "value"; if (field.Attributes & FAEnum) m_Impl << "))"; m_Impl << ", utils);" << std::endl << "\t\t\t" << "break;" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* NotifyField */ m_Header << "public:" << std::endl << "\t" << "virtual void NotifyField(int id, const Value& cookie = Empty) override;" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::NotifyField(int id, const Value& cookie)" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { " << klass.Parent << "::NotifyField(id, cookie); return; }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; num = 0; for (const Field& field : klass.Fields) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "Notify" << field.GetFriendlyName() << "(cookie);" << std::endl << "\t\t\t" << "break;" << std::endl; num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* NavigateField */ m_Header << "public:" << std::endl << "\t" << "virtual Object::Ptr NavigateField(int id) const override;" << std::endl; m_Impl << "Object::Ptr ObjectImpl<" << klass.Name << ">::NavigateField(int id) const" << std::endl << "{" << std::endl; if (!klass.Parent.empty()) m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl << "\t" << "if (real_id < 0) { return " << klass.Parent << "::NavigateField(id); }" << std::endl; m_Impl << "\t" << "switch ("; if (!klass.Parent.empty()) m_Impl << "real_id"; else m_Impl << "id"; m_Impl << ") {" << std::endl; num = 0; for (const Field& field : klass.Fields) { if (field.Attributes & FANavigation) { m_Impl << "\t\t" << "case " << num << ":" << std::endl << "\t\t\t" << "return Navigate" << field.GetFriendlyName() << "();" << std::endl; } num++; } m_Impl << "\t\t" << "default:" << std::endl << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl << "\t" << "}" << std::endl; m_Impl << "}" << std::endl << std::endl; /* getters */ for (const Field& field : klass.Fields) { std::string prot; if (field.Attributes & FAGetProtected) prot = "protected"; else prot = "public"; m_Header << prot << ":" << std::endl << "\t" << "virtual " << field.Type.GetRealType() << " Get" << field.GetFriendlyName() << "(void) const"; if (field.PureGetAccessor) { m_Header << " = 0;" << std::endl; } else { m_Header << ";" << std::endl; m_Impl << field.Type.GetRealType() << " ObjectImpl<" << klass.Name << ">::Get" << field.GetFriendlyName() << "(void) const" << std::endl << "{" << std::endl; if (field.GetAccessor.empty() && !(field.Attributes & FANoStorage)) m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ";" << std::endl; else m_Impl << field.GetAccessor << std::endl; m_Impl << "}" << std::endl << std::endl; } } /* setters */ for (const Field& field : klass.Fields) { std::string prot; if (field.Attributes & FASetProtected) prot = "protected"; else prot = "public"; m_Header << prot << ":" << std::endl << "\t" << "virtual void Set" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " value, bool suppress_events = false, const Value& cookie = Empty)"; if (field.PureSetAccessor) { m_Header << " = 0;" << std::endl; } else { m_Header << ";" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::Set" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " value, bool suppress_events, const Value& cookie)" << std::endl << "{" << std::endl; if (field.Type.IsName || !field.TrackAccessor.empty()) m_Impl << "\t" << "Value oldValue = Get" << field.GetFriendlyName() << "();" << std::endl; if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage)) m_Impl << "\t" << "m_" << field.GetFriendlyName() << " = value;" << std::endl; else m_Impl << field.SetAccessor << std::endl << std::endl; if (field.Type.IsName || !field.TrackAccessor.empty()) { if (field.Name != "active") { m_Impl << "\t" << "ConfigObject *dobj = dynamic_cast(this);" << std::endl << "\t" << "if (!dobj || dobj->IsActive())" << std::endl << "\t"; } m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(oldValue, value);" << std::endl; } m_Impl << "\t" << "if (!suppress_events)" << std::endl << "\t\t" << "Notify" << field.GetFriendlyName() << "(cookie);" << std::endl << "}" << std::endl << std::endl; } } m_Header << "protected:" << std::endl; bool needs_tracking = false; /* tracking */ for (const Field& field : klass.Fields) { if (!field.Type.IsName && field.TrackAccessor.empty()) continue; needs_tracking = true; m_Header << "\t" << "virtual void Track" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " oldValue, " << field.Type.GetArgumentType() << " newValue);"; m_Impl << "void ObjectImpl<" << klass.Name << ">::Track" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " oldValue, " << field.Type.GetArgumentType() << " newValue)" << std::endl << "{" << std::endl; if (!field.TrackAccessor.empty()) m_Impl << "\t" << field.TrackAccessor << std::endl; if (field.Type.TypeName != "String") { if (field.Type.ArrayRank > 0) { m_Impl << "\t" << "if (oldValue) {" << std::endl << "\t\t" << "ObjectLock olock(oldValue);" << std::endl << "\t\t" << "for (const String& ref : oldValue) {" << std::endl << "\t\t\t" << "DependencyGraph::RemoveDependency(this, ConfigObject::GetObject"; /* Ew */ if (field.Type.TypeName == "Zone" && m_Library == "base") m_Impl << "(\"Zone\", "; else m_Impl << "<" << field.Type.TypeName << ">("; m_Impl << "ref).get());" << std::endl << "\t\t" << "}" << std::endl << "\t" << "}" << std::endl << "\t" << "if (newValue) {" << std::endl << "\t\t" << "ObjectLock olock(newValue);" << std::endl << "\t\t" << "for (const String& ref : newValue) {" << std::endl << "\t\t\t" << "DependencyGraph::AddDependency(this, ConfigObject::GetObject"; /* Ew */ if (field.Type.TypeName == "Zone" && m_Library == "base") m_Impl << "(\"Zone\", "; else m_Impl << "<" << field.Type.TypeName << ">("; m_Impl << "ref).get());" << std::endl << "\t\t" << "}" << std::endl << "\t" << "}" << std::endl; } else { m_Impl << "\t" << "if (!oldValue.IsEmpty())" << std::endl << "\t\t" << "DependencyGraph::RemoveDependency(this, ConfigObject::GetObject"; /* Ew */ if (field.Type.TypeName == "Zone" && m_Library == "base") m_Impl << "(\"Zone\", "; else m_Impl << "<" << field.Type.TypeName << ">("; m_Impl << "oldValue).get());" << std::endl << "\t" << "if (!newValue.IsEmpty())" << std::endl << "\t\t" << "DependencyGraph::AddDependency(this, ConfigObject::GetObject"; /* Ew */ if (field.Type.TypeName == "Zone" && m_Library == "base") m_Impl << "(\"Zone\", "; else m_Impl << "<" << field.Type.TypeName << ">("; m_Impl << "newValue).get());" << std::endl; } } m_Impl << "}" << std::endl << std::endl; } /* navigation */ for (const Field& field : klass.Fields) { if ((field.Attributes & FANavigation) == 0) continue; m_Header << "public:" << std::endl << "\t" << "virtual Object::Ptr Navigate" << field.GetFriendlyName() << "(void) const"; if (field.PureNavigateAccessor) { m_Header << " = 0;" << std::endl; } else { m_Header << ";" << std::endl; m_Impl << "Object::Ptr ObjectImpl<" << klass.Name << ">::Navigate" << field.GetFriendlyName() << "(void) const" << std::endl << "{" << std::endl; if (field.NavigateAccessor.empty()) m_Impl << "\t" << "return Get" << field.GetFriendlyName() << "();" << std::endl; else m_Impl << "\t" << field.NavigateAccessor << std::endl; m_Impl << "}" << std::endl << std::endl; } } /* start/stop */ if (needs_tracking) { m_Header << "virtual void Start(bool runtimeCreated = false) override;" << std::endl << "virtual void Stop(bool runtimeRemoved = false) override;" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::Start(bool runtimeCreated)" << std::endl << "{" << std::endl << "\t" << klass.Parent << "::Start(runtimeCreated);" << std::endl << std::endl; for (const Field& field : klass.Fields) { if (!field.Type.IsName && field.TrackAccessor.empty()) continue; m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(Empty, Get" << field.GetFriendlyName() << "());" << std::endl; } m_Impl << "}" << std::endl << std::endl << "void ObjectImpl<" << klass.Name << ">::Stop(bool runtimeRemoved)" << std::endl << "{" << std::endl << "\t" << klass.Parent << "::Stop(runtimeRemoved);" << std::endl << std::endl; for (const Field& field : klass.Fields) { if (!field.Type.IsName && field.TrackAccessor.empty()) continue; m_Impl << "\t" << "Track" << field.GetFriendlyName() << "(Get" << field.GetFriendlyName() << "(), Empty);" << std::endl; } m_Impl << "}" << std::endl << std::endl; } /* notify */ for (const Field& field : klass.Fields) { std::string prot; if (field.Attributes & FASetProtected) prot = "protected"; else prot = "public"; m_Header << prot << ":" << std::endl << "\t" << "virtual void Notify" << field.GetFriendlyName() << "(const Value& cookie = Empty);" << std::endl; m_Impl << "void ObjectImpl<" << klass.Name << ">::Notify" << field.GetFriendlyName() << "(const Value& cookie)" << std::endl << "{" << std::endl; if (field.Name != "active") { m_Impl << "\t" << "ConfigObject *dobj = dynamic_cast(this);" << std::endl << "\t" << "if (!dobj || dobj->IsActive())" << std::endl << "\t"; } m_Impl << "\t" << "On" << field.GetFriendlyName() << "Changed(static_cast<" << klass.Name << " *>(this), cookie);" << std::endl << "}" << std::endl << std::endl; } /* default */ for (const Field& field : klass.Fields) { std::string realType = field.Type.GetRealType(); m_Header << "private:" << std::endl << "\t" << "inline " << realType << " GetDefault" << field.GetFriendlyName() << "(void) const;" << std::endl; m_Impl << realType << " ObjectImpl<" << klass.Name << ">::GetDefault" << field.GetFriendlyName() << "(void) const" << std::endl << "{" << std::endl; if (field.DefaultAccessor.empty()) m_Impl << "\t" << "return " << realType << "();" << std::endl; else m_Impl << "\t" << field.DefaultAccessor << std::endl; m_Impl << "}" << std::endl << std::endl; } /* validators */ for (const Field& field : klass.Fields) { m_Header << "protected:" << std::endl << "\t" << "virtual void Validate" << field.GetFriendlyName() << "(" << field.Type.GetArgumentType() << " value, const ValidationUtils& utils);" << std::endl; } /* instance variables */ m_Header << "private:" << std::endl; for (const Field& field : klass.Fields) { if (field.Attributes & FANoStorage) continue; m_Header << "\t" << field.Type.GetRealType() << " m_" << field.GetFriendlyName() << ";" << std::endl; } /* signal */ m_Header << "public:" << std::endl; for (const Field& field : klass.Fields) { m_Header << "\t" << "static boost::signals2::signal&, const Value&)> On" << field.GetFriendlyName() << "Changed;" << std::endl; m_Impl << std::endl << "boost::signals2::signal&, const Value&)> ObjectImpl<" << klass.Name << ">::On" << field.GetFriendlyName() << "Changed;" << std::endl << std::endl; } } if (klass.Name == "ConfigObject") m_Header << "\t" << "friend class ConfigItem;" << std::endl; if (!klass.TypeBase.empty()) m_Header << "\t" << "friend class " << klass.TypeBase << ";" << std::endl; m_Header << "};" << std::endl << std::endl; for (const Field& field : klass.Fields) { m_MissingValidators[std::make_pair(klass.Name, field.GetFriendlyName())] = field; } } void ClassCompiler::CodeGenValidator(const std::string& name, const std::string& klass, const std::vector& rules, const std::string& field, const FieldType& fieldType, ValidatorType validatorType) { m_Impl << "static void TIValidate" << name << "(const intrusive_ptr >& object, "; if (validatorType != ValidatorField) m_Impl << "const String& key, "; m_Impl << fieldType.GetArgumentType() << " value, std::vector& location, const ValidationUtils& utils)" << std::endl << "{" << std::endl; if (validatorType == ValidatorField) { bool required = false; for (const Rule& rule : rules) { if ((rule.Attributes & RARequired) && rule.Pattern == field) { required = true; break; } } if (fieldType.GetRealType() != "int" && fieldType.GetRealType() != "double") { if (fieldType.GetRealType() == "Value" || fieldType.GetRealType() == "String") m_Impl << "\t" << "if (value.IsEmpty())" << std::endl; else m_Impl << "\t" << "if (!value)" << std::endl; if (required) m_Impl << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), location, \"This attribute must not be empty.\"));" << std::endl; else m_Impl << "\t\t" << "return;" << std::endl; m_Impl << std::endl; } } if (validatorType != ValidatorField) m_Impl << "\t" << "bool known_attribute = false;" << std::endl; bool type_check = false; int i = 0; for (const Rule& rule : rules) { if (rule.Attributes & RARequired) continue; i++; if (validatorType == ValidatorField && rule.Pattern != field) continue; m_Impl << "\t" << "do {" << std::endl; if (validatorType != ValidatorField) { if (rule.Pattern != "*") { if (rule.Pattern.find_first_of("*?") != std::string::npos) m_Impl << "\t\t" << "if (!Utility::Match(\"" << rule.Pattern << "\", key))" << std::endl; else m_Impl << "\t\t" << "if (key != \"" << rule.Pattern << "\")" << std::endl; m_Impl << "\t\t\t" << "break;" << std::endl; } m_Impl << "\t\t" << "known_attribute = true;" << std::endl; } if (rule.IsName) { m_Impl << "\t\t" << "if (value.IsScalar()) {" << std::endl << "\t\t\t" << "if (utils.ValidateName(\"" << rule.Type << "\", value))" << std::endl << "\t\t\t\t" << "return;" << std::endl << "\t\t\t" << "else" << std::endl << "\t\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_pointer_cast(object), location, \"Object '\" + value + \"' of type '" << rule.Type << "' does not exist.\"));" << std::endl << "\t\t" << "}" << std::endl; } if (fieldType.GetRealType() == "Value") { if (rule.Type == "String") m_Impl << "\t\t" << "if (value.IsEmpty() || value.IsScalar())" << std::endl << "\t\t\t" << "return;" << std::endl; else if (rule.Type == "Number") { m_Impl << "\t\t" << "try {" << std::endl << "\t\t\t" << "Convert::ToDouble(value);" << std::endl << "\t\t\t" << "return;" << std::endl << "\t\t" << "} catch (...) { }" << std::endl; } } if (rule.Type == "Dictionary" || rule.Type == "Array" || rule.Type == "Function") { if (fieldType.GetRealType() == "Value") { m_Impl << "\t\t" << "if (value.IsObjectType<" << rule.Type << ">()) {" << std::endl; type_check = true; } else if (fieldType.GetRealType() != rule.Type + "::Ptr") { m_Impl << "\t\t" << "if (dynamic_pointer_cast<" << rule.Type << ">(value)) {" << std::endl; type_check = true; } if (!rule.Rules.empty()) { bool indent = false; if (rule.Type == "Dictionary") { if (type_check) m_Impl << "\t\t\t" << "Dictionary::Ptr dict = value;" << std::endl; else m_Impl << "\t\t" << "const Dictionary::Ptr& dict = value;" << std::endl; m_Impl << (type_check ? "\t" : "") << "\t\t" << "{" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "ObjectLock olock(dict);" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "for (const Dictionary::Pair& kv : dict) {" << std::endl << (type_check ? "\t" : "") << "\t\t\t\t" << "const String& akey = kv.first;" << std::endl << (type_check ? "\t" : "") << "\t\t\t\t" << "const Value& avalue = kv.second;" << std::endl; indent = true; } else if (rule.Type == "Array") { if (type_check) m_Impl << "\t\t\t" << "Array::Ptr arr = value;" << std::endl; else m_Impl << "\t\t" << "const Array::Ptr& arr = value;" << std::endl; m_Impl << (type_check ? "\t" : "") << "\t\t" << "Array::SizeType anum = 0;" << std::endl << (type_check ? "\t" : "") << "\t\t" << "{" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "ObjectLock olock(arr);" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "for (const Value& avalue : arr) {" << std::endl << (type_check ? "\t" : "") << "\t\t\t\t" << "String akey = Convert::ToString(anum);" << std::endl; indent = true; } else { m_Impl << (type_check ? "\t" : "") << "\t\t" << "String akey = \"\";" << std::endl << (type_check ? "\t" : "") << "\t\t" << "const Value& avalue = value;" << std::endl; } std::string subvalidator_prefix; if (validatorType == ValidatorField) subvalidator_prefix = klass; else subvalidator_prefix = name; m_Impl << (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "location.push_back(akey);" << std::endl << (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "TIValidate" << subvalidator_prefix << "_" << i << "(object, akey, avalue, location, utils);" << std::endl << (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "location.pop_back();" << std::endl; if (rule.Type == "Array") m_Impl << (type_check ? "\t" : "") << "\t\t\t\t" << "anum++;" << std::endl; if (rule.Type == "Dictionary" || rule.Type == "Array") { m_Impl << (type_check ? "\t" : "") << "\t\t\t" << "}" << std::endl << (type_check ? "\t" : "") << "\t\t" << "}" << std::endl; } for (const Rule& srule : rule.Rules) { if ((srule.Attributes & RARequired) == 0) continue; if (rule.Type == "Dictionary") { m_Impl << (type_check ? "\t" : "") << "\t\t" << "if (dict->Get(\"" << srule.Pattern << "\").IsEmpty())" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_pointer_cast(object), location, \"Required dictionary item '" << srule.Pattern << "' is not set.\"));" << std::endl; } else if (rule.Type == "Array") { int index = -1; std::stringstream idxbuf; idxbuf << srule.Pattern; idxbuf >> index; if (index == -1) { std::cerr << "Invalid index for 'required' keyword: " << srule.Pattern; std::exit(1); } m_Impl << (type_check ? "\t" : "") << "\t\t" << "if (arr.GetLength() < " << (index + 1) << ")" << std::endl << (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), location, \"Required index '" << index << "' is not set.\"));" << std::endl; } } } m_Impl << (type_check ? "\t" : "") << "\t\t" << "return;" << std::endl; if (fieldType.GetRealType() == "Value" || fieldType.GetRealType() != rule.Type + "::Ptr") m_Impl << "\t\t" << "}" << std::endl; } m_Impl << "\t" << "} while (0);" << std::endl << std::endl; } if (type_check || validatorType != ValidatorField) { if (validatorType != ValidatorField) { m_Impl << "\t" << "if (!known_attribute)" << std::endl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_pointer_cast(object), location, \"Invalid attribute: \" + key));" << std::endl << "\t" << "else" << std::endl; } m_Impl << (validatorType != ValidatorField ? "\t" : "") << "\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_pointer_cast(object), location, \"Invalid type.\"));" << std::endl; } m_Impl << "}" << std::endl << std::endl; } void ClassCompiler::CodeGenValidatorSubrules(const std::string& name, const std::string& klass, const std::vector& rules) { int i = 0; for (const Rule& rule : rules) { if (rule.Attributes & RARequired) continue; i++; if (!rule.Rules.empty()) { ValidatorType subtype; if (rule.Type == "Array") subtype = ValidatorArray; else if (rule.Type == "Dictionary") subtype = ValidatorDictionary; else { std::cerr << "Invalid sub-validator type: " << rule.Type << std::endl; std::exit(EXIT_FAILURE); } std::ostringstream namebuf; namebuf << name << "_" << i; CodeGenValidatorSubrules(namebuf.str(), klass, rule.Rules); FieldType ftype; ftype.IsName = false; ftype.TypeName = "Value"; CodeGenValidator(namebuf.str(), klass, rule.Rules, rule.Pattern, ftype, subtype); } } } void ClassCompiler::HandleValidator(const Validator& validator, const ClassDebugInfo&) { CodeGenValidatorSubrules(validator.Name, validator.Name, validator.Rules); for (const auto& it : m_MissingValidators) CodeGenValidator(it.first.first + it.first.second, it.first.first, validator.Rules, it.second.Name, it.second.Type, ValidatorField); for (const auto& it : m_MissingValidators) { m_Impl << "void ObjectImpl<" << it.first.first << ">::Validate" << it.first.second << "(" << it.second.Type.GetArgumentType() << " value, const ValidationUtils& utils)" << std::endl << "{" << std::endl << "\t" << "SimpleValidate" << it.first.second << "(value, utils);" << std::endl << "\t" << "std::vector location;" << std::endl << "\t" << "location.push_back(\"" << it.second.Name << "\");" << std::endl << "\t" << "TIValidate" << it.first.first << it.first.second << "(this, value, location, utils);" << std::endl << "\t" << "location.pop_back();" << std::endl << "}" << std::endl << std::endl; } m_MissingValidators.clear(); } void ClassCompiler::HandleMissingValidators(void) { for (const auto& it : m_MissingValidators) { m_Impl << "void ObjectImpl<" << it.first.first << ">::Validate" << it.first.second << "(" << it.second.Type.GetArgumentType() << " value, const ValidationUtils& utils)" << std::endl << "{" << std::endl << "\t" << "SimpleValidate" << it.first.second << "(value, utils);" << std::endl << "}" << std::endl << std::endl; } m_MissingValidators.clear(); } void ClassCompiler::CompileFile(const std::string& inputpath, const std::string& implpath, const std::string& headerpath) { std::ifstream input; input.open(inputpath.c_str(), std::ifstream::in); if (!input) { std::cerr << "Could not open input file: " << inputpath << std::endl; std::exit(EXIT_FAILURE); } std::string tmpheaderpath = headerpath + ".tmp"; std::ofstream oheader; oheader.open(tmpheaderpath.c_str(), std::ofstream::out); if (!oheader) { std::cerr << "Could not open header file: " << tmpheaderpath << std::endl; std::exit(EXIT_FAILURE); } std::string tmpimplpath = implpath + ".tmp"; std::ofstream oimpl; oimpl.open(tmpimplpath.c_str(), std::ofstream::out); if (!oimpl) { std::cerr << "Could not open implementation file: " << tmpimplpath << std::endl; std::exit(EXIT_FAILURE); } CompileStream(inputpath, input, oimpl, oheader); input.close(); oimpl.close(); oheader.close(); #ifdef _WIN32 _unlink(headerpath.c_str()); #endif /* _WIN32 */ if (rename(tmpheaderpath.c_str(), headerpath.c_str()) < 0) { std::cerr << "Could not rename header file: " << tmpheaderpath << " -> " << headerpath << std::endl; std::exit(EXIT_FAILURE); } #ifdef _WIN32 _unlink(implpath.c_str()); #endif /* _WIN32 */ if (rename(tmpimplpath.c_str(), implpath.c_str()) < 0) { std::cerr << "Could not rename implementation file: " << tmpimplpath << " -> " << implpath << std::endl; std::exit(EXIT_FAILURE); } } std::string ClassCompiler::BaseName(const std::string& path) { char *dir = strdup(path.c_str()); std::string result; if (dir == NULL) throw std::bad_alloc(); #ifndef _WIN32 result = basename(dir); #else /* _WIN32 */ result = PathFindFileName(dir); #endif /* _WIN32 */ free(dir); return result; } std::string ClassCompiler::FileNameToGuardName(const std::string& fname) { std::string result = fname; std::locale locale; for (auto& ch : result) { ch = std::toupper(ch, locale); if (ch == '.') ch = '_'; } return result; } void ClassCompiler::CompileStream(const std::string& path, std::istream& input, std::ostream& oimpl, std::ostream& oheader) { input.exceptions(std::istream::badbit); std::string guard_name = FileNameToGuardName(BaseName(path)); oheader << "#ifndef " << guard_name << std::endl << "#define " << guard_name << std::endl << std::endl; oheader << "#include \"base/object.hpp\"" << std::endl << "#include \"base/type.hpp\"" << std::endl << "#include \"base/value.hpp\"" << std::endl << "#include \"base/array.hpp\"" << std::endl << "#include \"base/dictionary.hpp\"" << std::endl << "#include " << std::endl << std::endl; oimpl << "#include \"base/exception.hpp\"" << std::endl << "#include \"base/objectlock.hpp\"" << std::endl << "#include \"base/utility.hpp\"" << std::endl << "#include \"base/convert.hpp\"" << std::endl << "#include \"base/dependencygraph.hpp\"" << std::endl << "#include \"base/logger.hpp\"" << std::endl << "#include \"base/function.hpp\"" << std::endl << "#include \"base/configtype.hpp\"" << std::endl << "#include " << std::endl << "#ifdef _MSC_VER" << std::endl << "#pragma warning( push )" << std::endl << "#pragma warning( disable : 4244 )" << std::endl << "#pragma warning( disable : 4800 )" << std::endl << "#endif /* _MSC_VER */" << std::endl << std::endl; ClassCompiler ctx(path, input, oimpl, oheader); ctx.Compile(); oheader << "#endif /* " << guard_name << " */" << std::endl; oimpl << "#ifdef _MSC_VER" << std::endl << "#pragma warning ( pop )" << std::endl << "#endif /* _MSC_VER */" << std::endl; } icinga2-2.8.1/tools/mkclass/classcompiler.hpp000066400000000000000000000145751322762156600212320ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef CLASSCOMPILER_H #define CLASSCOMPILER_H #include #include #include #include #include namespace icinga { struct ClassDebugInfo { std::string path; int first_line; int first_column; int last_line; int last_column; }; enum FieldAccessorType { FTGet, FTSet, FTDefault, FTTrack, FTNavigate }; struct FieldAccessor { FieldAccessorType Type; std::string Accessor; bool Pure; FieldAccessor(FieldAccessorType type, const std::string& accessor, bool pure) : Type(type), Accessor(accessor), Pure(pure) { } }; /* keep this in sync with lib/base/type.hpp */ enum FieldAttribute { FAEphemeral = 1, FAConfig = 2, FAState = 4, FAEnum = 8, FAGetProtected = 16, FASetProtected = 32, FANoStorage = 64, FALoadDependency = 128, FARequired = 256, FANavigation = 512, FANoUserModify = 1024, FANoUserView = 2048, FADeprecated = 4096 }; struct FieldType { bool IsName; std::string TypeName; int ArrayRank; FieldType(void) : IsName(false), ArrayRank(0) { } inline std::string GetRealType(void) const { if (ArrayRank > 0) return "Array::Ptr"; if (IsName) return "String"; return TypeName; } inline std::string GetArgumentType(void) const { std::string realType = GetRealType(); if (realType == "bool" || realType == "double" || realType == "int") return realType; else return "const " + realType + "&"; } }; struct Field { int Attributes; FieldType Type; std::string Name; std::string AlternativeName; std::string GetAccessor; bool PureGetAccessor; std::string SetAccessor; bool PureSetAccessor; std::string DefaultAccessor; std::string TrackAccessor; std::string NavigationName; std::string NavigateAccessor; bool PureNavigateAccessor; Field(void) : Attributes(0), PureGetAccessor(false), PureSetAccessor(false), PureNavigateAccessor(false) { } inline std::string GetFriendlyName(void) const { if (!AlternativeName.empty()) return AlternativeName; bool cap = true; std::string name = Name; for (size_t i = 0; i < name.size(); i++) { if (name[i] == '_') { cap = true; continue; } if (cap) { name[i] = toupper(name[i]); cap = false; } } name.erase( std::remove(name.begin(), name.end(), '_'), name.end() ); /* TODO: figure out name */ return name; } }; enum TypeAttribute { TAAbstract = 1, TAVarArgConstructor = 2 }; struct Klass { std::string Name; std::string Parent; std::string TypeBase; int Attributes; std::vector Fields; std::vector LoadDependencies; }; enum RuleAttribute { RARequired = 1 }; struct Rule { int Attributes; bool IsName; std::string Type; std::string Pattern; std::vector Rules; }; enum ValidatorType { ValidatorField, ValidatorArray, ValidatorDictionary }; struct Validator { std::string Name; std::vector Rules; }; class ClassCompiler { public: ClassCompiler(const std::string& path, std::istream& input, std::ostream& oimpl, std::ostream& oheader); ~ClassCompiler(void); void Compile(void); std::string GetPath(void) const; void InitializeScanner(void); void DestroyScanner(void); void *GetScanner(void); size_t ReadInput(char *buffer, size_t max_size); void HandleInclude(const std::string& path, const ClassDebugInfo& locp); void HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp); void HandleImplInclude(const std::string& path, const ClassDebugInfo& locp); void HandleAngleImplInclude(const std::string& path, const ClassDebugInfo& locp); void HandleClass(const Klass& klass, const ClassDebugInfo& locp); void HandleValidator(const Validator& validator, const ClassDebugInfo& locp); void HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp); void HandleNamespaceEnd(const ClassDebugInfo& locp); void HandleCode(const std::string& code, const ClassDebugInfo& locp); void HandleLibrary(const std::string& library, const ClassDebugInfo& locp); void HandleMissingValidators(void); void CodeGenValidator(const std::string& name, const std::string& klass, const std::vector& rules, const std::string& field, const FieldType& fieldType, ValidatorType validatorType); void CodeGenValidatorSubrules(const std::string& name, const std::string& klass, const std::vector& rules); static void CompileFile(const std::string& inputpath, const std::string& implpath, const std::string& headerpath); static void CompileStream(const std::string& path, std::istream& input, std::ostream& oimpl, std::ostream& oheader); static void OptimizeStructLayout(std::vector& fields); private: std::string m_Path; std::istream& m_Input; std::ostream& m_Impl; std::ostream& m_Header; void *m_Scanner; std::string m_Library; std::map, Field> m_MissingValidators; static unsigned long SDBM(const std::string& str, size_t len); static std::string BaseName(const std::string& path); static std::string FileNameToGuardName(const std::string& path); }; } #endif /* CLASSCOMPILER_H */ icinga2-2.8.1/tools/mkclass/mkclass.cpp000066400000000000000000000033111322762156600200040ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include "classcompiler.hpp" #include using namespace icinga; int main(int argc, char **argv) { if (argc < 4) { std::cerr << "Syntax: " << argv[0] << " " << std::endl; return 1; } ClassCompiler::CompileFile(argv[1], argv[2], argv[3]); } icinga2-2.8.1/tools/mkembedconfig/000077500000000000000000000000001322762156600170025ustar00rootroot00000000000000icinga2-2.8.1/tools/mkembedconfig/CMakeLists.txt000066400000000000000000000024561322762156600215510ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. add_executable(mkembedconfig mkembedconfig.c) set_target_properties ( mkembedconfig PROPERTIES FOLDER Bin ) macro(MKEMBEDCONFIG_TARGET EmbedInput EmbedOutput) add_custom_command( OUTPUT ${EmbedOutput} COMMAND mkembedconfig ARGS ${EmbedInput} ${CMAKE_CURRENT_BINARY_DIR}/${EmbedOutput} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS mkembedconfig ${EmbedInput} ) set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/${EmbedOutput} PROPERTY EXCLUDE_UNITY_BUILD TRUE) endmacro() icinga2-2.8.1/tools/mkembedconfig/mkembedconfig.c000066400000000000000000000045551322762156600217510ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include #include int main(int argc, char **argv) { FILE *infp, *outfp; if (argc < 3) { fprintf(stderr, "Syntax: %s \n", argv[0]); return EXIT_FAILURE; } infp = fopen(argv[1], "r"); if (!infp) { perror("fopen"); return EXIT_FAILURE; } outfp = fopen(argv[2], "w"); if (!outfp) { fclose(infp); perror("fopen"); return EXIT_FAILURE; } fprintf(outfp, "/* This file has been automatically generated\n" " from the input file \"%s\". */\n\n", argv[1]); fputs("#include \"config/configfragment.hpp\"\n\nnamespace {\n\nconst char *fragment = R\"CONFIG_FRAGMENT(", outfp); while (!feof(infp)) { char buf[1024]; size_t rc = fread(buf, 1, sizeof(buf), infp); if (rc == 0) break; fwrite(buf, rc, 1, outfp); } fprintf(outfp, ")CONFIG_FRAGMENT\";\n\nREGISTER_CONFIG_FRAGMENT(\"%s\", fragment);\n\n}", argv[1]); fclose(outfp); fclose(infp); return EXIT_SUCCESS; } icinga2-2.8.1/tools/mkunity/000077500000000000000000000000001322762156600157105ustar00rootroot00000000000000icinga2-2.8.1/tools/mkunity/CMakeLists.txt000066400000000000000000000043701322762156600204540ustar00rootroot00000000000000# Icinga 2 # Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. define_property( SOURCE PROPERTY EXCLUDE_UNITY_BUILD BRIEF_DOCS "Whether to exclude the source file from unity builds" FULL_DOCS "Specified whether a source file should be excluded from unity builds and should be built separately" ) if(ICINGA2_UNITY_BUILD) add_executable(mkunity mkunity.c) set_target_properties ( mkunity PROPERTIES FOLDER Bin ) function(MKUNITY_TARGET Target Prefix UnityInputRef) set(UnityInput ${${UnityInputRef}}) set(UnityOutput ${CMAKE_CURRENT_BINARY_DIR}/${Target}_unity.cpp) set(RealSources "") set(UnitySources "") foreach(UnitySource ${UnityInput}) get_property(SourceExcluded SOURCE ${UnitySource} PROPERTY EXCLUDE_UNITY_BUILD) if(SourceExcluded MATCHES TRUE OR NOT ${UnitySource} MATCHES "\\.(cpp|cxx|cc)\$") list(APPEND RealSources ${UnitySource}) else() list(APPEND UnitySources ${UnitySource}) endif() endforeach() add_custom_command( OUTPUT ${UnityOutput} COMMAND mkunity ARGS ${Prefix} ${UnitySources} > ${UnityOutput}.tmp COMMAND ${CMAKE_COMMAND} ARGS -E copy ${UnityOutput}.tmp ${UnityOutput} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS mkunity ${UnityInput} ) list(APPEND RealSources ${UnityOutput}) set(${UnityInputRef} ${RealSources} PARENT_SCOPE) endfunction() endif() icinga2-2.8.1/tools/mkunity/mkunity.c000066400000000000000000000033211322762156600175530ustar00rootroot00000000000000/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #include #include int main(int argc, char **argv) { int i; if (argc < 3) { fprintf(stderr, "Syntax: %s [ ...]\n", argv[0]); return EXIT_FAILURE; } for (i = 2; i < argc; i++) { printf("#include \"%s/%s\"\n", argv[1], argv[i]); } return EXIT_SUCCESS; } icinga2-2.8.1/tools/selinux/000077500000000000000000000000001322762156600156775ustar00rootroot00000000000000icinga2-2.8.1/tools/selinux/icinga2.fc000066400000000000000000000017101322762156600175240ustar00rootroot00000000000000/etc/rc\.d/init\.d/icinga2 -- gen_context(system_u:object_r:icinga2_initrc_exec_t,s0) /usr/lib/systemd/system/icinga2.* -- gen_context(system_u:object_r:icinga2_unit_file_t,s0) /etc/icinga2(/.*)? gen_context(system_u:object_r:icinga2_etc_t,s0) /etc/icinga2/scripts(/.*)? -- gen_context(system_u:object_r:nagios_notification_plugin_exec_t,s0) /usr/sbin/icinga2 -- gen_context(system_u:object_r:icinga2_exec_t,s0) /usr/lib64/icinga2/sbin/icinga2 -- gen_context(system_u:object_r:icinga2_exec_t,s0) /var/lib/icinga2(/.*)? gen_context(system_u:object_r:icinga2_var_lib_t,s0) /var/log/icinga2(/.*)? gen_context(system_u:object_r:icinga2_log_t,s0) /var/run/icinga2(/.*)? gen_context(system_u:object_r:icinga2_var_run_t,s0) /var/run/icinga2/cmd(/.*)? gen_context(system_u:object_r:icinga2_command_t,s0) /var/spool/icinga2(/.*)? gen_context(system_u:object_r:icinga2_spool_t,s0) /var/cache/icinga2(/.*)? gen_context(system_u:object_r:icinga2_cache_t,s0) icinga2-2.8.1/tools/selinux/icinga2.if000066400000000000000000000226531322762156600175430ustar00rootroot00000000000000 ## policy for icinga2 ######################################## ## ## Execute TEMPLATE in the icinga2 domin. ## ## ## ## Domain allowed to transition. ## ## # interface(`icinga2_domtrans',` gen_require(` type icinga2_t, icinga2_exec_t; ') corecmd_search_bin($1) domtrans_pattern($1, icinga2_exec_t, icinga2_t) ') ######################################## ## ## Execute icinga2 server in the icinga2 domain. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_initrc_domtrans',` gen_require(` type icinga2_initrc_exec_t; ') init_labeled_script_domtrans($1, icinga2_initrc_exec_t) ') ######################################## ## ## Execute icinga2 daemon in the icinga2 domain. ## ## ## ## Domain allowed to transition. ## ## # interface(`icinga2_systemctl',` gen_require(` type icinga2_t; type icinga2_unit_file_t; ') systemd_exec_systemctl($1) allow $1 icinga2_unit_file_t:file read_file_perms; allow $1 icinga2_unit_file_t:service manage_service_perms; ps_process_pattern($1, icinga2_t) init_dbus_chat($1) ') ######################################## ## ## Allow the specified domain to read ## icinga2 configuration files. ## ## ## ## Domain allowed access. ## ## ## # interface(`icinga2_read_config',` gen_require(` type icinga2_etc_t; ') files_search_etc($1) list_dirs_pattern($1, icinga2_etc_t, icinga2_etc_t) read_files_pattern($1, icinga2_etc_t, icinga2_etc_t) ') ######################################## ## ## Allow the specified domain to read ## and write icinga2 configuration files. ## ## ## ## Domain allowed access. ## ## ## # interface(`icinga2_manage_config',` gen_require(` type icinga2_etc_t; ') files_search_etc($1) manage_dirs_pattern($1, icinga2_etc_t, icinga2_etc_t) manage_files_pattern($1, icinga2_etc_t, icinga2_etc_t) ') ######################################## ## ## Read icinga2's log files. ## ## ## ## Domain allowed access. ## ## ## # interface(`icinga2_read_log',` gen_require(` type icinga2_log_t; ') logging_search_logs($1) read_files_pattern($1, icinga2_log_t, icinga2_log_t) ') ######################################## ## ## Append to icinga2 log files. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_append_log',` gen_require(` type icinga2_log_t; ') logging_search_logs($1) append_files_pattern($1, icinga2_log_t, icinga2_log_t) ') ######################################## ## ## Manage icinga2 log files ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_manage_log',` gen_require(` type icinga2_log_t; ') logging_search_logs($1) manage_dirs_pattern($1, icinga2_log_t, icinga2_log_t) manage_files_pattern($1, icinga2_log_t, icinga2_log_t) manage_lnk_files_pattern($1, icinga2_log_t, icinga2_log_t) ') ######################################## ## ## Search icinga2 lib directories. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_search_lib',` gen_require(` type icinga2_var_lib_t; ') allow $1 icinga2_var_lib_t:dir search_dir_perms; files_search_var_lib($1) ') ######################################## ## ## Read icinga2 lib files. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_read_lib_files',` gen_require(` type icinga2_var_lib_t; ') files_search_var_lib($1) read_files_pattern($1, icinga2_var_lib_t, icinga2_var_lib_t) ') ######################################## ## ## Manage icinga2 lib files. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_manage_lib_files',` gen_require(` type icinga2_var_lib_t; ') files_search_var_lib($1) manage_files_pattern($1, icinga2_var_lib_t, icinga2_var_lib_t) ') ######################################## ## ## Manage icinga2 lib directories. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_manage_lib_dirs',` gen_require(` type icinga2_var_lib_t; ') files_search_var_lib($1) manage_dirs_pattern($1, icinga2_var_lib_t, icinga2_var_lib_t) ') ######################################## ## ## Manage icinga2 spool files. ## ## ## ## Domain allowed access. ## ## # interface(`icinga2_manage_spool_files',` gen_require(` type icinga2_spool_t; ') files_search_var_lib($1) manage_files_pattern($1, icinga2_spool_t, icinga2_spool_t) ') ######################################## ## ## All of the rules required to administrate ## an icinga2 environment ## ## ## ## Domain allowed access. ## ## ## ## ## Role allowed access. ## ## ## # interface(`icinga2_admin',` gen_require(` type icinga2_t; type icinga2_initrc_exec_t; type icinga2_log_t; type icinga2_var_lib_t; ') allow $1 icinga2_t:process { signal_perms }; ps_process_pattern($1, icinga2_t) tunable_policy(`deny_ptrace',`',` allow $1 icinga2_t:process ptrace; ') icinga2_initrc_domtrans($1) domain_system_change_exemption($1) role_transition $2 icinga2_initrc_exec_t system_r; allow $2 system_r; files_list_etc($1) admin_pattern($1, icinga2_etc_t) logging_search_logs($1) admin_pattern($1, icinga2_log_t) files_search_var_lib($1) admin_pattern($1, icinga2_var_lib_t) admin_pattern($1, icinga2_var_run_t) admin_pattern($1, icinga2_command_t) admin_pattern($1, icinga2_spool_t) admin_pattern($1, icinga2_cache_t) icinga2_systemctl($1) admin_pattern($1, icinga2_unit_file_t) allow $1 icinga2_unit_file_t:service all_service_perms; optional_policy(` systemd_passwd_agent_exec($1) systemd_read_fifo_file_passwd_run($1) ') ') ######################################## ### ### Send icinga2 commands through pipe ### ### ### ### Domain allowed to send commands. ### ### # interface(`icinga2_send_commands',` gen_require(` type icinga2_var_run_t; ') files_search_pids($1) read_files_pattern($1, icinga2_var_run_t, icinga2_var_run_t) read_files_pattern($1, icinga2_command_t, icinga2_command_t) write_fifo_files_pattern($1, icinga2_command_t, icinga2_command_t) ') ######################################## ## ## For domains icinga2 should transition to (e.g. Plugins). ## ## ## ## Context of the executable. ## ## ## ## ## Domain icinga should transition to. ## ## # interface(`icinga2_execstrans',` gen_require(` type icinga2_t; ') domtrans_pattern(icinga2_t, $1, $2) ') ###################################### ## ## Dontaudit read and write an leaked file descriptors ## ## ## ## Domain to not audit. ## ## # interface(`icinga2_dontaudit_leaks_fifo',` gen_require(` type icinga2_t; ') dontaudit $1 icinga2_t:fifo_file write; ') ## Icinga2 administrator role. ######################################## ## ## Change to the Icinga2 administrator role. ## ## ## ## Role allowed access. ## ## ## # interface(`icinga2adm_role_change',` gen_require(` role icinga2adm_r; ') allow $1 icinga2adm_r; ') ######################################## ## ## For domains icinga2adm should transition to (e.g. Plugins). ## ## ## ## Context of the executable. ## ## ## ## ## Domain icinga should transition to. ## ## # interface(`icinga2adm_execstrans',` gen_require(` type icinga2adm_t; ') role icinga2adm_r types $2; allow icinga2adm_r system_r; type_transition icinga2adm_t $1:process $2; allow icinga2adm_t $2:process transition; allow $2 icinga2adm_t:process sigchld; role_transition icinga2adm_r $1 system_r; ') ######################################## ## ## Make a TCP connection to the icinga2 port. ## ## ## ## Domain allowed access. ## ## # interface(`corenet_tcp_connect_icinga2_port',` gen_require(` type icinga2_port_t; ') allow $1 icinga2_port_t:tcp_socket name_connect; ') icinga2-2.8.1/tools/selinux/icinga2.sh000077500000000000000000000044571322762156600175640ustar00rootroot00000000000000#!/bin/sh -e DIRNAME=`dirname $0` cd $DIRNAME USAGE="$0 [ --update ]" if [ `id -u` != 0 ]; then echo 'You must be root to run this script' exit 1 fi if [ $# -eq 1 ]; then if [ "$1" = "--update" ] ; then time=`ls -l --time-style="+%x %X" icinga2.te | awk '{ printf "%s %s", $6, $7 }'` rules=`ausearch --start $time -m avc --raw -se icinga2` if [ x"$rules" != "x" ] ; then echo "Found avc's to update policy with" echo -e "$rules" | audit2allow -R echo "Do you want these changes added to policy [y/n]?" read ANS if [ "$ANS" = "y" -o "$ANS" = "Y" ] ; then echo "Updating policy" echo -e "$rules" | audit2allow -R >> icinga2.te # Fall though and rebuild policy else exit 0 fi else echo "No new avcs found" exit 0 fi else echo -e $USAGE exit 1 fi elif [ $# -ge 2 ] ; then echo -e $USAGE exit 1 fi echo "Building and Loading Policy" set -x make -f /usr/share/selinux/devel/Makefile icinga2.pp || exit /usr/sbin/semodule -i icinga2.pp # Generate a man page off the installed module sepolicy manpage -p . -d icinga2_t # Fixing the file context on /usr/sbin/icinga2 /sbin/restorecon -F -R -v /usr/sbin/icinga2 /sbin/restorecon -F -R -v /usr/lib64/icinga2/sbin/icinga2 # Fixing the file context on /etc/rc\.d/init\.d/icinga2 #/sbin/restorecon -F -R -v /etc/rc\.d/init\.d/icinga2 # Fixing the file context on /usr/lib/systemd/system/icinga2.* /sbin/restorecon -F -R -v /usr/lib/systemd/system/icinga2.* # Fixing the file context on /etc/icinga2 /sbin/restorecon -F -R -v /etc/icinga2 # Fixing the file context on /var/log/icinga2 /sbin/restorecon -F -R -v /var/log/icinga2 # Fixing the file context on /var/lib/icinga2 /sbin/restorecon -F -R -v /var/lib/icinga2 # Fixing the file context on /var/run/icinga2 /sbin/restorecon -F -R -v /var/run/icinga2 # Fixing the file context on /var/cache/icinga2 /sbin/restorecon -F -R -v /var/cache/icinga2 # Fixing the file context on /var/spool/icinga2 /sbin/restorecon -F -R -v /var/spool/icinga2 # Label the port 5665 /sbin/semanage port -a -t icinga2_port_t -p tcp 5665 # Generate a rpm package for the newly generated policy pwd=$(pwd) #rpmbuild --define "_sourcedir ${pwd}" --define "_specdir ${pwd}" --define "_builddir ${pwd}" --define "_srcrpmdir ${pwd}" --define "_rpmdir ${pwd}" --define "_buildrootdir ${pwd}/.build" -ba icinga2_selinux.spec icinga2-2.8.1/tools/selinux/icinga2.te000066400000000000000000000170551322762156600175550ustar00rootroot00000000000000policy_module(icinga2, 0.1.4) ######################################## # # Declarations # ## ##

## Allow Icinga 2 to connect to all ports ##

##
gen_tunable(icinga2_can_connect_all, false) gen_tunable(httpd_can_connect_icinga2_api, true) gen_tunable(httpd_can_write_icinga2_command, true) require { type nagios_admin_plugin_t; type nagios_admin_plugin_exec_t; type nagios_checkdisk_plugin_t; type nagios_checkdisk_plugin_exec_t; type nagios_mail_plugin_t; type nagios_mail_plugin_exec_t; type nagios_services_plugin_t; type nagios_services_plugin_exec_t; type nagios_system_plugin_t; type nagios_system_plugin_exec_t; type nagios_unconfined_plugin_t; type nagios_unconfined_plugin_exec_t; type nagios_eventhandler_plugin_t; type nagios_eventhandler_plugin_exec_t; type nagios_openshift_plugin_t; type nagios_openshift_plugin_exec_t; type httpd_t; type system_mail_t; role staff_r; } type icinga2_t; type icinga2_exec_t; init_daemon_domain(icinga2_t, icinga2_exec_t) #permissive icinga2_t; type icinga2_initrc_exec_t; init_script_file(icinga2_initrc_exec_t) type icinga2_unit_file_t; systemd_unit_file(icinga2_unit_file_t) type icinga2_etc_t; files_config_file(icinga2_etc_t) type icinga2_log_t; logging_log_file(icinga2_log_t) type icinga2_var_lib_t; files_type(icinga2_var_lib_t) type icinga2_var_run_t; files_pid_file(icinga2_var_run_t) type icinga2_command_t; files_type(icinga2_command_t) type icinga2_spool_t; files_type(icinga2_spool_t) type icinga2_cache_t; files_type(icinga2_cache_t) type icinga2_tmp_t; files_tmp_file(icinga2_tmp_t) type icinga2_port_t; corenet_port(icinga2_port_t) ######################################## # # icinga2 local policy # allow icinga2_t self:capability { setgid setuid sys_resource }; allow icinga2_t self:process { setsched signal setrlimit }; allow icinga2_t self:fifo_file rw_fifo_file_perms; allow icinga2_t self:unix_dgram_socket create_socket_perms; allow icinga2_t self:unix_stream_socket create_stream_socket_perms; list_dirs_pattern(icinga2_t, icinga2_etc_t, icinga2_etc_t) read_files_pattern(icinga2_t, icinga2_etc_t, icinga2_etc_t) read_lnk_files_pattern(icinga2_t, icinga2_etc_t, icinga2_etc_t) manage_dirs_pattern(icinga2_t, icinga2_log_t, icinga2_log_t) manage_files_pattern(icinga2_t, icinga2_log_t, icinga2_log_t) manage_lnk_files_pattern(icinga2_t, icinga2_log_t, icinga2_log_t) logging_log_filetrans(icinga2_t, icinga2_log_t, { dir file lnk_file }) manage_dirs_pattern(icinga2_t, icinga2_var_lib_t, icinga2_var_lib_t) manage_files_pattern(icinga2_t, icinga2_var_lib_t, icinga2_var_lib_t) manage_lnk_files_pattern(icinga2_t, icinga2_var_lib_t, icinga2_var_lib_t) files_var_lib_filetrans(icinga2_t, icinga2_var_lib_t, { dir file lnk_file }) manage_dirs_pattern(icinga2_t, icinga2_var_run_t, icinga2_var_run_t) manage_files_pattern(icinga2_t, icinga2_var_run_t, icinga2_var_run_t) files_pid_filetrans(icinga2_t, icinga2_var_run_t, { dir file }) manage_dirs_pattern(icinga2_t, icinga2_command_t, icinga2_command_t) manage_files_pattern(icinga2_t, icinga2_command_t, icinga2_command_t) manage_fifo_files_pattern(icinga2_t, icinga2_command_t, icinga2_command_t) manage_dirs_pattern(icinga2_t, icinga2_spool_t, icinga2_spool_t) manage_files_pattern(icinga2_t, icinga2_spool_t, icinga2_spool_t) files_spool_filetrans(icinga2_t, icinga2_spool_t, { dir file }) manage_dirs_pattern(icinga2_t, icinga2_cache_t, icinga2_cache_t) manage_files_pattern(icinga2_t, icinga2_cache_t, icinga2_cache_t) manage_files_pattern(icinga2_t, icinga2_tmp_t, icinga2_tmp_t) manage_dirs_pattern(icinga2_t, icinga2_tmp_t, icinga2_tmp_t) files_tmp_filetrans(icinga2_t, icinga2_tmp_t, { dir file }) domain_use_interactive_fds(icinga2_t) files_read_etc_files(icinga2_t) auth_use_nsswitch(icinga2_t) miscfiles_read_localization(icinga2_t) corecmd_exec_shell(icinga2_t) corecmd_exec_bin(icinga2_t) kernel_read_system_state(icinga2_t) kernel_read_network_state(icinga2_t) # should be moved to nagios_plugin_template in nagios.if icinga2_execstrans(nagios_admin_plugin_exec_t, nagios_admin_plugin_t) icinga2_execstrans(nagios_checkdisk_plugin_exec_t, nagios_checkdisk_plugin_t) icinga2_execstrans(nagios_mail_plugin_exec_t, nagios_mail_plugin_t) icinga2_execstrans(nagios_services_plugin_exec_t, nagios_services_plugin_t) icinga2_execstrans(nagios_system_plugin_exec_t, nagios_system_plugin_t) icinga2_execstrans(nagios_unconfined_plugin_exec_t, nagios_unconfined_plugin_t) icinga2_execstrans(nagios_eventhandler_plugin_exec_t, nagios_eventhandler_plugin_t) icinga2_execstrans(nagios_openshift_plugin_exec_t, nagios_openshift_plugin_t) # should be moved nagios.te nagios_plugin_template(notification) icinga2_execstrans(nagios_notification_plugin_exec_t, nagios_notification_plugin_t) allow nagios_notification_plugin_t icinga2_etc_t:dir search; allow nagios_notification_plugin_t nagios_notification_plugin_exec_t:dir search; #permissive nagios_notification_plugin_t; corecmd_exec_bin(nagios_notification_plugin_t) hostname_exec(nagios_notification_plugin_t) type nagios_notification_plugin_tmp_t; files_tmp_file(nagios_notification_plugin_tmp_t) manage_files_pattern(nagios_notification_plugin_t, nagios_notification_plugin_tmp_t, nagios_notification_plugin_tmp_t) manage_dirs_pattern(nagios_notification_plugin_t, nagios_notification_plugin_tmp_t, nagios_notification_plugin_tmp_t) files_tmp_filetrans(nagios_notification_plugin_t, nagios_notification_plugin_tmp_t, { dir file }) auth_dontaudit_read_passwd(nagios_notification_plugin_t) fs_dontaudit_getattr_xattr_fs(nagios_notification_plugin_t) optional_policy(` mta_send_mail(nagios_notification_plugin_t) ') icinga2_dontaudit_leaks_fifo(system_mail_t) allow icinga2_t icinga2_port_t:tcp_socket name_bind; allow icinga2_t self:tcp_socket create_stream_socket_perms; corenet_tcp_connect_icinga2_port(icinga2_t) mysql_stream_connect(icinga2_t) mysql_tcp_connect(icinga2_t) postgresql_stream_connect(icinga2_t) postgresql_tcp_connect(icinga2_t) # graphite is using port 2003 which is lmtp_port_t corenet_tcp_connect_lmtp_port(icinga2_t) # This is for other feature that do not use a confined port # or if you run one one with a non standard port. tunable_policy(`icinga2_can_connect_all',` corenet_tcp_connect_all_ports(icinga2_t) ') ######################################## # # Icinga Webinterfaces # optional_policy(` # should be a boolean in apache-policy tunable_policy(`httpd_can_write_icinga2_command',` icinga2_send_commands(httpd_t) ') ') optional_policy(` # should be a boolean in apache-policy tunable_policy(`httpd_can_connect_icinga2_api',` corenet_tcp_connect_icinga2_port(httpd_t) ') ') ######################################## # # Icinga2 Admin Role # userdom_unpriv_user_template(icinga2adm) icinga2_admin(icinga2adm_t, icinga2adm_r) allow icinga2adm_t self:capability { dac_read_search dac_override }; # should be moved to staff.te icinga2adm_role_change(staff_r) # should be moved to nagios_plugin_template in nagios.if icinga2adm_execstrans(nagios_admin_plugin_exec_t, nagios_admin_plugin_t) icinga2adm_execstrans(nagios_checkdisk_plugin_exec_t, nagios_checkdisk_plugin_t) icinga2adm_execstrans(nagios_mail_plugin_exec_t, nagios_mail_plugin_t) icinga2adm_execstrans(nagios_services_plugin_exec_t, nagios_services_plugin_t) icinga2adm_execstrans(nagios_system_plugin_exec_t, nagios_system_plugin_t) icinga2adm_execstrans(nagios_unconfined_plugin_exec_t, nagios_unconfined_plugin_t) icinga2adm_execstrans(nagios_eventhandler_plugin_exec_t, nagios_eventhandler_plugin_t) icinga2adm_execstrans(nagios_openshift_plugin_exec_t, nagios_openshift_plugin_t) icinga2adm_execstrans(nagios_notification_plugin_exec_t, nagios_notification_plugin_t) icinga2-2.8.1/tools/syntax/000077500000000000000000000000001322762156600155365ustar00rootroot00000000000000icinga2-2.8.1/tools/syntax/nano/000077500000000000000000000000001322762156600164715ustar00rootroot00000000000000icinga2-2.8.1/tools/syntax/nano/icinga2.nanorc000066400000000000000000000133561322762156600212170ustar00rootroot00000000000000### Nano synteax file ### Icinga2 object configuration file syntax "icinga2" "/etc/icinga2/.*\.conf$" "/usr/share/icinga2/include/(plugin|itl|.*\.conf$)" ## objects types icolor brightgreen "object[ \t]+(host|hostgroup|service|servicegroup|user|usergroup)" icolor brightgreen "object[ \t]+(checkcommand|notificationcommand|eventcommand|notification)" icolor brightgreen "object[ \t]+(timeperiod|scheduleddowntime|dependency|perfdatawriter)" icolor brightgreen "object[ \t]+(graphitewriter|idomysqlconnection|idomysqlconnection)" icolor brightgreen "object[ \t]+(livestatuslistener|statusdatawriter|externalcommandlistener)" icolor brightgreen "object[ \t]+(compatlogger|checkresultreader|checkcomponent|notificationcomponent)" icolor brightgreen "object[ \t]+(filelogger|sysloglogger|apilistener|endpoint|zone)" ## apply def icolor brightgreen "apply[ \t]+(Service|Dependency|Notification|ScheduledDowntime)" ## objects attributes icolor red "(^|^\s+)(accept_commands|accept_config|action_url|address|address6|arguments|author|bind_host)" icolor red "(^|^\s+)(bind_port|ca_path|categories|cert_path|check_command|check_interval)" icolor red "(^|^\s+)(check_period|child_host_name|child_service_name|cleanup|command|command_endpoint|command_path)" icolor red "(^|^\s+)(comment|compat_log_path|crl_path|database|disable_checks|disable_notifications)" icolor red "(^|^\s+)(display_name|duration|email|enable_active_checks|enable_event_handler)" icolor red "(^|^\s+)(enable_flapping|enable_ha|enable_notifications|enable_passive_checks|enable_perfdata)" icolor red "(^|^\s+)(endpoints|env|event_command|failover_timeout|fixed|flapping_threshold|groups|host)" icolor red "(^|^\s+)(host_format_template|host_name|host_name_template|host_perfdata_path|host_temp_path|icon_image)" icolor red "(^|^\s+)(icon_image_alt|instance_description|instance_name|interval|key_path|log_dir)" icolor red "(^|^\s+)(log_duration|max_check_attempts|methods|name|notes|notes_url|objects_path)" icolor red "(^|^\s+)(pager|parent|parent_host_name|parent_service_name|password|path|period)" icolor red "(^|^\s+)(port|ranges|retry_interval|rotation_interval|rotation_method)" icolor red "(^|^\s+)(service_format_template|service_name|service_name_template|service_perfdata_path|service_temp_path)" icolor red "(^|^\s+)(severity|socket_path|socket_type|spool_dir|states|status_path|table_prefix)" icolor red "(^|^\s+)(timeout|times|types|update_interval|user|user_groups|users|volatile|zone)" icolor red "(^|^\s+)(vars\.\w+)" ## keywords icolor red "(^|^\s+)|(icinga2Keyword|template|const|import|include|include_recursive|var|function|return|to|use|locals|globals|this)\s+" ## Assign conditions icolor magenta "(assign|ignone)[ \t]+where" ## Global functions icolor white "(regex|match|len|union|intersection|keys|string|number|bool|random|log|typeof|get_time|exit)" ## Accessor Functions icolor white "(get_host|get_service|get_user|get_check_command|get_event_command|get_notification_command)" icolor white "(get_host_group|get_service_group|get_user_group|get_time_period)" ## Math functions icolor white "(Math.E|Math.LN2|Math.LN10|Math.LOG2E|Math.PI|Math.SQRT1_2|Math.SQRT2)" icolor white "(Math.abs|Math.acos|Math.asin|Math.atan|Math.atan2|Math.ceil|Math.cos)" icolor white "(Math.exp|Math.floor|Math.isinf|Math.isnan|Math.log|Math.max|Math.min)" icolor white "(Math.pow|Math.random|Math.round|Math.sign|Math.sin|Math.sqrt|Math.tan)" ## Json functions icolor white "(Json.encode|Json.decode)" ## String functions icolor white "(\.to_string)" icolor white "(\.find)" icolor white "(\.contains)" icolor white "(\.len)" icolor white "(\.lower)" icolor white "(\.upper)" icolor white "(\.replace)" icolor white "(\.split)" icolor white "(\.substr)" ## Array and Dict Functions icolor white "(\.add)" icolor white "(\.clear)" icolor white "(\.clone)" icolor white "(\.contains)" icolor white "(\.len)" icolor white "(\.remove)" icolor white "(\.set)" icolor white "(\.remove)" icolor white "(\.sort)" icolor white "(\.join)" icolor white "(\.clone)" icolor white "(\.call)" icolor white "(\.callv)" ## Conditional statements icolor white "(if|else)" ## Loops icolor white "(while|for|break|continue)" ## Operators icolor green "\s(\.)\s" icolor green "\s(!)\s" icolor green "\s(\~)\s" icolor green "\s(\+)\s" icolor green "\s(-)\s" icolor green "\s(\*)\s" icolor green "\s(/)\s" icolor green "\s(%)\s" icolor green "\s(=)\s" icolor green "\s(<)\s" icolor green "\s(>)\s" icolor green "\s(<<)\s" icolor green "\s(>>)\s" icolor green "\s(<=)\s" icolor green "\s(>=)\s" icolor green "\s(in)\s" icolor green "\s(!in)\s" icolor green "\s(==)\s" icolor green "\s(!=)\s" icolor green "\s(&)\s" icolor green "\s(\^)\s" icolor green "\s(|)\s" icolor green "\s(&&)\s" icolor green "\s(||)\s" icolor green "\s(=>)\s" icolor green "\s(\+=)\s" icolor green "\s(-=)\s" icolor green "\s(\*=)\s" icolor green "\s(/=)\s" ## Global constats icolor yellow "(PrefixDir|SysconfDir|ZonesDir|LocalStateDir|RunDir|PkgDataDir|StatePath|ObjectsPath)" icolor yellow "(PidPath|NodeName|ApplicationType|EnableNotifications|EnableEventHandlers|EnableFlapping)" icolor yellow "(EnableHostChecks|EnableServiceChecks|EnablePerfdata|UseVfork|RunAsUser|RunAsGroup|PluginDir)" icolor yellow "(Vars\s+)" ## Boolean icolor blue "(true|false)" # Null icolor blue "(null)" ## comments color brightblue "\/\/.*" color brightblue "^[ \t]*\*\($\|[ \t]\+\)" color brightblue start="/\*" end="\*/" ## Braces and Parens definition # - Braces are used in dictionary definition color magenta "(\(|\))" color magenta "(\[|\])" color magenta "(\{|\})" ## type definitions # - double quotes " # - single quotes ' # - brackets <> color brightyellow "'" color brightyellow """ color brightyellow start="<" end=">" icinga2-2.8.1/tools/syntax/vim/000077500000000000000000000000001322762156600163315ustar00rootroot00000000000000icinga2-2.8.1/tools/syntax/vim/ftdetect/000077500000000000000000000000001322762156600201335ustar00rootroot00000000000000icinga2-2.8.1/tools/syntax/vim/ftdetect/icinga2.vim000066400000000000000000000001721322762156600221640ustar00rootroot00000000000000" Modify au BufNewFile,BufRead /*etc/icinga2/*.conf,/*usr/share/icinga2/include/{itl,plugins,*.conf} set filetype=icinga2 icinga2-2.8.1/tools/syntax/vim/syntax/000077500000000000000000000000001322762156600176575ustar00rootroot00000000000000icinga2-2.8.1/tools/syntax/vim/syntax/icinga2.vim000066400000000000000000000245661322762156600217250ustar00rootroot00000000000000" Vim syntax file " Filename: icinga2.vim " Language: Icinga2 object configuration file " Author: Carlos Cesario " Version: 0.0.2 " Based: javascript.vim / nagios.vim " For version 5.x: Clear all syntax items " For version 6.x: Quit when a syntax file was already loaded if !exists("main_syntax") if version < 600 syntax clear elseif exists("b:current_syntax") finish endif let main_syntax = 'icinga2' endif " case off syntax case ignore " comments syn keyword icinga2CommentTodo TODO FIXME XXX TBD contained syn match icinga2LineComment "\/\/.*" contains=icinga2CommentTodo syn match icinga2LineComment "#.*" contains=icinga2CommentTodo syn match icinga2CommentSkip "^[ \t]*\*\($\|[ \t]\+\)" syn region icinga2Comment start="/\*" end="\*/" contains=icinga2CommentTodo " type definitions " - double quotes " " - single quotes ' " - brackets <> syn region StringD start=+"+ end=+"\|$+ syn region StringS start=+'+ end=+'\|$+ syn match angleBrackets "<\w\+>" " Braces and Parens definition " Braces are used in dictionary definition syn match Braces "[{}\[\]]" syn match Parens "[()]" " objects types syn match icinga2ObjDef "object[ \t]\+\(hostgroup\|host\|servicegroup\|service\|usergroup\|user\)" syn match icinga2ObjDef "object[ \t]\+\(checkcommand\|notificationcommand\|eventcommand\|notification\)" syn match icinga2Objdef "object[ \t]\+\(timeperiod\|scheduleddowntime\|dependency\|perfdatawriter\)" syn match icinga2ObjDef "object[ \t]\+\(graphitewriter\|idomysqlconnection\|idomysqlconnection\)" syn match icinga2ObjDef "object[ \t]\+\(livestatuslistener\|statusdatawriter\|externalcommandlistener\)" syn match icinga2ObjDef "object[ \t]\+\(compatlogger\|checkresultreader\|checkcomponent\|notificationcomponent\)" syn match icinga2ObjDef "object[ \t]\+\(filelogger\|sysloglogger\|icingaapplication\|apilistener\|apiuser\|endpoint\|zone\)" " apply def syn match icinga2ApplyDef "apply[ \t]\+\(Service\|Dependency\|Notification\|ScheduledDowntime\)" " objects attributes syn keyword icinga2ObjAttr contained accept_commands accept_config action_url address address6 arguments author bind_host syn keyword icinga2ObjAttr contained bind_port ca_path categories cert_path check_command check_interval syn keyword icinga2ObjAttr contained check_period child_host_name child_service_name cleanup client_cn command command_endpoint command_path syn keyword icinga2ObjAttr contained comment compat_log_path crl_path database disable_checks disable_notifications syn keyword icinga2ObjAttr contained display_name duration email enable_active_checks enable_event_handlers enable_event_handler syn keyword icinga2ObjAttr contained enable_flapping enable_ha enable_host_checks enable_notifications enable_passive_checks enable_perfdata syn keyword icinga2ObjAttr contained enable_service_checks endpoints env event_command failover_timeout fixed flapping_threshold groups host syn keyword icinga2ObjAttr contained host_format_template host_name host_name_template host_perfdata_path host_temp_path icon_image syn keyword icinga2ObjAttr contained icon_image_alt instance_description instance_name interval key_path log_dir syn keyword icinga2ObjAttr contained log_duration max_check_attempts methods name notes notes_url objects_path syn keyword icinga2ObjAttr contained pager parent parent_host_name parent_service_name password path period permissions syn keyword icinga2ObjAttr contained port ranges retry_interval rotation_interval rotation_method syn keyword icinga2ObjAttr contained service_format_template service_name service_name_template service_perfdata_path service_temp_path syn keyword icinga2ObjAttr contained severity socket_path socket_type spool_dir states status_path table_prefix syn keyword icinga2ObjAttr contained timeout times types update_interval user user_groups users volatile zone syn match icinga2ObjAttr contained "\(vars.\w\+\)" " keywords syn keyword icinga2Keyword template const import include include_recursive var function return to use locals globals this " Assign conditions syn match icinga2AssignCond contained "\(assign[ \t]\+\where\|ignore[ \t]\+\where\)" " Global functions syn keyword icinga2GFunction contained regex match cidr_match len union intersection keys string syn keyword icinga2GFunction contained number bool random log typeof get_time parse_performance_data dirname syn keyword icinga2GFunction contained basename escape_shell_arg escape_shell_cmd escape_create_process_arg exit " Accessor Functions syn keyword icinga2AFunction contained get_host get_service get_user get_check_command get_event_command get_notification_command syn keyword icinga2AFunction contained get_host_group get_service_group get_user_group get_time_period " Math functions syn match icinga2MathFunction contained "\(Math.E\|Math.LN2\|Math.LN10\|Math.LOG2E\|Math.PI\|Math.SQRT1_2\|Math.SQRT2\)" syn match icinga2MathFunction contained "\(Math.abs\|Math.acos\|Math.asin\|Math.atan\|Math.atan2\|Math.ceil\|Math.cos\)" syn match icinga2MathFunction contained "\(Math.exp\|Math.floor\|Math.isinf\|Math.isnan\|Math.log\|Math.max\|Math.min\)" syn match icinga2MathFunction contained "\(Math.pow\|Math.random\|Math.round\|Math.sign\|Math.sin\|Math.sqrt\|Math.tan\)" " Json functions syn match icinga2JsonFunction contained "\(Json.encode\|Json.decode\)" " String functions syn match icinga2StrFunction contained "\(\.find\)" syn match icinga2StrFunction contained "\(\.contains\)" syn match icinga2StrFunction contained "\(\.len\)" syn match icinga2StrFunction contained "\(\.lower\)" syn match icinga2StrFunction contained "\(\.upper\)" syn match icinga2StrFunction contained "\(\.replace\)" syn match icinga2StrFunction contained "\(\.split\)" syn match icinga2StrFunction contained "\(\.substr\)" syn match icinga2StrFunction contained "\(\.to_string\)" syn match icinga2StrFunction contained "\(\.reverse\)" " Array and Dict Functions syn match icinga2ArrFunction contained "\(\.clone\)" syn match icinga2ArrFunction contained "\(\.add(\)" syn match icinga2ArrFunction contained "\(\.clear\)" syn match icinga2ArrFunction contained "\(\.shallow_clone\)" syn match icinga2ArrFunction contained "\(\.contains\)" syn match icinga2ArrFunction contained "\(\.len\)" syn match icinga2ArrFunction contained "\(\.remove\)" syn match icinga2ArrFunction contained "\(\.set\)" syn match icinga2ArrFunction contained "\(\.get\)" syn match icinga2ArrFunction contained "\(\.sort\)" syn match icinga2ArrFunction contained "\(\.join\)" syn match icinga2ArrFunction contained "\(\.reverse\)" syn match icinga2ArrFunction contained "\(\.keys\)" syn match icinga2ArrFunction contained "\(\.call\)" syn match icinga2ArrFunction contained "\(\.callv\)" " Conditional statements syn keyword icinga2Cond if else " Loops syn keyword icinga2Loop while for break continue " Operators syn match icinga2Operators "[ \t]\+\(\.\)\+" syn match icinga2Operators "[ \t]\+\(!\)\+" syn match icinga2Operators "[ \t]\+\(\~\)\+" syn match icinga2Operators "[ \t]\+\(+\)\+" syn match icinga2Operators "[ \t]\+\(-\)\+" syn match icinga2Operators "[ \t]\+\(*\)\+" syn match icinga2Operators "[ \t]\+\(/[^/\*]\)\+" syn match icinga2Operators "[ \t]\+\(%\)\+" syn match icinga2Operators "[ \t]\+\(+\)\+" syn match icinga2Operators "[ \t]\+\(-\)\+" syn match icinga2Operators "[ \t]\+\(=\)\+" syn match icinga2Operators "[ \t]\+\(<\)[ \t]\+" syn match icinga2Operators "[ \t]\+\(>\)[ \t]\+" syn match icinga2Operators "[ \t]\+\(<<\)\+" syn match icinga2Operators "[ \t]\+\(>>\)\+" syn match icinga2Operators "[ \t]\+\(<=\)\+" syn match icinga2Operators "[ \t]\+\(>=\)\+" syn match icinga2Operators "[ \t]\+\(in\)\+" syn match icinga2Operators "[ \t]\+\(!in\)\+" syn match icinga2Operators "[ \t]\+\(==\)\+" syn match icinga2Operators "[ \t]\+\(!=\)\+" syn match icinga2Operators "[ \t]\+\(&\)\+" syn match icinga2Operators "[ \t]\+\(\^\)\+" syn match icinga2Operators "[ \t]\+\(|\)\+" syn match icinga2Operators "[ \t]\+\(&&\)\+" syn match icinga2Operators "[ \t]\+\(||\)\+" syn match icinga2Operators "[ \t]\+\(=>\)\+" syn match icinga2Operators "[ \t]\+\(+=\)\+" syn match icinga2Operators "[ \t]\+\(-=\)\+" syn match icinga2Operators "[ \t]\+\(*=\)\+" syn match icinga2Operators "[ \t]\+\(/=\)\+" " global constats syn keyword icinga2Gconst PrefixDir SysconfDir ZonesDir LocalStateDir RunDir PkgDataDir StatePath ObjectsPath syn keyword icinga2Gconst PidPath NodeName ApplicationType UseVfork RunAsUser RunAsGroup PluginDir " global types syn keyword icinga2Gconst Number String Boolean Array Dictionary Value Object ConfigObject Command CheckResult syn keyword icinga2Gconst Checkable CustomVarObject DbConnection Type PerfdataValue Comment Downtime Logger Application " values type syn keyword valueBoolean contained true false syn keyword valueNull contained null syn region nagiosDefBody start='{' end='}' \ contains=icinga2Comment, icinga2LineComment, StringD, Braces, Parens, icinga2ObjDef, \ icinga2ApplyDef, icinga2ObjAttr, icinga2Keyword, icinga2Keyword, icinga2AssignCond, \ icinga2Cond, icinga2Loop, icinga2Operators, icinga2GFunction, icinga2AFunction, \ icinga2MathFunction, icinga2Gconst, icinga2JsonFunction, icinga2StrFunction, \ icinga2ArrFunction, valueBoolean, valueNull " Highlighting hi link icinga2Comment Comment hi link icinga2LineComment Comment hi link icinga2CommentTodo Todo hi link Braces Function hi link Parens Function hi link StringS String hi link StringD String hi link angleBrackets String hi link icinga2ObjDef Statement hi link icinga2ApplyDef Statement hi link icinga2ObjAttr Define hi link icinga2Keyword Keyword hi link icinga2AssignCond Conditional hi link icinga2Cond Statement hi link icinga2Loop Statement hi link icinga2Operators Operator hi link icinga2AFunction Function hi link icinga2MathFunction Function hi link icinga2GFunction Function hi link icinga2JsonFunction Function hi link icinga2StrFunction Function hi link icinga2ArrFunction Function hi link icinga2Gconst Statement hi link valueBoolean Boolean hi link valueNull Special