diff options
Diffstat (limited to 'doc/20-script-debugger.md')
-rw-r--r-- | doc/20-script-debugger.md | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/doc/20-script-debugger.md b/doc/20-script-debugger.md new file mode 100644 index 0000000..e8ee6db --- /dev/null +++ b/doc/20-script-debugger.md @@ -0,0 +1,177 @@ +# Script Debugger <a id="script-debugger"></a> + +You can run the Icinga 2 daemon with the `-X` (`--script-debugger`) +parameter to enable the script debugger: + +```bash +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): + +```bash +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 <a id="script-debugger-config-errors"></a> + +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 variable 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 <a id="script-debugger-breakpoints"></a> + +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 +``` + +## Debugging API Filters <a id="script-debugger-api-filters"></a> + +Queries against the [Icinga 2 REST API](12-icinga2-api.md#icinga2-api) can use +filters, just like available in `assign where` expressions. If these filters cause +an internal error, they return an empty result to the caller. + +In order to analyse these server-side errors, you can use the script debugger. + +The following example tries filter for all host objects where the custom variable +`os` is set. There are various possibilities to check that, one of them would be +`host.vars.os != ""`. Another idea is to use the [contains](18-library-reference.md#dictionary-contains) method on the custom +attribute dictionary like this: `host.vars.contains("os")`. + +```bash +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": "host.vars.contains(\"os\")", "attrs": [ "__name" ], "joins": [ "host.name", "host.vars" ], "pretty": true }' +``` + +This will fail on all hosts which don't have any custom variable specified. + +``` +# icinga2 daemon -X + +Breakpoint encountered. +Exception: Error: Argument is not a callable object. +Location: in <API query>: 1:0-1:23 +You can inspect expressions (such as variables) by entering them at the prompt. +To leave the debugger and continue the program use "$continue". + +<1> => this.host + +... + + vars = null + +<2> => $continue +``` + +By definition, a type method can only be invoked on an actual object. + +In order to stay safe, add more checks to the API filter: + +- `host.vars && host.vars.contains("os")` or +- `host.vars && typeof(host.vars) == Dictionary && host.vars.contains("os")` + +Example: + +```bash +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": "host.vars && typeof(host.vars) == Dictionary && host.vars.contains(\"os\")", "attrs": [ "__name" ], "joins": [ "host.name", "host.vars" ], "pretty": true }' +``` |