Today I want to present an Icinga 2-based monitoring use case where concepts of the powerful Icinga 2 DSL functional language come into play. The use case is based on mapping the status of a Host/Service Object via passive check results only. For this kind of use case, any accidental active status check could potentially overwrite the current status of the object.
Such use cases typically appear when monitoring incoming SNMP Traps, or mapping the status results provided by a third party Icinga 2 system. In these situations it’s important to avoid an accidental status change by an operator while performing for instance an active check or when clicking on the “Check now” action.
An experienced IcingaWeb2 administrator might think this should be solved via icingaweb2 role settings. Unfortunately as discussed in the open GitHub issue, it’s simply not possible to deny the “actions” permission for just some subset of hosts (i.e., the passive hosts) while simultaneously granting the same permission for other “active” objects. Therefore it’s necessary to prevent the status change on the passive hosts in some other way.
Any approach that implements a Plugin Script to calculate the status for a given Object and then returns that same status would be rather inefficient. In comparison, the Icinga 2 runtime variables provide all the required information, whereas the Icinga2 DSL allows them to be perfectly integrated in the monitoring configuration.
Icinga DSL (Domain Specific Language) is a powerful and flexible language used to define configuration objects and rules in Icinga. It allows users to write custom scripts and expressions to define monitoring behavior, notifications, and other aspects of the Icinga system. With Icinga DSL, users can create complex monitoring rules and configurations that would be difficult or even impossible to achieve using the standard configuration methods. It’s used within Icinga Director, a configuration tool for Icinga, to define advanced monitoring scenarios.
Some of the key advantages for using Icinga DSL include:
We start by defining a Host Command that can reflect the current status of a monitoring object onto itself in the case of an active check execution. The first step requires defining a command and argument value as a DLS instruction. When generating the DSL instruction with Director web UI, the surrounding “{{ }}” for defining the function is generated.
The function first resolves the host name of the check execution from the runtime variable. This can be accomplished by calling the macro function. In the next step we retrieve the desired host object by calling the “get_host()” method, and finally extract the desired attribute values from the returned object. That integer or string value is returned to the command variable.
To extract the current status code value, we can proceed with the following DSL Expression:
var strhost = macro("$host.name$")
var objhost = get_host(strhost)
var int_exit_status = objhost.last_check_result.state
return int_exit_status
Since the results of a host command should define both:
we slightly change the previous code snippet to the following:
var strhost = macro("$host.name$")
var objhost = get_host(strhost)
var str_output = objhost.last_check_result.output
return str_output
Given that, here’s how it looks in Director:
And here’s what the preview looks like:
If we apply this host command via a host template to the host object(s), we’ll see this result:
And if we perform the Check now action we see:
All this seems to be rather magical, but luckily there’s a nice approach to debugging Icinga 2 runtime values via the icinga2 console. Take a look at the documentation for more details about using the CLI console.
Now I’ll give you a short example of how to connect to the console in your NetEye environment and inspect our relevant runtime variable. Connect to the console and then run the following steps:
# cat /neteye/shared/icinga2/conf/icinga2/conf.d/api-users.conf
/**
* The ApiUser objects are used for authentication against the API.
*/
object ApiUser "root" {
password = "your-secret-key"
permissions = [ "*" ]
}
# export ICINGA2_API_USERNAME=root
# export ICINGA2_API_PASSWORD= your-secret-key
# icinga2-master console --connect 'https://root@localhost:5665/'
Icinga 2 (version: r2.14.0-1)
<1> => var h = get_host("dummy-selfStatus")
<2> => h.last_check_result
{
active = false
check_source = "neteye4.mydomain"
command = null
execution_end = 1704906173.819249
execution_start = 1704906173.819249
exit_status = 0.000000
output = "Host UP"
performance_data = null
previous_hard_state = 2.000000
schedule_end = 1704906173.819249
schedule_start = 1704906173.819249
scheduling_source = " neteye4.mydomain "
state = 0.000000
ttl = 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 = 2.000000
state_type = 1.000000
}
}
<3> => h.last_check_result.state
0.000000
<4> => h.last_check_result.output
OK: Host UP
Enjoy interacting with you Icinga2 objects! 😉
Did you find this article interesting? Does it match your skill set? Our customers often present us with problems that need customized solutions. In fact, we’re currently hiring for roles just like this and others here at Würth Phoenix.