Author: @mfrosch
Last Edit: 2019-03-28
Today we step into the depths of the Icinga 2 DSL and try to find a nice way to combine the state of several services into one.
This approach takes a list of hosts with one service on each and check if a minimum is OK before warning or critical.
In Icinga 1.x this would be achieved by check_cluster
using macros like $SERVICESTATEID:host:service$
.
Features
- Nice Markup with Links and HTML for Icinga 2
- Check working internally in Icinga 2
- Simple definition appart from the
CheckCommand
- Verbose state information
- Fallback to unknown as appropriate
Services
Let’s define services:
apply Service "http alive" {
import "http"
// more details
assign where host.vars.cluster = "webfrontend"
}
object Host "webfrontend" {
//...
}
object Service "cluster http alive" {
import "default service"
command = "cluster_services"
vars.cluster_label = "HTTP Webfrontend"
vars.cluster_hosts = [
"web1.example.com",
"web2.example.com",
"web3.example.com",
"web4.example.com",
]
vars.cluster_service = "http alive"
vars.cluster_min_warn = 2
vars.cluster_min_crit = 1
}
Internals
Fields / Vars:
cluster_label
Label to be shown in the outputcluster_hosts
An array of hosts involved in the clustercluster_service
Name of the service on on cluster hosts to checkcluster_min_warn
Minimum Services that must be OK before state is WARNINGcluster_min_crit
Minimum Services that must be OK before state is CRITICALicingaweb_baseurl
If you need a more specific base URL than/icingaweb2
object CheckCommand "cluster_services" {
import "plugin-check-command"
command = [ PluginDir + "/check_dummy" ]
arguments += {
output = {
order = 2
skip_key = true
value = {{
var count_ok = 0
var count_warning = 0
var count_critical = 0
var count_unknown = 0
var outputs = []
var hosts = macro("$cluster_hosts$")
var service = macro("$cluster_service$")
var label = macro("$cluster_label$")
var icingaweb = macro("$icingaweb_baseurl$")
if (!icingaweb) {
icingaweb = "/icingaweb2"
}
for (var host in hosts) {
var s = get_service(host, service)
var link = "<a class=\"action-link\" href=\"" + icingaweb + "/monitoring/service/show?host=" + host + "&service=" + service +"\">" + host + "</a>"
var line = "[" + link + "] "
if (s) {
if (s.state == 0) {
count_ok += 1
line += "[OK] "
} else if (s.state == 1) {
count_warning += 1
line += "[WARNING] "
} else if (s.state == 2) {
count_critical += 1
line += "[CRITICAL] "
} else {
count_unknown += 1
line += "[UNKNOWN] "
}
if (s.last_check_result) {
line += s.last_check_result.output.split("\n")[0]
} else {
line += "<no check result>"
}
} else {
line += "<missing>"
count_unknown += 1
}
outputs.add(line)
}
return "Cluster " + label + ": " + count_ok + " ok, " + count_warning + " warning, " + count_critical + " critical, " + count_unknown + " unknown" + "\n<div class=\"preformatted\">" + outputs.join("\n") + "</div>"
}}
}
state = {
order = 1
skip_key = true
value = {{
var count_ok = 0
var hosts = macro("$cluster_hosts$")
var service = macro("$cluster_service$")
var min_warn = macro("$cluster_min_warn$")
var min_crit = macro("$cluster_min_crit$")
for (var host in hosts) {
var s = get_service(host, service)
if (s) {
count += 1
if (s.state == 0) {
count_ok += 1
}
}
}
if (count_ok < min_crit) {
return 2
} else if (count_ok < min_warn) {
return 1
} else {
return 3
}
}}
}
}
vars.cluster_min_crit = 1
vars.cluster_min_warn = 1
}
Summary
- This could have been done with
dummy
instead of the externalcheck_dummy
, but it is compatible with Director like this
Although the example here is not with HTTP states, the output in Icinga Web 2 looks like this:
Any questions or comments?