1# Language Reference <a id="language-reference"></a> 2 3## Object Definition <a id="object-definition"></a> 4 5Icinga 2 features an object-based configuration format. You can define new 6objects using the `object` keyword: 7 8``` 9object Host "host1.example.org" { 10 display_name = "host1" 11 12 address = "192.168.0.1" 13 address6 = "2001:db8:1234::42" 14} 15``` 16 17In general you need to write each statement on a new line. Expressions started 18with `{`, `(` and `[` extend until the matching closing character and can be broken 19up into multiple lines. 20 21Alternatively you can write multiple statements on a single line by separating 22them with a semicolon: 23 24``` 25object Host "host1.example.org" { 26 display_name = "host1" 27 28 address = "192.168.0.1"; address6 = "2001:db8:1234::42" 29} 30``` 31 32Each object is uniquely identified by its type (`Host`) and name 33(`host1.example.org`). Some types have composite names, e.g. the 34`Service` type which uses the `host_name` attribute and the name 35you specified to generate its object name. 36 37Exclamation marks (!) are not permitted in object names. 38 39Objects can contain a comma-separated list of property 40declarations. Instead of commas semicolons may also be used. 41The following data types are available for property values: 42 43All objects have at least the following attributes: 44 45Attribute | Description 46---------------------|----------------------------- 47name | The name of the object. This attribute can be modified in the object definition to override the name specified with the `object` directive. 48type | The type of the object. 49 50## Expressions <a id="expressions"></a> 51 52The following expressions can be used on the right-hand side of assignments. 53 54### Numeric Literals <a id="numeric-literals"></a> 55 56A floating-point number. 57 58Example: 59 60``` 6127.3 62``` 63 64### Duration Literals <a id="duration-literals"></a> 65 66Similar to floating-point numbers except for the fact that they support 67suffixes to help with specifying time durations. 68 69Example: 70 71``` 722.5m 73``` 74 75Supported suffixes include ms (milliseconds), s (seconds), m (minutes), 76h (hours) and d (days). 77 78Duration literals are converted to seconds by the config parser and 79are treated like numeric literals. 80 81### String Literals <a id="string-literals"></a> 82 83A string. 84 85Example: 86 87``` 88"Hello World!" 89``` 90 91#### String Literals Escape Sequences <a id="string-literals-escape-sequences"></a> 92 93Certain characters need to be escaped. The following escape sequences 94are supported: 95 96Character | Escape sequence 97--------------------------|------------------------------------ 98" | \\" 99\\ | \\\\ 100<TAB> | \\t 101<CARRIAGE-RETURN> | \\r 102<LINE-FEED> | \\n 103<BEL> | \\b 104<FORM-FEED> | \\f 105 106In addition to these pre-defined escape sequences you can specify 107arbitrary ASCII characters using the backslash character (\\) followed 108by an ASCII character in octal encoding. 109 110### Multi-line String Literals <a id="multiline-string-literals"></a> 111 112Strings spanning multiple lines can be specified by enclosing them in 113{{{ and }}}. 114 115Example: 116 117``` 118{{{This 119is 120a multi-line 121string.}}} 122``` 123 124Unlike in ordinary strings special characters do not have to be escaped 125in multi-line string literals. 126 127### Boolean Literals <a id="boolean-literals"></a> 128 129The keywords `true` and `false` are used to denote truth values. 130 131### Null Value <a id="null-value"></a> 132 133The `null` keyword can be used to specify an empty value. 134 135### Dictionary <a id="dictionary"></a> 136 137An unordered list of key-value pairs. Keys must be unique and are 138compared in a case-sensitive manner. 139 140Individual key-value pairs must either be comma-separated or on separate lines. 141The comma after the last key-value pair is optional. 142 143Example: 144 145``` 146{ 147 address = "192.168.0.1" 148 port = 443 149} 150``` 151 152Identifiers may not contain certain characters (e.g. space) or start 153with certain characters (e.g. digits). If you want to use a dictionary 154key that is not a valid identifier, you can enclose the key in double 155quotes. 156 157### Array <a id="array"></a> 158 159An ordered list of values. 160 161Individual array elements must be comma-separated. 162The comma after the last element is optional. 163 164Example: 165 166``` 167[ "hello", 42 ] 168``` 169 170An array may simultaneously contain values of different types, such as 171strings and numbers. 172 173### Operators <a id="expression-operators"></a> 174 175The following operators are supported in expressions. The operators are sorted by descending precedence. 176 177Operator | Precedence | Examples (Result) | Description 178---------|------------|-----------------------------------------------|-------------------------------- 179`()` | 1 | (3 + 3) * 5 | Groups sub-expressions 180`()` | 1 | Math.random() | Calls a function 181`[]` | 1 | a[3] | Array subscript 182`.` | 1 | a.b | Element access 183`!` | 2 | !"Hello" (false), !false (true) | Logical negation of the operand 184`~` | 2 | ~true (false) | Bitwise negation of the operand 185`+` | 2 | +3 | Unary plus 186`-` | 2 | -3 | Unary minus 187`&` | 2 | &var (reference to 'var') | Reference operator 188`*` | 2 | *var | Indirection operator 189`*` | 3 | 5m * 10 (3000) | Multiplies two numbers 190`/` | 3 | 5m / 5 (60) | Divides two numbers 191`%` | 3 | 17 % 12 (5) | Remainder after division 192`+` | 4 | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings 193`-` | 4 | 3 - 1 (2) | Subtracts two numbers 194`<<` | 5 | 4 << 8 (1024) | Left shift 195`>>` | 5 | 1024 >> 4 (64) | Right shift 196`<` | 6 | 3 < 5 (true) | Less than 197`>` | 6 | 3 > 5 (false) | Greater than 198`<=` | 6 | 3 <= 3 (true) | Less than or equal 199`>=` | 6 | 3 >= 3 (true) | Greater than or equal 200`in` | 7 | "foo" in [ "foo", "bar" ] (true) | Element contained in array 201`!in` | 7 | "foo" !in [ "bar", "baz" ] (true) | Element not contained in array 202`==` | 8 | "hello" == "hello" (true), 3 == 5 (false) | Equal to 203`!=` | 8 | "hello" != "world" (true), 3 != 3 (false) | Not equal to 204`&` | 9 | 7 & 3 (3) | Binary AND 205`^` | 10 | 17 ^ 12 (29) | Bitwise XOR 206<code>|</code> | 11 | 2 | 3 (3) | Binary OR 207<code>||</code> | 12 | true || false (true), 0 || 7 (7)| Logical OR 208`&&` | 13 | true && false (false), 3 && 7 (7), 0 && 7 (0) | Logical AND 209`=` | 14 | a = 3 | Assignment 210`=>` | 15 | x => x * x (function with arg x) | Lambda, for loop 211`?` | 16 | (2 * 3 > 5) ? 1 : 0 (1) | [Ternary operator](17-language-reference.md#conditional-statements-ternary) 212 213### References <a id="references"></a> 214 215A reference to a value can be obtained using the `&` operator. The `*` operator can be used 216to dereference a reference: 217 218``` 219var value = "Hello!" 220var p = &value /* p refers to value */ 221*p = "Hi!" 222log(value) // Prints "Hi!" because the variable was changed 223``` 224 225### Namespaces <a id="namespaces"></a> 226 227Namespaces can be used to organize variables and functions. They are used to avoid name conflicts. The `namespace` 228keyword is used to create a new namespace: 229 230``` 231namespace Utils { 232 function calculate() { 233 return 2 + 2 234 } 235} 236``` 237 238The namespace is made available as a global variable which has the namespace's name (e.g. `Utils`): 239 240``` 241Utils.calculate() 242``` 243 244The `using` keyword can be used to make all attributes in a namespace available to a script without having to 245explicitly specify the namespace's name for each access: 246 247``` 248using Utils 249calculate() 250``` 251 252The `using` keyword only has an effect for the current file and only for code that follows the keyword: 253 254``` 255calculate() // This will not work. 256using Utils 257``` 258 259The following namespaces are automatically imported as if by using the `using` keyword: 260 261* System 262* System.Configuration 263* Types 264* Icinga 265 266### Function Calls <a id="function-calls"></a> 267 268Functions can be called using the `()` operator: 269 270``` 271const MyGroups = [ "test1", "test" ] 272 273{ 274 check_interval = len(MyGroups) * 1m 275} 276``` 277 278A list of available functions is available in the [Library Reference](18-library-reference.md#library-reference) chapter. 279 280## Assignments <a id="dictionary-operators"></a> 281 282In addition to the `=` operator shown above a number of other operators 283to manipulate attributes are supported. Here's a list of all 284available operators (the outermost `{` `}` stand for a local variable scope): 285 286### Operator = <a id="operator-assignment"></a> 287 288Sets an attribute to the specified value. 289 290Example: 291 292``` 293{ 294 a = 5 295 a = 7 296} 297``` 298 299In this example `a` has the value `7` after both instructions are executed. 300 301### Operator += <a id="operator-additive-assignment"></a> 302 303The += operator is a shortcut. The following expression: 304 305``` 306{ 307 a = [ "hello" ] 308 a += [ "world" ] 309} 310``` 311 312is equivalent to: 313 314``` 315{ 316 a = [ "hello" ] 317 a = a + [ "world" ] 318} 319``` 320 321### Operator -= <a id="operator-substractive-assignment"></a> 322 323The -= operator is a shortcut. The following expression: 324 325``` 326{ 327 a = 10 328 a -= 5 329} 330``` 331 332is equivalent to: 333 334``` 335{ 336 a = 10 337 a = a - 5 338} 339``` 340 341### Operator \*= <a id="operator-multiply-assignment"></a> 342 343The *= operator is a shortcut. The following expression: 344 345``` 346{ 347 a = 60 348 a *= 5 349} 350``` 351 352is equivalent to: 353 354``` 355{ 356 a = 60 357 a = a * 5 358} 359``` 360 361### Operator /= <a id="operator-dividing-assignment"></a> 362 363The /= operator is a shortcut. The following expression: 364 365``` 366{ 367 a = 300 368 a /= 5 369} 370``` 371 372is equivalent to: 373 374``` 375{ 376 a = 300 377 a = a / 5 378} 379``` 380 381## Indexer <a id="indexer"></a> 382 383The indexer syntax provides a convenient way to set dictionary elements. 384 385Example: 386 387``` 388{ 389 hello.key = "world" 390} 391``` 392 393Example (alternative syntax): 394 395``` 396{ 397 hello["key"] = "world" 398} 399``` 400 401This is equivalent to writing: 402 403``` 404{ 405 hello += { 406 key = "world" 407 } 408} 409``` 410 411If the `hello` attribute does not already have a value, it is automatically initialized to an empty dictionary. 412 413## Template Imports <a id="template-imports"></a> 414 415Objects can import attributes from other objects. 416 417Example: 418 419``` 420template Host "default-host" { 421 vars.colour = "red" 422} 423 424template Host "test-host" { 425 import "default-host" 426 427 vars.colour = "blue" 428} 429 430object Host "localhost" { 431 import "test-host" 432 433 address = "127.0.0.1" 434 address6 = "::1" 435} 436``` 437 438The `default-host` and `test-host` objects are marked as templates 439using the `template` keyword. Unlike ordinary objects templates are not 440instantiated at run-time. Parent objects do not necessarily have to be 441templates, however in general they are. 442 443The `vars` dictionary for the `localhost` object contains all three 444custom variables and the custom variable `colour` has the value `"blue"`. 445 446Parent objects are resolved in the order they're specified using the 447`import` keyword. 448 449Default templates which are automatically imported into all object definitions 450can be specified using the `default` keyword: 451 452``` 453template CheckCommand "plugin-check-command" default { 454 // ... 455} 456``` 457 458Default templates are imported before any other user-specified statement in an 459object definition is evaluated. 460 461If there are multiple default templates the order in which they are imported 462is unspecified. 463 464## Constants <a id="constants"></a> 465 466Global constants can be set using the `const` keyword: 467 468``` 469const VarName = "some value" 470``` 471 472Once defined a constant can be accessed from any file. Constants cannot be changed 473once they are set. 474 475> **Tip** 476> 477> Best practice is to manage constants in the [constants.conf](04-configuration.md#constants-conf) file. 478 479### Icinga 2 Specific Constants <a id="icinga-constants"></a> 480 481Icinga 2 provides a number of special global constants. These include directory paths, global configuration 482and runtime parameters for the application version and (build) platform. 483 484#### Directory Path Constants <a id="icinga-constants-director-path"></a> 485 486Constant | Description 487--------------------|------------------- 488ConfigDir |**Read-only.** Main configuration directory. Usually set to `/etc/icinga2`. 489DataDir |**Read-only.** Runtime data for the Icinga daemon. Usually set to `/var/lib/icinga2`. 490LogDir |**Read-only.** Logfiles from the daemon. Usually set to `/var/log/icinga2`. 491CacheDir |**Read-only.** Cached status information of the daemon. Usually set to `/var/cache/icinga2`. 492SpoolDir |**Read-only.** Spool directory for certain data outputs. Usually set to `/var/spool/icinga2`. 493InitRunDir |**Read-only.** Directory for PID files and sockets in daemon mode. Usually set to `/run/icinga2`. 494ZonesDir |**Read-only.** Contains the path of the zones.d directory. Defaults to `ConfigDir + "/zones.d"`. 495 496#### Global Configuration Constants <a id="icinga-constants-global-config"></a> 497 498Constant | Description 499--------------------|------------------- 500Vars |**Read-write.** Contains a dictionary with global custom variables. Not set by default. 501NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. 502ReloadTimeout |**Read-write.** Defines the reload timeout for child processes. Defaults to `300s`. 503Environment |**Read-write.** The name of the Icinga environment. Included in the SNI host name for outbound connections. Not set by default. 504RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. 505RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. 506MaxConcurrentChecks |**Read-write.** The number of max checks run simultaneously. Defaults to `512`. 507ApiBindHost |**Read-write.** Overrides the default value for the ApiListener `bind_host` attribute. Defaults to `::` if IPv6 is supported by the operating system and to `0.0.0.0` otherwise. 508ApiBindPort |**Read-write.** Overrides the default value for the ApiListener `bind_port` attribute. Not set by default. 509 510#### Application Runtime Constants <a id="icinga-constants-application-runtime"></a> 511 512Constant | Description 513--------------------|------------------- 514PlatformName |**Read-only.** The name of the operating system, e.g. `Ubuntu`. 515PlatformVersion |**Read-only.** The version of the operating system, e.g. `14.04.3 LTS`. 516PlatformKernel |**Read-only.** The name of the operating system kernel, e.g. `Linux`. 517PlatformKernelVersion|**Read-only.** The version of the operating system kernel, e.g. `3.13.0-63-generic`. 518BuildCompilerName |**Read-only.** The name of the compiler Icinga was built with, e.g. `Clang`. 519BuildCompilerVersion|**Read-only.** The version of the compiler Icinga was built with, e.g. `7.3.0.7030031`. 520BuildHostName |**Read-only.** The name of the host Icinga was built on, e.g. `acheron`. 521ApplicationVersion |**Read-only.** The application version, e.g. `2.9.0`. 522 523#### Additional Constants <a id="icinga-constants-additional"></a> 524 525Writable constants can be specified on the CLI using the `--define/-D` parameter. 526 527> **Note for v2.10+** 528> 529> Default paths which include `/etc` and `/var` as base directory continue to work 530> based on the `SysconfDir` and `LocalStateDir` constants respectively. 531 532In addition to that, the constants below are used to define specific file paths. You should never need 533to change them, as they are pre-compiled based on the constants above. 534 535Variable |Description 536--------------------|------------------- 537StatePath |**Read-write.** Contains the path of the Icinga 2 state file. Defaults to `DataDir + "/icinga2.state"`. 538ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects file. Defaults to `CacheDir + "/icinga2.debug"`. 539PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to `InitRunDir + "/icinga2.pid"`. 540PkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to `PrefixDir + "/share/icinga2"`. 541 542The constants below have been used until Icinga v2.10, and are still intact. You don't need them 543for future builds and configuration based on the newly available constants above. 544 545Variable |Description 546--------------------|------------------- 547PrefixDir |**Read-only.** Contains the installation prefix that was specified with `cmake -DCMAKE_INSTALL_PREFIX`. `Defaults to "/usr/local"`. 548SysconfDir |**Read-only.** Contains the path of the sysconf directory. Defaults to `PrefixDir + "/etc"`. 549LocalStateDir |**Read-only.** Contains the path of the local state directory. Defaults to `PrefixDir + "/var"`. 550RunDir |**Read-only.** Contains the path of the run directory. Defaults to `LocalStateDir + "/run"`. 551 552#### Advanced Constants and Variables <a id="icinga-constants-advanced"></a> 553 554Advanced runtime constants. Please only use them if advised by support or developers. 555 556Variable | Description 557---------------------------|------------------- 558EventEngine |**Read-write.** The name of the socket event engine, can be `poll` or `epoll`. The epoll interface is only supported on Linux. 559AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to `false`. 560 561Advanced sysconfig environment variables, defined in `/etc/sysconfig/icinga2` (RHEL/SLES) or `/etc/default/icinga2` (Debian/Ubuntu). 562 563Variable | Description 564---------------------------|------------------- 565ICINGA2\_RLIMIT\_FILES |**Read-write.** Defines the resource limit for `RLIMIT_NOFILE` that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. 566ICINGA2\_RLIMIT\_PROCESSES |**Read-write.** Defines the resource limit for `RLIMIT_NPROC` that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. 567ICINGA2\_RLIMIT\_STACK |**Read-write.** Defines the resource limit for `RLIMIT_STACK` that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. 568 569#### Debug Constants and Variables <a id="icinga-constants-debug"></a> 570 571These constants are only available in debug builds for developers and help with tracing messages and attaching to debuggers. 572 573Variable | Description 574---------------------------|------------------- 575Internal.DebugJsonRpc | **Read-write.** Setting this to `1` prints the raw JSON-RPC message to STDOUT. 576Internal.DebugWorkerDelay | **Read-write.** Delays the main worker process by X seconds after forked from the umbrella process. This helps with attaching LLDB which cannot follow child forks like GDB. 577 578Example: 579 580``` 581$ icinga2 daemon -DInternal.DebugWorkerDelay=120 582Closed FD 6 which we inherited from our parent process. 583[2020-01-29 12:22:33 +0100] information/cli: Icinga application loader (version: v2.11.0-477-gfe8701d77; debug) 584[2020-01-29 12:22:33 +0100] information/RunWorker: DEBUG: Current PID: 85253. Sleeping for 120 seconds to allow lldb/gdb -p <PID> attachment. 585 586$ lldb -p 85253 587(lldb) b icinga::Checkable::ProcessCheckResult 588(lldb) c 589``` 590 591 592## Apply <a id="apply"></a> 593 594The `apply` keyword can be used to create new objects which are associated with 595another group of objects. 596 597``` 598apply Service "ping" to Host { 599 import "generic-service" 600 601 check_command = "ping4" 602 603 assign where host.name == "localhost" 604} 605``` 606 607In this example the `assign where` condition is a boolean expression which is 608evaluated for all objects of type `Host` and a new service with name "ping" 609is created for each matching host. [Expression operators](17-language-reference.md#expression-operators) 610may be used in `assign where` conditions. 611 612The `to` keyword and the target type may be omitted if there is only one target 613type, e.g. for the `Service` type. 614 615Depending on the object type used in the `apply` expression additional local 616variables may be available for use in the `where` condition: 617 618Source Type | Target Type | Variables 619------------------|-------------|-------------- 620Service | Host | host 621Dependency | Host | host 622Dependency | Service | host, service 623Notification | Host | host 624Notification | Service | host, service 625ScheduledDowntime | Host | host 626ScheduledDowntime | Service | host, service 627 628Any valid config attribute can be accessed using the `host` and `service` 629variables. For example, `host.address` would return the value of the host's 630"address" attribute -- or null if that attribute isn't set. 631 632More usage examples are documented in the [monitoring basics](03-monitoring-basics.md#using-apply-expressions) 633chapter. 634 635## Apply For <a id="apply-for"></a> 636 637[Apply](17-language-reference.md#apply) rules can be extended with the 638[for loop](17-language-reference.md#for-loops) keyword. 639 640``` 641apply Service "prefix-" for (key => value in host.vars.dictionary) to Host { 642 import "generic-service" 643 644 check_command = "ping4" 645 vars.host_value = value 646} 647``` 648 649Any valid config attribute can be accessed using the `host` and `service` 650variables. The attribute must be of the Array or Dictionary type. In this example 651`host.vars.dictionary` is of the Dictionary type which needs a key-value-pair 652as iterator. 653 654In this example all generated service object names consist of `prefix-` and 655the value of the `key` iterator. The prefix string can be omitted if not required. 656 657The `key` and `value` variables can be used for object attribute assignment, e.g. for 658setting the `check_command` attribute or custom variables as command parameters. 659 660`apply for` rules are first evaluated against all objects matching the `for loop` list 661and afterwards the `assign where` and `ignore where` conditions are evaluated. 662 663It is not necessary to check attributes referenced in the `for loop` expression 664for their existance using an additional `assign where` condition. 665 666More usage examples are documented in the [monitoring basics](03-monitoring-basics.md#using-apply-for) 667chapter. 668 669## Group Assign <a id="group-assign"></a> 670 671Group objects can be assigned to specific member objects using the `assign where` 672and `ignore where` conditions. 673 674``` 675object HostGroup "linux-servers" { 676 display_name = "Linux Servers" 677 678 assign where host.vars.os == "Linux" 679} 680``` 681 682In this example the `assign where` condition is a boolean expression which is evaluated 683for all objects of the type `Host`. Each matching host is added as member to the host group 684with the name "linux-servers". Membership exclusion can be controlled using the `ignore where` 685condition. [Expression operators](17-language-reference.md#expression-operators) may be used in `assign where` and 686`ignore where` conditions. 687 688Source Type | Variables 689------------------|-------------- 690HostGroup | host 691ServiceGroup | host, service 692UserGroup | user 693 694 695## Boolean Values <a id="boolean-values"></a> 696 697The `assign where`, `ignore where`, `if` and `while` statements, the `!` operator as 698well as the `bool()` function convert their arguments to a boolean value based on the 699following rules: 700 701Description | Example Value | Boolean Value 702---------------------|-------------------|-------------- 703Empty value | null | false 704Zero | 0 | false 705Non-zero integer | -23945 | true 706Empty string | "" | false 707Non-empty string | "Hello" | true 708Empty array | [] | false 709Non-empty array | [ "Hello" ] | true 710Empty dictionary | {} | false 711Non-empty dictionary | { key = "value" } | true 712 713For a list of supported expression operators for `assign where` and `ignore where` 714statements, see [expression operators](17-language-reference.md#expression-operators). 715 716## Comments <a id="comments"></a> 717 718The Icinga 2 configuration format supports C/C++-style and shell-style comments. 719 720Example: 721 722``` 723/* 724 This is a comment. 725 */ 726object Host "localhost" { 727 check_interval = 30 // this is also a comment. 728 retry_interval = 15 # yet another comment 729} 730``` 731 732## Includes <a id="includes"></a> 733 734Other configuration files can be included using the `include` directive. 735Paths must be relative to the configuration file that contains the 736`include` directive. 737 738Example: 739 740``` 741include "some/other/file.conf" 742include "conf.d/*.conf" 743``` 744 745Wildcard includes are not recursive. 746 747Icinga also supports include search paths similar to how they work in a 748C/C++ compiler: 749 750``` 751include <itl> 752``` 753 754Note the use of angle brackets instead of double quotes. This causes the 755config compiler to search the include search paths for the specified 756file. By default $PREFIX/share/icinga2/include is included in the list of search 757paths. Additional include search paths can be added using 758[command-line options](11-cli-commands.md#config-include-path). 759 760Wildcards are not permitted when using angle brackets. 761 762## Recursive Includes <a id="recursive-includes"></a> 763 764The `include_recursive` directive can be used to recursively include all 765files in a directory which match a certain pattern. 766 767Example: 768 769``` 770include_recursive "conf.d", "*.conf" 771include_recursive "templates" 772``` 773 774The first parameter specifies the directory from which files should be 775recursively included. 776 777The file names need to match the pattern given in the second parameter. 778When no pattern is specified the default pattern "*.conf" is used. 779 780## Zone Includes <a id="zone-includes"></a> 781 782> **Note** 783> 784> This is an internal functionality consumed by Icinga itself. 785> 786> The preferred way for users managing configuration files in 787> zones is to use the [cluster config sync](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync) 788> or [REST API config packages](12-icinga2-api.md#icinga2-api-config-management). 789 790The `include_zones` recursively includes all subdirectories for the 791given path. 792 793In addition to that it sets the `zone` attribute for all objects created 794in these subdirectories to the name of the subdirectory. 795 796Example: 797 798``` 799include_zones "etc", "zones.d", "*.conf" 800include_zones "puppet", "puppet-zones" 801``` 802 803The first parameter specifies a tag name for this directive. Each `include_zones` 804invocation should use a unique tag name. When copying the zones' configuration 805files Icinga uses the tag name as the name for the destination directory in 806`/var/lib/icinga2/api/config`. 807 808The second parameter specifies the directory which contains the subdirectories. 809 810The file names need to match the pattern given in the third parameter. 811When no pattern is specified the default pattern "*.conf" is used. 812 813## Library directive <a id="library"></a> 814 815The `library` directive was used to manually load additional 816libraries. Starting with version 2.9 it is no longer necessary to explicitly load 817libraries and this directive has no effect. 818 819## Functions <a id="functions"></a> 820 821Functions can be defined using the `function` keyword. 822 823Example: 824 825``` 826function multiply(a, b) { 827 return a * b 828} 829``` 830 831When encountering the `return` keyword further execution of the function is terminated and 832the specified value is supplied to the caller of the function: 833 834``` 835log(multiply(3, 5)) 836``` 837 838In this example the `multiply` function we declared earlier is invoked with two arguments (3 and 5). 839The function computes the product of those arguments and makes the result available to the 840function's caller. 841 842When no value is supplied for the `return` statement the function returns `null`. 843 844Functions which do not have a `return` statement have their return value set to the value of the 845last expression which was performed by the function. For example, we could have also written our 846`multiply` function like this: 847 848``` 849function multiply(a, b) { 850 a * b 851} 852``` 853 854Anonymous functions can be created by omitting the name in the function definition. The 855resulting function object can be used like any other value: 856 857``` 858var fn = function() { 3 } 859 860fn() /* Returns 3 */ 861``` 862 863## Lambda Expressions <a id="lambdas"></a> 864 865Functions can also be declared using the alternative lambda syntax. 866 867Example: 868 869``` 870f = (x) => x * x 871``` 872 873Multiple statements can be used by putting the function body into braces: 874 875``` 876f = (x) => { 877 log("Lambda called") 878 x * x 879} 880``` 881 882Just like with ordinary functions the return value is the value of the last statement. 883 884For lambdas which take exactly one argument the braces around the arguments can be omitted: 885 886``` 887f = x => x * x 888``` 889 890### Lambda Expressions with Closures <a id="lambdas-closures"></a> 891 892Lambda expressions which take a given number of arguments may need additional 893variable values from the outer scope. When the lambda expression does not allow 894to change the interface, [closures](17-language-reference.md#closures) come into play. 895 896``` 897var y 898 899f = ((x) use(y) => x == y) 900``` 901 902Note that the braces around arguments are always required when using closures. 903 904A more concrete example: 905 906Within the DSL, you want to [filter](18-library-reference.md#array-filter) an array of HostGroup objects by their name. 907The filter function takes one argument being a function callback which either returns 908`true` or `false`. Matching items are collected into the result set. 909 910``` 911get_objects(HostGroup).filter((hg) => hg.name == "linux-servers") 912``` 913 914Instead of hardcoding the matching hostgroup name into the lambda scope, you want 915to control the value from the outside configuration values, e.g. in a custom variable 916or global constant. 917 918``` 919var hg_filter_name = "linux-servers" 920 921get_objects(HostGroup).filter((hg) use(hg_filter_name) => hg.name == hg_filter_name) 922``` 923 924You can also use this example vice versa and extract host object matching a specific 925host group name. 926 927``` 928var hg_filter_name = "linux-servers" 929 930get_objects(Host).filter((h) use (hg_search_name) => hg_search_name in h.groups).map(h => h.name) 931``` 932 933Note that this example makes use of the [map](18-library-reference.md#array-map) method for the Array type which 934extracts the host name attribute from the full object into a new array. 935 936## Abbreviated Lambda Syntax <a id="nullary-lambdas"></a> 937 938Lambdas which take no arguments can also be written using the abbreviated lambda syntax. 939 940Example: 941 942``` 943f = {{ 3 }} 944``` 945 946This creates a new function which returns the value 3. 947 948## Variable Scopes <a id="variable-scopes"></a> 949 950When setting a variable Icinga checks the following scopes in this order whether the variable 951already exists there: 952 953* Local Scope 954* `this` Scope 955* Global Scope 956 957The local scope contains variables which only exist during the invocation of the current function, 958object or apply statement. Local variables can be declared using the `var` keyword: 959 960``` 961function multiply(a, b) { 962 var temp = a * b 963 return temp 964} 965``` 966 967Each time the `multiply` function is invoked a new `temp` variable is used which is in no way 968related to previous invocations of the function. 969 970When setting a variable which has not previously been declared as local using the `var` keyword 971the `this` scope is used. 972 973The `this` scope refers to the current object which the function or object/apply statement 974operates on. 975 976``` 977object Host "localhost" { 978 check_interval = 5m 979} 980``` 981 982In this example the `this` scope refers to the "localhost" object. The `check_interval` attribute 983is set for this particular host. 984 985You can explicitly access the `this` scope using the `this` keyword: 986 987``` 988object Host "localhost" { 989 var check_interval = 5m 990 991 /* This explicitly specifies that the attribute should be set 992 * for the host, if we had omitted `this.` the (poorly named) 993 * local variable `check_interval` would have been modified instead. 994 */ 995 this.check_interval = 1m 996} 997``` 998Similarly the keywords `locals` and `globals` are available to access the local and global scope. 999 1000Functions also have a `this` scope. However unlike for object/apply statements the `this` scope for 1001a function is set to whichever object was used to invoke the function. Here's an example: 1002 1003``` 1004 hm = { 1005 h_word = null 1006 1007 function init(word) { 1008 h_word = word 1009 } 1010 } 1011 1012 /* Let's invoke the init() function */ 1013 hm.init("hello") 1014``` 1015 1016We're using `hm.init` to invoke the function which causes the value of `hm` to become the `this` 1017scope for this function call. 1018 1019## Closures <a id="closures"></a> 1020 1021By default `function`s, `object`s and `apply` rules do not have access to variables declared 1022outside of their scope (except for global variables). 1023 1024In order to access variables which are defined in the outer scope the `use` keyword can be used: 1025 1026``` 1027function MakeHelloFunction(name) { 1028 return function() use(name) { 1029 log("Hello, " + name) 1030 } 1031} 1032``` 1033 1034In this case a new variable `name` is created inside the inner function's scope which has the 1035value of the `name` function argument. 1036 1037Alternatively a different value for the inner variable can be specified: 1038 1039``` 1040function MakeHelloFunction(name) { 1041 return function() use (greeting = "Hello, " + name) { 1042 log(greeting) 1043 } 1044} 1045``` 1046 1047## Conditional Statements <a id="conditional-statements"></a> 1048 1049### Conditional Statements: if/else <a id="conditional-statements-if-else"></a> 1050 1051Sometimes it can be desirable to only evaluate statements when certain conditions are met. The if/else 1052construct can be used to accomplish this. 1053 1054Example: 1055 1056``` 1057a = 3 1058 1059if (a < 5) { 1060 a *= 7 1061} else if (a > 10) { 1062 a *= 5 1063} else { 1064 a *= 2 1065} 1066``` 1067 1068An if/else construct can also be used in place of any other value. The value of an if/else statement 1069is the value of the last statement which was evaluated for the branch which was taken: 1070 1071``` 1072a = if (true) { 1073 log("Taking the 'true' branch") 1074 7 * 3 1075} else { 1076 log("Taking the 'false' branch") 1077 9 1078} 1079``` 1080 1081This example prints the log message "Taking the 'true' branch" and the `a` variable is set to 21 (7 * 3). 1082 1083The value of an if/else construct is null if the condition evaluates to false and no else branch is given. 1084 1085### Conditional Statements: Ternary Operator <a id="conditional-statements-ternary"></a> 1086 1087Instead of if/else condition chains, you can also use the ternary operator `?` 1088with assignments. Values are separated with a colon `:` character. 1089 1090``` 1091cond ? cond_val_true : cond_val_false 1092``` 1093 1094Whether the first condition matches, the first value is returned, if not, the else and second 1095branch value is returned. 1096 1097The following example evaluates a condition and either assigns `1` or `0` 1098to the local variable. 1099 1100``` 1101<1> => var x = (2 * 3 > 5) ? 1 : 0 1102null 1103<2> => x 11041.000000 1105<3> => var x = (2 * 3 > 7) ? 1 : 0 1106null 1107<4> => x 11080.000000 1109``` 1110 1111Additional examples with advanced condition chaining: 1112 1113``` 1114<1> => 1 ? 2 : 3 ? 4 : 5 ? 6 : 7 11152.000000 1116<2> => 0 ? 2 : 3 ? 4 : 5 ? 6 : 7 11174.000000 1118<3> => 0 ? 2 : 0 ? 4 : 5 ? 6 : 7 11196.000000 1120<4> => 0 ? 2 : 0 ? 4 : 0 ? 6 : 7 11217.000000 1122<5> => 1 + 0 ? 2 : 3 + 4 11232.000000 1124<6> => 0 + 0 ? 2 : 3 + 4 11257.000000 1126<7> => (()=>{ return 1 ? 2 : 3 })() 11272.000000 1128<8> => var x = 1 ? 2 : 3 1129null 1130<9> => x 11312.000000 1132``` 1133 1134 1135## While Loops <a id="while-loops"></a> 1136 1137The `while` statement checks a condition and executes the loop body when the condition evaluates to `true`. 1138This is repeated until the condition is no longer true. 1139 1140Example: 1141 1142``` 1143var num = 5 1144 1145while (num > 5) { 1146 log("Test") 1147 num -= 1 1148} 1149``` 1150 1151The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword 1152skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword 1153breaks out of the loop. 1154 1155## For Loops <a id="for-loops"></a> 1156 1157The `for` statement can be used to iterate over arrays and dictionaries. 1158 1159Example: 1160 1161``` 1162var list = [ "a", "b", "c" ] 1163 1164for (var item in list) { 1165 log("Item: " + item) 1166} 1167``` 1168 1169The loop body is evaluated once for each item in the array. The variable `item` is declared as a local 1170variable just as if the `var` keyword had been used. 1171 1172Iterating over dictionaries can be accomplished in a similar manner: 1173 1174``` 1175var dict = { a = 3, b = 7 } 1176 1177for (var key => var value in dict) { 1178 log("Key: " + key + ", Value: " + value) 1179} 1180``` 1181 1182The `continue` and `break` keywords can be used to control how the loop is executed: The `continue` keyword 1183skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword 1184breaks out of the loop. 1185 1186The `var` keyword is optional when declaring variables in the loop's header. Variables declared without the `var` 1187keyword are nonetheless local to the function. 1188 1189## Constructors <a id="constructor"></a> 1190 1191In order to create a new value of a specific type constructor calls may be used. 1192 1193Example: 1194 1195``` 1196var pd = PerfdataValue() 1197pd.label = "test" 1198pd.value = 10 1199``` 1200 1201You can also try to convert an existing value to another type by specifying it as an argument for the constructor call. 1202 1203Example: 1204 1205``` 1206var s = String(3) /* Sets s to "3". */ 1207``` 1208 1209## Throwing Exceptions <a id="throw"></a> 1210 1211Built-in commands may throw exceptions to signal errors such as invalid arguments. User scripts can throw exceptions 1212using the `throw` keyword. 1213 1214Example: 1215 1216``` 1217throw "An error occurred." 1218``` 1219 1220## Handling Exceptions <a id="try-except"></a> 1221 1222Exceptions can be handled using the `try` and `except` keywords. When an exception occurs while executing code in the 1223`try` clause no further statements in the `try` clause are evaluated and the `except` clause is executed instead. 1224 1225Example: 1226 1227``` 1228try { 1229 throw "Test" 1230 1231 log("This statement won't get executed.") 1232} except { 1233 log("An error occurred in the try clause.") 1234} 1235``` 1236 1237## Breakpoints <a id="breakpoints"></a> 1238 1239The `debugger` keyword can be used to insert a breakpoint. It may be used at any place where an assignment would also be a valid expression. 1240 1241By default breakpoints have no effect unless Icinga is started with the `--script-debugger` command-line option. When the script debugger is enabled Icinga stops execution of the script when it encounters a breakpoint and spawns a console which lets the user inspect the current state of the execution environment. 1242 1243## Types <a id="types"></a> 1244 1245All values have a static type. The `typeof` function can be used to determine the type of a value: 1246 1247``` 1248typeof(3) /* Returns an object which represents the type for numbers */ 1249``` 1250 1251The following built-in types are available: 1252 1253Type | Examples | Description 1254-----------|-------------------|------------------------ 1255Number | 3.7 | A numerical value. 1256Boolean | true, false | A boolean value. 1257String | "hello" | A string. 1258Array | [ "a", "b" ] | An array. 1259Dictionary | { a = 3 } | A dictionary. 1260 1261Depending on which libraries are loaded additional types may become available. The `icinga` 1262library implements a whole bunch of other [object types](09-object-types.md#object-types), 1263e.g. Host, Service, CheckCommand, etc. 1264 1265Each type has an associated type object which describes the type's semantics. These 1266type objects are made available using global variables which match the type's name: 1267 1268``` 1269/* This logs 'true' */ 1270log(typeof(3) == Number) 1271``` 1272 1273The type object's `prototype` property can be used to find out which methods a certain type 1274supports: 1275 1276``` 1277/* This returns: ["contains","find","len","lower","replace","reverse","split","substr","to_string","trim","upper"] */ 1278keys(String.prototype) 1279``` 1280 1281Additional documentation on type methods is available in the 1282[library reference](18-library-reference.md#library-reference). 1283 1284## Location Information <a id="location-information"></a> 1285 1286The location of the currently executing script can be obtained using the 1287`current_filename` and `current_line` keywords. 1288 1289Example: 1290 1291``` 1292log("Hello from '" + current_filename + "' in line " + current_line) 1293``` 1294 1295## Reserved Keywords <a id="reserved-keywords"></a> 1296 1297These keywords are reserved and must not be used as constants or custom variables. 1298 1299``` 1300object 1301template 1302include 1303include_recursive 1304include_zones 1305library 1306null 1307true 1308false 1309const 1310var 1311this 1312globals 1313locals 1314use 1315default 1316ignore_on_error 1317current_filename 1318current_line 1319apply 1320to 1321where 1322import 1323assign 1324ignore 1325function 1326return 1327break 1328continue 1329for 1330if 1331else 1332while 1333throw 1334try 1335except 1336in 1337using 1338namespace 1339``` 1340You can escape reserved keywords using the `@` character. The following example 1341tries to set `vars.include` which references a reserved keyword and generates 1342an error: 1343 1344``` 1345[2014-09-15 17:24:00 +0200] critical/config: Location: 1346/etc/icinga2/conf.d/hosts/localhost.conf(13): vars.sla = "24x7" 1347/etc/icinga2/conf.d/hosts/localhost.conf(14): 1348/etc/icinga2/conf.d/hosts/localhost.conf(15): vars.include = "some cmdb export field" 1349 ^^^^^^^ 1350/etc/icinga2/conf.d/hosts/localhost.conf(16): } 1351/etc/icinga2/conf.d/hosts/localhost.conf(17): 1352 1353Config error: in /etc/icinga2/conf.d/hosts/localhost.conf: 15:8-15:14: syntax error, unexpected include (T_INCLUDE), expecting T_IDENTIFIER 1354[2014-09-15 17:24:00 +0200] critical/config: 1 errors, 0 warnings. 1355``` 1356 1357You can escape the `include` keyword by prefixing it with an additional `@` character: 1358 1359``` 1360object Host "localhost" { 1361 import "generic-host" 1362 1363 address = "127.0.0.1" 1364 address6 = "::1" 1365 1366 vars.os = "Linux" 1367 vars.sla = "24x7" 1368 1369 vars.@include = "some cmdb export field" 1370} 1371``` 1372