Documentation: Add function usage examples to advanced topics

Includes typeof() examples, referenced to command variable scopes
and examples from community support.

fixes #9297
fixes #9310
fixes #9311
This commit is contained in:
Michael Friedrich 2015-06-16 19:04:40 +02:00
parent ca674da0d2
commit 909467574c
1 changed files with 160 additions and 0 deletions

View File

@ -208,6 +208,166 @@ Use the `period` attribute to assign time periods to
period = "workhours" period = "workhours"
} }
## <a id="use-functions-object-config"></a> 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](3-monitoring-basics.md#custom-attributes-functions)
* Returning boolean expressions for [set_if](5-advanced-topics.md#use-functions-command-arguments-setif) inside command arguments
* Returning a [command](5-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](5-advanced-topics.md#use-functions-command-arguments-setif) or [command](5-advanced-topics.md#use-functions-command-attribute).
Tips when implementing functions:
* Use [log()](20-library-reference.md#global-functions) 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.
### <a id="use-functions-command-arguments-setif"></a> Use Functions in Command Arguments set_if
The `set_if` attribute inside the command arguments definition in the
[CheckCommand object definition](6-object-types.md#objecttype-checkcommand) is primarly used to
evaluate whether the command parameter should be set or not.
By default you can evaluate runtime macros for their existance, and 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](19-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" {
import "plugin-check-command"
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](20-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](19-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
}
}}
}
### <a id="use-functions-command-attribute"></a> Use Functions as Command Attribute
This comes in handy for [NotificationCommands](6-object-types.md#objecttype-notificationcommand)
or [EventCommands](6-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" {
import "plugin-notification-command"
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 = {
}
}
## <a id="access-object-attributes-at-runtime"></a> Access Object Attributes at Runtime ## <a id="access-object-attributes-at-runtime"></a> Access Object Attributes at Runtime
The [Object Accessor Functions](20-library-reference.md#object-accessor-functions) The [Object Accessor Functions](20-library-reference.md#object-accessor-functions)