summaryrefslogtreecommitdiffstats
path: root/doc/08-advanced-topics.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/08-advanced-topics.md')
-rw-r--r--doc/08-advanced-topics.md1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/doc/08-advanced-topics.md b/doc/08-advanced-topics.md
new file mode 100644
index 0000000..34330ed
--- /dev/null
+++ b/doc/08-advanced-topics.md
@@ -0,0 +1,1208 @@
+# Advanced Topics <a id="advanced-topics"></a>
+
+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 <a id="downtimes"></a>
+
+Downtimes can be scheduled for planned server maintenance or
+any other targeted service outage you are aware of in advance.
+
+Downtimes suppress notifications and can trigger other
+downtimes too. If the downtime was set by accident, or the duration
+exceeds the maintenance windows, you can manually cancel the downtime.
+
+### Scheduling a downtime <a id="scheduling-downtime"></a>
+
+The most convenient way to schedule planned downtimes is to create
+them in Icinga Web 2 inside the host/service detail view. Select
+multiple hosts/services from the listing with the shift key to
+schedule multiple downtimes.
+
+![Downtime in Icinga Web 2](images/advanced-topics/icingaweb2_downtime_handled.png)
+
+In addition to that you can schedule a downtime by using the Icinga 2 API action
+[schedule-downtime](12-icinga2-api.md#icinga2-api-actions-schedule-downtime).
+This is especially useful to schedule a downtime on-demand inside a (remote) backup
+script, or create maintenance downtimes from a cron job for specific dates and intervals.
+
+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.
+
+Planned downtimes are also taken into account for SLA reporting
+tools calculating the SLAs based on the state and downtime history.
+
+### Fixed and Flexible Downtimes <a id="fixed-flexible-downtimes"></a>
+
+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!).
+
+#### Fixed Downtime <a id="fixed-downtime"></a>
+
+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 id="flexible-downtime"></a>
+
+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 <a id="triggered-downtimes"></a>
+
+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 <a id="recurring-downtimes"></a>
+
+[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
+}
+```
+
+Icinga 2 attempts to find the next possible segment from a ScheduledDowntime object's
+`ranges` attribute, and wont create multiple downtimes in the future. In case you need
+all these downtimes planned and visible for the next days, weeks or months, schedule them
+manually via the [REST API](12-icinga2-api.md#icinga2-api-actions-schedule-downtime) using
+a script or cron job.
+
+> **Note**
+>
+> If ScheduledDowntime objects are synced in a distributed high-availability setup,
+> both will create the next possible downtime on their own. These runtime generated
+> downtimes are synced among both zone instances, and you may see sort-of duplicate downtimes
+> in Icinga Web 2.
+
+
+## Comments <a id="comments-intro"></a>
+
+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 <a id="acknowledgements"></a>
+
+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 <a id="sticky-acknowledgements"></a>
+
+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 <a id="expiring-acknowledgements"></a>
+
+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 <a id="timeperiods"></a>
+
+[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.
+
+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" {
+ 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" {
+ 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"
+ }
+}
+```
+
+### Across midnight <a id="timeperiods-across-midnight"></a>
+
+If you want to specify a notification period across midnight,
+you can define it the following way:
+
+```
+object TimePeriod "across-midnight" {
+ display_name = "Nightly Notification"
+ ranges = {
+ "saturday" = "22:00-24:00"
+ "sunday" = "00:00-03:00"
+ }
+}
+```
+
+Starting with v2.11 this can be shortened to using
+the first day as start with an overlapping range into
+the next day:
+
+```
+object TimePeriod "do-not-disturb" {
+ display_name = "Weekend DND"
+ ranges = {
+ "saturday" = "22:00-06:00"
+ }
+}
+```
+
+### Across several days, weeks or months <a id="timeperiods-across-days-weeks-months"></a>
+
+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" {
+ 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:
+
+```
+apply Notification "mail-icingaadmin" to Service {
+ import "mail-service-notification"
+ user_groups = host.vars.notification.mail.groups
+ users = host.vars.notification.mail.users
+
+ period = "workhours"
+
+ assign where host.vars.notification.mail
+}
+```
+
+### Time Periods Inclusion and Exclusion <a id="timeperiods-includes-excludes"></a>
+
+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" {
+ 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" {
+ 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" {
+ 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"
+ }
+}
+```
+
+### Time zone handling <a id="timeperiods-timezones"></a>
+
+Icinga 2 takes the OS' time zone including DST changes into account.
+
+Times inside DST changes are interpreted as before the DST changes.
+I.e. for the time zone Europe/Berlin:
+
+* On 2020-10-25 03:00 CEST the time jumps back to 02:00 CET.
+ For Icinga 02:30 means 02:30 CEST.
+* On 2021-02-28 02:00 CET the time jumps forward to 03:00 CEST.
+ For Icinga (the actually not existing) 02:30 refers to CET
+ and effectively means 03:30 CEST.
+
+## External Passive Check Results <a id="external-check-results"></a>
+
+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 <a id="check-result-freshness"></a>
+
+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
+```
+
+> **Tip**
+>
+> The [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result) REST API
+> action allows to overrule the pre-defined check interval with a specified TTL in Icinga 2 v2.9+.
+
+If the freshness checks fail, Icinga 2 will execute the defined check command unless active checks are disabled.
+
+Best practice is to define a [dummy](10-icinga-template-library.md#itl-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 <a id="check-flapping"></a>
+
+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
+suppressed 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](09-object-types.md#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.
+
+The attribute `flapping_ignore_states` allows to ignore state changes to specified states during the flapping calculation.
+
+`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 <a id="check-flapping-how-it-works"></a>
+
+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 are 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 and Hosts <a id="volatile-services-hosts"></a>
+
+The `volatile` option, if enabled for a host or service, makes it treat every [state change](03-monitoring-basics.md#hard-soft-states)
+as a `HARD` state change. It is comparable to `max_check_attempts = 1`. With this any `NOT-OK` result will
+ignore `max_check_attempts` and trigger notifications etc. It will further cause any additional `NOT-OK`
+result to re-send notifications.
+
+It may be reasonable to have a volatile service which stays in a `HARD` state 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.
+
+A common example are security checks where each `NOT-OK` check result should immediately trigger a notification.
+
+The default for this option is `false` and should only be enabled when required.
+
+
+## Monitoring Icinga 2 <a id="monitoring-icinga"></a>
+
+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 | [sar-perf](10-icinga-template-library.md#plugin-contrib-command-sar-perf)
+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), [Icinga certificate monitoring](https://icinga.com/products/icinga-certificate-monitoring/)
+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 TLS certificate expiration.
+This can be done using the [Icinga certificate monitoring](https://icinga.com/products/icinga-certificate-monitoring/) module.
+
+
+
+## Advanced Configuration Hints <a id="advanced-configuration-hints"></a>
+
+### Advanced Use of Apply Rules <a id="advanced-use-of-apply-rules"></a>
+
+[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 variable 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 variable
+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 <a id="use-functions-object-config"></a>
+
+There is a limited scope where functions can be used as object attributes such as:
+
+* As value for [Custom Variables](03-monitoring-basics.md#custom-variables-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 variables 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.
+
+#### Register and Use Global Functions <a id="use-functions-global-register"></a>
+
+[Functions](17-language-reference.md#functions) can be registered into the global scope. This allows custom functions being available
+in objects and other functions. Keep in mind that these functions are not marked
+as side-effect-free and as such are not available via the REST API.
+
+Add a new configuration file `functions.conf` and include it into the [icinga2.conf](04-configuration.md#icinga2-conf)
+configuration file in the very beginning, e.g. after `constants.conf`. You can also manage global
+functions inside `constants.conf` if you prefer.
+
+The following function converts a given state parameter into a returned string value. The important
+bits for registering it into the global scope are:
+
+* `globals.<unique_function_name>` adds a new globals entry.
+* `function()` specifies that a call to `state_to_string()` executes a function.
+* Function parameters are defined inside the `function()` definition.
+
+```
+globals.state_to_string = function(state) {
+ if (state == 2) {
+ return "Critical"
+ } else if (state == 1) {
+ return "Warning"
+ } else if (state == 0) {
+ return "OK"
+ } else if (state == 3) {
+ return "Unknown"
+ } else {
+ log(LogWarning, "state_to_string", "Unknown state " + state + " provided.")
+ }
+}
+```
+
+The else-condition allows for better error handling. This warning will be shown in the Icinga 2
+log file once the function is called.
+
+> **Note**
+>
+> If these functions are used in a distributed environment, you must ensure to deploy them
+> everywhere needed.
+
+In order to test-drive the newly created function, restart Icinga 2 and use the [debug console](11-cli-commands.md#cli-command-console)
+to connect to the REST API.
+
+```
+$ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/'
+Icinga 2 (version: v2.11.0)
+<1> => globals.state_to_string(1)
+"Warning"
+<2> => state_to_string(2)
+"Critical"
+```
+
+You can see that this function is now registered into the [global scope](17-language-reference.md#variable-scopes). The function call
+`state_to_string()` can be used in any object at static config compile time or inside runtime
+lambda functions.
+
+The following service object example uses the service state and converts it to string output.
+The function definition is not optimized and is enrolled for better readability including a log message.
+
+```
+object Service "state-test" {
+ check_command = "dummy"
+ host_name = NodeName
+
+ vars.dummy_state = 2
+
+ vars.dummy_text = {{
+ var h = macro("$host.name$")
+ var s = macro("$service.name$")
+
+ var state = get_service(h, s).state
+
+ log(LogInformation, "dummy_state", "Host: " + h + " Service: " + s + " State: " + state)
+
+ return state_to_string(state)
+ }}
+}
+```
+
+
+#### Use Custom Functions as Attribute <a id="custom-functions-as-attribute"></a>
+
+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 <a id="use-functions-assign-where"></a>
+
+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 variable `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 variable 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")
+}
+```
+
+#### Use Functions in Command Arguments set_if <a id="use-functions-command-arguments-setif"></a>
+
+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 variable `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(LogInformation, "checkcommand set_if", "custom variable compellent_checks is not a dictionary, ignoring it.")
+ return false
+ }
+ } else {
+ log(LogWarning, "checkcommand set_if", "empty custom variables")
+ return false
+ }
+ }}
+ }
+```
+
+#### Use Functions as Command Attribute <a id="use-functions-command-attribute"></a>
+
+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 variable 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 variable `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 = [ ConfigDir + "/scripts/" + mailscript ]
+ log(LogCritical, "me", cmd)
+ return cmd
+ }}
+
+ env = {
+ }
+}
+```
+
+### Access Object Attributes at Runtime <a id="access-object-attributes-at-runtime"></a>
+
+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 <a id="access-object-attributes-at-runtime-cluster-check"></a>
+
+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 <a id="access-object-attributes-at-runtime-time-dependent-thresholds"></a>
+
+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" {
+ 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 <a id="advanced-value-types"></a>
+
+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 <a id="advanced-value-types-checkresult"></a>
+
+ 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.
+ scheduling\_source | String | Name of the node scheduling 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.
+ ttl | Number | Time-to-live duration in seconds for this check result. The next expected check result is `now + ttl` where freshness checks are executed.
+
+### PerfdataValue <a id="advanced-value-types-perfdatavalue"></a>
+
+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.