From 8958d2f69fc2fa40e154baca443a1e6cb8eaad55 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 27 Mar 2014 12:30:24 +0100 Subject: [PATCH 01/25] Implement the "import" keyword. Refs #5869 --- .../files/etc/icinga2/conf.d/passive.conf | 6 +- doc/3.02-commands.md | 15 ++- doc/3.03-macros.md | 34 ++++--- doc/3.04-notifications.md | 4 +- doc/3.05-using-templates.md | 8 +- doc/3.06-groups.md | 8 +- doc/3.07-time-periods.md | 8 +- doc/3.15-monitoring-remote-clients.md | 28 ++++-- doc/4.1-configuration-syntax.md | 10 +- doc/4.3-object-types.md | 16 +++- doc/4.5-best-practice.md | 8 +- doc/6.01-downtimes.md | 6 +- doc/6.04-cluster.md | 8 +- doc/6.05-domains.md | 6 +- doc/8-differences-between-icinga-1x-and-2.md | 12 ++- etc/icinga2/conf.d/generic-host.conf | 16 +++- etc/icinga2/conf.d/localhost.conf | 4 +- etc/icinga2/conf.d/notifications.conf | 4 +- etc/icinga2/conf.d/timeperiods.conf | 12 ++- etc/icinga2/conf.d/users.conf | 4 +- itl/command-common.conf | 92 ++++++++++++++----- lib/config/aexpression.cpp | 16 ++++ lib/config/aexpression.h | 1 + lib/config/config_lexer.ll | 1 + lib/config/config_parser.yy | 58 +++--------- lib/config/configitem.cpp | 44 +-------- lib/config/configitem.h | 10 +- lib/config/configitembuilder.cpp | 14 +-- lib/config/configitembuilder.h | 4 - lib/icinga/host-apply.cpp | 17 ++-- lib/icinga/host.cpp | 19 ++-- lib/icinga/service-dependency.cpp | 12 ++- lib/icinga/service-downtime.cpp | 11 ++- lib/icinga/service-notification.cpp | 11 ++- test/jenkins/files/configs/eventhandler.conf | 4 +- test/jenkins/files/configs/notifications.conf | 4 +- 36 files changed, 310 insertions(+), 225 deletions(-) diff --git a/.vagrant-puppet/files/etc/icinga2/conf.d/passive.conf b/.vagrant-puppet/files/etc/icinga2/conf.d/passive.conf index 84057c211..b9c741c2f 100644 --- a/.vagrant-puppet/files/etc/icinga2/conf.d/passive.conf +++ b/.vagrant-puppet/files/etc/icinga2/conf.d/passive.conf @@ -3,7 +3,9 @@ * in the conf.d directory (e.g. one per host). By default all *.conf * files in this directory are included. */ -object Host "nsca-ng" inherits "generic-host" { +object Host "nsca-ng" { + import "generic-host", + display_name = "nsca-ng test", services["PassiveService1"] = { @@ -15,4 +17,4 @@ object Host "nsca-ng" inherits "generic-host" { templates = [ "generic-service" ], check_command = "passive", }, -} \ No newline at end of file +} diff --git a/doc/3.02-commands.md b/doc/3.02-commands.md index 4f3cddc40..f64318bfc 100644 --- a/doc/3.02-commands.md +++ b/doc/3.02-commands.md @@ -59,7 +59,9 @@ then use these macros on the command line. > the service using the check command `disk`. The macros can also > be inherited from a parent template using additive inheritance (`+=`). - object CheckCommand "disk" inherits "plugin-check-command" { + object CheckCommand "disk" { + import "plugin-check-command", + command = [ "$plugindir$/check_disk", "-w", "$wfree$%", @@ -76,7 +78,8 @@ The host `localhost` with the service `disk` checks all disks with modified macros (warning thresholds at `10%`, critical thresholds at `5%` free disk space). - object Host "localhost" inherits "generic-host" { + object Host "localhost" { + import "generic-host", services["disk"] = { templates = [ "generic-service" ], @@ -112,7 +115,9 @@ notification itself (`email` macro attribute provided as `$USERMACRO$`). If you require default macro definitions, you can add a macro dictionary as shown for the `CheckCommand` object. - object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { + object NotificationCommand "mail-service-notification" { + import "plugin-notification-command", + command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ], export_macros = [ @@ -187,7 +192,9 @@ send a check result using the `process_check_result` script forcibly changing the service state back to `OK` (`-r 0`) providing some debug information in the check output (`-o`). - object EventCommand "plugin-event-process-check-result" inherits "plugin-event-command" { + object EventCommand "plugin-event-process-check-result" { + import "plugin-event-command", + command = [ "$plugindir$/process_check_result", "-H", diff --git a/doc/3.03-macros.md b/doc/3.03-macros.md index 6c1b67cdb..5880ef3ab 100644 --- a/doc/3.03-macros.md +++ b/doc/3.03-macros.md @@ -21,7 +21,9 @@ using the available runtime macros for output formatting. Here is an example of a command definition which uses user-defined macros: - object CheckCommand "my-ping" inherits "plugin-check-command" { + object CheckCommand "my-ping" { + import "plugin-check-command", + command = [ "$plugindir$/check_ping", "-4", @@ -126,8 +128,10 @@ Node 2: CheckCommand definition: - object CheckCommand "whatever" inherits "plugin-check-command" { - command = "$plugindir$/check_whatever" + object CheckCommand "whatever" { + import "plugin-check-command", + + command = "$plugindir$/check_whatever" } On Node 1, this will be evaluated into `/usr/lib/icinga/plugins/check_whatever`. @@ -246,18 +250,20 @@ be exported as environment variables prior to executing the command. This is useful for example for hiding sensitive information on the command line output when passing credentials to database checks: - object CheckCommand "mysql-health" inherits "plugin-check-command" { - command = "$plugindir$/check_mysql -H $address$ -d $db$", - /* default macro values */ - macros = { - "MYSQLUSER" = "icinga_check", - "MYSQLPASS" = "1c1ng42r0xx" - }, + object CheckCommand "mysql-health" { + import "plugin-check-command", - export_macros = [ - "MYSQLUSER", - "MYSQLPASS" - ] + command = "$plugindir$/check_mysql -H $address$ -d $db$", + /* default macro values */ + macros = { + "MYSQLUSER" = "icinga_check", + "MYSQLPASS" = "1c1ng42r0xx" + }, + + export_macros = [ + "MYSQLUSER", + "MYSQLPASS" + ] } ### Configuration Macros diff --git a/doc/3.04-notifications.md b/doc/3.04-notifications.md index 86b8d820f..9a91a1a66 100644 --- a/doc/3.04-notifications.md +++ b/doc/3.04-notifications.md @@ -58,7 +58,9 @@ your environment. There are various macros available at runtime execution of the `NotificationCommand`. The example below may or may not fit your needs. - object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { + object NotificationCommand "mail-service-notification" { + import "plugin-notification-command", + command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ], export_macros = [ diff --git a/doc/3.05-using-templates.md b/doc/3.05-using-templates.md index 0cb0a403a..ad77951dc 100644 --- a/doc/3.05-using-templates.md +++ b/doc/3.05-using-templates.md @@ -15,11 +15,15 @@ configuration: check = "ping" } - object Host "my-server1" inherits "linux-server" { + object Host "my-server1" { + import "linux-server", + macros["address"] = "10.0.0.1" } - object Host "my-server2" inherits "linux-server" { + object Host "my-server2" { + import "linux-server", + macros["address"] = "10.0.0.2" } diff --git a/doc/3.06-groups.md b/doc/3.06-groups.md index 4e53e3389..8b3763c24 100644 --- a/doc/3.06-groups.md +++ b/doc/3.06-groups.md @@ -61,13 +61,17 @@ the user groups are associated as attributes in `Notification` objects. groups = [ "windows-mssql-admins" ] } - object User "win-mssql-noc" inherits "generic-windows-mssql-users" { + object User "win-mssql-noc" { + import "generic-windows-mssql-users", + macros = { "email" = "noc@company.com" } } - object User "win-mssql-ops" inherits "generic-windows-mssql-users" { + object User "win-mssql-ops" { + import "generic-windows-mssql-users", + macros = { "email" = "ops@company.com" } diff --git a/doc/3.07-time-periods.md b/doc/3.07-time-periods.md index 2ba56d154..a95a54402 100644 --- a/doc/3.07-time-periods.md +++ b/doc/3.07-time-periods.md @@ -31,7 +31,9 @@ If you don't set any `check_period` or `notification_period` attribute on your configuration objects Icinga 2 assumes `24x7` as time period as shown below. - object TimePeriod "24x7" inherits "legacy-timeperiod" { + object TimePeriod "24x7" { + import "legacy-timeperiod", + display_name = "Icinga 2 24x7 TimePeriod", ranges = { "monday" = "00:00-24:00", @@ -48,7 +50,9 @@ If your operation staff should only be notified during workhours create a new timeperiod named `workhours` defining a work day with 09:00 to 17:00. - object TimePeriod "workhours" inherits "legacy-timeperiod" { + object TimePeriod "workhours" { + import "legacy-timeperiod", + display_name = "Icinga 2 8x5 TimePeriod", ranges = { "monday" = "09:00-17:00", diff --git a/doc/3.15-monitoring-remote-clients.md b/doc/3.15-monitoring-remote-clients.md index 7a95dd76c..ab2ab5a2b 100644 --- a/doc/3.15-monitoring-remote-clients.md +++ b/doc/3.15-monitoring-remote-clients.md @@ -25,7 +25,9 @@ The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and only def additional macros (note the `+=` operator) as command parameters for the `oid` (`community` is already set): - object Host "remote-snmp-host" inherits "generic-host" { + object Host "remote-snmp-host" { + import "generic-host", + ... services["uptime"] = { templates = [ "generic-service" ], @@ -44,7 +46,9 @@ additional macros (note the `+=` operator) as command parameters for the `oid` Calling a plugin using the SSH protocol to execute a plugin on the remote server fetching its return code and output. `check_by_ssh` is available in the [Monitoring Plugins package](#setting-up-check-plugins). - object CheckCommand "check_by_ssh_swap" inherits "plugin-check-command" { + object CheckCommand "check_by_ssh_swap" { + import "plugin-check-command", + command = [ "$plugindir$/check_by_ssh", "-l", "remoteuser", "-H", "$address$", @@ -52,7 +56,9 @@ its return code and output. `check_by_ssh` is available in the [Monitoring Plugi ] } - object Host "remote-ssh-host" inherits "generic-host" { + object Host "remote-ssh-host" { + import "generic-host", + ... services["swap"] = { templates = [ "generic-service" ], @@ -82,14 +88,18 @@ remote client. Example: - object CheckCommand "check_nrpe" inherits "plugin-check-command" { + object CheckCommand "check_nrpe" { + import "plugin-check-command", + command = [ "$plugindir$/check_nrpe", "-H", "$address$", "-c", "$remote_nrpe_command$", ], } - object Host "remote-nrpe-host" inherits "generic-host" { + object Host "remote-nrpe-host" { + import "generic-host", + ... services["users"] = { templates = [ "generic-service" ], @@ -122,7 +132,9 @@ the required output and performance counters. Example: - object CheckCommand "check_nscp" inherits "plugin-check-command" { + object CheckCommand "check_nscp" { + import "plugin-check-command", + command = [ "$plugindir$/check_nt", "-H", "$address$", "-p", "$port$", @@ -138,7 +150,9 @@ Example: } } - object Host "remote-windows-host" inherits "generic-host" { + object Host "remote-windows-host" { + import "generic-host", + ... services["users"] = { templates = [ "generic-service" ], diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index 5dd7d9c01..516de5abf 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -317,11 +317,15 @@ Example: macros["color"] = "red" } - template Host "test-host" inherits "default-host" { + template Host "test-host" { + import "default-host", + macros["color"] = "blue" } - object Host "localhost" inherits "test-host" { + object Host "localhost" { + import "test-host", + macros["address"] = "127.0.0.1", macros["address6"] = "::1" } @@ -337,7 +341,7 @@ templates though in general they are. > `color` has the value `"blue"`. Parent objects are resolved in the order they're specified using the -`inherits` keyword. +`import` keyword. ### Disable/Override Objects and Attributes diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md index 0af7c07de..5eca34b3e 100644 --- a/doc/4.3-object-types.md +++ b/doc/4.3-object-types.md @@ -327,7 +327,9 @@ when notifications should be sent out. Example: - object TimePeriod "24x7" inherits "legacy-timeperiod" { + object TimePeriod "24x7" { + import "legacy-timeperiod", + display_name = "Icinga 2 24x7 TimePeriod", ranges = { "monday" = "00:00-24:00", @@ -431,7 +433,9 @@ defined here. Example: - object CheckCommand "check_snmp" inherits "plugin-check-command" { + object CheckCommand "check_snmp" { + import "plugin-check-command", + command = "$plugindir$/check_snmp -H $address$ -C $community$ -o $oid$", macros = { @@ -457,7 +461,9 @@ A notification command definition. Example: - object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { + object NotificationCommand "mail-service-notification" { + import "plugin-notification-command", + command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ], export_macros = [ @@ -497,7 +503,9 @@ An event command definition. Example: - object EventCommand "restart-httpd-event" inherits "plugin-event-command" { + object EventCommand "restart-httpd-event" { + import "plugin-event-command", + command = "/opt/bin/restart-httpd.sh", } diff --git a/doc/4.5-best-practice.md b/doc/4.5-best-practice.md index 04f69c6c5..0e495c8f0 100644 --- a/doc/4.5-best-practice.md +++ b/doc/4.5-best-practice.md @@ -81,7 +81,9 @@ does not fit everyone, split it into two. Or rather inherit that template into a new template, and override/disable unwanted values. - template Service "generic-service-disable-notifications" inherits "generic-service" { + template Service "generic-service-disable-notifications" { + import "generic-service", + notifications["mail-icingaadmin"] = null } @@ -201,8 +203,8 @@ downtimes through the template automatism. check = "ping4" } - object Host "localhost" inherits "linux-server" { - + object Host "localhost" { + import "linux-server", } diff --git a/doc/6.01-downtimes.md b/doc/6.01-downtimes.md index 6d2ab0b19..aa98de558 100644 --- a/doc/6.01-downtimes.md +++ b/doc/6.01-downtimes.md @@ -88,7 +88,9 @@ Example: } } - object Host "localhost" inherits "generic-host" { + object Host "localhost" { + import "generic-host", + ... services["load"] = { templates = [ "generic-service" ], @@ -99,4 +101,4 @@ Example: templates = [ "backup-downtime" ] } }, - } \ No newline at end of file + } diff --git a/doc/6.04-cluster.md b/doc/6.04-cluster.md index 4834cd58b..86b18cf71 100644 --- a/doc/6.04-cluster.md +++ b/doc/6.04-cluster.md @@ -210,7 +210,9 @@ If you require specific services to be only executed by one or more checker node within the cluster, you must define `authorities` as additional service object attribute. Required Endpoints must be defined as array. - object Host "dmz-host1" inherits "generic-host" { + object Host "dmz-host1" { + import "generic-host", + services["dmz-oracledb"] = { templates = [ "generic-service" ], authorities = [ "icinga-node-1" ], @@ -232,7 +234,9 @@ one or more configured nodes are not connected. Example: - object Host "icinga2a" inherits "generic-host" { + object Host "icinga2a" { + import "generic-host", + services["cluster"] = { templates = [ "generic-service" ], check_interval = 1m, diff --git a/doc/6.05-domains.md b/doc/6.05-domains.md index 157816c75..24b593d79 100644 --- a/doc/6.05-domains.md +++ b/doc/6.05-domains.md @@ -15,7 +15,9 @@ by any cluster event message, and could be checked by the local authority too pr a different state history. `icinga-node-dmz-2` still receives all cluster message updates from the `icinga-node-dmz-1` endpoint. - object Host "dmz-host1" inherits "generic-host" { + object Host "dmz-host1" { + import "generic-host", + services["dmz-oracledb"] = { templates = [ "generic-service" ], domains = [ "dmz-db" ], @@ -28,4 +30,4 @@ from the `icinga-node-dmz-1` endpoint. icinga-node-dmz-1 = DomainPrivReadOnly, icinga-node-dmz-2 = DomainPrivReadWrite } - } \ No newline at end of file + } diff --git a/doc/8-differences-between-icinga-1x-and-2.md b/doc/8-differences-between-icinga-1x-and-2.md index 82e7f60f4..b79f7fe12 100644 --- a/doc/8-differences-between-icinga-1x-and-2.md +++ b/doc/8-differences-between-icinga-1x-and-2.md @@ -123,15 +123,17 @@ uses the `template` identifier: template Service "ping4-template" { } Icinga 1.x objects inherit from templates using the `use` attribute. -Icinga 2 uses the keyword `inherits` after the object name and requires a -comma-separated list with template names in double quotes. +Icinga 2 uses the keyword `import` with template names in double quotes. define service { service_description testservice use tmpl1,tmpl2,tmpl3 } - object Service "testservice" inherits "tmpl1", "tmpl2", "tmpl3" { + object Service "testservice" { + import "tmpl1", + import "tmpl2", + import "tmpl3" } ## Object attributes @@ -375,7 +377,9 @@ The preferred way of assigning objects to groups is by using a template: } } - object Host "web-dev" inherits "dev-host" { } + object Host "web-dev" { + import "dev-host" + } Host groups in Icinga 2 cannot be used to associate services with all members of that group. The example above shows how to use templates to accomplish diff --git a/etc/icinga2/conf.d/generic-host.conf b/etc/icinga2/conf.d/generic-host.conf index 3094fd2cd..f0df83bdf 100644 --- a/etc/icinga2/conf.d/generic-host.conf +++ b/etc/icinga2/conf.d/generic-host.conf @@ -6,7 +6,9 @@ template Host "generic-host" { } -template Host "linux-server" inherits "generic-host" { +template Host "linux-server" { + import "generic-host", + groups += [ "linux-servers" ], services["ping4"] = { @@ -18,7 +20,9 @@ template Host "linux-server" inherits "generic-host" { check = "ping4" } -template Host "windows-server" inherits "generic-host" { +template Host "windows-server" { + import "generic-host", + groups += [ "windows-servers" ], services["ping4"] = { @@ -30,7 +34,9 @@ template Host "windows-server" inherits "generic-host" { check = "ping4" } -template Host "generic-printer" inherits "generic-host" { +template Host "generic-printer" { + import "generic-host", + services["ping4"] = { templates = [ "generic-service" ], @@ -40,7 +46,9 @@ template Host "generic-printer" inherits "generic-host" { check = "ping4" } -template Host "generic-switch" inherits "generic-host" { +template Host "generic-switch" { + import "generic-host", + services["ping4"] = { templates = [ "generic-service" ], diff --git a/etc/icinga2/conf.d/localhost.conf b/etc/icinga2/conf.d/localhost.conf index 807011582..0d64eeaa2 100644 --- a/etc/icinga2/conf.d/localhost.conf +++ b/etc/icinga2/conf.d/localhost.conf @@ -3,7 +3,9 @@ * in the conf.d directory (e.g. one per host). By default all *.conf * files in this directory are included. */ -object Host "localhost" inherits "linux-server" { +object Host "localhost" { + import "linux-server", + display_name = "localhost", services["icinga"] = { diff --git a/etc/icinga2/conf.d/notifications.conf b/etc/icinga2/conf.d/notifications.conf index 5bd59810c..79d363a2d 100644 --- a/etc/icinga2/conf.d/notifications.conf +++ b/etc/icinga2/conf.d/notifications.conf @@ -22,7 +22,9 @@ template Notification "mail-notification" { notification_period = "24x7" } -object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { +object NotificationCommand "mail-service-notification" { + import "plugin-notification-command", + command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ], export_macros = [ diff --git a/etc/icinga2/conf.d/timeperiods.conf b/etc/icinga2/conf.d/timeperiods.conf index 2f870062e..1b62306d8 100644 --- a/etc/icinga2/conf.d/timeperiods.conf +++ b/etc/icinga2/conf.d/timeperiods.conf @@ -3,7 +3,9 @@ * 'legacy-timeperiod' template from the ITL. */ -object TimePeriod "24x7" inherits "legacy-timeperiod" { +object TimePeriod "24x7" { + import "legacy-timeperiod", + display_name = "Icinga 2 24x7 TimePeriod", ranges = { "monday" = "00:00-24:00", @@ -16,7 +18,9 @@ object TimePeriod "24x7" inherits "legacy-timeperiod" { } } -object TimePeriod "9to5" inherits "legacy-timeperiod" { +object TimePeriod "9to5" { + import "legacy-timeperiod", + display_name = "Icinga 2 9to5 TimePeriod", ranges = { "monday" = "09:00-17:00", @@ -27,7 +31,9 @@ object TimePeriod "9to5" inherits "legacy-timeperiod" { } } -object TimePeriod "never" inherits "legacy-timeperiod" { +object TimePeriod "never" { + import "legacy-timeperiod", + display_name = "Icinga 2 never TimePeriod", ranges = { } diff --git a/etc/icinga2/conf.d/users.conf b/etc/icinga2/conf.d/users.conf index 953a9b903..4e427adcb 100644 --- a/etc/icinga2/conf.d/users.conf +++ b/etc/icinga2/conf.d/users.conf @@ -3,7 +3,9 @@ * group 'icingaadmins'. */ -object User "icingaadmin" inherits "generic-user" { +object User "icingaadmin" { + import "generic-user", + display_name = "Icinga 2 Admin", groups = [ "icingaadmins" ], diff --git a/itl/command-common.conf b/itl/command-common.conf index 71e5e9b89..8c54cca8c 100644 --- a/itl/command-common.conf +++ b/itl/command-common.conf @@ -17,7 +17,9 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -object CheckCommand "ping4" inherits "plugin-check-command" { +object CheckCommand "ping4" { + import "plugin-check-command", + command = [ "$plugindir$/check_ping", "-4", @@ -40,7 +42,9 @@ object CheckCommand "ping4" inherits "plugin-check-command" { } } -object CheckCommand "ping6" inherits "plugin-check-command" { +object CheckCommand "ping6" { + import "plugin-check-command", + command = [ "$plugindir$/check_ping", "-6", @@ -63,7 +67,9 @@ object CheckCommand "ping6" inherits "plugin-check-command" { } } -object CheckCommand "dummy" inherits "plugin-check-command" { +object CheckCommand "dummy" { + import "plugin-check-command", + command = [ "$plugindir$/check_dummy", "$state$", @@ -76,14 +82,18 @@ object CheckCommand "dummy" inherits "plugin-check-command" { } } -object CheckCommand "passive" inherits "dummy" { +object CheckCommand "passive" { + import "dummy", + macros = { state = 3, text = "No Passive Check Result Received." } } -object CheckCommand "tcp" inherits "plugin-check-command" { +object CheckCommand "tcp" { + import "plugin-check-command", + command = [ "$plugindir$/check_tcp", "-H", "$address$", @@ -91,7 +101,9 @@ object CheckCommand "tcp" inherits "plugin-check-command" { ] } -object CheckCommand "udp" inherits "plugin-check-command" { +object CheckCommand "udp" { + import "plugin-check-command", + command = [ "$plugindir$/check_udp", "-H", "$address$", @@ -99,42 +111,54 @@ object CheckCommand "udp" inherits "plugin-check-command" { ] } -object CheckCommand "http_vhost" inherits "plugin-check-command" { +object CheckCommand "http_vhost" { + import "plugin-check-command", + command = [ "$plugindir$/check_http", "-H", "$vhost$" ] } -object CheckCommand "http_ip" inherits "plugin-check-command" { +object CheckCommand "http_ip" { + import "plugin-check-command", + command = [ "$plugindir$/check_http", "-H", "$address$" ] } -object CheckCommand "https_vhost" inherits "plugin-check-command" { +object CheckCommand "https_vhost" { + import "plugin-check-command", + command = [ "$plugindir$/check_http", "-H", "$vhost$", "-S" ] } -object CheckCommand "https_ip" inherits "plugin-check-command" { +object CheckCommand "https_ip" { + import "plugin-check-command", + command = [ "$plugindir$/check_http", "-I", "$address$", "-S" ] } -object CheckCommand "smtp" inherits "plugin-check-command" { +object CheckCommand "smtp" { + import "plugin-check-command", + command = [ "$plugindir$/check_smtp", "-H", "$address$" ] } -object CheckCommand "ssmtp" inherits "plugin-check-command" { +object CheckCommand "ssmtp" { + import "plugin-check-command", + command = [ "$plugindir$/check_ssmtp", "-H", "$address$", @@ -146,21 +170,27 @@ object CheckCommand "ssmtp" inherits "plugin-check-command" { } } -object CheckCommand "ntp_time" inherits "plugin-check-command" { +object CheckCommand "ntp_time" { + import "plugin-check-command", + command = [ "$plugindir$/check_ntp_time", "-H", "$address$" ] } -object CheckCommand "ssh" inherits "plugin-check-command" { +object CheckCommand "ssh" { + import "plugin-check-command", + command = [ "$plugindir$/check_ssh", "$address$" ] } -object CheckCommand "disk" inherits "plugin-check-command" { +object CheckCommand "disk" { + import "plugin-check-command", + command = [ "$plugindir$/check_disk", "-w", "$wfree$%", @@ -173,7 +203,9 @@ object CheckCommand "disk" inherits "plugin-check-command" { } } -object CheckCommand "users" inherits "plugin-check-command" { +object CheckCommand "users"{ + import "plugin-check-command", + command = [ "$plugindir$/check_users", "-w", "$wgreater$", @@ -186,7 +218,9 @@ object CheckCommand "users" inherits "plugin-check-command" { } } -object CheckCommand "processes" inherits "plugin-check-command" { +object CheckCommand "processes"{ + import "plugin-check-command", + command = [ "$plugindir$/check_procs", "-w", "$wgreater$", @@ -199,7 +233,9 @@ object CheckCommand "processes" inherits "plugin-check-command" { } } -object CheckCommand "load" inherits "plugin-check-command" { +object CheckCommand "load"{ + import "plugin-check-command", + command = [ "$plugindir$/check_load", "-w", "$wload1$,$wload5$,$wload15$", @@ -217,7 +253,9 @@ object CheckCommand "load" inherits "plugin-check-command" { } } -object CheckCommand "snmp" inherits "plugin-check-command" { +object CheckCommand "snmp"{ + import "plugin-check-command", + command = [ "$plugindir$/check_snmp", "-H", "$address$", @@ -230,19 +268,27 @@ object CheckCommand "snmp" inherits "plugin-check-command" { } } -object CheckCommand "snmp-uptime" inherits "snmp" { +object CheckCommand "snmp-uptime"{ + import "snmp", + macros += { oid = "1.3.6.1.2.1.1.3.0" } } -object CheckCommand "icinga" inherits "icinga-check-command" { +object CheckCommand "icinga"{ + import "icinga-check-command", + } -object CheckCommand "cluster" inherits "cluster-check-command" { +object CheckCommand "cluster"{ + import "cluster-check-command", + } -object CheckCommand "snmp-extend" inherits "plugin-check-command" { +object CheckCommand "snmp-extend"{ + import "plugin-check-command", + command = [ IcingaSysconfDir + "/icinga2/scripts/snmp-extend.sh", "$HOSTADDRESS$", diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index c1f1b3a66..09b055ec8 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -19,6 +19,7 @@ #include "config/aexpression.h" #include "config/configerror.h" +#include "config/configitem.h" #include "base/array.h" #include "base/serializer.h" #include "base/context.h" @@ -459,3 +460,18 @@ Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& loc return dict->Get(expr->m_Operand2); } + +Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value type = expr->EvaluateOperand1(locals); + Value name = expr->EvaluateOperand2(locals); + + ConfigItem::Ptr item = ConfigItem::GetObject(type, name); + + if (!item) + BOOST_THROW_EXCEPTION(ConfigError("Import references unknown template: '" + name + "'")); + + item->GetExpressionList()->Evaluate(locals); + + return Empty; +} diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index 6a0236205..05bf14500 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -79,6 +79,7 @@ public: static Value OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpImport(const AExpression *expr, const Dictionary::Ptr& locals); private: OpCallback m_Operator; diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 06e116113..4d28b0974 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -224,6 +224,7 @@ const return T_CONST; apply return T_APPLY; to return T_TO; where return T_WHERE; +import return T_IMPORT; \<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; } \>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; } \<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 95cea330a..69e716e63 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -144,6 +144,7 @@ using namespace icinga; %token T_APPLY "apply (T_APPLY)" %token T_TO "to (T_TO)" %token T_WHERE "where (T_WHERE)" +%token T_IMPORT "import (T_IMPORT)" %type identifier %type rterm_items %type rterm_items_inner @@ -154,8 +155,6 @@ using namespace icinga; %type rbinary_op %type type %type partial_specifier -%type object_inherits_list -%type object_inherits_specifier %type rterm %type rterm_scope %type lterm @@ -411,9 +410,9 @@ object: { m_Abstract = false; } - object_declaration identifier rterm object_inherits_specifier rterm_scope + object_declaration identifier rterm rterm_scope { - DebugInfo di = DebugInfoRange(@2, @6); + DebugInfo di = DebugInfoRange(@2, @5); ConfigItemBuilder::Ptr item = make_shared(di); AExpression::Ptr aexpr = static_cast(*$4); @@ -444,16 +443,8 @@ object: item->SetName(name); - if ($5) { - BOOST_FOREACH(const String& parent, *$5) { - item->AddParent(parent); - } - - delete $5; - } - - AExpression::Ptr exprl = static_cast(*$6); - delete $6; + AExpression::Ptr exprl = static_cast(*$5); + delete $5; exprl->MakeInline(); item->AddExpression(exprl); @@ -473,38 +464,6 @@ object_declaration: T_OBJECT m_Abstract = true; } -object_inherits_list: - { - $$ = NULL; - } - | T_STRING - { - $$ = new std::vector(); - $$->push_back($1); - free($1); - } - | object_inherits_list ',' T_STRING - { - if ($1) - $$ = $1; - else - $$ = new std::vector(); - - $$->push_back($3); - free($3); - } - ; - -object_inherits_specifier: - { - $$ = NULL; - } - | T_INHERITS object_inherits_list - { - $$ = $2; - } - ; - lbinary_op: T_SET | T_SET_PLUS | T_SET_MINUS @@ -661,6 +620,13 @@ rterm: T_STRING $$ = new Value(make_shared(&AExpression::OpFunctionCall, $1, make_shared(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4))); free($1); } + | T_IMPORT rterm + { + AExpression::Ptr avar = make_shared(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2)); + AExpression::Ptr aexpr = static_cast(*$2); + delete $2; + $$ = new Value(make_shared(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2))); + } | T_IDENTIFIER { $$ = new Value(make_shared(&AExpression::OpVariable, $1, @1)); diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 8668dbf3c..dbdfaee99 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -44,15 +44,13 @@ ConfigItem::ItemMap ConfigItem::m_Items; * @param unit The unit of the item. * @param abstract Whether the item is a template. * @param exprl Expression list for the item. - * @param parents Parent objects for the item. * @param debuginfo Debug information. */ ConfigItem::ConfigItem(const String& type, const String& name, bool abstract, const AExpression::Ptr& exprl, - const std::vector& parents, const DebugInfo& debuginfo, - const Dictionary::Ptr& scope) + const DebugInfo& debuginfo, const Dictionary::Ptr& scope) : m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false), - m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo), + m_ExpressionList(exprl), m_DebugInfo(debuginfo), m_Scope(scope) { } @@ -112,42 +110,6 @@ AExpression::Ptr ConfigItem::GetExpressionList(void) const return m_ExpressionList; } -AExpression::Ptr ConfigItem::GetLinkedExpressionList(void) -{ - ASSERT(OwnsLock()); - - if (m_LinkedExpressionList) - return m_LinkedExpressionList; - - Array::Ptr subexprs = make_shared(); - - BOOST_FOREACH(const String& name, m_ParentNames) { - ConfigItem::Ptr parent = ConfigItem::GetObject(m_Type, name); - - if (!parent) { - std::ostringstream message; - message << "Parent object '" << name << "' does not" - " exist (" << m_DebugInfo << ")"; - ConfigCompilerContext::GetInstance()->AddMessage(true, message.str(), m_DebugInfo); - } else { - AExpression::Ptr pexprl; - - { - ObjectLock olock(parent); - pexprl = parent->GetLinkedExpressionList(); - } - - subexprs->Add(pexprl); - } - } - - subexprs->Add(m_ExpressionList); - - m_LinkedExpressionList = make_shared(&AExpression::OpDict, subexprs, true, m_DebugInfo); - - return m_LinkedExpressionList; -} - Dictionary::Ptr ConfigItem::GetProperties(void) { ASSERT(OwnsLock()); @@ -155,7 +117,7 @@ Dictionary::Ptr ConfigItem::GetProperties(void) if (!m_Properties) { m_Properties = make_shared(); m_Properties->Set("__parent", m_Scope); - GetLinkedExpressionList()->Evaluate(m_Properties); + GetExpressionList()->Evaluate(m_Properties); m_Properties->Remove("__parent"); VERIFY(m_Properties->Get("__type") == GetType() && m_Properties->Get("__name") == GetName()); diff --git a/lib/config/configitem.h b/lib/config/configitem.h index 7af2918dc..09f1c33d8 100644 --- a/lib/config/configitem.h +++ b/lib/config/configitem.h @@ -45,8 +45,8 @@ public: DECLARE_PTR_TYPEDEFS(ConfigItem); ConfigItem(const String& type, const String& name, bool abstract, - const AExpression::Ptr& exprl, const std::vector& parents, - const DebugInfo& debuginfo, const Dictionary::Ptr& scope); + const AExpression::Ptr& exprl, const DebugInfo& debuginfo, + const Dictionary::Ptr& scope); String GetType(void) const; String GetName(void) const; @@ -54,7 +54,7 @@ public: std::vector GetParents(void) const; - AExpression::Ptr GetLinkedExpressionList(void); + AExpression::Ptr GetExpressionList(void) const; Dictionary::Ptr GetProperties(void); DynamicObject::Ptr Commit(void); @@ -74,8 +74,6 @@ public: static void DiscardItems(void); private: - AExpression::Ptr GetExpressionList(void) const; - String m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether this is a template. */ @@ -88,8 +86,6 @@ private: DebugInfo m_DebugInfo; /**< Debug information. */ Dictionary::Ptr m_Scope; /**< variable scope. */ - AExpression::Ptr m_LinkedExpressionList; - DynamicObject::Ptr m_Object; static boost::mutex m_Mutex; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index dbae3768e..18ea4e939 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -60,11 +60,6 @@ void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope) m_Scope = scope; } -void ConfigItemBuilder::AddParent(const String& parent) -{ - m_Parents.push_back(parent); -} - void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr) { m_Expressions->Add(expr); @@ -90,18 +85,13 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); } - BOOST_FOREACH(const String& parent, m_Parents) { - if (parent == m_Name) - BOOST_THROW_EXCEPTION(std::invalid_argument("Configuration item '" + m_Name + "' of type '" + m_Type + "' must not inherit from itself.")); - } - Array::Ptr exprs = make_shared(); exprs->Add(make_shared(&AExpression::OpSet, "__type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); - exprs->Add(make_shared(&AExpression::OpSet, "__name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "__name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); return make_shared(m_Type, m_Name, m_Abstract, exprl, - m_Parents, m_DebugInfo, m_Scope); + m_DebugInfo, m_Scope); } diff --git a/lib/config/configitembuilder.h b/lib/config/configitembuilder.h index 74fa75df6..14537f1d8 100644 --- a/lib/config/configitembuilder.h +++ b/lib/config/configitembuilder.h @@ -47,8 +47,6 @@ public: void SetAbstract(bool abstract); void SetScope(const Dictionary::Ptr& scope); - void AddParent(const String& parent); - void AddExpression(const AExpression::Ptr& expr); ConfigItem::Ptr Compile(void); @@ -57,8 +55,6 @@ private: String m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether the item is abstract. */ - std::vector m_Parents; /**< The names of parent configuration - items. */ Array::Ptr m_Expressions; /**< Expressions for this item. */ DebugInfo m_DebugInfo; /**< Debug information. */ Dictionary::Ptr m_Scope; /**< variable scope. */ diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp index 010987ba4..fd48006cb 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -49,8 +49,10 @@ void Host::EvaluateApplyRules(const std::vector& rules) locals->Set("hostgroups", groups); BOOST_FOREACH(const ApplyRule& rule, rules) { + DebugInfo di = rule.GetDebugInfo(); + std::ostringstream msgbuf; - msgbuf << "Evaluating 'apply' rule (" << rule.GetDebugInfo() << ")"; + msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); Value result = rule.GetExpression()->Evaluate(locals); @@ -60,27 +62,30 @@ void Host::EvaluateApplyRules(const std::vector& rules) continue; } catch (...) { std::ostringstream msgbuf; - msgbuf << "Apply rule (" << rule.GetDebugInfo() << ") returned invalid data type, expected bool: " + JsonSerialize(result); + msgbuf << "Apply rule (" << di << ") returned invalid data type, expected bool: " + JsonSerialize(result); Log(LogCritical, "icinga", msgbuf.str()); continue; } std::ostringstream msgbuf2; - msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << rule.GetDebugInfo(); + msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << di; Log(LogDebug, "icinga", msgbuf2.str()); std::ostringstream namebuf; namebuf << host->GetName() << "!apply!" << rule.GetTemplate(); String name = namebuf.str(); - ConfigItemBuilder::Ptr builder = make_shared(rule.GetDebugInfo()); + ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Service"); builder->SetName(name); builder->SetScope(rule.GetScope()); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, host->GetName(), rule.GetDebugInfo()), rule.GetDebugInfo())); - builder->AddParent(rule.GetTemplate()); + AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Service", di); + AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, rule.GetTemplate(), di); + builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); + + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, host->GetName(), di), di)); ConfigItem::Ptr serviceItem = builder->Compile(); serviceItem->Register(); diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 386605473..2306c762a 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -118,7 +118,7 @@ void Host::UpdateSlaveServices(void) { ObjectLock ilock(item); - exprl = item->GetLinkedExpressionList(); + exprl = item->GetExpressionList(); } DebugInfo di; @@ -130,12 +130,6 @@ void Host::UpdateSlaveServices(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Service"); builder->SetName(name); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "display_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); - - if (!kv.second.IsObjectType()) - BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary.")); Dictionary::Ptr service = kv.second; @@ -145,10 +139,19 @@ void Host::UpdateSlaveServices(void) ObjectLock olock(templates); BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); + AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Service", di); + AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); + builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); } } + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "display_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); + + if (!kv.second.IsObjectType()) + BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary.")); + /* Clone attributes from the service expression list. */ Array::Ptr svc_exprl = make_shared(); exprl->ExtractPath(path, svc_exprl); diff --git a/lib/icinga/service-dependency.cpp b/lib/icinga/service-dependency.cpp index 36b455bee..ea41d83c6 100644 --- a/lib/icinga/service-dependency.cpp +++ b/lib/icinga/service-dependency.cpp @@ -198,7 +198,7 @@ void Service::UpdateSlaveDependencies(void) { ObjectLock ilock(item); - exprl = item->GetLinkedExpressionList(); + exprl = item->GetExpressionList(); } DebugInfo di; @@ -210,8 +210,7 @@ void Service::UpdateSlaveDependencies(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Dependency"); builder->SetName(name); - builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); + Dictionary::Ptr dependency = kv.second; @@ -221,10 +220,15 @@ void Service::UpdateSlaveDependencies(void) ObjectLock tlock(templates); BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); + AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Dependency", di); + AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); + builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); } } + builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); + /* Clone attributes from the scheduled downtime expression list. */ Array::Ptr sd_exprl = make_shared(); exprl->ExtractPath(path, sd_exprl); diff --git a/lib/icinga/service-downtime.cpp b/lib/icinga/service-downtime.cpp index d914284a4..aa11fd797 100644 --- a/lib/icinga/service-downtime.cpp +++ b/lib/icinga/service-downtime.cpp @@ -347,7 +347,7 @@ void Service::UpdateSlaveScheduledDowntimes(void) { ObjectLock ilock(item); - exprl = item->GetLinkedExpressionList(); + exprl = item->GetExpressionList(); } DebugInfo di; @@ -359,8 +359,6 @@ void Service::UpdateSlaveScheduledDowntimes(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("ScheduledDowntime"); builder->SetName(name); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); Dictionary::Ptr scheduledDowntime = kv.second; @@ -370,10 +368,15 @@ void Service::UpdateSlaveScheduledDowntimes(void) ObjectLock tlock(templates); BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); + AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "ScheduledDowntime", di); + AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); + builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); } } + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); + /* Clone attributes from the scheduled downtime expression list. */ Array::Ptr sd_exprl = make_shared(); exprl->ExtractPath(path, sd_exprl); diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 5fb711aa4..6a4942ac9 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -126,7 +126,7 @@ void Service::UpdateSlaveNotifications(void) { ObjectLock ilock(item); - exprl = item->GetLinkedExpressionList(); + exprl = item->GetExpressionList(); } DebugInfo di; @@ -138,8 +138,6 @@ void Service::UpdateSlaveNotifications(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Notification"); builder->SetName(name); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); Dictionary::Ptr notification = kv.second; @@ -149,10 +147,15 @@ void Service::UpdateSlaveNotifications(void) ObjectLock tlock(templates); BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); + AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Notification", di); + AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); + builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); } } + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); + /* Clone attributes from the notification expression list. */ Array::Ptr nfc_exprl = make_shared(); exprl->ExtractPath(path, nfc_exprl); diff --git a/test/jenkins/files/configs/eventhandler.conf b/test/jenkins/files/configs/eventhandler.conf index 308f833b5..54e52523a 100644 --- a/test/jenkins/files/configs/eventhandler.conf +++ b/test/jenkins/files/configs/eventhandler.conf @@ -1,4 +1,6 @@ -object EventCommand "test_event" inherits "plugin-event-command" { +object EventCommand "test_event" { + import "plugin-event-command", + command = {{{echo "\ $$HOSTNAME$HOSTNAME$\ |HOSTNAME=$HOSTNAME$\ diff --git a/test/jenkins/files/configs/notifications.conf b/test/jenkins/files/configs/notifications.conf index 1c6a0ae5a..b30d57f4d 100644 --- a/test/jenkins/files/configs/notifications.conf +++ b/test/jenkins/files/configs/notifications.conf @@ -24,7 +24,9 @@ template Notification "mail-notification" { /** * 1:1 copy of the default command */ -object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { +object NotificationCommand "mail-service-notification" { + import "plugin-notification-command", + command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ], export_macros = [ From de81baf515d45f3d3892cea25759d21970a07529 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 11:21:59 +0100 Subject: [PATCH 02/25] Remove inline service/notification/downtime definitions. Refs #5875 --- lib/config/aexpression.cpp | 60 ------------------- lib/config/aexpression.h | 2 - lib/icinga/host.cpp | 77 ------------------------ lib/icinga/host.h | 2 - lib/icinga/icinga-type.conf | 55 ------------------ lib/icinga/service-dependency.cpp | 90 ----------------------------- lib/icinga/service-downtime.cpp | 70 ---------------------- lib/icinga/service-notification.cpp | 71 ----------------------- lib/icinga/service.cpp | 4 -- lib/icinga/service.h | 6 -- 10 files changed, 437 deletions(-) diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 09b055ec8..307c05d80 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -53,66 +53,6 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const } } -void AExpression::ExtractPath(const std::vector& path, const Array::Ptr& result) const -{ - ASSERT(!path.empty()); - - if (m_Operator == &AExpression::OpDict) { - Array::Ptr exprl = m_Operand1; - ObjectLock olock(exprl); - BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { - expr->ExtractPath(path, result); - } - } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus || - m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply || - m_Operator == &AExpression::OpSetDivide) && path[0] == m_Operand1) { - AExpression::Ptr exprl = m_Operand2; - - if (path.size() == 1) { - if (m_Operator == &AExpression::OpSet) - result->Clear(); - - if (exprl->m_Operator != &AExpression::OpDict) - BOOST_THROW_EXCEPTION(ConfigError("The '" + path[0] + "' attribute must be a dictionary.") << errinfo_debuginfo(m_DebugInfo)); - - Array::Ptr subexprl = exprl->m_Operand1; - ObjectLock olock(subexprl); - BOOST_FOREACH(const AExpression::Ptr& expr, subexprl) { - result->Add(expr); - } - - return; - } - - std::vector sub_path(path.begin() + 1, path.end()); - exprl->ExtractPath(sub_path, result); - } -} - -void AExpression::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const -{ - ASSERT(!path.empty()); - - if (m_Operator == &AExpression::OpDict) { - Array::Ptr exprl = m_Operand1; - ObjectLock olock(exprl); - BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { - expr->FindDebugInfoPath(path, result); - } - } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus || - m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply || - m_Operator == &AExpression::OpSetDivide) && path[0] == m_Operand1) { - AExpression::Ptr exprl = m_Operand2; - - if (path.size() == 1) { - result = m_DebugInfo; - } else { - std::vector sub_path(path.begin() + 1, path.end()); - exprl->FindDebugInfoPath(sub_path, result); - } - } -} - void AExpression::MakeInline(void) { if (m_Operator == &AExpression::OpDict) diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index 05bf14500..5ad540220 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -42,8 +42,6 @@ public: AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di); Value Evaluate(const Dictionary::Ptr& locals) const; - void ExtractPath(const std::vector& path, const Array::Ptr& result) const; - void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; void MakeInline(void); diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 2306c762a..cf40a2a06 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -57,8 +57,6 @@ void Host::OnConfigLoaded(void) hg->AddMember(GetSelf()); } } - - UpdateSlaveServices(); } void Host::Stop(void) @@ -92,81 +90,6 @@ bool Host::IsReachable(DependencyType dt, shared_ptr *failedDependen return hc->IsReachable(dt, failedDependency); } -void Host::UpdateSlaveServices(void) -{ - ASSERT(!OwnsLock()); - - Dictionary::Ptr service_descriptions = GetServiceDescriptions(); - - if (!service_descriptions ||service_descriptions->GetLength() == 0) - return; - - ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName()); - - ObjectLock olock(service_descriptions); - BOOST_FOREACH(const Dictionary::Pair& kv, service_descriptions) { - std::ostringstream namebuf; - namebuf << GetName() << "!" << kv.first; - String name = namebuf.str(); - - std::vector path; - path.push_back("services"); - path.push_back(kv.first); - - AExpression::Ptr exprl; - - { - ObjectLock ilock(item); - - exprl = item->GetExpressionList(); - } - - DebugInfo di; - exprl->FindDebugInfoPath(path, di); - - if (di.Path.IsEmpty()) - di = item->GetDebugInfo(); - - ConfigItemBuilder::Ptr builder = make_shared(di); - builder->SetType("Service"); - builder->SetName(name); - - Dictionary::Ptr service = kv.second; - - Array::Ptr templates = service->Get("templates"); - - if (templates) { - ObjectLock olock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Service", di); - AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); - builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); - } - } - - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "display_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); - - if (!kv.second.IsObjectType()) - BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary.")); - - /* Clone attributes from the service expression list. */ - Array::Ptr svc_exprl = make_shared(); - exprl->ExtractPath(path, svc_exprl); - - builder->AddExpression(make_shared(&AExpression::OpDict, svc_exprl, true, di)); - - builder->SetScope(item->GetScope()); - - ConfigItem::Ptr serviceItem = builder->Compile(); - serviceItem->Register(); - DynamicObject::Ptr dobj = serviceItem->Commit(); - dobj->OnConfigLoaded(); - } -} - std::set Host::GetServices(void) const { boost::mutex::scoped_lock lock(m_ServicesMutex); diff --git a/lib/icinga/host.h b/lib/icinga/host.h index c49fab286..bf1ae422e 100644 --- a/lib/icinga/host.h +++ b/lib/icinga/host.h @@ -114,8 +114,6 @@ private: mutable boost::mutex m_ServicesMutex; std::map > m_Services; - void UpdateSlaveServices(void); - static void RefreshServicesCache(void); }; diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index a969f9e59..79ce65faf 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -23,25 +23,6 @@ type Host { %attribute array "groups" { %attribute name(HostGroup) "*" }, - %attribute dictionary "services" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Service) "*" - }, - - %attribute any "*" - } - }, - - %attribute dictionary "dependencies" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Dependency) "*" - }, - - %attribute any "*" - } - }, %attribute dictionary "macros" { %attribute string "*" @@ -93,42 +74,10 @@ type Service { %attribute number "volatile", - %attribute dictionary "dependencies" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Dependency) "*" - }, - - %attribute any "*" - } - }, - %attribute array "groups" { %attribute name(ServiceGroup) "*" }, - %attribute dictionary "notifications" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Notification) "*" - }, - - %attribute any "*" - } - }, - - %attribute dictionary "scheduled_downtimes" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(ScheduledDowntime) "*" - }, - - %attribute any "*" - } - }, - - %attribute any "templates", - %attribute array "authorities" { %attribute name(Endpoint) "*" }, @@ -170,8 +119,6 @@ type Notification { %attribute number "notification_type_filter", %attribute number "notification_state_filter", - %attribute any "templates", - %attribute array "authorities" { %attribute name(Endpoint) "*" }, @@ -278,8 +225,6 @@ type ScheduledDowntime { %attribute dictionary "ranges" { %attribute string "*" }, - - %attribute any "templates" } type Dependency { diff --git a/lib/icinga/service-dependency.cpp b/lib/icinga/service-dependency.cpp index ea41d83c6..d17e99501 100644 --- a/lib/icinga/service-dependency.cpp +++ b/lib/icinga/service-dependency.cpp @@ -154,93 +154,3 @@ std::set Service::GetChildServices(void) const return parents; } -void Service::UpdateSlaveDependencies(void) -{ - /* - * pass == 0 -> steal host's dependency definitions - * pass == 1 -> service's dependencies - */ - for (int pass = 0; pass < 2; pass++) { - /* Service dependency descs */ - Dictionary::Ptr descs; - - if (pass == 0 && !IsHostCheck()) - continue; - - if (pass == 0) - descs = GetHost()->GetDependencyDescriptions(); - else - descs = GetDependencyDescriptions(); - - if (!descs || descs->GetLength() == 0) - continue; - - ConfigItem::Ptr item; - - if (pass == 0) - item = ConfigItem::GetObject("Host", GetHost()->GetName()); - else - item = ConfigItem::GetObject("Service", GetName()); - - ObjectLock olock(descs); - - BOOST_FOREACH(const Dictionary::Pair& kv, descs) { - std::ostringstream namebuf; - namebuf << GetName() << "!" << kv.first; - String name = namebuf.str(); - - std::vector path; - path.push_back("dependencies"); - path.push_back(kv.first); - - AExpression::Ptr exprl; - - { - ObjectLock ilock(item); - - exprl = item->GetExpressionList(); - } - - DebugInfo di; - exprl->FindDebugInfoPath(path, di); - - if (di.Path.IsEmpty()) - di = item->GetDebugInfo(); - - ConfigItemBuilder::Ptr builder = make_shared(di); - builder->SetType("Dependency"); - builder->SetName(name); - - - Dictionary::Ptr dependency = kv.second; - - Array::Ptr templates = dependency->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Dependency", di); - AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); - builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); - } - } - - builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); - - /* Clone attributes from the scheduled downtime expression list. */ - Array::Ptr sd_exprl = make_shared(); - exprl->ExtractPath(path, sd_exprl); - - builder->AddExpression(make_shared(&AExpression::OpDict, sd_exprl, true, di)); - - builder->SetScope(item->GetScope()); - - ConfigItem::Ptr dependencyItem = builder->Compile(); - dependencyItem->Register(); - DynamicObject::Ptr dobj = dependencyItem->Commit(); - dobj->OnConfigLoaded(); - } - } -} diff --git a/lib/icinga/service-downtime.cpp b/lib/icinga/service-downtime.cpp index aa11fd797..93df0d8e2 100644 --- a/lib/icinga/service-downtime.cpp +++ b/lib/icinga/service-downtime.cpp @@ -321,73 +321,3 @@ int Service::GetDowntimeDepth(void) const return downtime_depth; } -void Service::UpdateSlaveScheduledDowntimes(void) -{ - /* Service scheduled downtime descs */ - Dictionary::Ptr descs = GetScheduledDowntimeDescriptions(); - - if (!descs || descs->GetLength() == 0) - return; - - ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName()); - - ObjectLock olock(descs); - - BOOST_FOREACH(const Dictionary::Pair& kv, descs) { - std::ostringstream namebuf; - namebuf << GetName() << "!" << kv.first; - String name = namebuf.str(); - - std::vector path; - path.push_back("scheduled_downtimes"); - path.push_back(kv.first); - - AExpression::Ptr exprl; - - { - ObjectLock ilock(item); - - exprl = item->GetExpressionList(); - } - - DebugInfo di; - exprl->FindDebugInfoPath(path, di); - - if (di.Path.IsEmpty()) - di = item->GetDebugInfo(); - - ConfigItemBuilder::Ptr builder = make_shared(di); - builder->SetType("ScheduledDowntime"); - builder->SetName(name); - - Dictionary::Ptr scheduledDowntime = kv.second; - - Array::Ptr templates = scheduledDowntime->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "ScheduledDowntime", di); - AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); - builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); - } - } - - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); - - /* Clone attributes from the scheduled downtime expression list. */ - Array::Ptr sd_exprl = make_shared(); - exprl->ExtractPath(path, sd_exprl); - - builder->AddExpression(make_shared(&AExpression::OpDict, sd_exprl, true, di)); - - builder->SetScope(item->GetScope()); - - ConfigItem::Ptr scheduledDowntimeItem = builder->Compile(); - scheduledDowntimeItem->Register(); - DynamicObject::Ptr dobj = scheduledDowntimeItem->Commit(); - dobj->OnConfigLoaded(); - } -} diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 6a4942ac9..ed49fb8f8 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -100,77 +100,6 @@ void Service::RemoveNotification(const Notification::Ptr& notification) m_Notifications.erase(notification); } -void Service::UpdateSlaveNotifications(void) -{ - /* Service notification descs */ - Dictionary::Ptr descs = GetNotificationDescriptions(); - - if (!descs || descs->GetLength() == 0) - return; - - ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName()); - - ObjectLock olock(descs); - - BOOST_FOREACH(const Dictionary::Pair& kv, descs) { - std::ostringstream namebuf; - namebuf << GetName() << "!" << kv.first; - String name = namebuf.str(); - - std::vector path; - path.push_back("notifications"); - path.push_back(kv.first); - - AExpression::Ptr exprl; - - { - ObjectLock ilock(item); - - exprl = item->GetExpressionList(); - } - - DebugInfo di; - exprl->FindDebugInfoPath(path, di); - - if (di.Path.IsEmpty()) - di = item->GetDebugInfo(); - - ConfigItemBuilder::Ptr builder = make_shared(di); - builder->SetType("Notification"); - builder->SetName(name); - - Dictionary::Ptr notification = kv.second; - - Array::Ptr templates = notification->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Notification", di); - AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, tmpl, di); - builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); - } - } - - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); - - /* Clone attributes from the notification expression list. */ - Array::Ptr nfc_exprl = make_shared(); - exprl->ExtractPath(path, nfc_exprl); - - builder->AddExpression(make_shared(&AExpression::OpDict, nfc_exprl, true, di)); - - builder->SetScope(item->GetScope()); - - ConfigItem::Ptr notificationItem = builder->Compile(); - notificationItem->Register(); - DynamicObject::Ptr dobj = notificationItem->Commit(); - dobj->OnConfigLoaded(); - } -} - bool Service::GetEnableNotifications(void) const { if (!GetOverrideEnableNotifications().IsEmpty()) diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index a0c933cbd..c2b0de52c 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -76,10 +76,6 @@ void Service::OnConfigLoaded(void) if (m_Host) m_Host->AddService(GetSelf()); - UpdateSlaveNotifications(); - UpdateSlaveScheduledDowntimes(); - UpdateSlaveDependencies(); - SetSchedulingOffset(Utility::Random()); } diff --git a/lib/icinga/service.h b/lib/icinga/service.h index f4deaf5b7..3a76626f1 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -220,8 +220,6 @@ public: bool IsInDowntime(void) const; bool IsAcknowledged(void); - void UpdateSlaveScheduledDowntimes(void); - /* Comments */ static int GetNextCommentID(void); @@ -251,8 +249,6 @@ public: void ResetNotificationNumbers(void); - void UpdateSlaveNotifications(void); - /* Event Handler */ void ExecuteEventHandler(void); @@ -284,8 +280,6 @@ public: void RemoveReverseDependency(const shared_ptr& dep); std::set > GetReverseDependencies(void) const; - void UpdateSlaveDependencies(void); - protected: virtual void Start(void); From b28998750033c4501c1e1da6ae11df8a0b28861d Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 12:17:22 +0100 Subject: [PATCH 03/25] Implement the "." operator. Refs #5876 --- lib/config/aexpression.cpp | 33 ++++++++++++++++++++++++++------- lib/config/config_parser.yy | 34 +++++++++++++++++++++++++++------- lib/icinga/host-apply.cpp | 7 +------ 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 307c05d80..7df7e85e7 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -27,6 +27,7 @@ #include "base/scriptvariable.h" #include "base/utility.h" #include "base/objectlock.h" +#include "base/object.h" #include #include #include @@ -194,7 +195,9 @@ Value AExpression::OpIn(const AExpression *expr, const Dictionary::Ptr& locals) { Value right = expr->EvaluateOperand2(locals); - if (!right.IsObjectType()) + if (right.IsEmpty()) + return false; + else if (!right.IsObjectType()) BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right))); Value left = expr->EvaluateOperand1(locals); @@ -393,12 +396,28 @@ Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& l Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals) { - Dictionary::Ptr dict = OpVariable(expr, locals); - - if (!dict) - BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope.")); - - return dict->Get(expr->m_Operand2); + Value value = expr->EvaluateOperand1(locals); + Value index = expr->EvaluateOperand2(locals); + + if (value.IsObjectType()) { + Dictionary::Ptr dict = value; + return dict->Get(index); + } else if (value.IsObjectType()) { + Object::Ptr object = value; + const Type *type = object->GetReflectionType(); + + if (!type) + BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection")); + + int field = type->GetFieldId(index); + + if (field == -1) + BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'")); + + return object->GetField(field); + } else { + BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'")); + } } Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals) diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 69e716e63..6286d1c93 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -165,10 +165,11 @@ using namespace icinga; %left T_NOT_IN %nonassoc T_EQUAL %nonassoc T_NOT_EQUAL -%left '+' '-' -%left '*' '/' -%left '&' -%left '|' +%left T_PLUS T_MINUS +%left T_MULTIPLY T_DIVIDE_OP +%left T_BINARY_AND +%left T_BINARY_OR +%left '.' %right '~' %right '!' %{ @@ -528,6 +529,19 @@ lterm: identifier lbinary_op rterm $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6))); free($1); } + | identifier '.' T_IDENTIFIER lbinary_op rterm + { + AExpression::Ptr subexpr = make_shared($4, $3, static_cast(*$5), DebugInfoRange(@1, @5)); + free($3); + delete $5; + + Array::Ptr subexprl = make_shared(); + subexprl->Add(subexpr); + + AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5)); + $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @5))); + free($1); + } | rterm { $$ = $1; @@ -614,6 +628,12 @@ rterm: T_STRING { $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, @1)); } + | rterm '.' T_IDENTIFIER + { + $$ = new Value(make_shared(&AExpression::OpIndexer, static_cast(*$1), make_shared(&AExpression::OpLiteral, $3, @3), DebugInfoRange(@1, @3))); + delete $1; + free($3); + } | T_IDENTIFIER '(' rterm_items ')' { Array::Ptr arguments = Array::Ptr($3); @@ -642,10 +662,10 @@ rterm: T_STRING $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); delete $2; } - | identifier '[' T_STRING ']' + | rterm '[' rterm ']' { - $$ = new Value(make_shared(&AExpression::OpIndexer, $1, $3, DebugInfoRange(@1, @4))); - free($1); + $$ = new Value(make_shared(&AExpression::OpIndexer, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @4))); + delete $1; free($3); } | '[' rterm_items ']' diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp index fd48006cb..070824934 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -41,12 +41,7 @@ void Host::EvaluateApplyRules(const std::vector& rules) CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'"); Dictionary::Ptr locals = make_shared(); - locals->Set("host", host->GetName()); - - Array::Ptr groups = host->GetGroups(); - if (!groups) - groups = make_shared(); - locals->Set("hostgroups", groups); + locals->Set("host", host); BOOST_FOREACH(const ApplyRule& rule, rules) { DebugInfo di = rule.GetDebugInfo(); From 7ee12781184b35ae6478732d2a4d0025e59f9d12 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 13:25:40 +0100 Subject: [PATCH 04/25] Implement the new syntax for the "apply" keyword. Refs #5878 --- lib/config/aexpression.cpp | 5 +++ lib/config/aexpression.h | 1 + lib/config/applyrule.cpp | 38 +++++++++++------ lib/config/applyrule.h | 23 ++++++---- lib/config/config_lexer.ll | 3 +- lib/config/config_parser.yy | 84 +++++++++++++++++++++++++++---------- lib/icinga/host-apply.cpp | 24 +++-------- 7 files changed, 116 insertions(+), 62 deletions(-) diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 7df7e85e7..5e038e848 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -121,6 +121,11 @@ Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& loca return ~(long)expr->EvaluateOperand1(locals); } +Value AExpression::OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return !expr->EvaluateOperand1(locals).ToBool(); +} + Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals) { return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals); diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index 5ad540220..a51ce357b 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -50,6 +50,7 @@ public: static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals); diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index c31fd2b07..8556108c8 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -18,19 +18,21 @@ ******************************************************************************/ #include "config/applyrule.h" +#include "base/logger_fwd.h" using namespace icinga; ApplyRule::RuleMap ApplyRule::m_Rules; ApplyRule::CallbackMap ApplyRule::m_Callbacks; -ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) - : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di), m_Scope(scope) +ApplyRule::ApplyRule(const String& name, const AExpression::Ptr& expression, + const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope) + : m_Name(name), m_Expression(expression), m_Filter(filter), m_DebugInfo(di), m_Scope(scope) { } -String ApplyRule::GetTemplate(void) const +String ApplyRule::GetName(void) const { - return m_Template; + return m_Name; } AExpression::Ptr ApplyRule::GetExpression(void) const @@ -38,6 +40,11 @@ AExpression::Ptr ApplyRule::GetExpression(void) const return m_Expression; } +AExpression::Ptr ApplyRule::GetFilter(void) const +{ + return m_Filter; +} + DebugInfo ApplyRule::GetDebugInfo(void) const { return m_DebugInfo; @@ -48,30 +55,37 @@ Dictionary::Ptr ApplyRule::GetScope(void) const return m_Scope; } -void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) +void ApplyRule::AddRule(const String& sourceType, const String& name, + const AExpression::Ptr& expression, const AExpression::Ptr& filter, + const DebugInfo& di, const Dictionary::Ptr& scope) { - m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di, scope)); + m_Rules[sourceType].push_back(ApplyRule(name, expression, filter, di, scope)); +} + +bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const +{ + return m_Filter->Evaluate(scope); } void ApplyRule::EvaluateRules(void) { - std::pair kv; + std::pair > kv; BOOST_FOREACH(kv, m_Callbacks) { RuleMap::const_iterator it = m_Rules.find(kv.first); if (it == m_Rules.end()) continue; - kv.second(it->second); + kv.second.first(it->second); } } -void ApplyRule::RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback) +void ApplyRule::RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority) { - m_Callbacks[std::make_pair(sourceType, targetType)] = callback; + m_Callbacks[sourceType] = make_pair(callback, priority); } -bool ApplyRule::IsValidCombination(const String& sourceType, const String& targetType) +bool ApplyRule::IsValidType(const String& sourceType) { - return m_Callbacks.find(std::make_pair(sourceType, targetType)) != m_Callbacks.end(); + return m_Callbacks.find(sourceType) != m_Callbacks.end(); } diff --git a/lib/config/applyrule.h b/lib/config/applyrule.h index 3fba61006..b7eac024a 100644 --- a/lib/config/applyrule.h +++ b/lib/config/applyrule.h @@ -34,32 +34,37 @@ namespace icinga class I2_CONFIG_API ApplyRule { public: - typedef std::pair TypeCombination; typedef boost::function& rules)> Callback; - typedef std::map CallbackMap; - typedef std::map > RuleMap; + typedef std::map > CallbackMap; + typedef std::map > RuleMap; - String GetTemplate(void) const; + String GetName(void) const; AExpression::Ptr GetExpression(void) const; + AExpression::Ptr GetFilter(void) const; DebugInfo GetDebugInfo(void) const; Dictionary::Ptr GetScope(void) const; - static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); + bool EvaluateFilter(const Dictionary::Ptr& scope) const; + + static void AddRule(const String& sourceType, const String& name, const AExpression::Ptr& expression, + const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope); static void EvaluateRules(void); - static void RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback); - static bool IsValidCombination(const String& sourceType, const String& targetType); + static void RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority); + static bool IsValidType(const String& sourceType); private: - String m_Template; + String m_Name; AExpression::Ptr m_Expression; + AExpression::Ptr m_Filter; DebugInfo m_DebugInfo; Dictionary::Ptr m_Scope; static CallbackMap m_Callbacks; static RuleMap m_Rules; - ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); + ApplyRule(const String& tmpl, const AExpression::Ptr& expression, + const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope); }; } diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 4d28b0974..98f272ac3 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -222,9 +222,10 @@ set return T_VAR; var return T_VAR; const return T_CONST; apply return T_APPLY; -to return T_TO; where return T_WHERE; import return T_IMPORT; +assign return T_ASSIGN; +ignore return T_IGNORE; \<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; } \>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; } \<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 6286d1c93..dac3daa08 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -142,9 +142,10 @@ using namespace icinga; %token T_INHERITS "inherits (T_INHERITS)" %token T_PARTIAL "partial (T_PARTIAL)" %token T_APPLY "apply (T_APPLY)" -%token T_TO "to (T_TO)" %token T_WHERE "where (T_WHERE)" %token T_IMPORT "import (T_IMPORT)" +%token T_ASSIGN "assign (T_ASSIGN)" +%token T_IGNORE "ignore (T_IGNORE)" %type identifier %type rterm_items %type rterm_items_inner @@ -192,6 +193,10 @@ static ConfigType::Ptr m_Type; static Dictionary::Ptr m_ModuleScope; +static bool m_Apply; +static AExpression::Ptr m_Assign; +static AExpression::Ptr m_Ignore; + void ConfigCompiler::Compile(void) { m_ModuleScope = make_shared(); @@ -542,6 +547,34 @@ lterm: identifier lbinary_op rterm $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @5))); free($1); } + | T_IMPORT rterm + { + AExpression::Ptr avar = make_shared(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2)); + AExpression::Ptr aexpr = static_cast(*$2); + delete $2; + $$ = new Value(make_shared(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2))); + } + | T_ASSIGN T_WHERE rterm + { + if (!m_Apply) + BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context.")); + + m_Assign = make_shared(&AExpression::OpLogicalOr, m_Assign, static_cast(*$3), DebugInfoRange(@1, @3)); + delete $3; + + $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3))); + } + | T_IGNORE T_WHERE rterm + { + if (!m_Apply) + BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context.")); + + m_Ignore = make_shared(&AExpression::OpLogicalOr, m_Ignore, static_cast(*$3), DebugInfoRange(@1, @3)); + + delete $3; + + $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3))); + } | rterm { $$ = $1; @@ -640,13 +673,6 @@ rterm: T_STRING $$ = new Value(make_shared(&AExpression::OpFunctionCall, $1, make_shared(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4))); free($1); } - | T_IMPORT rterm - { - AExpression::Ptr avar = make_shared(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2)); - AExpression::Ptr aexpr = static_cast(*$2); - delete $2; - $$ = new Value(make_shared(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2))); - } | T_IDENTIFIER { $$ = new Value(make_shared(&AExpression::OpVariable, $1, @1)); @@ -654,7 +680,7 @@ rterm: T_STRING } | '!' rterm { - $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); + $$ = new Value(make_shared(&AExpression::OpLogicalNegate, static_cast(*$2), DebugInfoRange(@1, @2))); delete $2; } | '~' rterm @@ -688,22 +714,36 @@ rterm: T_STRING } ; -optional_template: /* empty */ - | T_TEMPLATE - ; - -apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE rterm +apply: { - if (!ApplyRule::IsValidCombination($3, $6)) { - BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'.") << errinfo_debuginfo(@1)); - } + m_Apply = true; + m_Assign = make_shared(&AExpression::OpLiteral, false, DebugInfo()); + m_Ignore = make_shared(&AExpression::OpLiteral, false, DebugInfo()); + } + T_APPLY identifier rterm rterm + { + m_Apply = false; - Array::Ptr arguments = make_shared(); - arguments->Add(*$8); - delete $8; + AExpression::Ptr aname = static_cast(*$4); + delete $4; + String type = $3; + free($3); + String name = aname->Evaluate(m_ModuleScope); - AExpression::Ptr aexpr = make_shared(&AExpression::OpFunctionCall, "bool", make_shared(&AExpression::OpLiteral, arguments, @8), @8); + if (!ApplyRule::IsValidType(type)) + BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(@2)); - ApplyRule::AddRule($3, $4, $6, aexpr, DebugInfoRange(@1, @8), m_ModuleScope); + AExpression::Ptr exprl = static_cast(*$5); + delete $5; + + exprl->MakeInline(); + + // assign && !ignore + AExpression::Ptr rex = make_shared(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5)); + AExpression::Ptr filter = make_shared(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5)); + ApplyRule::AddRule(type, name, exprl, filter, DebugInfoRange(@1, @5), m_ModuleScope); + + m_Assign.reset(); + m_Ignore.reset(); } %% diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp index 070824934..3fed31047 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -32,7 +32,7 @@ INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler); void Host::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules); + ApplyRule::RegisterType("Service", &Host::EvaluateApplyRules, 1); } void Host::EvaluateApplyRules(const std::vector& rules) @@ -50,25 +50,15 @@ void Host::EvaluateApplyRules(const std::vector& rules) msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); - Value result = rule.GetExpression()->Evaluate(locals); - - try { - if (!static_cast(result)) - continue; - } catch (...) { - std::ostringstream msgbuf; - msgbuf << "Apply rule (" << di << ") returned invalid data type, expected bool: " + JsonSerialize(result); - Log(LogCritical, "icinga", msgbuf.str()); - + if (!rule.EvaluateFilter(locals)) continue; - } std::ostringstream msgbuf2; - msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << di; + msgbuf2 << "Applying service '" << rule.GetName() << "' to host '" << host->GetName() << "' for rule " << di; Log(LogDebug, "icinga", msgbuf2.str()); std::ostringstream namebuf; - namebuf << host->GetName() << "!apply!" << rule.GetTemplate(); + namebuf << host->GetName() << "!" << rule.GetName(); String name = namebuf.str(); ConfigItemBuilder::Ptr builder = make_shared(di); @@ -76,11 +66,9 @@ void Host::EvaluateApplyRules(const std::vector& rules) builder->SetName(name); builder->SetScope(rule.GetScope()); - AExpression::Ptr atype = make_shared(&AExpression::OpLiteral, "Service", di); - AExpression::Ptr atmpl = make_shared(&AExpression::OpLiteral, rule.GetTemplate(), di); - builder->AddExpression(make_shared(&AExpression::OpImport, atype, atmpl, di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, host->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, rule.GetName(), di), di)); + builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); serviceItem->Register(); From 54063f0b9f66e1767494c30b213f2bacdfb0b2a0 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 13:52:29 +0100 Subject: [PATCH 05/25] Rename __name and __type properties. Refs #5870 --- components/checker/checker-type.conf | 2 +- components/cluster/cluster-type.conf | 16 +- components/compat/compat-type.conf | 22 +- .../db_ido_mysql/db_ido_mysql-type.conf | 16 +- .../db_ido_pgsql/db_ido_pgsql-type.conf | 16 +- components/demo/demo-type.conf | 2 +- components/livestatus/livestatus-type.conf | 12 +- .../notification/notification-type.conf | 2 +- components/perfdata/perfdata-type.conf | 14 +- lib/base/dynamicobject.ti | 4 +- lib/base/serializer.cpp | 6 +- lib/config/base-type.conf | 36 +-- lib/config/config_lexer.ll | 18 +- lib/config/config_parser.yy | 2 +- lib/config/configitem.cpp | 2 +- lib/config/configitembuilder.cpp | 4 +- lib/db_ido/db_ido-type.conf | 38 +-- lib/hello/hello-type.conf | 2 +- lib/icinga/icinga-type.conf | 226 +++++++++--------- lib/remote/remote-type.conf | 24 +- 20 files changed, 232 insertions(+), 232 deletions(-) diff --git a/components/checker/checker-type.conf b/components/checker/checker-type.conf index 5c02261a9..0880bb8f6 100644 --- a/components/checker/checker-type.conf +++ b/components/checker/checker-type.conf @@ -17,5 +17,5 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type CheckerComponent { +%type CheckerComponent { } diff --git a/components/cluster/cluster-type.conf b/components/cluster/cluster-type.conf index 71497cb2c..12f97f34b 100644 --- a/components/cluster/cluster-type.conf +++ b/components/cluster/cluster-type.conf @@ -17,22 +17,22 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type ClusterListener { - %attribute string "cert_path", +%type ClusterListener { + %attribute %string "cert_path", %require "cert_path", - %attribute string "key_path", + %attribute %string "key_path", %require "key_path", - %attribute string "ca_path", + %attribute %string "ca_path", %require "ca_path", - %attribute string "crl_path", + %attribute %string "crl_path", - %attribute string "bind_host", - %attribute string "bind_port", + %attribute %string "bind_host", + %attribute %string "bind_port", - %attribute array "peers" { + %attribute %array "peers" { %attribute name(Endpoint) "*" } } diff --git a/components/compat/compat-type.conf b/components/compat/compat-type.conf index d0a0271ca..a086dc440 100644 --- a/components/compat/compat-type.conf +++ b/components/compat/compat-type.conf @@ -17,23 +17,23 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type StatusDataWriter { - %attribute string "status_path", - %attribute string "objects_path", - %attribute number "update_interval" +%type StatusDataWriter { + %attribute %string "status_path", + %attribute %string "objects_path", + %attribute %number "update_interval" } -type ExternalCommandListener { - %attribute string "command_path" +%type ExternalCommandListener { + %attribute %string "command_path" } -type CompatLogger { +%type CompatLogger { %validator "ValidateRotationMethod", - %attribute string "log_dir", - %attribute string "rotation_method" + %attribute %string "log_dir", + %attribute %string "rotation_method" } -type CheckResultReader { - %attribute string "spool_dir" +%type CheckResultReader { + %attribute %string "spool_dir" } diff --git a/components/db_ido_mysql/db_ido_mysql-type.conf b/components/db_ido_mysql/db_ido_mysql-type.conf index 7ffa3df9d..74750efcb 100644 --- a/components/db_ido_mysql/db_ido_mysql-type.conf +++ b/components/db_ido_mysql/db_ido_mysql-type.conf @@ -17,15 +17,15 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type IdoMysqlConnection inherits DbConnection { - %attribute string "host", - %attribute number "port", +%type IdoMysqlConnection %inherits DbConnection { + %attribute %string "host", + %attribute %number "port", - %attribute string "user", - %attribute string "password", + %attribute %string "user", + %attribute %string "password", - %attribute string "database", + %attribute %string "database", - %attribute string "instance_name", - %attribute string "instance_description" + %attribute %string "instance_name", + %attribute %string "instance_description" } diff --git a/components/db_ido_pgsql/db_ido_pgsql-type.conf b/components/db_ido_pgsql/db_ido_pgsql-type.conf index 125b70e78..eb60db951 100644 --- a/components/db_ido_pgsql/db_ido_pgsql-type.conf +++ b/components/db_ido_pgsql/db_ido_pgsql-type.conf @@ -17,15 +17,15 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type IdoPgsqlConnection inherits DbConnection { - %attribute string "host", - %attribute number "port", +%type IdoPgsqlConnection %inherits DbConnection { + %attribute %string "host", + %attribute %number "port", - %attribute string "user", - %attribute string "password", + %attribute %string "user", + %attribute %string "password", - %attribute string "database", + %attribute %string "database", - %attribute string "instance_name", - %attribute string "instance_description" + %attribute %string "instance_name", + %attribute %string "instance_description" } diff --git a/components/demo/demo-type.conf b/components/demo/demo-type.conf index 60a726126..29eeac37a 100644 --- a/components/demo/demo-type.conf +++ b/components/demo/demo-type.conf @@ -17,5 +17,5 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type Demo { +%type Demo { } diff --git a/components/livestatus/livestatus-type.conf b/components/livestatus/livestatus-type.conf index adeeff805..ec4a2097c 100644 --- a/components/livestatus/livestatus-type.conf +++ b/components/livestatus/livestatus-type.conf @@ -17,14 +17,14 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type LivestatusListener { +%type LivestatusListener { %validator "ValidateSocketType", - %attribute string "socket_type", + %attribute %string "socket_type", - %attribute string "socket_path", - %attribute string "bind_host", - %attribute string "bind_port", + %attribute %string "socket_path", + %attribute %string "bind_host", + %attribute %string "bind_port", - %attribute string "compat_log_path", + %attribute %string "compat_log_path", } diff --git a/components/notification/notification-type.conf b/components/notification/notification-type.conf index 9acf6631f..bcb3f676b 100644 --- a/components/notification/notification-type.conf +++ b/components/notification/notification-type.conf @@ -17,5 +17,5 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type NotificationComponent { +%type NotificationComponent { } diff --git a/components/perfdata/perfdata-type.conf b/components/perfdata/perfdata-type.conf index 739f22dba..bc6a8479d 100644 --- a/components/perfdata/perfdata-type.conf +++ b/components/perfdata/perfdata-type.conf @@ -17,13 +17,13 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type PerfdataWriter { - %attribute string "perfdata_path", - %attribute string "format_template", - %attribute number "rotation_interval" +%type PerfdataWriter { + %attribute %string "perfdata_path", + %attribute %string "format_template", + %attribute %number "rotation_interval" } -type GraphiteWriter { - %attribute string "host", - %attribute string "port", +%type GraphiteWriter { + %attribute %string "host", + %attribute %string "port", } diff --git a/lib/base/dynamicobject.ti b/lib/base/dynamicobject.ti index c68aec7ad..eaab51266 100644 --- a/lib/base/dynamicobject.ti +++ b/lib/base/dynamicobject.ti @@ -3,8 +3,8 @@ namespace icinga abstract class DynamicObject { - [config] String __name (Name); - [config, get_protected] String __type (TypeName); + [config] String name (Name); + [config, get_protected] String type (TypeName); [config] Dictionary::Ptr methods; [config] Dictionary::Ptr custom; [config] Array::Ptr domains; diff --git a/lib/base/serializer.cpp b/lib/base/serializer.cpp index c28ca4280..76370f302 100644 --- a/lib/base/serializer.cpp +++ b/lib/base/serializer.cpp @@ -113,7 +113,7 @@ static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes) fields->Set(field.Name, Serialize(input->GetField(i), attributeTypes)); } - fields->Set("__type", type->GetName()); + fields->Set("type", type->GetName()); return fields; } @@ -151,7 +151,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary if (object) type = object->GetReflectionType(); else - type = Type::GetByName(input->Get("__type")); + type = Type::GetByName(input->Get("type")); if (!type) return object; @@ -230,7 +230,7 @@ Value icinga::Deserialize(const Object::Ptr& object, const Value& value, bool sa ASSERT(dict != NULL); - if (!dict->Contains("__type")) + if (!dict->Contains("type")) return DeserializeDictionary(dict, safe_mode, attributeTypes); return DeserializeObject(object, dict, safe_mode, attributeTypes); diff --git a/lib/config/base-type.conf b/lib/config/base-type.conf index d23c17b67..1dfdd0a77 100644 --- a/lib/config/base-type.conf +++ b/lib/config/base-type.conf @@ -17,40 +17,40 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type DynamicObject { - %require "__name", - %attribute string "__name", +%type DynamicObject { + %require "name", + %attribute %string "name", - %require "__type", - %attribute string "__type", + %require "type", + %attribute %string "type", - %attribute dictionary "methods", + %attribute %dictionary "methods", - %attribute dictionary "custom" { - %attribute string "*" + %attribute %dictionary "custom" { + %attribute %string "*" }, - %attribute array "domains" { - %attribute string "*" + %attribute %array "domains" { + %attribute %string "*" } } -type Logger { - %attribute string "severity" +%type Logger { + %attribute %string "severity" } -type FileLogger inherits Logger { +%type FileLogger %inherits Logger { %require "path", - %attribute string "path" + %attribute %string "path" } -type SyslogLogger inherits Logger { +%type SyslogLogger %inherits Logger { } -type Script { +%type Script { %require "language", - %attribute string "language", + %attribute %string "language", %require "code", - %attribute string "code" + %attribute %string "code" } diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 98f272ac3..ff23c3d83 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -197,23 +197,23 @@ static char *lb_steal(lex_buf *lb) [ \t\r\n] /* ignore whitespace */ { -type return T_TYPE; -dictionary { yylval->type = TypeDictionary; return T_TYPE_DICTIONARY; } -array { yylval->type = TypeArray; return T_TYPE_ARRAY; } -number { yylval->type = TypeNumber; return T_TYPE_NUMBER; } -string { yylval->type = TypeString; return T_TYPE_STRING; } -scalar { yylval->type = TypeScalar; return T_TYPE_SCALAR; } -any { yylval->type = TypeAny; return T_TYPE_ANY; } -name { yylval->type = TypeName; return T_TYPE_NAME; } +%type return T_TYPE; +%dictionary { yylval->type = TypeDictionary; return T_TYPE_DICTIONARY; } +%array { yylval->type = TypeArray; return T_TYPE_ARRAY; } +%number { yylval->type = TypeNumber; return T_TYPE_NUMBER; } +%string { yylval->type = TypeString; return T_TYPE_STRING; } +%scalar { yylval->type = TypeScalar; return T_TYPE_SCALAR; } +%any { yylval->type = TypeAny; return T_TYPE_ANY; } +%name { yylval->type = TypeName; return T_TYPE_NAME; } %validator { return T_VALIDATOR; } %require { return T_REQUIRE; } %attribute { return T_ATTRIBUTE; } +%inherits return T_INHERITS; object return T_OBJECT; template return T_TEMPLATE; include return T_INCLUDE; include_recursive return T_INCLUDE_RECURSIVE; library return T_LIBRARY; -inherits return T_INHERITS; null return T_NULL; partial return T_PARTIAL; true { yylval->num = 1; return T_NUMBER; } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index dac3daa08..c7571a2b3 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -549,7 +549,7 @@ lterm: identifier lbinary_op rterm } | T_IMPORT rterm { - AExpression::Ptr avar = make_shared(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2)); + AExpression::Ptr avar = make_shared(&AExpression::OpVariable, "type", DebugInfoRange(@1, @2)); AExpression::Ptr aexpr = static_cast(*$2); delete $2; $$ = new Value(make_shared(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2))); diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index dbdfaee99..f646e9ed0 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -120,7 +120,7 @@ Dictionary::Ptr ConfigItem::GetProperties(void) GetExpressionList()->Evaluate(m_Properties); m_Properties->Remove("__parent"); - VERIFY(m_Properties->Get("__type") == GetType() && m_Properties->Get("__name") == GetName()); + VERIFY(m_Properties->Get("type") == GetType() && m_Properties->Get("name") == GetName()); } return m_Properties; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 18ea4e939..0a730b2af 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -86,9 +86,9 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) } Array::Ptr exprs = make_shared(); - exprs->Add(make_shared(&AExpression::OpSet, "__type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); - exprs->Add(make_shared(&AExpression::OpSet, "__name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); diff --git a/lib/db_ido/db_ido-type.conf b/lib/db_ido/db_ido-type.conf index 881848634..b85608b75 100644 --- a/lib/db_ido/db_ido-type.conf +++ b/lib/db_ido/db_ido-type.conf @@ -17,26 +17,26 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type DbConnection { - %attribute string "table_prefix", +%type DbConnection { + %attribute %string "table_prefix", - %attribute dictionary "cleanup" { - %attribute number "acknowledgements_age", - %attribute number "commenthistory_age", - %attribute number "contactnotifications_age", - %attribute number "contactnotificationmethods_age", - %attribute number "downtimehistory_age", - %attribute number "eventhandlers_age", - %attribute number "externalcommands_age", - %attribute number "flappinghistory_age", - %attribute number "hostchecks_age", - %attribute number "logentries_age", - %attribute number "notifications_age", - %attribute number "processevents_age", - %attribute number "statehistory_age", - %attribute number "servicechecks_age", - %attribute number "systemcommands_age", + %attribute %dictionary "cleanup" { + %attribute %number "acknowledgements_age", + %attribute %number "commenthistory_age", + %attribute %number "contactnotifications_age", + %attribute %number "contactnotificationmethods_age", + %attribute %number "downtimehistory_age", + %attribute %number "eventhandlers_age", + %attribute %number "externalcommands_age", + %attribute %number "flappinghistory_age", + %attribute %number "hostchecks_age", + %attribute %number "logentries_age", + %attribute %number "notifications_age", + %attribute %number "processevents_age", + %attribute %number "statehistory_age", + %attribute %number "servicechecks_age", + %attribute %number "systemcommands_age", }, - %attribute number "categories" + %attribute %number "categories" } diff --git a/lib/hello/hello-type.conf b/lib/hello/hello-type.conf index 836934662..12a05bba8 100644 --- a/lib/hello/hello-type.conf +++ b/lib/hello/hello-type.conf @@ -17,5 +17,5 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type Hello { +%type Hello { } diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index 79ce65faf..946cdfccb 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -17,228 +17,228 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type Host { - %attribute string "display_name", - %attribute string "check", - %attribute array "groups" { - %attribute name(HostGroup) "*" +%type Host { + %attribute %string "display_name", + %attribute %string "check", + %attribute %array "groups" { + %attribute %name(HostGroup) "*" }, - %attribute dictionary "macros" { - %attribute string "*" + %attribute %dictionary "macros" { + %attribute %string "*" } } -type HostGroup { - %attribute string "display_name" +%type HostGroup { + %attribute %string "display_name" } -type IcingaApplication { +%type IcingaApplication { } -type IcingaStatusWriter { - %attribute string "status_path", - %attribute number "update_interval" +%type IcingaStatusWriter { + %attribute %string "status_path", + %attribute %number "update_interval" } -type Service { +%type Service { %require "host", - %attribute name(Host) "host", + %attribute %name(Host) "host", - %attribute string "short_name", + %attribute %string "short_name", - %attribute string "display_name", + %attribute %string "display_name", - %attribute dictionary "macros" { - %attribute string "*" + %attribute %dictionary "macros" { + %attribute %string "*" }, %require "check_command", - %attribute name(CheckCommand) "check_command", - %attribute number "max_check_attempts", - %attribute name(TimePeriod) "check_period", - %attribute number "check_interval", - %attribute number "retry_interval", + %attribute %name(CheckCommand) "check_command", + %attribute %number "max_check_attempts", + %attribute %name(TimePeriod) "check_period", + %attribute %number "check_interval", + %attribute %number "retry_interval", - %attribute number "enable_notifications", - %attribute number "enable_active_checks", - %attribute number "enable_passive_checks", - %attribute number "enable_event_handler", + %attribute %number "enable_notifications", + %attribute %number "enable_active_checks", + %attribute %number "enable_passive_checks", + %attribute %number "enable_event_handler", - %attribute name(EventCommand) "event_command", + %attribute %name(EventCommand) "event_command", - %attribute number "enable_flapping", - %attribute number "flapping_threshold", + %attribute %number "enable_flapping", + %attribute %number "flapping_threshold", - %attribute number "enable_perfdata", + %attribute %number "enable_perfdata", - %attribute number "volatile", + %attribute %number "volatile", - %attribute array "groups" { - %attribute name(ServiceGroup) "*" + %attribute %array "groups" { + %attribute %name(ServiceGroup) "*" }, - %attribute array "authorities" { - %attribute name(Endpoint) "*" + %attribute %array "authorities" { + %attribute %name(Endpoint) "*" }, } -type ServiceGroup { - %attribute string "display_name" +%type ServiceGroup { + %attribute %string "display_name" } -type Notification { +%type Notification { %require "host", - %attribute name(Host) "host", + %attribute %name(Host) "host", %require "service", - %attribute string "service", + %attribute %string "service", - %attribute dictionary "macros" { - %attribute string "*" + %attribute %dictionary "macros" { + %attribute %string "*" }, - %attribute array "users" { - %attribute name(User) "*" + %attribute %array "users" { + %attribute %name(User) "*" }, - %attribute array "user_groups" { - %attribute name(UserGroup) "*" + %attribute %array "user_groups" { + %attribute %name(UserGroup) "*" }, - %attribute dictionary "times" { - %attribute number "begin", - %attribute number "end", + %attribute %dictionary "times" { + %attribute %number "begin", + %attribute %number "end", }, %require "notification_command", - %attribute name(NotificationCommand) "notification_command", + %attribute %name(NotificationCommand) "notification_command", - %attribute number "notification_interval", - %attribute name(TimePeriod) "notification_period", + %attribute %number "notification_interval", + %attribute %name(TimePeriod) "notification_period", - %attribute number "notification_type_filter", - %attribute number "notification_state_filter", + %attribute %number "notification_%type_filter", + %attribute %number "notification_state_filter", - %attribute array "authorities" { - %attribute name(Endpoint) "*" + %attribute %array "authorities" { + %attribute %name(Endpoint) "*" }, } -type User { - %attribute string "display_name", +%type User { + %attribute %string "display_name", - %attribute dictionary "macros" { - %attribute string "*" + %attribute %dictionary "macros" { + %attribute %string "*" }, - %attribute array "groups" { - %attribute name(UserGroup) "*" + %attribute %array "groups" { + %attribute %name(UserGroup) "*" }, - %attribute number "enable_notifications", - %attribute number "notification_type_filter", - %attribute number "notification_state_filter", - %attribute name(TimePeriod) "notification_period" + %attribute %number "enable_notifications", + %attribute %number "notification_%type_filter", + %attribute %number "notification_state_filter", + %attribute %name(TimePeriod) "notification_period" } -type UserGroup { - %attribute string "display_name" +%type UserGroup { + %attribute %string "display_name" } -type TimePeriod { - %attribute string "display_name", +%type TimePeriod { + %attribute %string "display_name", %require "methods", - %attribute dictionary "methods" { + %attribute %dictionary "methods" { %require "update", - %attribute string "update" + %attribute %string "update" }, /* %if (methods.update == "LegacyTimePeriod") { */ // %require "ranges", - %attribute dictionary "ranges" { - %attribute string "*" + %attribute %dictionary "ranges" { + %attribute %string "*" } /* } */ } -type Command { +%type Command { %require "methods", - %attribute dictionary "methods" { + %attribute %dictionary "methods" { %require "execute", - %attribute string "execute" + %attribute %string "execute" }, /* %if (methods.execute == "PluginNotification" || methods.execute == "PluginCheck" || methods.execute == "PluginEvent") { */ // %require "command", - %attribute string "command", - %attribute array "command" { - %attribute string "*" + %attribute %string "command", + %attribute %array "command" { + %attribute %string "*" }, - %attribute array "export_macros" { - %attribute string "*" + %attribute %array "export_macros" { + %attribute %string "*" }, - %attribute array "escape_macros" { - %attribute string "*" + %attribute %array "escape_macros" { + %attribute %string "*" }, - %attribute dictionary "macros" { - %attribute string "*" + %attribute %dictionary "macros" { + %attribute %string "*" }, - %attribute number "timeout" + %attribute %number "timeout" /* } */ } -type CheckCommand inherits Command { +%type CheckCommand %inherits Command { } -type NotificationCommand inherits Command { +%type NotificationCommand %inherits Command { } -type EventCommand inherits Command { +%type EventCommand %inherits Command { } -type Domain { - %attribute dictionary "acl" { - %attribute number "*" +%type Domain { + %attribute %dictionary "acl" { + %attribute %number "*" } } -type ScheduledDowntime { +%type ScheduledDowntime { %require "host", - %attribute name(Host) "host", + %attribute %name(Host) "host", %require "service", - %attribute string "service", + %attribute %string "service", %require "author", - %attribute string "author", + %attribute %string "author", %require "comment", - %attribute string "comment", + %attribute %string "comment", - %attribute number "duration", - %attribute number "fixed", + %attribute %number "duration", + %attribute %number "fixed", %require "ranges", - %attribute dictionary "ranges" { - %attribute string "*" + %attribute %dictionary "ranges" { + %attribute %string "*" }, } -type Dependency { +%type Dependency { %require "parent_host", - %attribute name(Host) "parent_host", - %attribute string "parent_service", + %attribute %name(Host) "parent_host", + %attribute %string "parent_service", %require "child_host", - %attribute name(Host) "child_host", - %attribute string "child_service", + %attribute %name(Host) "child_host", + %attribute %string "child_service", - %attribute name(TimePeriod) "period", + %attribute %name(TimePeriod) "period", - %attribute number "state_filter", - %attribute number "disable_checks", - %attribute number "disable_notifications" + %attribute %number "state_filter", + %attribute %number "disable_checks", + %attribute %number "disable_notifications" } diff --git a/lib/remote/remote-type.conf b/lib/remote/remote-type.conf index 37530293f..f12945825 100644 --- a/lib/remote/remote-type.conf +++ b/lib/remote/remote-type.conf @@ -17,26 +17,26 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -type Endpoint { +%type Endpoint { %require "host", - %attribute string "host", + %attribute %string "host", %require "port", - %attribute string "port", + %attribute %string "port", - %attribute array "config_files" { - %attribute string "*" + %attribute %array "config_files" { + %attribute %string "*" }, - %attribute array "config_files_recursive" { - %attribute string "*", - %attribute dictionary "*" { - %attribute string "path", - %attribute string "pattern" + %attribute %array "config_files_recursive" { + %attribute %string "*", + %attribute %dictionary "*" { + %attribute %string "path", + %attribute %string "pattern" } }, - %attribute array "accept_config" { - %attribute name(Endpoint) "*" + %attribute %array "accept_config" { + %attribute %name(Endpoint) "*" } } From 8ab39194f1671f7c0e6bd78052ec27a09497114a Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 14:25:16 +0100 Subject: [PATCH 06/25] Unknown attributes should be a config error. Refs #5883 --- lib/config/configtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/configtype.cpp b/lib/config/configtype.cpp index a8713eff8..3245fceb9 100644 --- a/lib/config/configtype.cpp +++ b/lib/config/configtype.cpp @@ -180,7 +180,7 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, } if (overallResult == ValidationUnknownField) - ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations)); + ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations)); else if (overallResult == ValidationInvalidType) { String message = "Invalid value for attribute: " + LocationToString(locations); From 0e79abb8f24ae327d9faab0283b9342a3e31ad18 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 14:46:19 +0100 Subject: [PATCH 07/25] Implement instance variable "templates" for config objects. Refs #5884 --- lib/base/dynamicobject.ti | 1 + lib/config/base-type.conf | 4 ++++ lib/config/configitembuilder.cpp | 3 +++ 3 files changed, 8 insertions(+) diff --git a/lib/base/dynamicobject.ti b/lib/base/dynamicobject.ti index eaab51266..682eb228d 100644 --- a/lib/base/dynamicobject.ti +++ b/lib/base/dynamicobject.ti @@ -5,6 +5,7 @@ abstract class DynamicObject { [config] String name (Name); [config, get_protected] String type (TypeName); + [config, get_protected] Array::Ptr templates; [config] Dictionary::Ptr methods; [config] Dictionary::Ptr custom; [config] Array::Ptr domains; diff --git a/lib/config/base-type.conf b/lib/config/base-type.conf index 1dfdd0a77..66411d726 100644 --- a/lib/config/base-type.conf +++ b/lib/config/base-type.conf @@ -24,6 +24,10 @@ %require "type", %attribute %string "type", + %attribute %array "templates" { + %attribute %string "*" + }, + %attribute %dictionary "methods", %attribute %dictionary "custom" { diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 0a730b2af..56383b7ef 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -86,6 +86,9 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) } Array::Ptr exprs = make_shared(); + Array::Ptr templateArray = make_shared(); + templateArray->Add(m_Name); + exprs->Add(make_shared(&AExpression::OpSetPlus, "templates", make_shared(&AExpression::OpLiteral, templateArray, m_DebugInfo), m_DebugInfo)); exprs->Add(make_shared(&AExpression::OpSet, "type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); exprs->Add(make_shared(&AExpression::OpSet, "name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); From fa11e5a97e97ad7bd0b1117648009695f0626e08 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 16:32:15 +0100 Subject: [PATCH 08/25] Update example config. Refs #5878 --- etc/icinga2/conf.d/generic-host.conf | 51 ++++----- etc/icinga2/conf.d/generic-service.conf | 17 +-- etc/icinga2/conf.d/generic-user.conf | 14 --- etc/icinga2/conf.d/localhost.conf | 131 ++++++++++++------------ lib/config/aexpression.cpp | 2 + lib/config/config_parser.yy | 10 +- 6 files changed, 101 insertions(+), 124 deletions(-) diff --git a/etc/icinga2/conf.d/generic-host.conf b/etc/icinga2/conf.d/generic-host.conf index f0df83bdf..e6be42e07 100644 --- a/etc/icinga2/conf.d/generic-host.conf +++ b/etc/icinga2/conf.d/generic-host.conf @@ -1,59 +1,44 @@ /** * Provides default settings for hosts. By convention - * all hosts should inherit from this template. + * all hosts should import this template. */ template Host "generic-host" { + check = "ping4" +} +apply Service "ping4" { + import "generic-service", + + check_command = "ping4", + + assign where "generic-host" in host.templates +} + +apply Service "ping6" { + import "generic-service", + + check_command = "ping6", + + assign where "generic-host" in host.templates, + ignore where !host.macros.address6 } template Host "linux-server" { import "generic-host", groups += [ "linux-servers" ], - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" } template Host "windows-server" { import "generic-host", groups += [ "windows-servers" ], - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" } template Host "generic-printer" { import "generic-host", - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" } template Host "generic-switch" { import "generic-host", - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" } diff --git a/etc/icinga2/conf.d/generic-service.conf b/etc/icinga2/conf.d/generic-service.conf index 4f4711cef..33bb2b138 100644 --- a/etc/icinga2/conf.d/generic-service.conf +++ b/etc/icinga2/conf.d/generic-service.conf @@ -1,15 +1,18 @@ /** * Provides default settings for services. By convention - * all services should inherit from this template. + * all services should import this template. */ template Service "generic-service" { max_check_attempts = 3, check_interval = 5m, retry_interval = 1m, - enable_perfdata = true, - - notifications["mail-icingaadmin"] = { - templates = [ "mail-notification" ], - user_groups = [ "icingaadmins" ] - } + enable_perfdata = true +} + +apply Notification "mail-icingaadmin" { + import "mail-notification", + + user_groups = [ "icingaadmins"], + + assign where "generic-service" in service.templates } diff --git a/etc/icinga2/conf.d/generic-user.conf b/etc/icinga2/conf.d/generic-user.conf index 66f78cd88..a95985fa5 100644 --- a/etc/icinga2/conf.d/generic-user.conf +++ b/etc/icinga2/conf.d/generic-user.conf @@ -4,19 +4,5 @@ */ template User "generic-user" { - enable_notifications = true, - notification_period = "24x7", - notification_state_filter = StateFilterWarning | - StateFilterCritical | - StateFilterUnknown, - notification_type_filter = NotificationFilterProblem | - NotificationFilterAcknowledgement | - NotificationFilterRecovery | - NotificationFilterCustom | - NotificationFilterFlappingStart | - NotificationFilterFlappingEnd | - NotificationFilterDowntimeStart | - NotificationFilterDowntimeEnd | - NotificationFilterDowntimeRemoved } diff --git a/etc/icinga2/conf.d/localhost.conf b/etc/icinga2/conf.d/localhost.conf index 0d64eeaa2..2f2bd6390 100644 --- a/etc/icinga2/conf.d/localhost.conf +++ b/etc/icinga2/conf.d/localhost.conf @@ -6,70 +6,69 @@ object Host "localhost" { import "linux-server", - display_name = "localhost", - - services["icinga"] = { - templates = [ "generic-service" ], - - check_command = "icinga" - }, - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - services["ping6"] = { - templates = [ "generic-service" ], - - check_command = "ping6" - }, - - services["http"] = { - templates = [ "generic-service" ], - - check_command = "http_ip" - }, - - services["ssh"] = { - templates = [ "generic-service" ], - - check_command = "ssh" - }, - - services["load"] = { - templates = [ "generic-service" ], - - check_command = "load", - - scheduled_downtimes["backup"] = { - templates = [ "backup-downtime" ] - } - }, - - services["processes"] = { - templates = [ "generic-service" ], - - check_command = "processes" - }, - - services["users"] = { - templates = [ "generic-service" ], - - check_command = "users" - }, - - services["disk"] = { - templates = [ "generic-service" ], - - check_command = "disk" - }, - - macros = { - address = "127.0.0.1", - address6 = "::1", - }, - - check = "ping4", + macros.address = "127.0.0.1", + macros.address6 = "::1" } + +apply Service "icinga" { + import "generic-service", + + check_command = "icinga", + + assign where host.name == "localhost" +} + +apply Service "http" { + import "generic-service", + + check_command = "http_ip", + + assign where host.name == "localhost" +} + +apply Service "ssh" { + import "generic-service", + + check_command = "ssh", + + assign where host.name == "localhost" +} + +apply Service "load" { + import "generic-service", + + check_command = "load", + + assign where host.name == "localhost" +} + +apply ScheduledDowntime "backup-downtime" { + import "backup-downtime", + + assign where service.host == "localhost" && service.short_name == "load" +} + +apply Service "processes" { + import "generic-service", + + check_command = "processes", + + assign where host.name == "localhost" +} + +apply Service "users" { + import "generic-service", + + check_command = "users", + + assign where host.name == "localhost" +} + +apply Service "disk" { + import "generic-service", + + check_command = "disk", + + assign where host.name == "localhost" +} + diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 5e038e848..2533bd911 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -420,6 +420,8 @@ Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& loc BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'")); return object->GetField(field); + } else if (value.IsEmpty()) { + return Empty; } else { BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'")); } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index c7571a2b3..cb794c266 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -146,6 +146,7 @@ using namespace icinga; %token T_IMPORT "import (T_IMPORT)" %token T_ASSIGN "assign (T_ASSIGN)" %token T_IGNORE "ignore (T_IGNORE)" + %type identifier %type rterm_items %type rterm_items_inner @@ -160,19 +161,20 @@ using namespace icinga; %type rterm_scope %type lterm %type variable_decl + %left T_LOGICAL_OR %left T_LOGICAL_AND -%left T_IN -%left T_NOT_IN %nonassoc T_EQUAL %nonassoc T_NOT_EQUAL +%nonassoc T_IN +%nonassoc T_NOT_IN %left T_PLUS T_MINUS %left T_MULTIPLY T_DIVIDE_OP %left T_BINARY_AND %left T_BINARY_OR -%left '.' %right '~' %right '!' +%left '.' %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); @@ -731,7 +733,7 @@ apply: String name = aname->Evaluate(m_ModuleScope); if (!ApplyRule::IsValidType(type)) - BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(@2)); + BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3))); AExpression::Ptr exprl = static_cast(*$5); delete $5; From adce8e95bc5ae50596254faee2ee035b74215a5c Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 18:26:46 +0100 Subject: [PATCH 09/25] Move the apply rule handler to the Service class. Refs #5878 --- lib/icinga/CMakeLists.txt | 4 ++-- lib/icinga/host.h | 3 --- lib/icinga/{host-apply.cpp => service-apply.cpp} | 10 +++++----- lib/icinga/service.h | 3 +++ 4 files changed, 10 insertions(+), 10 deletions(-) rename lib/icinga/{host-apply.cpp => service-apply.cpp} (92%) diff --git a/lib/icinga/CMakeLists.txt b/lib/icinga/CMakeLists.txt index 5ea9d54ff..ca0607913 100644 --- a/lib/icinga/CMakeLists.txt +++ b/lib/icinga/CMakeLists.txt @@ -43,12 +43,12 @@ add_library(icinga SHARED api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th - externalcommandprocessor.cpp host.cpp host.th host-apply.cpp hostgroup.cpp hostgroup.th + externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp icingastatuswriter.th legacytimeperiod.cpp macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th - pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-check.cpp + pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-apply.cpp service-check.cpp service-comment.cpp service.cpp service-dependency.cpp service-downtime.cpp service-event.cpp service-flapping.cpp service.th servicegroup.cpp servicegroup.th service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th diff --git a/lib/icinga/host.h b/lib/icinga/host.h index bf1ae422e..5e0dfa056 100644 --- a/lib/icinga/host.h +++ b/lib/icinga/host.h @@ -102,9 +102,6 @@ public: virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const; - static void RegisterApplyRuleHandler(void); - static void EvaluateApplyRules(const std::vector& rules); - protected: virtual void Stop(void); diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/service-apply.cpp similarity index 92% rename from lib/icinga/host-apply.cpp rename to lib/icinga/service-apply.cpp index 3fed31047..61aa9fe4b 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -17,7 +17,7 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#include "icinga/host.h" +#include "icinga/service.h" #include "config/configitembuilder.h" #include "base/initialize.h" #include "base/dynamictype.h" @@ -28,14 +28,14 @@ using namespace icinga; -INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler); +INITIALIZE_ONCE(&Service::RegisterApplyRuleHandler); -void Host::RegisterApplyRuleHandler(void) +void Service::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterType("Service", &Host::EvaluateApplyRules, 1); + ApplyRule::RegisterType("Service", &Service::EvaluateApplyRules, 1); } -void Host::EvaluateApplyRules(const std::vector& rules) +void Service::EvaluateApplyRules(const std::vector& rules) { BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects()) { CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'"); diff --git a/lib/icinga/service.h b/lib/icinga/service.h index 3a76626f1..657dcddcf 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -280,6 +280,9 @@ public: void RemoveReverseDependency(const shared_ptr& dep); std::set > GetReverseDependencies(void) const; + static void RegisterApplyRuleHandler(void); + static void EvaluateApplyRules(const std::vector& rules); + protected: virtual void Start(void); From 8a1bbc0ace40fd4b8cbbe5bd2971a73d380579c7 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 19:45:07 +0100 Subject: [PATCH 10/25] Make the real object name available for use in templates. Refs #5882 --- lib/config/configitembuilder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 56383b7ef..13d9b7c91 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -89,9 +89,13 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) Array::Ptr templateArray = make_shared(); templateArray->Add(m_Name); exprs->Add(make_shared(&AExpression::OpSetPlus, "templates", make_shared(&AExpression::OpLiteral, templateArray, m_DebugInfo), m_DebugInfo)); - exprs->Add(make_shared(&AExpression::OpSet, "type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); + + if (!m_Abstract) { + exprs->Add(make_shared(&AExpression::OpSet, "type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); + } + exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); - exprs->Add(make_shared(&AExpression::OpSet, "name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); From 33ae12d08499ced08f2990da6420fd4599f19980 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 22:58:05 +0100 Subject: [PATCH 11/25] Implement apply support for scheduled downtimes and notifications. Refs #5880 --- lib/config/applyrule.cpp | 1 + lib/icinga/CMakeLists.txt | 8 +-- lib/icinga/notification-apply.cpp | 80 ++++++++++++++++++++++++++ lib/icinga/notification.h | 4 ++ lib/icinga/scheduleddowntime-apply.cpp | 80 ++++++++++++++++++++++++++ lib/icinga/scheduleddowntime.h | 4 ++ 6 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 lib/icinga/notification-apply.cpp create mode 100644 lib/icinga/scheduleddowntime-apply.cpp diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index 8556108c8..fc959107f 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -69,6 +69,7 @@ bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const void ApplyRule::EvaluateRules(void) { + // TODO: priority std::pair > kv; BOOST_FOREACH(kv, m_Callbacks) { RuleMap::const_iterator it = m_Rules.find(kv.first); diff --git a/lib/icinga/CMakeLists.txt b/lib/icinga/CMakeLists.txt index ca0607913..5242952b7 100644 --- a/lib/icinga/CMakeLists.txt +++ b/lib/icinga/CMakeLists.txt @@ -47,10 +47,10 @@ add_library(icinga SHARED icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp icingastatuswriter.th legacytimeperiod.cpp macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th - notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th - pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-apply.cpp service-check.cpp - service-comment.cpp service.cpp service-dependency.cpp service-downtime.cpp service-event.cpp - service-flapping.cpp service.th servicegroup.cpp servicegroup.th + notification.cpp notification.th notification-apply.cpp perfdatavalue.cpp perfdatavalue.th + pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th scheduleddowntime-apply.cpp + service-apply.cpp service-check.cpp service-comment.cpp service.cpp service-dependency.cpp + service-downtime.cpp service-event.cpp service-flapping.cpp service.th servicegroup.cpp servicegroup.th service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th usergroup.cpp usergroup.th icinga-type.cpp ) diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp new file mode 100644 index 000000000..b5390bebe --- /dev/null +++ b/lib/icinga/notification-apply.cpp @@ -0,0 +1,80 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "icinga/service.h" +#include "config/configitembuilder.h" +#include "base/initialize.h" +#include "base/dynamictype.h" +#include "base/convert.h" +#include "base/logger_fwd.h" +#include "base/context.h" +#include + +using namespace icinga; + +INITIALIZE_ONCE(&Notification::RegisterApplyRuleHandler); + +void Notification::RegisterApplyRuleHandler(void) +{ + ApplyRule::RegisterType("Notification", &Notification::EvaluateApplyRules, 2); +} + +void Notification::EvaluateApplyRules(const std::vector& rules) +{ + BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects()) { + CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'"); + + Dictionary::Ptr locals = make_shared(); + locals->Set("host", service->GetHost()); + locals->Set("service", service); + + BOOST_FOREACH(const ApplyRule& rule, rules) { + DebugInfo di = rule.GetDebugInfo(); + + std::ostringstream msgbuf; + msgbuf << "Evaluating 'apply' rule (" << di << ")"; + CONTEXT(msgbuf.str()); + + if (!rule.EvaluateFilter(locals)) + continue; + + std::ostringstream msgbuf2; + msgbuf2 << "Applying notification '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di; + Log(LogDebug, "icinga", msgbuf2.str()); + + std::ostringstream namebuf; + namebuf << service->GetName() << "!" << rule.GetName(); + String name = namebuf.str(); + + ConfigItemBuilder::Ptr builder = make_shared(di); + builder->SetType("Notification"); + builder->SetName(name); + builder->SetScope(rule.GetScope()); + + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(rule.GetExpression()); + + ConfigItem::Ptr serviceItem = builder->Compile(); + serviceItem->Register(); + DynamicObject::Ptr dobj = serviceItem->Commit(); + dobj->OnConfigLoaded(); + } + } +} diff --git a/lib/icinga/notification.h b/lib/icinga/notification.h index 6348aa428..559501bdc 100644 --- a/lib/icinga/notification.h +++ b/lib/icinga/notification.h @@ -25,6 +25,7 @@ #include "icinga/user.h" #include "icinga/usergroup.h" #include "icinga/timeperiod.h" +#include "config/applyrule.h" #include "base/array.h" namespace icinga @@ -86,6 +87,9 @@ public: static boost::signals2::signal OnNextNotificationChanged; + static void RegisterApplyRuleHandler(void); + static void EvaluateApplyRules(const std::vector& rules); + protected: virtual void Start(void); virtual void Stop(void); diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp new file mode 100644 index 000000000..f7ad097ef --- /dev/null +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -0,0 +1,80 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "icinga/scheduleddowntime.h" +#include "config/configitembuilder.h" +#include "base/initialize.h" +#include "base/dynamictype.h" +#include "base/convert.h" +#include "base/logger_fwd.h" +#include "base/context.h" +#include + +using namespace icinga; + +INITIALIZE_ONCE(&ScheduledDowntime::RegisterApplyRuleHandler); + +void ScheduledDowntime::RegisterApplyRuleHandler(void) +{ + ApplyRule::RegisterType("ScheduledDowntime", &ScheduledDowntime::EvaluateApplyRules, 2); +} + +void ScheduledDowntime::EvaluateApplyRules(const std::vector& rules) +{ + BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects()) { + CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'"); + + Dictionary::Ptr locals = make_shared(); + locals->Set("host", service->GetHost()); + locals->Set("service", service); + + BOOST_FOREACH(const ApplyRule& rule, rules) { + DebugInfo di = rule.GetDebugInfo(); + + std::ostringstream msgbuf; + msgbuf << "Evaluating 'apply' rule (" << di << ")"; + CONTEXT(msgbuf.str()); + + if (!rule.EvaluateFilter(locals)) + continue; + + std::ostringstream msgbuf2; + msgbuf2 << "Applying scheduled downtime '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di; + Log(LogDebug, "icinga", msgbuf2.str()); + + std::ostringstream namebuf; + namebuf << service->GetName() << "!" << rule.GetName(); + String name = namebuf.str(); + + ConfigItemBuilder::Ptr builder = make_shared(di); + builder->SetType("ScheduledDowntime"); + builder->SetName(name); + builder->SetScope(rule.GetScope()); + + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(rule.GetExpression()); + + ConfigItem::Ptr serviceItem = builder->Compile(); + serviceItem->Register(); + DynamicObject::Ptr dobj = serviceItem->Commit(); + dobj->OnConfigLoaded(); + } + } +} diff --git a/lib/icinga/scheduleddowntime.h b/lib/icinga/scheduleddowntime.h index 5db94c296..75e634268 100644 --- a/lib/icinga/scheduleddowntime.h +++ b/lib/icinga/scheduleddowntime.h @@ -23,6 +23,7 @@ #include "icinga/i2-icinga.h" #include "icinga/scheduleddowntime.th" #include "icinga/service.h" +#include "config/applyrule.h" #include namespace icinga @@ -43,6 +44,9 @@ public: Service::Ptr GetService(void) const; + static void RegisterApplyRuleHandler(void); + static void EvaluateApplyRules(const std::vector& rules); + protected: virtual void Start(void); From 66e769672cd89774f868105e101f3ae419239209 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 23:00:20 +0100 Subject: [PATCH 12/25] Fix failed assertion in ConfigItem::GetProperties. Refs #5870 --- lib/config/configitem.cpp | 2 ++ lib/config/configitembuilder.cpp | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index f646e9ed0..5f3052b35 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -116,6 +116,8 @@ Dictionary::Ptr ConfigItem::GetProperties(void) if (!m_Properties) { m_Properties = make_shared(); + m_Properties->Set("type", m_Type); + m_Properties->Set("name", m_Name); m_Properties->Set("__parent", m_Scope); GetExpressionList()->Evaluate(m_Properties); m_Properties->Remove("__parent"); diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 13d9b7c91..dc4f20b7f 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -89,12 +89,6 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) Array::Ptr templateArray = make_shared(); templateArray->Add(m_Name); exprs->Add(make_shared(&AExpression::OpSetPlus, "templates", make_shared(&AExpression::OpLiteral, templateArray, m_DebugInfo), m_DebugInfo)); - - if (!m_Abstract) { - exprs->Add(make_shared(&AExpression::OpSet, "type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); - exprs->Add(make_shared(&AExpression::OpSet, "name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); - } - exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); From 6ef2cdb0eb08dcdd2277c9af00f62ac27cbc6fc0 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 23:03:53 +0100 Subject: [PATCH 13/25] Implement apply support for dependencies. Refs #5880 --- lib/icinga/CMakeLists.txt | 2 +- lib/icinga/dependency-apply.cpp | 80 +++++++++++++++++++++++++++++++++ lib/icinga/dependency.h | 4 ++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 lib/icinga/dependency-apply.cpp diff --git a/lib/icinga/CMakeLists.txt b/lib/icinga/CMakeLists.txt index 5242952b7..ab9ed192d 100644 --- a/lib/icinga/CMakeLists.txt +++ b/lib/icinga/CMakeLists.txt @@ -42,7 +42,7 @@ mkembedconfig_target(icinga-type.conf icinga-type.cpp) add_library(icinga SHARED api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th - domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th + dependency-apply.cpp domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp icingastatuswriter.th legacytimeperiod.cpp diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp new file mode 100644 index 000000000..989090e0f --- /dev/null +++ b/lib/icinga/dependency-apply.cpp @@ -0,0 +1,80 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "icinga/dependency.h" +#include "config/configitembuilder.h" +#include "base/initialize.h" +#include "base/dynamictype.h" +#include "base/convert.h" +#include "base/logger_fwd.h" +#include "base/context.h" +#include + +using namespace icinga; + +INITIALIZE_ONCE(&Dependency::RegisterApplyRuleHandler); + +void Dependency::RegisterApplyRuleHandler(void) +{ + ApplyRule::RegisterType("Dependency", &Dependency::EvaluateApplyRules, 2); +} + +void Dependency::EvaluateApplyRules(const std::vector& rules) +{ + BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects()) { + CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'"); + + Dictionary::Ptr locals = make_shared(); + locals->Set("host", service->GetHost()); + locals->Set("service", service); + + BOOST_FOREACH(const ApplyRule& rule, rules) { + DebugInfo di = rule.GetDebugInfo(); + + std::ostringstream msgbuf; + msgbuf << "Evaluating 'apply' rule (" << di << ")"; + CONTEXT(msgbuf.str()); + + if (!rule.EvaluateFilter(locals)) + continue; + + std::ostringstream msgbuf2; + msgbuf2 << "Applying dependency '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di; + Log(LogDebug, "icinga", msgbuf2.str()); + + std::ostringstream namebuf; + namebuf << service->GetName() << "!" << rule.GetName(); + String name = namebuf.str(); + + ConfigItemBuilder::Ptr builder = make_shared(di); + builder->SetType("Dependency"); + builder->SetName(name); + builder->SetScope(rule.GetScope()); + + builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(rule.GetExpression()); + + ConfigItem::Ptr serviceItem = builder->Compile(); + serviceItem->Register(); + DynamicObject::Ptr dobj = serviceItem->Commit(); + dobj->OnConfigLoaded(); + } + } +} diff --git a/lib/icinga/dependency.h b/lib/icinga/dependency.h index 481dedc1d..1daccd721 100644 --- a/lib/icinga/dependency.h +++ b/lib/icinga/dependency.h @@ -23,6 +23,7 @@ #include "icinga/i2-icinga.h" #include "icinga/dependency.th" #include "icinga/service.h" +#include "config/applyrule.h" #include "base/array.h" #include "base/dictionary.h" @@ -47,6 +48,9 @@ public: bool IsAvailable(DependencyType dt) const; + static void RegisterApplyRuleHandler(void); + static void EvaluateApplyRules(const std::vector& rules); + protected: virtual void OnStateLoaded(void); virtual void Stop(void); From 3ce7262aa88e75c02dc45f39be6623f101c31e70 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 28 Mar 2014 23:14:37 +0100 Subject: [PATCH 14/25] Update auto-discovery scripts. Refs #5878 --- contrib/discover-snmp.py | 17 +++++++++-------- contrib/discover.py | 27 ++++++++++++++------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/contrib/discover-snmp.py b/contrib/discover-snmp.py index ca0820188..a7dec81fe 100755 --- a/contrib/discover-snmp.py +++ b/contrib/discover-snmp.py @@ -48,14 +48,15 @@ for line in out.split("\n"): plugin = "".join([chr(int(ch)) for ch in plugin]) plugins.append(plugin) -print("template Host \"snmp-extend:%s\" {" % (ipaddr)) -print(" macros[\"community\"] = \"%s\"," % (community)) for plugin in plugins: - print(" services[\"%s\"] = {" % (plugin)) - print(" templates = [ \"snmp-extend-service\" ],") - print(" check_command = \"snmp-extend\",") - print(" macros[\"plugin\"] = \"%s\"" % (plugin)) - print(" },") -print("}") + print("apply Service \"%s\" {" % (plugin)) + print(" import \"snmp-extend-service\",") + print() + print(" check_command = \"snmp-extend\",") + print(" macros[\"community\"] = \"%s\"," % (community)) + print() + print(" assign where host.macros.address == \"%s\"" % (ipaddr)) + print("}") + print() sys.exit(0) diff --git a/contrib/discover.py b/contrib/discover.py index ddbdaf3ec..a24d35f41 100755 --- a/contrib/discover.py +++ b/contrib/discover.py @@ -106,22 +106,23 @@ def process_host(host_element): hosts[name] = { "name": name, "address": address, "services": services } def print_host(host): - print "object Host \"%s\" inherits \"discovered-host\" {" % (host["name"]) - print "\tmacros[\"address\"] = \"%s\"," % (host["address"]) - - for serv, service in host["services"].iteritems(): - print "" - print "\tservices[\"%s\"] = {" % (serv) - print "\t\ttemplates = [ \"discovered-service\" ]," - print "" - print "\t\tcheck_command = \"%s\"," % (service["command"]) - print "" - print "\t\tmacros[\"port\"] = %s" % (service["port"]) - print "\t}," - + print "object Host \"%s\" {" % (host["name"]) + print "\timport \"discovered-host\"," + print "" + print "\tmacros.address = \"%s\"," % (host["address"]) print "}" print "" + for serv, service in host["services"].iteritems(): + print "apply Service \"%s\" {" % (serv) + print "\timport \"discovered-service\"," + print "" + print "\tcheck_command = \"%s\"," % (service["command"]) + print "" + print "\tmacros.port = %s" % (service["port"]) + print "}" + print "" + for arg in sys.argv[1:]: # Expects XML output from 'nmap -oX' dom = parse(arg) From 4428b8c6eed1c4b8f96186603e58ddf29734288f Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 01:13:28 +0100 Subject: [PATCH 15/25] Update documentation. Refs #5878 --- doc/1-about.md | 8 +- doc/2.1-setting-up-icinga-2.md | 119 ++++++++++--------- doc/2.6-running-icinga-2.md | 2 +- doc/3.01-hosts-and-services.md | 19 +-- doc/3.02-commands.md | 33 ++--- doc/3.03-macros.md | 10 +- doc/3.04-notifications.md | 95 +++++++-------- doc/3.05-using-templates.md | 50 +++----- doc/3.06-groups.md | 27 ++--- doc/3.07-time-periods.md | 17 ++- doc/3.14-check-result-files.md | 2 - doc/3.15-monitoring-remote-clients.md | 97 ++++++--------- doc/4.1-configuration-syntax.md | 53 +++++---- doc/4.3-object-types.md | 29 ++--- doc/4.5-best-practice.md | 52 +++----- doc/6.01-downtimes.md | 18 +-- doc/6.04-cluster.md | 22 ++-- doc/6.06-dependencies.md | 45 +++---- doc/8-differences-between-icinga-1x-and-2.md | 25 ++-- 19 files changed, 307 insertions(+), 416 deletions(-) diff --git a/doc/1-about.md b/doc/1-about.md index 36afb5ab5..da0ade501 100644 --- a/doc/1-about.md +++ b/doc/1-about.md @@ -2,10 +2,10 @@ ## What is Icinga 2? -Icinga 2 is an enterprise-grade open source monitoring system which keeps watch over networks -and any conceivable network resource, notifies the user of errors and recoveries and generates -performance data for reporting. Scalable and extensible, Icinga 2 can monitor complex, large -environments across dispersed locations. +Icinga 2 is an open source monitoring system which keeps watch over network resources, +notifies users of outages and recoveries and generates performance data for reporting. +Scalable and extensible, Icinga 2 can monitor complex, large environments across +multiple locations. ## Licensing diff --git a/doc/2.1-setting-up-icinga-2.md b/doc/2.1-setting-up-icinga-2.md index 71a3043f4..23d8e82c6 100644 --- a/doc/2.1-setting-up-icinga-2.md +++ b/doc/2.1-setting-up-icinga-2.md @@ -131,65 +131,76 @@ The `conf.d/localhost.conf` file contains our first host definition: * files in this directory are included. */ object Host "localhost" { - services["ping4"] = { - templates = [ "generic-service" ], + import "linux-server", - check_command = "ping4" - }, - - services["ping6"] = { - templates = [ "generic-service" ], - - check_command = "ping6" - }, - - services["http"] = { - templates = [ "generic-service" ], - - check_command = "http_ip" - }, - - services["ssh"] = { - templates = [ "generic-service" ], - - check_command = "ssh" - }, - - services["load"] = { - templates = [ "generic-service" ], - - check_command = "load" - }, - - services["processes"] = { - templates = [ "generic-service" ], - - check_command = "processes" - }, - - services["users"] = { - templates = [ "generic-service" ], - - check_command = "users" - }, - - services["disk"] = { - templates = [ "generic-service" ], - - check_command = "disk" - }, - - macros = { - address = "127.0.0.1", - address6 = "::1", - }, - - check = "ping4", + macros.address = "127.0.0.1", + macros.address6 = "::1" } + apply Service "icinga" { + import "generic-service", + + check_command = "icinga", + + assign where host.name == "localhost" + } + + apply Service "http" { + import "generic-service", + + check_command = "http_ip", + + assign where host.name == "localhost" + } + + apply Service "ssh" { + import "generic-service", + + check_command = "ssh", + + assign where host.name == "localhost" + } + + apply Service "load" { + import "generic-service", + + check_command = "load", + + assign where host.name == "localhost" + } + + apply ScheduledDowntime "backup-downtime" { + import "backup-downtime", + + assign where service.host == "localhost" && service.short_name == "load" + } + + apply Service "processes" { + import "generic-service", + + check_command = "processes", + + assign where host.name == "localhost" + } + + apply Service "users" { + import "generic-service", + + check_command = "users", + + assign where host.name == "localhost" + } + + apply Service "disk" { + import "generic-service", + + check_command = "disk", + + assign where host.name == "localhost" + } This defines a host named "localhost" which has a couple of services. Services -may inherit from one or more service templates. +may import one or more service templates. The command objects `ping4`, `ping6`, `http_ip`, `ssh`, `load`, `processes`, `users` and `disk` are all provided by the Icinga Template Library (short ITL) which diff --git a/doc/2.6-running-icinga-2.md b/doc/2.6-running-icinga-2.md index 211c8657a..8b650c299 100644 --- a/doc/2.6-running-icinga-2.md +++ b/doc/2.6-running-icinga-2.md @@ -32,7 +32,7 @@ Icinga 2's init script is installed in `/etc/init.d/icinga2` by default: -V [ --version ] show version information -l [ --library ] arg load a library -I [ --include ] arg add include search directory - -D [ --define] args define a constant + -D [ --define] args define a constant -c [ --config ] arg parse a configuration file -C [ --validate ] exit after validating the configuration -Z [ --no-validate ] skip validating the configuration diff --git a/doc/3.01-hosts-and-services.md b/doc/3.01-hosts-and-services.md index 177164686..108976ca2 100644 --- a/doc/3.01-hosts-and-services.md +++ b/doc/3.01-hosts-and-services.md @@ -15,17 +15,18 @@ on the same physical device. Here is an example of a host object which defines two child services: object Host "my-server1" { - services["ping4"] = { - check_command = "ping4" - }, + macros.address = "10.0.0.1", + check = "ping4" + } - services["http"] = { - check_command = "http_ip" - }, + apply Service "ping4" { + check_command = "ping4" + assign where host.name == "my-server1" + } - check = "ping4", - - macros["address"] = "10.0.0.1" + apply Service "http" { + check_command = "http_ip" + assign where host.name == "my-server1" } The example host `my-server1` creates two services which belong to this host: diff --git a/doc/3.02-commands.md b/doc/3.02-commands.md index f64318bfc..9eb8ee02e 100644 --- a/doc/3.02-commands.md +++ b/doc/3.02-commands.md @@ -68,10 +68,8 @@ then use these macros on the command line. "-c", "$cfree$%" ], - macros += { - wfree = 20, - cfree = 10, - } + macros.wfree = 20, + macros.cfree = 10 } The host `localhost` with the service `disk` checks all disks with modified @@ -80,21 +78,18 @@ space). object Host "localhost" { import "generic-host", + + macros.address = "127.0.0.1", + macros.address6 = "::1" + } - services["disk"] = { - templates = [ "generic-service" ], - - check_command = "disk", - macros += { - wfree = 10, - cfree = 5 - } - }, - - macros = { - address = "127.0.0.1", - address6 = "::1", - }, + apply Service "disk" { + import "generic-service", + + check_command = "disk", + + macros.wfree = 10, + macros.cfree = 5 } @@ -209,5 +204,3 @@ information in the check output (`-o`). "Event Handler triggered in state '$SERVICESTATE$' with output '$SERVICEOUTPUT$'." ] } - - diff --git a/doc/3.03-macros.md b/doc/3.03-macros.md index 5880ef3ab..5cb76565a 100644 --- a/doc/3.03-macros.md +++ b/doc/3.03-macros.md @@ -75,14 +75,12 @@ values for some of the latency thresholds and timeouts. When using the `my-ping` command you can override all or some of the macros in the service definition like this: - object Host "my-server1" { - services["ping"] = { - check_command = "my-ping", + apply Service "ping" { + check_command = "my-ping", - macros["packets"] = 10 // Overrides the default value of 5 given in the command - }, + macros.packets = 10 // Overrides the default value of 5 given in the command - macros["address"] = "10.0.0.1" + assign where host.name == "my-server1" } If a macro isn't defined anywhere an empty value is used and a warning is diff --git a/doc/3.04-notifications.md b/doc/3.04-notifications.md index 9a91a1a66..edcb164ac 100644 --- a/doc/3.04-notifications.md +++ b/doc/3.04-notifications.md @@ -113,21 +113,17 @@ to the defined notifications. That way you'll save duplicated attributes in each > > The `TimePeriod` `24x7` is shipped as example configuration with Icinga 2. -Use the `generic-notification` template for the `mail` notification defined -inline to the host's service `ping4` and assign the `icingaadmin` user. +Use the `apply` keyword to create `Notification` objects for your services: - object Host "localhost" { - services["ping4"] = { - notifications["mail"] = { - templates = [ "generic-notification" ], - notification_command = "mail-notification", - users = [ "icingaadmin" ], - } - } + apply Notification "mail" { + import "generic-notification", + + notification_command = "mail-notification", + users = [ "icingaadmin" ], + + assign where service.short_name == "ping4" } -Notifications can be defined in `Service` templates inherited to the objects. - > **Note** > > Instead of assigning users to notifications, you can also add the `user_groups` @@ -156,7 +152,7 @@ notifications between start and end time. object User "icinga-oncall-2nd-level" { display_name = "Icinga 2nd Level", - enable_notifications = 1, + enable_notifications = true, macros = { "mobile" = "+49123456781" @@ -165,10 +161,9 @@ notifications between start and end time. object User "icinga-oncall-1st-level" { display_name = "Icinga 1st Level", - enable_notifications = 1, + enable_notifications = true, - macros = { - "mobile" = "+49123456782" + macros.mobile = "+49123456782" } } @@ -200,35 +195,35 @@ If the problem does not get resolved or acknowledged preventing further notifica the `escalation-sms-1st-level` user will be escalated `1h` after the initial problem was notified, but only for one hour (`2h` as `end` key for the `times` dictionary). - object Host "localhost" { - services["ping4"] = { - notifications["mail"] = { - templates = [ "generic-notification" ], - notification_command = "mail-notification", - users = [ "icingaadmin" ], - }, - notifications["escalation-sms-2nd-level"] = { - templates = [ "generic-notification" ], - notification_command = "sms-notification", - users = [ "icinga-oncall-2nd-level" ], + apply Notification "mail" { + import "generic-notification", + notification_command = "mail-notification", + users = [ "icingaadmin" ], + + assign where service.short_name == "ping4" + } + + apply Notification "escalation-sms-2nd-level" { + import "generic-notification", + notification_command = "sms-notification", + users = [ "icinga-oncall-2nd-level" ], - times = { - begin = 30m, - end = 1h - } - }, - notifications["escalation-sms-1st-level"] = { - templates = [ "generic-notification" ], - notification_command = "sms-notification", - users = [ "icinga-oncall-1st-level" ], - - times = { - begin = 1h, - end = 2h - } - } + times = { + begin = 30m, + end = 1h } } + + apply Notification "escalation-sms-1st-level" { + import "generic-notification", + notification_command = "sms-notification", + users = [ "icinga-oncall-1st-level" ], + + times = { + begin = 1h, + end = 2h + } + } > **Note** > @@ -245,18 +240,12 @@ dictionary and set `begin = 15m` as key and value if you want to suppress notifi in the first 15 minutes. Leave out the `end` key - if not set, Icinga 2 will not check against any end time for this notification. - object Host "localhost" { - services["ping4"] = { - notifications["mail"] = { - templates = [ "generic-notification" ], - notification_command = "mail-notification", - users = [ "icingaadmin" ], + apply Notification "mail" { + import "generic-notification", + notification_command = "mail-notification", + users = [ "icingaadmin" ], - times = { - begin = 15m // delay first notification - } - } - } + times.begin = 15m // delay first notification } > **Note** diff --git a/doc/3.05-using-templates.md b/doc/3.05-using-templates.md index ad77951dc..373973cae 100644 --- a/doc/3.05-using-templates.md +++ b/doc/3.05-using-templates.md @@ -7,46 +7,28 @@ For example, rather than manually creating a `ping` service object for each of your hosts you can use templates to avoid having to copy & paste parts of your configuration: - template Host "linux-server" { - services["ping"] = { - check_command = "ping4" - }, - - check = "ping" + template Service "generic-service" { + max_check_attempts = 3, + check_interval = 5m, + retry_interval = 1m, + enable_perfdata = true } - object Host "my-server1" { - import "linux-server", - - macros["address"] = "10.0.0.1" + apply Service "ping4" { + import "generic-service", + check_command = "ping4", + assign where host.macros.address } - object Host "my-server2" { - import "linux-server", - - macros["address"] = "10.0.0.2" + apply Service "ping6" { + import "generic-service", + check_command = "ping6", + assign where host.macros.address6 } -In this example both `my-server1` and `my-server2` each get their own `ping` -service check. Each host gets its own host `check` defined as the `ping` -service too. +In this example both `ping4` and `ping6` services inherit properties from the +template `generic-service`. -Objects as well as templates themselves can inherit from an arbitrary number of +Objects as well as templates themselves can import an arbitrary number of templates. Attributes inherited from a template can be overridden in the object if necessary. - -Templates can also be used in service and notification definitions using the -`templates` attribute: - - template Service "weekend-service" { - check_interval = 0.5m, - check_period = "weekend" - } - - object Host "my-server1" { - services["backup"] { - check_command = "backup-check", - - templates = [ "weekend-service" ] - } - } diff --git a/doc/3.06-groups.md b/doc/3.06-groups.md index 8b3763c24..e9e3f9425 100644 --- a/doc/3.06-groups.md +++ b/doc/3.06-groups.md @@ -37,17 +37,16 @@ Then add your hosts to this hostgroup template Host "windows-mssql-template" { groups = [ "windows" ], - macros = { - "mssql_port" = 1433 + macros.mssql_port = 1433 } } object Host "mssql-srv1" { - templates = [ "windows-mssql-template" ] + import "windows-mssql-template" } object Host "mssql-srv2" { - templates = [ "windows-mssql-template" ] + import "windows-mssql-template" } This can be done for service and user groups the same way. Additionally @@ -64,25 +63,17 @@ the user groups are associated as attributes in `Notification` objects. object User "win-mssql-noc" { import "generic-windows-mssql-users", - macros = { - "email" = "noc@company.com" - } + macros.email = "noc@example.com" } object User "win-mssql-ops" { import "generic-windows-mssql-users", - macros = { - "email" = "ops@company.com" - } + macros.email = "ops@example.com" } - object Host "localhost" { - services["ping4"] = { - notifications["mail"] = { - templates = [ "generic-notification" ], - notification_command = "mail-notification", - user_groups = [ "windows-admins" ], - } - } + apply Service "ping4" { + import "generic-notification", + notification_command = "mail-notification", + user_groups = [ "windows-admins" ], } diff --git a/doc/3.07-time-periods.md b/doc/3.07-time-periods.md index a95a54402..44cb6a0e2 100644 --- a/doc/3.07-time-periods.md +++ b/doc/3.07-time-periods.md @@ -66,13 +66,12 @@ create a new timeperiod named `workhours` defining a work day with Assign the timeperiod as `notification_period` to the `Notification` object then. - object Host "localhost" { - services["ping4"] = { - notifications["mail"] = { - templates = [ "generic-notification" ], - notification_command = "mail-notification", - users = [ "icingaadmin" ], - notification_period = "workhours" - } - } + apply Notification "mail" { + import "generic-notification", + + notification_command = "mail-notification", + users = [ "icingaadmin" ], + notification_period = "workhours" + + assign where host.name == "localhost" } diff --git a/doc/3.14-check-result-files.md b/doc/3.14-check-result-files.md index 4226c3768..c02934ca1 100644 --- a/doc/3.14-check-result-files.md +++ b/doc/3.14-check-result-files.md @@ -17,5 +17,3 @@ on-demand in your Icinga 2 objects configuration. spool_dir = "/data/check-results" } - - diff --git a/doc/3.15-monitoring-remote-clients.md b/doc/3.15-monitoring-remote-clients.md index ab2ab5a2b..401b225fb 100644 --- a/doc/3.15-monitoring-remote-clients.md +++ b/doc/3.15-monitoring-remote-clients.md @@ -21,24 +21,18 @@ binaries. The [Monitoring Plugins package](#setting-up-check-plugins) ships the `check_snmp` plugin binary, but there are plenty of [existing plugins](#integrate-additional-plugins) for specific use cases already around, for example monitoring Cisco routers. -The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and only defines -additional macros (note the `+=` operator) as command parameters for the `oid` -(`community` is already set): +The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and just +overrides the `oid` macro. A service is created for all hosts which +have the `community` macro set. - object Host "remote-snmp-host" { - import "generic-host", + apply Service "uptime" { + import "generic-service", - ... - services["uptime"] = { - templates = [ "generic-service" ], - check_command = "snmp", - macros += { - "oid" = "1.3.6.1.2.1.1.3.0" - } - }, - macros = { - "address" = "192.168.1.101" - } + templates = [ "generic-service" ], + check_command = "snmp", + macros.oid = "1.3.6.1.2.1.1.3.0", + + assign where host.macros.community } #### SSH @@ -56,24 +50,17 @@ its return code and output. `check_by_ssh` is available in the [Monitoring Plugi ] } - object Host "remote-ssh-host" { - import "generic-host", - - ... - services["swap"] = { - templates = [ "generic-service" ], - check_command = "check_by_ssh_swap", - macros = { + apply Service "swap" { + import "generic-service", + check_command = "check_by_ssh_swap", + macros = { "warn" = "50%", "crit" = "75%" - } - }, - macros = { - "address" = "192.168.1.102" } + + assign where host.name == "remote-ssh-host" } - #### NRPE [NRPE](http://docs.icinga.org/latest/en/nrpe.html) runs as daemon on the remote client including @@ -83,7 +70,7 @@ remote client. > **Note** > -> The NRPE daemon uses its own proprietary configuration format in nrpe.cfg while `check_nrpe` +> The NRPE daemon uses its own configuration format in nrpe.cfg while `check_nrpe` > can be embedded into the Icinga 2 `CheckCommand` configuration syntax. Example: @@ -97,27 +84,19 @@ Example: ], } - object Host "remote-nrpe-host" { - import "generic-host", + apply Service "users" { + import "generic-service", + + check_command = "check_nrpe", + macros.remote_nrpe_command = "check_users", - ... - services["users"] = { - templates = [ "generic-service" ], - check_command = "check_nrpe", - macros = { - "remote_nrpe_command" = "check_users" - } - }, - macros = { - "address" = "192.168.1.103" - } + assign where host.name == "remote-nrpe-host" } nrpe.cfg: command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10 - #### NSClient++ [NSClient++](http://nsclient.org) works on both Windows and Linux platforms and is well @@ -150,23 +129,18 @@ Example: } } - object Host "remote-windows-host" { - import "generic-host", - - ... - services["users"] = { - templates = [ "generic-service" ], - check_command = "check_nscp", - macros += { - "remote_nscp_command" = "USEDDISKSPACE", - "partition" = "c", - "warn" = "70", - "crit" = "80" - } - }, - macros = { - "address" = "192.168.1.104" + apply Service "users" { + import "generic-service", + + check_command = "check_nscp", + macros += { + "remote_nscp_command" = "USEDDISKSPACE", + "partition" = "c", + "warn" = "70", + "crit" = "80" } + + assign where host.name == "remote-windows-host" } For details on the `NSClient++` configuration please refer to the [official documentation](http://www.nsclient.org/nscp/wiki/doc/configuration/0.4.x). @@ -180,13 +154,12 @@ For details on the `NSClient++` configuration please refer to the [official docu A dedicated Icinga 2 agent supporting all platforms and using the native Icinga 2 communication protocol supported with SSL certificates, IPv4/IPv6 -support, etc is on the [development roadmap](https://dev.icinga.org/projects/i2?jump=issues). +support, etc. is on the [development roadmap](https://dev.icinga.org/projects/i2?jump=issues). Meanwhile remote checkers in a [Cluster](#cluster) setup could act as immediate replacement, but without any local configuration - or pushing their standalone configuration back to the master node including their check result messages. - ### Passive Check Results and SNMP Traps > **Note** diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index 516de5abf..95b312e78 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -385,21 +385,29 @@ Constants cannot be changed once they are set. ### Apply The `apply` keyword can be used to associate a template with another group of -objects. The exact effect of this association depends on the two object types. +objects. The exact effect of this association depends on the object type. - template Service "ping-service" { - short_name = "ping", - check_command = "ping4" + apply Service "ping" { + import "generic-service", + + check_command = "ping4", + + assign where host.name == "localhost" } - apply template Service "ping-service" to Host where host == "localhost" +In this example the `assign where` condition is an expression which is +evaluated for all objects of type Host and a new service with name "ping" +is created for each matching host. -In this example the `where` condition is a constant expression which is -evaluated for all objects of type Host and a new service is created for each -matching host. +Depending on the object type used in the `apply` expression additional local +variables may be available for use in the `where` condition: -Depending on the object types used in the `apply` expression additional local -variables may be available for use in the `where` condition. + Type |Variables + -----------------|---------------- + Dependency |host, service + Notification |host, service + Service |host + ScheduledDowntime|host, service ### Comments @@ -484,18 +492,18 @@ you can specify which attributes are allowed in an object definition. Example: - type Pizza { + %type Pizza { %require "radius", - %attribute number "radius", + %attribute %number "radius", - %attribute dictionary "ingredients" { + %attribute %dictionary "ingredients" { %validator "ValidateIngredients", - %attribute string "*", + %attribute %string "*", - %attribute dictionary "*" { - %attribute number "quantity", - %attribute string "name" + %attribute %dictionary "*" { + %attribute %number "quantity", + %attribute %string "name" } }, @@ -524,10 +532,11 @@ The Pizza definition provides the following validation rules: Valid types for type rules include: -* any -* number -* string -* scalar (an alias for string) -* dictionary +* %any +* %number +* %string +* %scalar (an alias for string) +* %dictionary +* %array --> diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md index 5eca34b3e..5889c82bc 100644 --- a/doc/4.3-object-types.md +++ b/doc/4.3-object-types.md @@ -21,15 +21,6 @@ Example: templates = [ "ping" ] }, - services["http"] = { - templates = [ "my-http" ], - - macros = { - vhost = "test1.example.org", - port = 81 - } - }, - check = "ping" } @@ -40,8 +31,6 @@ Attributes: display_name |**Optional.** A short description of the host. check |**Optional.** A service that is used to determine whether the host is up or down. This must be a service short name of a service that belongs to the host. groups |**Optional.** A list of host groups this host belongs to. - services |**Optional.** Inline definition of services. Each dictionary item specifies a service.

