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/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/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) diff --git a/doc/1-about.md b/doc/1-about.md index 36afb5ab5..00e89ee0c 100644 --- a/doc/1-about.md +++ b/doc/1-about.md @@ -2,10 +2,11 @@ ## 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 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. ## Licensing diff --git a/doc/2.1-setting-up-icinga-2.md b/doc/2.1-setting-up-icinga-2.md index 71a3043f4..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" } @@ -131,70 +130,86 @@ 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" } - -This defines a host named "localhost" which has a couple of services. Services -may inherit from 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 -we enabled earlier by including the `itl/itl.conf` configuration file. +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", + + 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" + } + +The `apply` keyword can be used to dynamically create services for all hosts based +on rules. + +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. 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/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 4f3cddc40..9eb8ee02e 100644 --- a/doc/3.02-commands.md +++ b/doc/3.02-commands.md @@ -59,39 +59,37 @@ 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$%", "-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 macros (warning thresholds at `10%`, critical thresholds at `5%` free disk space). - object Host "localhost" inherits "generic-host" { + 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 } @@ -112,7 +110,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 +187,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", @@ -202,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 6c1b67cdb..5cb76565a 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", @@ -73,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 @@ -126,8 +126,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 +248,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..edcb164ac 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 = [ @@ -111,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` @@ -154,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" @@ -163,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" } } @@ -198,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** > @@ -243,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 0cb0a403a..373973cae 100644 --- a/doc/3.05-using-templates.md +++ b/doc/3.05-using-templates.md @@ -7,42 +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" inherits "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" inherits "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 4e53e3389..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 @@ -61,24 +60,20 @@ the user groups are associated as attributes in `Notification` objects. groups = [ "windows-mssql-admins" ] } - object User "win-mssql-noc" inherits "generic-windows-mssql-users" { - macros = { - "email" = "noc@company.com" - } + object User "win-mssql-noc" { + import "generic-windows-mssql-users", + + macros.email = "noc@example.com" } - object User "win-mssql-ops" inherits "generic-windows-mssql-users" { - macros = { - "email" = "ops@company.com" - } + object User "win-mssql-ops" { + import "generic-windows-mssql-users", + + 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 2ba56d154..44cb6a0e2 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", @@ -62,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.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/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 7a95dd76c..401b225fb 100644 --- a/doc/3.15-monitoring-remote-clients.md +++ b/doc/3.15-monitoring-remote-clients.md @@ -21,22 +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" inherits "generic-host" { - ... - 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" - } + apply Service "uptime" { + import "generic-service", + + templates = [ "generic-service" ], + check_command = "snmp", + macros.oid = "1.3.6.1.2.1.1.3.0", + + assign where host.macros.community } #### SSH @@ -44,7 +40,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,22 +50,17 @@ its return code and output. `check_by_ssh` is available in the [Monitoring Plugi ] } - object Host "remote-ssh-host" inherits "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 @@ -77,37 +70,33 @@ 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: - 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" { - ... - services["users"] = { - templates = [ "generic-service" ], - check_command = "check_nrpe", - macros = { - "remote_nrpe_command" = "check_users" - } - }, - macros = { - "address" = "192.168.1.103" - } + apply Service "users" { + import "generic-service", + + check_command = "check_nrpe", + macros.remote_nrpe_command = "check_users", + + 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 @@ -122,7 +111,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,21 +129,18 @@ Example: } } - object Host "remote-windows-host" inherits "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). @@ -166,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 5dd7d9c01..6485496ae 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 +--------------------------|------------------------------------ +" | \\" +\\ | \\\\ +<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,60 +314,41 @@ 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" inherits "default-host" { - macros["color"] = "blue" + template Host "test-host" { + import "default-host", + + macros.color = "blue" } - object Host "localhost" inherits "test-host" { - macros["address"] = "127.0.0.1", - macros["address6"] = "::1" + object Host "localhost" { + import "test-host", + + 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 -`inherits` 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 +`import` keyword. ### Constants @@ -368,34 +356,59 @@ Global constants can be set using the `const` keyword: const VarName = "some value" -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 -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. +The `apply` keyword can be used to create new objects which are associated with +another group of objects. - 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 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. -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. +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 @@ -433,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). @@ -459,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: @@ -467,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. diff --git a/doc/4.2-global-variables.md b/doc/4.2-global-variables.md index eb9560504..169e10295 100644 --- a/doc/4.2-global-variables.md +++ b/doc/4.2-global-variables.md @@ -4,7 +4,7 @@ Icinga 2 provides a number of special global constants. Some of them can be over Variable |Description --------------------------|------------------- -IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to /usr/local +IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to "/usr/local". IcingaSysconfDir |**Read-only.** Contains the path of the sysconf directory. Defaults to IcingaPrefixDir + "/etc". IcingaLocalStateDir |**Read-only.** Contains the path of the local state directory. Defaults to IcingaPrefixDir + "/var". IcingaPkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to IcingaPrefixDir + "/share/icinga2". diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md index 0af7c07de..3a60a7ba2 100644 --- a/doc/4.3-object-types.md +++ b/doc/4.3-object-types.md @@ -17,19 +17,6 @@ Example: groups = [ "all-hosts" ], - services["ping"] = { - templates = [ "ping" ] - }, - - services["http"] = { - templates = [ "my-http" ], - - macros = { - vhost = "test1.example.org", - port = 81 - } - }, - check = "ping" } @@ -40,8 +27,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 +53,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 +100,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 +127,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 +185,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: @@ -327,7 +310,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", @@ -345,7 +330,7 @@ Attributes: Name |Description ----------------|---------------- display_name |**Optional.** A short description of the time period. - methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should just inherit from the "legacy-timeperiod" template to take care of this setting. + methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should import the "legacy-timeperiod" template to take care of this setting. ranges |**Required.** A dictionary containing information which days and durations apply to this timeperiod. The `/etc/icinga2/conf.d/timeperiods.conf` file is usually used to define @@ -358,8 +343,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: @@ -431,7 +416,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 = { @@ -444,7 +431,7 @@ Attributes: Name |Description ----------------|---------------- - methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should just inherit from the "plugin-check-command" template to take care of this setting. + methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should import the "plugin-check-command" template to take care of this setting. command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command. @@ -457,7 +444,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 = [ @@ -480,7 +469,7 @@ Attributes: Name |Description ----------------|---------------- - methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should just inherit from the "plugin-notification-command" template to take care of this setting. + methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should import the "plugin-notification-command" template to take care of this setting. command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command. @@ -497,7 +486,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", } @@ -506,7 +497,7 @@ Attributes: Name |Description ----------------|---------------- - methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should just inherit from the "plugin-event-command" template to take care of this setting. + methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should import the "plugin-event-command" template to take care of this setting. command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command. export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command. diff --git a/doc/4.5-best-practice.md b/doc/4.5-best-practice.md index 04f69c6c5..841202b5b 100644 --- a/doc/4.5-best-practice.md +++ b/doc/4.5-best-practice.md @@ -3,9 +3,11 @@ ### Configuration File and Directory Structure Icinga 2 does not care how you name your files and/or directories as long as -you'll include them accordingly in the [icinga2.conf](#icinga2-conf) file. +you include them in the [icinga2.conf](#icinga2-conf) file. + +By default, the `conf.d` directory is included recursively looking for files +which match the pattern `*.conf`. -By default, `conf.d` is included recursively looking for `*.conf` file endings. If you're putting/generating your configuration structure in there, you do not need to touch the [icinga2.conf](#icinga2-conf) file. This becomes useful with external addons not having write permissions to this file such as LConf. @@ -41,7 +43,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 +55,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. @@ -81,15 +80,16 @@ 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 } ### 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 @@ -145,20 +145,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", @@ -168,6 +165,8 @@ downtimes through the template automatism. ranges = { "sunday" = "02:00-03:00" } + + assign where "generic-service" in service.templates } template Service "generic-service" { @@ -175,35 +174,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" inherits "linux-server" { + 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 6d2ab0b19..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,17 +86,7 @@ Example: saturday = "02:00-03:00", sunday = "02:00-03:00" } + + assign where "backup" in service.groups } - object Host "localhost" inherits "generic-host" { - ... - services["load"] = { - templates = [ "generic-service" ], - - check_command = "load", - - scheduled_downtimes["backup"] = { - 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..7727c3eac 100644 --- a/doc/6.04-cluster.md +++ b/doc/6.04-cluster.md @@ -210,11 +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" inherits "generic-host" { - services["dmz-oracledb"] = { - templates = [ "generic-service" ], - authorities = [ "icinga-node-1" ], - } + apply Service "dmz-oracledb" { + import "generic-service", + + authorities = [ "icinga-node-1" ], + + assign where "oracle" in host.groups } > **Tip** @@ -232,13 +233,14 @@ one or more configured nodes are not connected. Example: - object Host "icinga2a" inherits "generic-host" { - services["cluster"] = { - templates = [ "generic-service" ], + apply Service "cluster" { + import "generic-service", + check_interval = 1m, check_command = "cluster", - authorities = [ "icinga2a" ] - }, + authorities = [ "icinga2a" ], + + assign where host.name = "icinga2a" } > **Note** 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/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 82e7f60f4..33f2acc1e 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 @@ -216,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 @@ -369,17 +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" 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 -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 diff --git a/etc/icinga2/conf.d/generic-host.conf b/etc/icinga2/conf.d/generic-host.conf index 3094fd2cd..e6be42e07 100644 --- a/etc/icinga2/conf.d/generic-host.conf +++ b/etc/icinga2/conf.d/generic-host.conf @@ -1,51 +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" } -template Host "linux-server" inherits "generic-host" { +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" inherits "generic-host" { +template Host "windows-server" { + import "generic-host", + groups += [ "windows-servers" ], - - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" } -template Host "generic-printer" inherits "generic-host" { - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" +template Host "generic-printer" { + import "generic-host", } -template Host "generic-switch" inherits "generic-host" { - services["ping4"] = { - templates = [ "generic-service" ], - - check_command = "ping4" - }, - - check = "ping4" +template Host "generic-switch" { + import "generic-host", } 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 807011582..2f2bd6390 100644 --- a/etc/icinga2/conf.d/localhost.conf +++ b/etc/icinga2/conf.d/localhost.conf @@ -3,71 +3,72 @@ * 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" { - display_name = "localhost", +object Host "localhost" { + import "linux-server", - 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/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/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/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/base/dynamicobject.ti b/lib/base/dynamicobject.ti index c68aec7ad..682eb228d 100644 --- a/lib/base/dynamicobject.ti +++ b/lib/base/dynamicobject.ti @@ -3,8 +3,9 @@ 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, get_protected] Array::Ptr templates; [config] Dictionary::Ptr methods; [config] Dictionary::Ptr custom; [config] Array::Ptr domains; 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(); } } diff --git a/lib/base/serializer.cpp b/lib/base/serializer.cpp index c28ca4280..88c2ad7ac 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; @@ -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; @@ -230,7 +231,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/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)"; } /** diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index c1f1b3a66..3e9e53f99 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" @@ -26,6 +27,8 @@ #include "base/scriptvariable.h" #include "base/utility.h" #include "base/objectlock.h" +#include "base/object.h" +#include "base/logger_fwd.h" #include #include #include @@ -43,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)) @@ -52,66 +63,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) @@ -179,6 +130,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); @@ -253,7 +209,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); @@ -341,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; @@ -368,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; @@ -394,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; @@ -420,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; @@ -446,16 +409,49 @@ 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; } 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 if (value.IsEmpty()) { + return Empty; + } else { + BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'")); + } +} + +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..a51ce357b 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); @@ -52,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); @@ -79,6 +78,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/applyrule.cpp b/lib/config/applyrule.cpp index c31fd2b07..58c58662d 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,56 @@ 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; - 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(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::RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback) +void ApplyRule::RegisterType(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback) { - m_Callbacks[std::make_pair(sourceType, targetType)] = callback; + m_Callbacks[sourceType] = make_pair(callback, targetType); } -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..90ebeecdf 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 String& targetType, const ApplyRule::Callback& callback); + 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/base-type.conf b/lib/config/base-type.conf index d23c17b67..66411d726 100644 --- a/lib/config/base-type.conf +++ b/lib/config/base-type.conf @@ -17,40 +17,44 @@ * 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 "custom" { - %attribute string "*" + %attribute %array "templates" { + %attribute %string "*" }, - %attribute array "domains" { - %attribute string "*" + %attribute %dictionary "methods", + + %attribute %dictionary "custom" { + %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 06e116113..1159ae6e4 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -197,33 +197,33 @@ 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; } false { yylval->num = 0; return T_NUMBER; } -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 95cea330a..771ced99d 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 @@ -121,7 +128,6 @@ using namespace icinga; %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)" @@ -142,8 +148,11 @@ 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 @@ -151,27 +160,25 @@ using namespace icinga; %type lterm_items_inner %type typerulelist %type lbinary_op -%type rbinary_op %type type %type partial_specifier -%type object_inherits_list -%type object_inherits_specifier %type rterm %type rterm_scope %type lterm -%type variable_decl + %left T_LOGICAL_OR %left T_LOGICAL_AND +%left T_BINARY_OR +%left T_BINARY_AND %left T_IN %left T_NOT_IN -%nonassoc T_EQUAL -%nonassoc T_NOT_EQUAL -%left '+' '-' -%left '*' '/' -%left '&' -%left '|' -%right '~' -%right '!' +%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 +%right '!' '~' +%left '.' '(' '[' %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); @@ -192,6 +199,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(); @@ -215,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 { @@ -265,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; @@ -277,16 +288,6 @@ variable: variable_decl identifier T_SET rterm } ; -variable_decl: T_VAR - { - $$ = true; - } - | T_CONST - { - $$ = false; - } - ; - identifier: T_IDENTIFIER | T_STRING { @@ -411,9 +412,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 +445,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 +466,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 @@ -551,52 +512,77 @@ 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 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 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 + { + 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; } ; - -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 { @@ -630,12 +616,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))); @@ -655,6 +635,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); @@ -668,7 +654,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 @@ -676,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 ']' @@ -694,30 +680,56 @@ rterm: T_STRING { $$ = $2; } - | rterm rbinary_op rterm + | 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: { - $$ = new Value(make_shared($2, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; + m_Apply = true; + m_Assign = make_shared(&AExpression::OpLiteral, false, DebugInfo()); + m_Ignore = make_shared(&AExpression::OpLiteral, false, DebugInfo()); } - ; - -optional_template: /* empty */ - | T_TEMPLATE - ; - -apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE rterm + T_APPLY identifier rterm rterm { - 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 = 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(DebugInfoRange(@2, @3))); - 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(@2, @5), m_ModuleScope); + + m_Assign.reset(); + m_Ignore.reset(); } %% 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/configitem.cpp b/lib/config/configitem.cpp index 8668dbf3c..5f3052b35 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,53 +110,19 @@ 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()); 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); - GetLinkedExpressionList()->Evaluate(m_Properties); + 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/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..4a6a8d6dd 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,19 @@ 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)); + Array::Ptr templateArray = make_shared(); + templateArray->Add(m_Name); + + 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); 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/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); 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); } 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/CMakeLists.txt b/lib/icinga/CMakeLists.txt index 5ea9d54ff..ab9ed192d 100644 --- a/lib/icinga/CMakeLists.txt +++ b/lib/icinga/CMakeLists.txt @@ -42,15 +42,15 @@ 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 - externalcommandprocessor.cpp host.cpp host.th host-apply.cpp hostgroup.cpp hostgroup.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 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 - 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/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp new file mode 100644 index 000000000..a99b10a24 --- /dev/null +++ b/lib/icinga/dependency-apply.cpp @@ -0,0 +1,87 @@ +/****************************************************************************** + * 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", "Service", &Dependency::EvaluateApplyRules); +} + +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, + 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(); + 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); diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 386605473..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,78 +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->GetLinkedExpressionList(); - } - - 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); - 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; - - Array::Ptr templates = service->Get("templates"); - - if (templates) { - ObjectLock olock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); - } - } - - /* 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..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); @@ -114,8 +111,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..946cdfccb 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -17,283 +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) "*" - }, - %attribute dictionary "services" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Service) "*" - }, - - %attribute any "*" - } +%type Host { + %attribute %string "display_name", + %attribute %string "check", + %attribute %array "groups" { + %attribute %name(HostGroup) "*" }, - %attribute dictionary "dependencies" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Dependency) "*" - }, - - %attribute any "*" - } - }, - - %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 dictionary "dependencies" { - %attribute dictionary "*" { - %attribute array "templates" { - %attribute name(Dependency) "*" - }, - - %attribute any "*" - } + %attribute %array "groups" { + %attribute %name(ServiceGroup) "*" }, - %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) "*" + %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 any "templates", - - %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 "*" }, - - %attribute any "templates" } -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/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp new file mode 100644 index 000000000..557f6e124 --- /dev/null +++ b/lib/icinga/notification-apply.cpp @@ -0,0 +1,88 @@ +/****************************************************************************** + * 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", "Service", &Notification::EvaluateApplyRules); +} + +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, + 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(); + 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..ff1ffb127 --- /dev/null +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -0,0 +1,88 @@ +/****************************************************************************** + * 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", "Service", &ScheduledDowntime::EvaluateApplyRules); +} + +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, + 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(); + 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); diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/service-apply.cpp similarity index 66% rename from lib/icinga/host-apply.cpp rename to lib/icinga/service-apply.cpp index 010987ba4..6433237e8 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,59 +28,55 @@ using namespace icinga; -INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler); +INITIALIZE_ONCE(&Service::RegisterApplyRuleHandler); -void Host::RegisterApplyRuleHandler(void) +void Service::RegisterApplyRuleHandler(void) { - ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules); + ApplyRule::RegisterType("Service", "Host", &Service::EvaluateApplyRules); } -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() + "'"); 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(); + std::ostringstream msgbuf; - msgbuf << "Evaluating 'apply' rule (" << rule.GetDebugInfo() << ")"; + 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 (" << rule.GetDebugInfo() << ") 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 " << rule.GetDebugInfo(); + 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(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()); + 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(); serviceItem->Register(); diff --git a/lib/icinga/service-dependency.cpp b/lib/icinga/service-dependency.cpp index 36b455bee..d17e99501 100644 --- a/lib/icinga/service-dependency.cpp +++ b/lib/icinga/service-dependency.cpp @@ -154,89 +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->GetLinkedExpressionList(); - } - - 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); - 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; - - Array::Ptr templates = dependency->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); - } - } - - /* 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 d914284a4..93df0d8e2 100644 --- a/lib/icinga/service-downtime.cpp +++ b/lib/icinga/service-downtime.cpp @@ -321,70 +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->GetLinkedExpressionList(); - } - - 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); - 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; - - Array::Ptr templates = scheduledDowntime->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); - } - } - - /* 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 5fb711aa4..ed49fb8f8 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -100,74 +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->GetLinkedExpressionList(); - } - - 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); - 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; - - Array::Ptr templates = notification->Get("templates"); - - if (templates) { - ObjectLock tlock(templates); - - BOOST_FOREACH(const Value& tmpl, templates) { - builder->AddParent(tmpl); - } - } - - /* 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..657dcddcf 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,7 +280,8 @@ public: void RemoveReverseDependency(const shared_ptr& dep); std::set > GetReverseDependencies(void) const; - void UpdateSlaveDependencies(void); + static void RegisterApplyRuleHandler(void); + static void EvaluateApplyRules(const std::vector& rules); protected: virtual void Start(void); 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) "*" } } 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 = [