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