The `templates` attribute can be used to specify an array of templates that should be inherited by the service.

The new service's name is "hostname!service" - where "service" is the dictionary key in the services dictionary.

The dictionary key is used as the service's short name. - dependencies |**Optional.** Inline definition of dependencies. Each dictionary item specifies a dependency.

The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.

The new dependency object's name is "hostname:service:dependency" - where "dependency" is the dictionary key in the dependencies dictionary. macros |**Optional.** A dictionary containing macros that are specific to this host. ### HostGroup @@ -68,8 +57,8 @@ by Icinga 2. > **Best Practice** > > Rather than creating a `Service` object for a specific host it is usually easier -> to just create a `Service` template and use the `services` attribute in the `Host` -> object to associate these templates with a host. +> to just create a `Service` template and use the `apply` keyword to assign the +> service to a number of hosts. Example: @@ -115,8 +104,6 @@ Attributes: flapping\_threshold|**Optional.** The flapping threshold in percent when a service is considered to be flapping. volatile |**Optional.** The volatile setting enables always `HARD` state types if `NOT-OK` state changes occur. groups |**Optional.** The service groups this service belongs to. - notifications |**Optional.** Inline definition of notifications. Each dictionary item specifies a notification.

The `templates` attribute can be used to specify an array of templates that should be inherited by the notification object.

The new notification object's name is "hostname:service:notification" - where "notification" is the dictionary key in the notifications dictionary. - dependencies |**Optional.** Inline definition of dependencies. Each dictionary item specifies a dependency.

The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.

The new dependency object's name is "hostname:service:dependency" - where "dependency" is the dictionary key in the dependencies dictionary. authorities |**Optional.** A list of Endpoints on which this service check will be executed in a cluster scenario. domains |**Optional.** A list of Domains for this service object in a cluster scenario. @@ -144,8 +131,8 @@ of service state changes and other events. > **Best Practice** > > Rather than creating a `Notification` object for a specific service it is usually easier -> to just create a `Notification` template and use the `notifications` attribute in the `Service` -> object to associate these templates with a service. +> to just create a `Notification` template and use the `apply` keyword to assign the +> notification to a number of services. Example: @@ -202,8 +189,8 @@ Dependency objects are used to specify dependencies between hosts and services. > **Best Practice** > > Rather than creating a `Dependency` object for a specific service it is usually easier -> to just create a `Dependency` template and using the `dependencies` attribute in the `Service` -> object to associate these templates with a service. +> to just create a `Dependency` template and use the `apply` keyword to assign the +> dependency to a number of services. Example: @@ -360,8 +347,8 @@ ScheduledDowntime objects can be used to set up recurring downtimes for services > **Best Practice** > > Rather than creating a `ScheduledDowntime` object for a specific service it is usually easier -> to just create a `ScheduledDowntime` template and use the `scheduled_downtimes` attribute in the `Service` -> object to associate these templates with a service. +> to just create a `ScheduledDowntime` template and use the `apply` keyword to assign the +> scheduled downtime to a number of services. Example: diff --git a/doc/4.5-best-practice.md b/doc/4.5-best-practice.md index 0e495c8f0..b6b13e934 100644 --- a/doc/4.5-best-practice.md +++ b/doc/4.5-best-practice.md @@ -41,7 +41,6 @@ your configuration directory tree and files: vienna/ hosts.conf - If you're planning to create a [cluster](#cluster) setup with Icinga 2 and your configuration master should deploy specific configuration parts to slave nodes, it's reasonable not to confuse it with configuration below `conf.d`. Rather @@ -54,8 +53,6 @@ create a dedicated directory and put all nodes into their own directories: node2/ node99/ - - If you are preferring to control what several parties drop into the configuration pool (for example different departments with their own standalone configuration), you can still deactivate the `conf.d` inclusion and use your own strategy. @@ -90,8 +87,7 @@ unwanted values. ### Inline Objects using Templates While it is reasonable to create single objects by your preferred configuration -tool, using templates and inheriting their attributes in inline objects will -save you a lot of typing extra work. +tool, using templates and the `apply` keyword will save you a lot of typing extra work. For instance, you can still create a host object, then a service object linking to it, after that a notification object referencing the service object, and last @@ -147,20 +143,17 @@ By doing that everytime for such a series of linked objects, your configuration will get bloated and unreadable. You've already read that [using templates](#best-practice-use-templates) will help here. -The `Notification` and `ScheduledDowntime` templates will be referenced in the service template and -inline definition (both locations are possible). -The `Service` template is referenced within the inline service array for the `Host` template. In the end -the `Host` object inherits from the `Host` template named `linux-server`. -That way similar hosts may just inherit the host template and get all services, notifications, scheduled -downtimes through the template automatism. +Using the `apply` keyword you can create services, notifications, scheduled downtimes and dependencies +for an arbitrary number of hosts and services respectively: - template Notification "mail-notification" { + apply Notification "mail-notification" { notification_command = "mail-service-notification", - users = [ "user1", "user2" ] + + assign where "generic-service" in service.templates } - template ScheduledDowntime "backup-downtime" { + apply ScheduledDowntime "backup-downtime" { author = "icingaadmin", comment = "Some comment", @@ -170,6 +163,8 @@ downtimes through the template automatism. ranges = { "sunday" = "02:00-03:00" } + + assign where "generic-service" in service.templates } template Service "generic-service" { @@ -177,35 +172,24 @@ downtimes through the template automatism. check_interval = 5m, retry_interval = 1m, enable_perfdata = true, + } - notifications["mail"] = { - templates = [ "mail-notification" ] - } + apply Service "ping4" { + import "generic-service", + + check_command = "ping4", + + assign where "linux-server" in host.templates } template Host "linux-server" { - display_name = "The best host there is", - groups = [ "all-hosts" ], - host_dependencies = [ "router" ], - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4", - - scheduled_downtimes["backup"] = { - templates = [ "backup-downtime" ] - } - }, - check = "ping4" } object Host "localhost" { import "linux-server", + + display_name = "The best host there is", } - - - diff --git a/doc/6.01-downtimes.md b/doc/6.01-downtimes.md index aa98de558..634f2d948 100644 --- a/doc/6.01-downtimes.md +++ b/doc/6.01-downtimes.md @@ -73,7 +73,7 @@ recurring downtimes for services. Example: - template ScheduledDowntime "backup-downtime" { + apply ScheduledDowntime "backup-downtime" { author = "icingaadmin", comment = "Scheduled downtime for backup", @@ -86,19 +86,7 @@ Example: saturday = "02:00-03:00", sunday = "02:00-03:00" } + + assign where "backup" in service.groups } - object Host "localhost" { - import "generic-host", - - ... - services["load"] = { - templates = [ "generic-service" ], - - check_command = "load", - - scheduled_downtimes["backup"] = { - templates = [ "backup-downtime" ] - } - }, - } diff --git a/doc/6.04-cluster.md b/doc/6.04-cluster.md index 86b18cf71..7727c3eac 100644 --- a/doc/6.04-cluster.md +++ b/doc/6.04-cluster.md @@ -210,13 +210,12 @@ If you require specific services to be only executed by one or more checker node within the cluster, you must define `authorities` as additional service object attribute. Required Endpoints must be defined as array. - object Host "dmz-host1" { - import "generic-host", + apply Service "dmz-oracledb" { + import "generic-service", - services["dmz-oracledb"] = { - templates = [ "generic-service" ], - authorities = [ "icinga-node-1" ], - } + authorities = [ "icinga-node-1" ], + + assign where "oracle" in host.groups } > **Tip** @@ -234,15 +233,14 @@ one or more configured nodes are not connected. Example: - object Host "icinga2a" { - import "generic-host", + apply Service "cluster" { + import "generic-service", - services["cluster"] = { - templates = [ "generic-service" ], check_interval = 1m, check_command = "cluster", - authorities = [ "icinga2a" ] - }, + authorities = [ "icinga2a" ], + + assign where host.name = "icinga2a" } > **Note** diff --git a/doc/6.06-dependencies.md b/doc/6.06-dependencies.md index bbbdd94af..a689ef3de 100644 --- a/doc/6.06-dependencies.md +++ b/doc/6.06-dependencies.md @@ -15,39 +15,30 @@ access by pinging the Google DNS server `google-dns` is a common method, but will fail in case the `dsl-router` host is down. Therefore the example below defines a host dependency which acts implicit as parent relation too. -Furthermore the host may be reachable but ping samples are dropped by the +Furthermore the host may be reachable but ping probes are dropped by the router's firewall. In case the `dsl-router``ping4` service check fails, all -further checks for the `google-dns` `ping4` service should be suppressed. -This is achieved by setting the `disable_checks` attribute to `true`. +further checks for the `ping4` service on host `google-dns` service should +be suppressed. This is achieved by setting the `disable_checks` attribute to `true`. object Host "dsl-router" { - services["ping4"] = { - templates = "generic-service", - check_command = "ping4" - } - - macros = { - address = "192.168.1.1", - }, + macros.address = "192.168.1.1" } object Host "google-dns" { - services["ping4"] = { - templates = "generic-service", - check_command = "ping4", - dependencies["dsl-router-ping4"] = { - parent_host = "dsl-router", - parent_service = "ping4", - disable_checks = true - } - } + macros.address = "8.8.8.8", + } - macros = { - address = "8.8.8.8", - }, + apply Service "ping4" { + import "generic-service", - dependencies["dsl-router"] = { - parent_host = "dsl-router" - }, + check_command = "ping4" - } \ No newline at end of file + assign where host.macros.address + } + + apply Dependency "internet" { + parent_host = "dsl-router", + disable_checks = true + + assign where host.name != "dsl-router" + } diff --git a/doc/8-differences-between-icinga-1x-and-2.md b/doc/8-differences-between-icinga-1x-and-2.md index b79f7fe12..33f2acc1e 100644 --- a/doc/8-differences-between-icinga-1x-and-2.md +++ b/doc/8-differences-between-icinga-1x-and-2.md @@ -218,12 +218,8 @@ In Icinga 1.x a service object is associated with a host by defining the to `hostgroup_name` or behavior changing regular expression. It's not possible to define a service definition within a host definition. -The preferred way of associating hosts with services in Icinga 2 are services -defined inline to the host object (or template) definition. Icinga 2 will -implicitely create a new service object on configuration activation. These -inline service definitions can reference service templates. -Linking a service to a host is still possible with the 'host' attribute in -a service object in Icinga 2. +The preferred way of associating hosts with services in Icinga 2 is by +using the `apply` keyword. ## Users @@ -371,19 +367,22 @@ The preferred way of assigning objects to groups is by using a template: template Host "dev-host" { groups += [ "dev-hosts" ], - - services["http"] = { - check_command = [ "http-ip" ] - } } object Host "web-dev" { import "dev-host" } -Host groups in Icinga 2 cannot be used to associate services with all members -of that group. The example above shows how to use templates to accomplish -the same effect. +In order to associate a service with all hosts in a host group the `apply` +keyword can be used: + + apply Service "ping" { + import "generic-service", + + check_command = "ping4", + + assign where "group" in host.groups + } ## Notifications From 64aa5d1b09ffd7e85302eaf19418e1b533b93a86 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 13:48:04 +0100 Subject: [PATCH 16/25] Dump AST execution state in debug mode. Refs #5878 --- icinga-app/icinga.cpp | 2 +- lib/config/aexpression.cpp | 9 ++++++++ lib/config/configerror.cpp | 2 +- lib/config/debuginfo.cpp | 45 ++++++++++++++++++++------------------ lib/config/debuginfo.h | 2 +- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index e48935455..abb43672b 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -89,7 +89,7 @@ static bool LoadConfigFiles(const String& appType, ValidationType validate) BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) { std::ostringstream locbuf; - ShowCodeFragment(locbuf, message.Location); + ShowCodeFragment(locbuf, message.Location, true); String location = locbuf.str(); String logmsg; diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 2533bd911..68cdc49b6 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -28,6 +28,7 @@ #include "base/utility.h" #include "base/objectlock.h" #include "base/object.h" +#include "base/logger_fwd.h" #include #include #include @@ -45,6 +46,14 @@ AExpression::AExpression(OpCallback op, const Value& operand1, const Value& oper Value AExpression::Evaluate(const Dictionary::Ptr& locals) const { try { +#ifdef _DEBUG + if (m_Operator != &AExpression::OpLiteral) { + std::ostringstream msgbuf; + ShowCodeFragment(msgbuf, m_DebugInfo, false); + Log(LogDebug, "config", "Executing:\n" + msgbuf.str()); + } +#endif /* _DEBUG */ + return m_Operator(this, locals); } catch (const std::exception& ex) { if (boost::get_error_info(ex)) diff --git a/lib/config/configerror.cpp b/lib/config/configerror.cpp index 1f3c092f7..bae40acca 100644 --- a/lib/config/configerror.cpp +++ b/lib/config/configerror.cpp @@ -38,6 +38,6 @@ std::string icinga::to_string(const errinfo_debuginfo& e) { std::ostringstream msgbuf; msgbuf << "Config location: " << e.value() << "\n"; - ShowCodeFragment(msgbuf, e.value()); + ShowCodeFragment(msgbuf, e.value(), true); return msgbuf.str(); } diff --git a/lib/config/debuginfo.cpp b/lib/config/debuginfo.cpp index ac809a625..9992a86ad 100644 --- a/lib/config/debuginfo.cpp +++ b/lib/config/debuginfo.cpp @@ -53,7 +53,7 @@ DebugInfo icinga::DebugInfoRange(const DebugInfo& start, const DebugInfo& end) #define EXTRA_LINES 2 -void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di) +void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose) { if (di.Path.IsEmpty()) return; @@ -61,41 +61,44 @@ void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di) std::ifstream ifs; ifs.open(di.Path.CStr(), std::ifstream::in); - int lineno = 1; + int lineno = 0; char line[1024]; while (ifs.good() && lineno <= di.LastLine + EXTRA_LINES) { + lineno++; + ifs.getline(line, sizeof(line)); for (int i = 0; line[i]; i++) if (line[i] == '\t') line[i] = ' '; - if (lineno >= di.FirstLine - EXTRA_LINES && lineno <= di.LastLine + EXTRA_LINES) { - String pathInfo = di.Path + "(" + Convert::ToString(lineno) + "): "; - out << pathInfo; - out << line << "\n"; + int extra_lines = verbose ? EXTRA_LINES : 0; - if (lineno >= di.FirstLine && lineno <= di.LastLine) { - int start, end; + if (lineno < di.FirstLine - extra_lines || lineno > di.LastLine + extra_lines) + continue; - start = 0; - end = strlen(line); + String pathInfo = di.Path + "(" + Convert::ToString(lineno) + "): "; + out << pathInfo; + out << line << "\n"; - if (lineno == di.FirstLine) - start = di.FirstColumn - 1; + if (lineno >= di.FirstLine && lineno <= di.LastLine) { + int start, end; - if (lineno == di.LastLine) - end = di.LastColumn; + start = 0; + end = strlen(line); - out << String(pathInfo.GetLength(), ' '); - out << String(start, ' '); - out << String(end - start, '^'); + if (lineno == di.FirstLine) + start = di.FirstColumn - 1; - out << "\n"; - } + if (lineno == di.LastLine) + end = di.LastColumn; + + out << String(pathInfo.GetLength(), ' '); + out << String(start, ' '); + out << String(end - start, '^'); + + out << "\n"; } - - lineno++; } } diff --git a/lib/config/debuginfo.h b/lib/config/debuginfo.h index 9620dee04..415f0bea7 100644 --- a/lib/config/debuginfo.h +++ b/lib/config/debuginfo.h @@ -64,7 +64,7 @@ I2_CONFIG_API std::ostream& operator<<(std::ostream& out, const DebugInfo& val); I2_CONFIG_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end); -I2_CONFIG_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di); +I2_CONFIG_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose); } From eb30f69454a1080194c237eb5f64b8116c329af0 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 23:02:55 +0100 Subject: [PATCH 17/25] Fix crash in DiagnosticInformation(). Refs #5870 --- lib/base/exception.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/base/exception.h b/lib/base/exception.h index 872f69fd4..79783c5e7 100644 --- a/lib/base/exception.h +++ b/lib/base/exception.h @@ -61,19 +61,22 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace if (boost::get_error_info(ex) == NULL) { result << std::endl; + if (!stack) + stack = GetLastExceptionStack(); + if (stack) result << *stack; - else - result << *GetLastExceptionStack(); + } if (boost::get_error_info(ex) == NULL) { result << std::endl; + if (!context) + context = GetLastExceptionContext(); + if (context) result << *context; - else - result << *GetLastExceptionContext(); } } From 9897358fc68ea3a3ed95a1f9546edbd8754f4d49 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 23:03:19 +0100 Subject: [PATCH 18/25] Add missing lock in DeserializeObject(). Refs #5870 --- lib/base/serializer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/base/serializer.cpp b/lib/base/serializer.cpp index 76370f302..88c2ad7ac 100644 --- a/lib/base/serializer.cpp +++ b/lib/base/serializer.cpp @@ -165,6 +165,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary instance = type->Instantiate(); } + ObjectLock olock(input); BOOST_FOREACH(const Dictionary::Pair& kv, input) { if (kv.first.IsEmpty()) continue; From d00a839620da2fc67abdf805b3a5edd99fa0598f Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 23:04:05 +0100 Subject: [PATCH 19/25] Fix incorrect debug info for "apply" rules. Refs #5870 --- lib/config/config_parser.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index cb794c266..7a6e1375e 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -743,7 +743,7 @@ apply: // assign && !ignore AExpression::Ptr rex = make_shared(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5)); AExpression::Ptr filter = make_shared(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5)); - ApplyRule::AddRule(type, name, exprl, filter, DebugInfoRange(@1, @5), m_ModuleScope); + ApplyRule::AddRule(type, name, exprl, filter, DebugInfoRange(@2, @5), m_ModuleScope); m_Assign.reset(); m_Ignore.reset(); From 14084735da90e5f4dcc250876ccb3cccf21b7919 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 29 Mar 2014 23:18:31 +0100 Subject: [PATCH 20/25] Make sure we evaluate "apply" rules in the right order. Refs #5870 --- lib/config/applyrule.cpp | 36 +++++++++++++++++++------- lib/config/applyrule.h | 4 +-- lib/icinga/dependency-apply.cpp | 2 +- lib/icinga/notification-apply.cpp | 2 +- lib/icinga/scheduleddowntime-apply.cpp | 2 +- lib/icinga/service-apply.cpp | 2 +- 6 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index fc959107f..58c58662d 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -69,21 +69,39 @@ bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const void ApplyRule::EvaluateRules(void) { - // TODO: priority - std::pair > kv; - BOOST_FOREACH(kv, m_Callbacks) { - RuleMap::const_iterator it = m_Rules.find(kv.first); + std::set completedTypes; - if (it == m_Rules.end()) - continue; + while (completedTypes.size() < m_Callbacks.size()) { + std::pair > kv; + BOOST_FOREACH(kv, m_Callbacks) { + const String& sourceType = kv.first; - kv.second.first(it->second); + if (completedTypes.find(sourceType) != completedTypes.end()) + continue; + + const Callback& callback = kv.second.first; + const String& targetType = kv.second.second; + + if (IsValidType(targetType) && completedTypes.find(targetType) == completedTypes.end()) + continue; + + completedTypes.insert(sourceType); + + RuleMap::const_iterator it = m_Rules.find(kv.first); + + if (it == m_Rules.end()) + continue; + + callback(it->second); + } } + + m_Rules.clear(); } -void ApplyRule::RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority) +void ApplyRule::RegisterType(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback) { - m_Callbacks[sourceType] = make_pair(callback, priority); + m_Callbacks[sourceType] = make_pair(callback, targetType); } bool ApplyRule::IsValidType(const String& sourceType) diff --git a/lib/config/applyrule.h b/lib/config/applyrule.h index b7eac024a..90ebeecdf 100644 --- a/lib/config/applyrule.h +++ b/lib/config/applyrule.h @@ -35,7 +35,7 @@ class I2_CONFIG_API ApplyRule { public: typedef boost::function& rules)> Callback; - typedef std::map > CallbackMap; + typedef std::map > CallbackMap; typedef std::map > RuleMap; String GetName(void) const; @@ -50,7 +50,7 @@ public: const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope); static void EvaluateRules(void); - static void RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority); + static void RegisterType(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback); static bool IsValidType(const String& sourceType); private: diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 989090e0f..24d614206 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -32,7 +32,7 @@ INITIALIZE_ONCE(&Dependency::RegisterApplyRuleHandler); void Dependency::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterType("Dependency", &Dependency::EvaluateApplyRules, 2); + ApplyRule::RegisterType("Dependency", "Service", &Dependency::EvaluateApplyRules); } void Dependency::EvaluateApplyRules(const std::vector& rules) diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index b5390bebe..48e6bdd22 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -32,7 +32,7 @@ INITIALIZE_ONCE(&Notification::RegisterApplyRuleHandler); void Notification::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterType("Notification", &Notification::EvaluateApplyRules, 2); + ApplyRule::RegisterType("Notification", "Service", &Notification::EvaluateApplyRules); } void Notification::EvaluateApplyRules(const std::vector& rules) diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index f7ad097ef..3ade63bf0 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -32,7 +32,7 @@ INITIALIZE_ONCE(&ScheduledDowntime::RegisterApplyRuleHandler); void ScheduledDowntime::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterType("ScheduledDowntime", &ScheduledDowntime::EvaluateApplyRules, 2); + ApplyRule::RegisterType("ScheduledDowntime", "Service", &ScheduledDowntime::EvaluateApplyRules); } void ScheduledDowntime::EvaluateApplyRules(const std::vector& rules) diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index 61aa9fe4b..89044285c 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -32,7 +32,7 @@ INITIALIZE_ONCE(&Service::RegisterApplyRuleHandler); void Service::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterType("Service", &Service::EvaluateApplyRules, 1); + ApplyRule::RegisterType("Service", "Host", &Service::EvaluateApplyRules); } void Service::EvaluateApplyRules(const std::vector& rules) From 04dcceef5921e0a0b5318bc752135d0f318588a1 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 30 Mar 2014 01:18:30 +0100 Subject: [PATCH 21/25] Implement Utility::GetSymbolName and Utility::GetSymbolSource for Windows. Refs #5870 --- lib/base/stacktrace.cpp | 41 ++++++++--------------------------------- lib/base/stacktrace.h | 6 ++---- lib/base/utility.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp index 182774ea3..dd7db0a5e 100644 --- a/lib/base/stacktrace.cpp +++ b/lib/base/stacktrace.cpp @@ -22,6 +22,7 @@ #include "base/utility.h" #include "base/convert.h" #include "base/application.h" +#include "base/initialize.h" #ifdef HAVE_BACKTRACE_SYMBOLS # include @@ -29,7 +30,7 @@ using namespace icinga; -boost::once_flag StackTrace::m_OnceFlag = BOOST_ONCE_INIT; +INITIALIZE_ONCE(&StackTrace::StaticInitialize); #ifdef _MSC_VER # pragma optimize("", off) @@ -37,8 +38,6 @@ boost::once_flag StackTrace::m_OnceFlag = BOOST_ONCE_INIT; StackTrace::StackTrace(void) { - boost::call_once(m_OnceFlag, &StackTrace::Initialize); - #ifdef HAVE_BACKTRACE_SYMBOLS m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0])); #else /* HAVE_BACKTRACE_SYMBOLS */ @@ -57,8 +56,6 @@ StackTrace::StackTrace(void) #ifdef _WIN32 StackTrace::StackTrace(PEXCEPTION_POINTERS exi) { - boost::call_once(m_OnceFlag, &StackTrace::Initialize); - STACKFRAME64 frame; int architecture; @@ -91,7 +88,7 @@ StackTrace::StackTrace(PEXCEPTION_POINTERS exi) } #endif /* _WIN32 */ -void StackTrace::Initialize(void) +void StackTrace::StaticInitialize(void) { #ifdef _WIN32 (void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); @@ -153,33 +150,11 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const # endif /* HAVE_BACKTRACE_SYMBOLS */ #else /* _WIN32 */ for (int i = ignoreFrames + 1; i < m_Count; i++) { - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - DWORD64 dwAddress = (DWORD64)m_Frames[i]; - DWORD dwDisplacement; - DWORD64 dwDisplacement64; - - IMAGEHLP_LINE64 line; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - fp << "\t(" << i - ignoreFrames - 1 << ") "; - - if (SymGetLineFromAddr64(GetCurrentProcess(), dwAddress, &dwDisplacement, &line)) - fp << line.FileName << ":" << line.LineNumber; - else - fp << "(unknown file/line)"; - - fp << ": "; - - if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, pSymbol)) - fp << pSymbol->Name << "+" << dwDisplacement64; - else - fp << "(unknown function)"; - - fp << std::endl; + fp << "\t(" << i - ignoreFrames - 1 << ") " + << Utility::GetSymbolSource(m_Frames[i]) + << ": " + << Utility::GetSymbolName(m_Frames[i]) + << std::endl; } #endif /* _WIN32 */ } diff --git a/lib/base/stacktrace.h b/lib/base/stacktrace.h index cd6828ff8..655dfc6ab 100644 --- a/lib/base/stacktrace.h +++ b/lib/base/stacktrace.h @@ -43,13 +43,11 @@ public: void Print(std::ostream& fp, int ignoreFrames = 0) const; + static void StaticInitialize(void); + private: void *m_Frames[64]; int m_Count; - - static boost::once_flag m_OnceFlag; - - static void Initialize(void); }; I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 189f77333..be921c6bb 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -128,7 +128,28 @@ String Utility::GetSymbolName(const void *addr) return dli.dli_sname; #endif /* HAVE_DLADDR */ - return ""; +#ifdef _WIN32 + char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 dwAddress = (DWORD64)addr; + DWORD64 dwDisplacement; + + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement, pSymbol)) { + char output[256]; + if (UnDecorateSymbolName(pSymbol->Name, output, sizeof(output), UNDNAME_COMPLETE)) + return String(output) + "+" + Convert::ToString(dwDisplacement); + else + return String(pSymbol->Name) + "+" + Convert::ToString(dwDisplacement); + } +#endif /* _WIN32 */ + + return "(unknown function)"; } String Utility::GetSymbolSource(const void *addr) @@ -142,7 +163,23 @@ String Utility::GetSymbolSource(const void *addr) } #endif /* HAVE_DLADDR */ - return ""; +#ifdef _WIN32 + char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 dwAddress = (DWORD64)addr; + DWORD dwDisplacement; + + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymGetLineFromAddr64(GetCurrentProcess(), dwAddress, &dwDisplacement, &line)) + return String(line.FileName) + ":" + Convert::ToString(line.LineNumber); +#endif /* _WIN32 */ + + return "(unknown file/line)"; } /** From ec0fdd3fd26be4651db75670b25fc838abe2bf45 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 30 Mar 2014 05:04:58 +0200 Subject: [PATCH 22/25] Fix operator precedence. Refs #5870 --- lib/config/config_parser.yy | 79 ++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 7a6e1375e..afd41f0e6 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -69,6 +69,13 @@ do { \ using namespace icinga; +static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *left, Value *right, DebugInfo& diLeft, DebugInfo& diRight) +{ + *result = new Value(make_shared(op, static_cast(*left), static_cast(*right), DebugInfoRange(diLeft, diRight))); + delete left; + delete right; +} + %} %pure-parser @@ -154,7 +161,6 @@ using namespace icinga; %type lterm_items_inner %type typerulelist %type lbinary_op -%type rbinary_op %type type %type partial_specifier %type rterm @@ -164,17 +170,17 @@ using namespace icinga; %left T_LOGICAL_OR %left T_LOGICAL_AND -%nonassoc T_EQUAL -%nonassoc T_NOT_EQUAL -%nonassoc T_IN -%nonassoc T_NOT_IN +%left T_BINARY_OR +%left T_BINARY_AND +%left T_IN +%left T_NOT_IN +%left T_EQUAL T_NOT_EQUAL +%left T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL +%left T_SHIFT_LEFT T_SHIFT_RIGHT %left T_PLUS T_MINUS %left T_MULTIPLY T_DIVIDE_OP -%left T_BINARY_AND -%left T_BINARY_OR -%right '~' -%right '!' -%left '.' +%right '!' '~' +%left '.' '(' '[' %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); @@ -582,29 +588,6 @@ lterm: identifier lbinary_op rterm $$ = $1; } ; - -rbinary_op: T_PLUS - | T_MINUS - | T_MULTIPLY - | T_DIVIDE_OP - | T_BINARY_AND - | T_BINARY_OR - | T_LESS_THAN - | T_GREATER_THAN - | T_LESS_THAN_OR_EQUAL - | T_GREATER_THAN_OR_EQUAL - | T_EQUAL - | T_NOT_EQUAL - | T_IN - | T_NOT_IN - | T_LOGICAL_AND - | T_LOGICAL_OR - | T_SHIFT_LEFT - | T_SHIFT_RIGHT - { - $$ = $1; - } - ; rterm_items: rterm_items_inner { @@ -638,12 +621,6 @@ rterm_items_inner: /* empty */ } ; -rbinary_op: '+' - { - $$ = &AExpression::OpAdd; - } - ; - rterm_scope: '{' lterm_items '}' { $$ = new Value(make_shared(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3))); @@ -708,12 +685,24 @@ rterm: T_STRING { $$ = $2; } - | rterm rbinary_op rterm - { - $$ = new Value(make_shared($2, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } + | rterm T_LOGICAL_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_LOGICAL_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_BINARY_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_BINARY_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_NOT_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_NOT_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_LESS_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_GREATER_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_SHIFT_LEFT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_PLUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_MINUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_MULTIPLY rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } + | rterm T_DIVIDE_OP rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); } ; apply: From 5179eebf09cf206bc1964c23a1027d2b8bc1fd1c Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 30 Mar 2014 10:00:11 +0200 Subject: [PATCH 23/25] Allow rterm in indexer ops. Refs #5870 --- lib/config/aexpression.cpp | 23 +++++++++++++--------- lib/config/config_parser.yy | 27 ++++++++++++++++---------- lib/config/configitembuilder.cpp | 7 ++++++- lib/icinga/dependency-apply.cpp | 11 +++++++++-- lib/icinga/notification-apply.cpp | 12 ++++++++++-- lib/icinga/scheduleddowntime-apply.cpp | 12 ++++++++++-- lib/icinga/service-apply.cpp | 12 ++++++++++-- 7 files changed, 76 insertions(+), 28 deletions(-) diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 68cdc49b6..3e9e53f99 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -299,14 +299,16 @@ Value AExpression::OpDict(const AExpression *expr, const Dictionary::Ptr& locals Value AExpression::OpSet(const AExpression *expr, const Dictionary::Ptr& locals) { + Value index = expr->EvaluateOperand1(locals); Value right = expr->EvaluateOperand2(locals); - locals->Set(expr->m_Operand1, right); + locals->Set(index, right); return right; } Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals) { - Value left = locals->Get(expr->m_Operand1); + Value index = expr->EvaluateOperand1(locals); + Value left = locals->Get(index); AExpression::Ptr exp_right = expr->m_Operand2; Dictionary::Ptr xlocals = locals; @@ -326,13 +328,14 @@ Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& loc dict->Remove("__parent"); } - locals->Set(expr->m_Operand1, result); + locals->Set(index, result); return result; } Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals) { - Value left = locals->Get(expr->m_Operand1); + Value index = expr->EvaluateOperand1(locals); + Value left = locals->Get(index); AExpression::Ptr exp_right = expr->m_Operand2; Dictionary::Ptr xlocals = locals; @@ -352,13 +355,14 @@ Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& lo dict->Remove("__parent"); } - locals->Set(expr->m_Operand1, result); + locals->Set(index, result); return result; } Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals) { - Value left = locals->Get(expr->m_Operand1); + Value index = expr->EvaluateOperand1(locals); + Value left = locals->Get(index); AExpression::Ptr exp_right = expr->m_Operand2; Dictionary::Ptr xlocals = locals; @@ -378,13 +382,14 @@ Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& dict->Remove("__parent"); } - locals->Set(expr->m_Operand1, result); + locals->Set(index, result); return result; } Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals) { - Value left = locals->Get(expr->m_Operand1); + Value index = expr->EvaluateOperand1(locals); + Value left = locals->Get(index); AExpression::Ptr exp_right = expr->m_Operand2; Dictionary::Ptr xlocals = locals; @@ -404,7 +409,7 @@ Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& l dict->Remove("__parent"); } - locals->Set(expr->m_Operand1, result); + locals->Set(index, result); return result; } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index afd41f0e6..0d093e76f 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -524,36 +524,43 @@ lterm_items_inner: /* empty */ lterm: identifier lbinary_op rterm { - AExpression::Ptr aexpr = static_cast(*$3); - $$ = new Value(make_shared($2, $1, aexpr, DebugInfoRange(@1, @3))); + AExpression::Ptr aindex = make_shared(&AExpression::OpLiteral, $1, @1); free($1); + + AExpression::Ptr aexpr = static_cast(*$3); + $$ = new Value(make_shared($2, aindex, aexpr, DebugInfoRange(@1, @3))); delete $3; } - | identifier '[' T_STRING ']' lbinary_op rterm + | identifier '[' rterm ']' lbinary_op rterm { - AExpression::Ptr subexpr = make_shared($5, $3, static_cast(*$6), DebugInfoRange(@1, @6)); - free($3); + AExpression::Ptr subexpr = make_shared($5, static_cast(*$3), static_cast(*$6), DebugInfoRange(@1, @6)); + delete $3; delete $6; Array::Ptr subexprl = make_shared(); subexprl->Add(subexpr); - AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6)); - $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6))); + AExpression::Ptr aindex = make_shared(&AExpression::OpLiteral, $1, @1); free($1); + + AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6)); + $$ = new Value(make_shared(&AExpression::OpSetPlus, aindex, expr, DebugInfoRange(@1, @6))); } | identifier '.' T_IDENTIFIER lbinary_op rterm { - AExpression::Ptr subexpr = make_shared($4, $3, static_cast(*$5), DebugInfoRange(@1, @5)); + AExpression::Ptr aindex = make_shared(&AExpression::OpLiteral, $1, @1); + AExpression::Ptr subexpr = make_shared($4, aindex, static_cast(*$5), DebugInfoRange(@1, @5)); free($3); delete $5; Array::Ptr subexprl = make_shared(); subexprl->Add(subexpr); - AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5)); - $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @5))); + AExpression::Ptr aindexl = make_shared(&AExpression::OpLiteral, $1, @1); free($1); + + AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5)); + $$ = new Value(make_shared(&AExpression::OpSetPlus, aindexl, expr, DebugInfoRange(@1, @5))); } | T_IMPORT rterm { diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index dc4f20b7f..4a6a8d6dd 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -88,7 +88,12 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) Array::Ptr exprs = make_shared(); Array::Ptr templateArray = make_shared(); templateArray->Add(m_Name); - exprs->Add(make_shared(&AExpression::OpSetPlus, "templates", make_shared(&AExpression::OpLiteral, templateArray, m_DebugInfo), m_DebugInfo)); + + exprs->Add(make_shared(&AExpression::OpSetPlus, + make_shared(&AExpression::OpLiteral, "templates", m_DebugInfo), + make_shared(&AExpression::OpLiteral, templateArray, m_DebugInfo), + m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 24d614206..a99b10a24 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -67,8 +67,15 @@ void Dependency::EvaluateApplyRules(const std::vector& rules) builder->SetName(name); builder->SetScope(rule.GetScope()); - builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "child_host", di), + make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), + di), di)); + + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "child_service", di), + make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index 48e6bdd22..557f6e124 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -67,8 +67,16 @@ void Notification::EvaluateApplyRules(const std::vector& rules) builder->SetName(name); builder->SetScope(rule.GetScope()); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "host", di), + make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), + di)); + + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "service", di), + make_shared(&AExpression::OpLiteral, service->GetShortName(), di), + di)); + builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 3ade63bf0..ff1ffb127 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -67,8 +67,16 @@ void ScheduledDowntime::EvaluateApplyRules(const std::vector& rules) builder->SetName(name); builder->SetScope(rule.GetScope()); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, service->GetShortName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "host", di), + make_shared(&AExpression::OpLiteral, service->GetHost()->GetName(), di), + di)); + + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "service", di), + make_shared(&AExpression::OpLiteral, service->GetShortName(), di), + di)); + builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index 89044285c..6433237e8 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -66,8 +66,16 @@ void Service::EvaluateApplyRules(const std::vector& rules) builder->SetName(name); builder->SetScope(rule.GetScope()); - builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, host->GetName(), di), di)); - builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, rule.GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "host", di), + make_shared(&AExpression::OpLiteral, host->GetName(), di), + di)); + + builder->AddExpression(make_shared(&AExpression::OpSet, + make_shared(&AExpression::OpLiteral, "short_name", di), + make_shared(&AExpression::OpLiteral, rule.GetName(), di), + di)); + builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); From 7a6172c135aea4c5910aa7e542729ca87623e2e4 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 30 Mar 2014 10:28:44 +0200 Subject: [PATCH 24/25] Remove support for the deprecated "var" and "set" keywords. Refs # --- doc/4.1-configuration-syntax.md | 31 +++++++++++++------------------ lib/config/config_lexer.ll | 2 -- lib/config/config_parser.yy | 16 ++-------------- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index 95b312e78..e739a20c3 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -2,8 +2,8 @@ ### Object Definition -Icinga 2 features an object-based configuration format. In order to -define objects the `object` keyword is used: +Icinga 2 features an object-based configuration format. You can define new +objects using the `object` keyword: object Host "host1.example.org" { display_name = "host1", @@ -66,15 +66,15 @@ Example: Certain characters need to be escaped. The following escape sequences are supported: - Character |Escape sequence - ------------------------------------|------------------------------------ - " |\\" - \\ |\\\\ - \ |\\t - \ |\\r - \ |\\n - \ |\\b - \ |\\f +Character |Escape sequence +------------------------------------|------------------------------------ +" |\\" +\\ |\\\\ +\ |\\t +\ |\\r +\ |\\n +\ |\\b +\ |\\f In addition to these pre-defined escape sequences you can specify arbitrary ASCII characters using the backslash character (\\) followed @@ -374,13 +374,8 @@ Global constants can be set using the `const` keyword: The value can be a string, number, array, or a dictionary. -Constants cannot be changed once they are set. - -> **Note** -> -> The `set` and `var` keywords are an alias for `const` and are available -> in order to provide compatibility with older versions. Their use is -> deprecated. +Once defined a constant can be access from any file. Constants cannot be changed +once they are set. ### Apply diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index ff23c3d83..1159ae6e4 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -218,8 +218,6 @@ null return T_NULL; partial return T_PARTIAL; true { yylval->num = 1; return T_NUMBER; } false { yylval->num = 0; return T_NUMBER; } -set return T_VAR; -var return T_VAR; const return T_CONST; apply return T_APPLY; where return T_WHERE; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 0d093e76f..771ced99d 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -128,7 +128,6 @@ static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *le %token T_LESS_THAN "< (T_LESS_THAN)" %token T_GREATER_THAN "> (T_GREATER_THAN)" -%token T_VAR "var (T_VAR)" %token T_CONST "const (T_CONST)" %token T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)" %token T_TYPE_ARRAY "array (T_TYPE_ARRAY)" @@ -166,7 +165,6 @@ static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *le %type rterm %type rterm_scope %type lterm -%type variable_decl %left T_LOGICAL_OR %left T_LOGICAL_AND @@ -228,7 +226,7 @@ statements: /* empty */ | statements statement ; -statement: object | type | include | include_recursive | library | variable | apply +statement: object | type | include | include_recursive | library | constant | apply { } | lterm { @@ -278,7 +276,7 @@ library: T_LIBRARY T_STRING } ; -variable: variable_decl identifier T_SET rterm +constant: T_CONST identifier T_SET rterm { AExpression::Ptr aexpr = static_cast(*$4); delete $4; @@ -290,16 +288,6 @@ variable: variable_decl identifier T_SET rterm } ; -variable_decl: T_VAR - { - $$ = true; - } - | T_CONST - { - $$ = false; - } - ; - identifier: T_IDENTIFIER | T_STRING { From 2034ff5eee8457180fe0aa73cb66c5954c9c4431 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 30 Mar 2014 11:52:39 +0200 Subject: [PATCH 25/25] Update documentation. Refs #5870 --- doc/1-about.md | 5 +- doc/2.1-setting-up-icinga-2.md | 38 +++++---- doc/2.2-setting-up-check-plugins.md | 51 +++++++----- doc/3.10-logging.md | 31 +++---- doc/4.1-configuration-syntax.md | 125 +++++++++++++++------------- doc/4.2-global-variables.md | 2 +- doc/4.3-object-types.md | 12 +-- doc/4.5-best-practice.md | 6 +- 8 files changed, 143 insertions(+), 127 deletions(-) diff --git a/doc/1-about.md b/doc/1-about.md index da0ade501..00e89ee0c 100644 --- a/doc/1-about.md +++ b/doc/1-about.md @@ -2,8 +2,9 @@ ## What is Icinga 2? -Icinga 2 is an open source monitoring system which keeps watch over network resources, -notifies users of outages and recoveries and generates performance data for reporting. +Icinga 2 is an open source monitoring system which checks the availability of your +network resources, notifies users of outages and generates performance data for reporting. + Scalable and extensible, Icinga 2 can monitor complex, large environments across multiple locations. diff --git a/doc/2.1-setting-up-icinga-2.md b/doc/2.1-setting-up-icinga-2.md index 23d8e82c6..7443d43ae 100644 --- a/doc/2.1-setting-up-icinga-2.md +++ b/doc/2.1-setting-up-icinga-2.md @@ -4,14 +4,14 @@ First of all you will have to install Icinga 2. The preferred way of doing this is to use the official Debian or RPM package repositories depending on which operating system and distribution you are running. - Distribution |Repository URL + Distribution | Repository URL ------------------------|--------------------------- - Debian |http://packages.icinga.org/debian/ - Ubuntu |http://packages.icinga.org/ubuntu/ - RHEL/CentOS 5 |http://packages.icinga.org/epel/5/release/ - RHEL/CentOS 6 |http://packages.icinga.org/epel/6/release/ - OpenSUSE 12.3 |http://packages.icinga.org/openSUSE/12.3/release/ - SLES 11 SP3 |http://packages.icinga.org/SUSE/sles11-sp3/release/ + Debian | http://packages.icinga.org/debian/ + Ubuntu | http://packages.icinga.org/ubuntu/ + RHEL/CentOS 5 | http://packages.icinga.org/epel/5/release/ + RHEL/CentOS 6 | http://packages.icinga.org/epel/6/release/ + OpenSUSE 12.3 | http://packages.icinga.org/openSUSE/12.3/release/ + SLES 11 SP3 | http://packages.icinga.org/SUSE/sles11-sp3/release/ Packages for distributions other than the ones listed above may also be available. Please check http://packages.icinga.org/ to see if packages @@ -29,8 +29,7 @@ to install the `icinga2` package. > **Note** > > On RHEL/CentOS and SLES you will need to use `chkconfig` to enable the -`icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2 -start`. +> `icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2 start`. Some parts of Icinga 2's functionality are available as separate packages: @@ -114,7 +113,7 @@ The `conf.d/macros.conf` file can be used to define global macros: /** * Global macros */ - set IcingaMacros = { + const IcingaMacros = { plugindir = "/usr/local/icinga/libexec" } @@ -137,6 +136,15 @@ The `conf.d/localhost.conf` file contains our first host definition: macros.address6 = "::1" } +This defines the host `localhost`. The `import` keyword is used to import +the `linux-server` template which takes care of setting up the `ping4` and +`ping6` services for the host as well as adding the host to the `linux-servers` +host group. + +The `macros` attribute can be used to define macros that are available for all +services which belong to this host. Most of the templates in the Icinga Template +Library require an `address` macro. + apply Service "icinga" { import "generic-service", @@ -199,13 +207,9 @@ The `conf.d/localhost.conf` file contains our first host definition: assign where host.name == "localhost" } -This defines a host named "localhost" which has a couple of services. Services -may import one or more service templates. +The `apply` keyword can be used to dynamically create services for all hosts based +on rules. -The command objects `ping4`, `ping6`, `http_ip`, `ssh`, `load`, `processes`, `users` +The command objects `http_ip`, `ssh`, `load`, `processes`, `users` and `disk` are all provided by the Icinga Template Library (short ITL) which we enabled earlier by including the `itl/itl.conf` configuration file. - -The `macros` attribute can be used to define macros that are available for all -services which belong to this host. Most of the templates in the Icinga Template -Library require an `address` macro. diff --git a/doc/2.2-setting-up-check-plugins.md b/doc/2.2-setting-up-check-plugins.md index 89dcb25ac..622fc7004 100644 --- a/doc/2.2-setting-up-check-plugins.md +++ b/doc/2.2-setting-up-check-plugins.md @@ -1,17 +1,18 @@ ## Setting up Check Plugins On its own Icinga 2 does not know how to check external services. The -[Monitoring Plugins Project](https://www.monitoring-plugins.org/) (former -Nagios Plugins) provides an extensive set of plugins which can be used by -Icinga 2 to check whether services are working properly. +[Monitoring Plugins Project](https://www.monitoring-plugins.org/) provides +an extensive set of plugins which can be used with Icinga 2 to check whether +services are working properly. The recommended way of installing these standard plugins is to use your distribution's package manager. > **Note** > -> The `Nagios Plugins` project was renamed to `Monitoring Plugins` project -> in Jan 2014. Therefore package names may still reflect the old name. +> The `Nagios Plugins` project was renamed to `Monitoring Plugins` +> in January 2014. At the time of this writing the packages are still +> using the old name. For your convenience here is a list of package names for some of the more popular operating systems/distributions: @@ -27,29 +28,41 @@ Depending on which directory your plugins are installed into you may need to update the `plugindir` macro in your Icinga 2 configuration. This macro is used by the service templates contained in the Icinga Template Library to determine where to find the plugin binaries. -Alternatively you can create a symbolic link pointing to the installation path -of the plugins. ### Integrate Additional Plugins -You may require a custom check plugin not provided by the official Nagios plugins. -All existing Nagios or Icinga 1.x plugins found on public community websites -will work with Icinga 2 as well. +For some services you may need additional check plugins which are not provided +by the official Monitoring Plugins project. + +All existing Nagios or Icinga 1.x plugins should work with Icinga 2. Here's a +list of popular community sites which host check plugins: * [MonitoringExchange](https://www.monitoringexchange.org) * [Icinga Wiki](https://wiki.icinga.org) -Once you have downloaded the plugin copy it into the directory defined by the global -`IcingaMacro` `$plugindir$` and make sure that the user the Icinga daemon is running as -can execute the the plugin binary. Plugins should support the `--help` parameter -providing details how they have to be called in your command definition later on. +The recommended way of setting up these plugins is to copy them to a common directory +and creating an extra global macro, e.g. `customplugindir` in your `macros.conf` +configuration file: - # cp check_snmp_int.pl /usr/local/icinga/libexec/ - # chmod +x /usr/local/icinga/libexec/check_snmp_int.pl - - # /usr/local/icinga/libexec/check_snmp_int.pl --help + # cp check_snmp_int.pl /opt/plugins + # chmod +x /opt/plugins/check_snmp_int.pl + + # cat /etc/icinga2/conf/macros.conf + /** + * Global macros + */ + const IcingaMacros = { + plugindir = "/usr/lib/nagios/plugins", + customplugindir = "/opt/monitoring" + } + +Prior to using the check plugin with Icinga 2 you should ensure that it is working properly +by trying to run it on the console using whichever user Icinga 2 is running as: + + # su - icinga -s /bin/bash + $ /opt/plugins/check_snmp_int.pl --help > **Note** > -> You may require additional libraries for scripts. Please consult the installation +> You may require additional libraries for some plugins. Please consult the installation > documentation and/or README for their installation requirements. diff --git a/doc/3.10-logging.md b/doc/3.10-logging.md index b83d7f915..0db6ba424 100644 --- a/doc/3.10-logging.md +++ b/doc/3.10-logging.md @@ -2,26 +2,19 @@ Icinga 2 supports three different types of logging: -* File logging (local Icinga 2 log file) -* Syslog facility logging (system's syslog application) +* File logging +* Syslog (on *NIX-based operating systems) * Console logging (`STDOUT` on tty) -> **Note** -> -> You can define multiple logging objects at once. +You can enable additional loggers using the `icinga2-enable-feature` +and `icinga2-disable-feature` commands to configure loggers: -The most common scenario will be logging Icinga 2's output to -syslog with severity `information`. - - object SyslogLogger "syslog" { - severity = "information" - } - -For debugging purposes you can install a `FileLogger` object -and forward the `debug` severity into an Icinga 2 debug file. - - object FileLogger "debug-file" { - severity = "debug", - path = "/var/log/icinga2/debug.log" - } +Feature | Description +---------|------------ +debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher) +mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher) +syslog | Syslog (severity: `warning` or higher) +By default file the `mainlog` feature is enabled. When running Icinga 2 +on a terminal log messages with severity `information` or higher are +written to the console. diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index e739a20c3..6485496ae 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -66,15 +66,15 @@ Example: Certain characters need to be escaped. The following escape sequences are supported: -Character |Escape sequence -------------------------------------|------------------------------------ -" |\\" -\\ |\\\\ -\ |\\t -\ |\\r -\ |\\n -\ |\\b -\ |\\f +Character | Escape sequence +--------------------------|------------------------------------ +" | \\" +\\ | \\\\ +<TAB> | \\t +<CARRIAGE-RETURN> | \\r +<LINE-FEED> | \\n +<BEL> | \\b +<FORM-FEED> | \\f In addition to these pre-defined escape sequences you can specify arbitrary ASCII characters using the backslash character (\\) followed @@ -154,7 +154,8 @@ The following operators are supported in expressions: Operator | Examples (Result) | Description ---------|-----------------------------------------------|-------------------------------- -!, ~ | ~true (false) | Bitwise negation of the operand +! | !"Hello" (false), !false (true) | Logical negation of the operand +~ | ~true (false) | Bitwise negation of the operand + | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings - | 3 - 1 (2) | Subtracts two numbers * | 5m * 10 (3000) | Multiplies two numbers @@ -295,6 +296,12 @@ The indexer syntax provides a convenient way to set dictionary elements. Example: + { + hello.key = "world" + } + +Example (alternative syntax): + { hello["key"] = "world" } @@ -307,80 +314,55 @@ This is equivalent to writing: } } -### Object Inheritance +### Template Imports -Objects can inherit attributes from other objects. +Objects can import attributes from other objects. Example: template Host "default-host" { - macros["color"] = "red" + macros.color = "red" } template Host "test-host" { import "default-host", - macros["color"] = "blue" + macros.color = "blue" } object Host "localhost" { import "test-host", - macros["address"] = "127.0.0.1", - macros["address6"] = "::1" + macros.address = "127.0.0.1", + macros.address6 = "::1" } The `default-host` and `test-host` objects are marked as templates using the `template` keyword. Unlike ordinary objects templates are not instantiated at run-time. Parent objects do not necessarily have to be -templates though in general they are. +templates, however in general they are. > **Note** > -> The final macros dictionary contains all three macros and the macro -> `color` has the value `"blue"`. +> The macros dictionary for the `localhost` object contains all three +> macros and the macro `color` has the value `"blue"`. Parent objects are resolved in the order they're specified using the `import` keyword. -### Disable/Override Objects and Attributes - -Object attributes can be overridden by defining the additional changed attribute -directly on the object. Use the `+=` operator for the inline services dictionary. - - services["overridden-custom-attr"] += { - custom = { - notes = "disabled all custom attr" - } - } - -If you don't require an attribute inherited from templates, you can simply -override its value by setting it explicitely to `null`. - - services["no-custom-attr"] += { - custom = null - } - -The same method applies for disabling services defined in the inline `services` -dictionary by explicitly overriding their value with `null`. - - services["ping6"] = null - ### Constants Global constants can be set using the `const` keyword: const VarName = "some value" -The value can be a string, number, array, or a dictionary. - Once defined a constant can be access from any file. Constants cannot be changed once they are set. ### Apply -The `apply` keyword can be used to associate a template with another group of -objects. The exact effect of this association depends on the object type. +The `apply` keyword can be used to create new objects which are associated with +another group of objects. apply Service "ping" { import "generic-service", @@ -390,19 +372,43 @@ objects. The exact effect of this association depends on the object type. assign where host.name == "localhost" } -In this example the `assign where` condition is an expression which is -evaluated for all objects of type Host and a new service with name "ping" +In this example the `assign where` condition is a boolean expression which is +evaluated for all objects of type `Host` and a new service with name "ping" is created for each matching host. Depending on the object type used in the `apply` expression additional local variables may be available for use in the `where` condition: - Type |Variables - -----------------|---------------- - Dependency |host, service - Notification |host, service - Service |host - ScheduledDowntime|host, service +Source Type | Target Type | Variables +-----------------|-------------|-------------- +Service | Host | host +Dependency | Service | host, service +Notification | Service | host, service +ScheduledDowntime| Service | host, service + +> **Note** +> +> Any valid config attribute can be accessed using the `host` and `service` +> variables. For example, `host.macros.address` would return the host's +> "address" macro - or null if it doesn't have that macro. + +### Boolean Values + +The `assign where` and `ignore where` statements, the unary `!`, `&&` and `||` +operators as well as the `bool()` function convert their arguments to a +boolean value based on the following rules: + +Description | Example Value | Boolean Value +---------------------|-------------------|-------------- +Empty value | null | false +Zero | 0 | false +Non-zero integer | -23945 | true +Empty string | "" | false +Non-empty string | "Hello" | true +Empty array | [] | false +Non-empty array | [ "Hello" ] | true +Empty dictionary | {} | false +Non-empty dictionary | { key = "value" } | true ### Comments @@ -440,7 +446,7 @@ C/C++ compiler: Note the use of angle brackets instead of double quotes. This causes the config compiler to search the include search paths for the specified -file. By default $PREFIX/icinga2 is included in the list of search +file. By default $PREFIX/share/icinga2 is included in the list of search paths. Additional include search paths can be added using [command-line options](#cmdline). @@ -466,7 +472,7 @@ When no pattern is specified the default pattern "*.conf" is used. The `library` directive can be used to manually load additional libraries. Libraries can be used to provide additional object types and -methods. +functions. Example: @@ -474,8 +480,8 @@ Example: > **Note** > -> The `icinga` library is automatically loaded at startup. You don't need -> to load it manually. +> The `icinga` and `methods` libraries is automatically loaded at startup. +> You don't need to load them manually.