Merge branch 'feature/config-5870' into next

Fixes #5845
Fixes #5848
Fixes #5870
Fixes #5872
Fixes #5875
Fixes #5876
Fixes #5878
Fixes #5880
Fixes #5882
Fixes #5883
Fixes #5884
Fixes #5885
This commit is contained in:
Gunnar Beutner 2014-03-30 11:58:32 +02:00
commit fd0bc8d321
86 changed files with 1684 additions and 1739 deletions

View File

@ -3,7 +3,9 @@
* in the conf.d directory (e.g. one per host). By default all *.conf * in the conf.d directory (e.g. one per host). By default all *.conf
* files in this directory are included. * 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", display_name = "nsca-ng test",
services["PassiveService1"] = { services["PassiveService1"] = {

View File

@ -17,5 +17,5 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type CheckerComponent { %type CheckerComponent {
} }

View File

@ -17,22 +17,22 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type ClusterListener { %type ClusterListener {
%attribute string "cert_path", %attribute %string "cert_path",
%require "cert_path", %require "cert_path",
%attribute string "key_path", %attribute %string "key_path",
%require "key_path", %require "key_path",
%attribute string "ca_path", %attribute %string "ca_path",
%require "ca_path", %require "ca_path",
%attribute string "crl_path", %attribute %string "crl_path",
%attribute string "bind_host", %attribute %string "bind_host",
%attribute string "bind_port", %attribute %string "bind_port",
%attribute array "peers" { %attribute %array "peers" {
%attribute name(Endpoint) "*" %attribute name(Endpoint) "*"
} }
} }

View File

@ -17,23 +17,23 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type StatusDataWriter { %type StatusDataWriter {
%attribute string "status_path", %attribute %string "status_path",
%attribute string "objects_path", %attribute %string "objects_path",
%attribute number "update_interval" %attribute %number "update_interval"
} }
type ExternalCommandListener { %type ExternalCommandListener {
%attribute string "command_path" %attribute %string "command_path"
} }
type CompatLogger { %type CompatLogger {
%validator "ValidateRotationMethod", %validator "ValidateRotationMethod",
%attribute string "log_dir", %attribute %string "log_dir",
%attribute string "rotation_method" %attribute %string "rotation_method"
} }
type CheckResultReader { %type CheckResultReader {
%attribute string "spool_dir" %attribute %string "spool_dir"
} }

View File

@ -17,15 +17,15 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type IdoMysqlConnection inherits DbConnection { %type IdoMysqlConnection %inherits DbConnection {
%attribute string "host", %attribute %string "host",
%attribute number "port", %attribute %number "port",
%attribute string "user", %attribute %string "user",
%attribute string "password", %attribute %string "password",
%attribute string "database", %attribute %string "database",
%attribute string "instance_name", %attribute %string "instance_name",
%attribute string "instance_description" %attribute %string "instance_description"
} }

View File

@ -17,15 +17,15 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type IdoPgsqlConnection inherits DbConnection { %type IdoPgsqlConnection %inherits DbConnection {
%attribute string "host", %attribute %string "host",
%attribute number "port", %attribute %number "port",
%attribute string "user", %attribute %string "user",
%attribute string "password", %attribute %string "password",
%attribute string "database", %attribute %string "database",
%attribute string "instance_name", %attribute %string "instance_name",
%attribute string "instance_description" %attribute %string "instance_description"
} }

View File

@ -17,5 +17,5 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type Demo { %type Demo {
} }

View File

@ -17,14 +17,14 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type LivestatusListener { %type LivestatusListener {
%validator "ValidateSocketType", %validator "ValidateSocketType",
%attribute string "socket_type", %attribute %string "socket_type",
%attribute string "socket_path", %attribute %string "socket_path",
%attribute string "bind_host", %attribute %string "bind_host",
%attribute string "bind_port", %attribute %string "bind_port",
%attribute string "compat_log_path", %attribute %string "compat_log_path",
} }

View File

@ -17,5 +17,5 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type NotificationComponent { %type NotificationComponent {
} }

View File

@ -17,13 +17,13 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type PerfdataWriter { %type PerfdataWriter {
%attribute string "perfdata_path", %attribute %string "perfdata_path",
%attribute string "format_template", %attribute %string "format_template",
%attribute number "rotation_interval" %attribute %number "rotation_interval"
} }
type GraphiteWriter { %type GraphiteWriter {
%attribute string "host", %attribute %string "host",
%attribute string "port", %attribute %string "port",
} }

View File

@ -48,14 +48,15 @@ for line in out.split("\n"):
plugin = "".join([chr(int(ch)) for ch in plugin]) plugin = "".join([chr(int(ch)) for ch in plugin])
plugins.append(plugin) plugins.append(plugin)
print("template Host \"snmp-extend:%s\" {" % (ipaddr))
print(" macros[\"community\"] = \"%s\"," % (community))
for plugin in plugins: for plugin in plugins:
print(" services[\"%s\"] = {" % (plugin)) print("apply Service \"%s\" {" % (plugin))
print(" templates = [ \"snmp-extend-service\" ],") print(" import \"snmp-extend-service\",")
print(" check_command = \"snmp-extend\",") print()
print(" macros[\"plugin\"] = \"%s\"" % (plugin)) print(" check_command = \"snmp-extend\",")
print(" },") print(" macros[\"community\"] = \"%s\"," % (community))
print("}") print()
print(" assign where host.macros.address == \"%s\"" % (ipaddr))
print("}")
print()
sys.exit(0) sys.exit(0)

View File

@ -106,22 +106,23 @@ def process_host(host_element):
hosts[name] = { "name": name, "address": address, "services": services } hosts[name] = { "name": name, "address": address, "services": services }
def print_host(host): def print_host(host):
print "object Host \"%s\" inherits \"discovered-host\" {" % (host["name"]) print "object Host \"%s\" {" % (host["name"])
print "\tmacros[\"address\"] = \"%s\"," % (host["address"]) print "\timport \"discovered-host\","
print ""
for serv, service in host["services"].iteritems(): print "\tmacros.address = \"%s\"," % (host["address"])
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 "}" print "}"
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:]: for arg in sys.argv[1:]:
# Expects XML output from 'nmap -oX' # Expects XML output from 'nmap -oX'
dom = parse(arg) dom = parse(arg)

View File

@ -2,10 +2,11 @@
## <a id="what-is-icinga2"></a> What is Icinga 2? ## <a id="what-is-icinga2"></a> What is Icinga 2?
Icinga 2 is an enterprise-grade open source monitoring system which keeps watch over networks Icinga 2 is an open source monitoring system which checks the availability of your
and any conceivable network resource, notifies the user of errors and recoveries and generates network resources, notifies users of outages and generates performance data for reporting.
performance data for reporting. Scalable and extensible, Icinga 2 can monitor complex, large
environments across dispersed locations. Scalable and extensible, Icinga 2 can monitor complex, large environments across
multiple locations.
## <a id="licensing"></a> Licensing ## <a id="licensing"></a> Licensing

View File

@ -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 is to use the official Debian or RPM package repositories depending on which
operating system and distribution you are running. operating system and distribution you are running.
Distribution |Repository URL Distribution | Repository URL
------------------------|--------------------------- ------------------------|---------------------------
Debian |http://packages.icinga.org/debian/ Debian | http://packages.icinga.org/debian/
Ubuntu |http://packages.icinga.org/ubuntu/ Ubuntu | http://packages.icinga.org/ubuntu/
RHEL/CentOS 5 |http://packages.icinga.org/epel/5/release/ RHEL/CentOS 5 | http://packages.icinga.org/epel/5/release/
RHEL/CentOS 6 |http://packages.icinga.org/epel/6/release/ RHEL/CentOS 6 | http://packages.icinga.org/epel/6/release/
OpenSUSE 12.3 |http://packages.icinga.org/openSUSE/12.3/release/ OpenSUSE 12.3 | http://packages.icinga.org/openSUSE/12.3/release/
SLES 11 SP3 |http://packages.icinga.org/SUSE/sles11-sp3/release/ SLES 11 SP3 | http://packages.icinga.org/SUSE/sles11-sp3/release/
Packages for distributions other than the ones listed above may also be Packages for distributions other than the ones listed above may also be
available. Please check http://packages.icinga.org/ to see if packages available. Please check http://packages.icinga.org/ to see if packages
@ -29,8 +29,7 @@ to install the `icinga2` package.
> **Note** > **Note**
> >
> On RHEL/CentOS and SLES you will need to use `chkconfig` to enable the > 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 > `icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2 start`.
start`.
Some parts of Icinga 2's functionality are available as separate packages: 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 * Global macros
*/ */
set IcingaMacros = { const IcingaMacros = {
plugindir = "/usr/local/icinga/libexec" 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. * files in this directory are included.
*/ */
object Host "localhost" { object Host "localhost" {
services["ping4"] = { import "linux-server",
templates = [ "generic-service" ],
check_command = "ping4" macros.address = "127.0.0.1",
}, macros.address6 = "::1"
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",
} }
This defines the host `localhost`. The `import` keyword is used to import
This defines a host named "localhost" which has a couple of services. Services the `linux-server` template which takes care of setting up the `ping4` and
may inherit from one or more service templates. `ping6` services for the host as well as adding the host to the `linux-servers`
host group.
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.
The `macros` attribute can be used to define macros that are available for all 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 services which belong to this host. Most of the templates in the Icinga Template
Library require an `address` macro. 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.

View File

@ -1,17 +1,18 @@
## <a id="setting-up-check-plugins"></a> Setting up Check Plugins ## <a id="setting-up-check-plugins"></a> Setting up Check Plugins
On its own Icinga 2 does not know how to check external services. The On its own Icinga 2 does not know how to check external services. The
[Monitoring Plugins Project](https://www.monitoring-plugins.org/) (former [Monitoring Plugins Project](https://www.monitoring-plugins.org/) provides
Nagios Plugins) provides an extensive set of plugins which can be used by an extensive set of plugins which can be used with Icinga 2 to check whether
Icinga 2 to check whether services are working properly. services are working properly.
The recommended way of installing these standard plugins is to use your The recommended way of installing these standard plugins is to use your
distribution's package manager. distribution's package manager.
> **Note** > **Note**
> >
> The `Nagios Plugins` project was renamed to `Monitoring Plugins` project > The `Nagios Plugins` project was renamed to `Monitoring Plugins`
> in Jan 2014. Therefore package names may still reflect the old name. > 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 For your convenience here is a list of package names for some of the more
popular operating systems/distributions: 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 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 by the service templates contained in the Icinga Template Library to determine
where to find the plugin binaries. where to find the plugin binaries.
Alternatively you can create a symbolic link pointing to the installation path
of the plugins.
### <a id="integrate-additional-plugins"></a> Integrate Additional Plugins ### <a id="integrate-additional-plugins"></a> Integrate Additional Plugins
You may require a custom check plugin not provided by the official Nagios plugins. For some services you may need additional check plugins which are not provided
All existing Nagios or Icinga 1.x plugins found on public community websites by the official Monitoring Plugins project.
will work with Icinga 2 as well.
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) * [MonitoringExchange](https://www.monitoringexchange.org)
* [Icinga Wiki](https://wiki.icinga.org) * [Icinga Wiki](https://wiki.icinga.org)
Once you have downloaded the plugin copy it into the directory defined by the global The recommended way of setting up these plugins is to copy them to a common directory
`IcingaMacro` `$plugindir$` and make sure that the user the Icinga daemon is running as and creating an extra global macro, e.g. `customplugindir` in your `macros.conf`
can execute the the plugin binary. Plugins should support the `--help` parameter configuration file:
providing details how they have to be called in your command definition later on.
# cp check_snmp_int.pl /usr/local/icinga/libexec/ # cp check_snmp_int.pl /opt/plugins
# chmod +x /usr/local/icinga/libexec/check_snmp_int.pl # chmod +x /opt/plugins/check_snmp_int.pl
# /usr/local/icinga/libexec/check_snmp_int.pl --help # 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** > **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. > documentation and/or README for their installation requirements.

View File

@ -32,7 +32,7 @@ Icinga 2's init script is installed in `/etc/init.d/icinga2` by default:
-V [ --version ] show version information -V [ --version ] show version information
-l [ --library ] arg load a library -l [ --library ] arg load a library
-I [ --include ] arg add include search directory -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 [ --config ] arg parse a configuration file
-C [ --validate ] exit after validating the configuration -C [ --validate ] exit after validating the configuration
-Z [ --no-validate ] skip validating the configuration -Z [ --no-validate ] skip validating the configuration

View File

@ -15,17 +15,18 @@ on the same physical device.
Here is an example of a host object which defines two child services: Here is an example of a host object which defines two child services:
object Host "my-server1" { object Host "my-server1" {
services["ping4"] = { macros.address = "10.0.0.1",
check_command = "ping4" check = "ping4"
}, }
services["http"] = { apply Service "ping4" {
check_command = "http_ip" check_command = "ping4"
}, assign where host.name == "my-server1"
}
check = "ping4", apply Service "http" {
check_command = "http_ip"
macros["address"] = "10.0.0.1" assign where host.name == "my-server1"
} }
The example host `my-server1` creates two services which belong to this host: The example host `my-server1` creates two services which belong to this host:

View File

@ -59,39 +59,37 @@ then use these macros on the command line.
> the service using the check command `disk`. The macros can also > the service using the check command `disk`. The macros can also
> be inherited from a parent template using additive inheritance (`+=`). > be inherited from a parent template using additive inheritance (`+=`).
object CheckCommand "disk" inherits "plugin-check-command" { object CheckCommand "disk" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_disk", "$plugindir$/check_disk",
"-w", "$wfree$%", "-w", "$wfree$%",
"-c", "$cfree$%" "-c", "$cfree$%"
], ],
macros += { macros.wfree = 20,
wfree = 20, macros.cfree = 10
cfree = 10,
}
} }
The host `localhost` with the service `disk` checks all disks with modified The host `localhost` with the service `disk` checks all disks with modified
macros (warning thresholds at `10%`, critical thresholds at `5%` free disk macros (warning thresholds at `10%`, critical thresholds at `5%` free disk
space). space).
object Host "localhost" inherits "generic-host" { object Host "localhost" {
import "generic-host",
services["disk"] = { macros.address = "127.0.0.1",
templates = [ "generic-service" ], macros.address6 = "::1"
}
check_command = "disk", apply Service "disk" {
macros += { import "generic-service",
wfree = 10,
cfree = 5
}
},
macros = { check_command = "disk",
address = "127.0.0.1",
address6 = "::1", 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 If you require default macro definitions, you can add a macro dictionary as shown for the
`CheckCommand` object. `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" ], command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [ 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 changing the service state back to `OK` (`-r 0`) providing some debug
information in the check output (`-o`). 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 = [ command = [
"$plugindir$/process_check_result", "$plugindir$/process_check_result",
"-H", "-H",
@ -202,5 +204,3 @@ information in the check output (`-o`).
"Event Handler triggered in state '$SERVICESTATE$' with output '$SERVICEOUTPUT$'." "Event Handler triggered in state '$SERVICESTATE$' with output '$SERVICEOUTPUT$'."
] ]
} }

View File

@ -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: 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 = [ command = [
"$plugindir$/check_ping", "$plugindir$/check_ping",
"-4", "-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 When using the `my-ping` command you can override all or some of the macros
in the service definition like this: in the service definition like this:
object Host "my-server1" { apply Service "ping" {
services["ping"] = { check_command = "my-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 If a macro isn't defined anywhere an empty value is used and a warning is
@ -126,8 +126,10 @@ Node 2:
CheckCommand definition: CheckCommand definition:
object CheckCommand "whatever" inherits "plugin-check-command" { object CheckCommand "whatever" {
command = "$plugindir$/check_whatever" import "plugin-check-command",
command = "$plugindir$/check_whatever"
} }
On Node 1, this will be evaluated into `/usr/lib/icinga/plugins/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 This is useful for example for hiding sensitive information on the command line output
when passing credentials to database checks: when passing credentials to database checks:
object CheckCommand "mysql-health" inherits "plugin-check-command" { object CheckCommand "mysql-health" {
command = "$plugindir$/check_mysql -H $address$ -d $db$", import "plugin-check-command",
/* default macro values */
macros = {
"MYSQLUSER" = "icinga_check",
"MYSQLPASS" = "1c1ng42r0xx"
},
export_macros = [ command = "$plugindir$/check_mysql -H $address$ -d $db$",
"MYSQLUSER", /* default macro values */
"MYSQLPASS" macros = {
] "MYSQLUSER" = "icinga_check",
"MYSQLPASS" = "1c1ng42r0xx"
},
export_macros = [
"MYSQLUSER",
"MYSQLPASS"
]
} }
### <a id="configuration-macros"></a> Configuration Macros ### <a id="configuration-macros"></a> Configuration Macros

View File

@ -58,7 +58,9 @@ your environment.
There are various macros available at runtime execution of the `NotificationCommand`. There are various macros available at runtime execution of the `NotificationCommand`.
The example below may or may not fit your needs. 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" ], command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [ 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. > The `TimePeriod` `24x7` is shipped as example configuration with Icinga 2.
Use the `generic-notification` template for the `mail` notification defined Use the `apply` keyword to create `Notification` objects for your services:
inline to the host's service `ping4` and assign the `icingaadmin` user.
object Host "localhost" { apply Notification "mail" {
services["ping4"] = { import "generic-notification",
notifications["mail"] = {
templates = [ "generic-notification" ], notification_command = "mail-notification",
notification_command = "mail-notification", users = [ "icingaadmin" ],
users = [ "icingaadmin" ],
} assign where service.short_name == "ping4"
}
} }
Notifications can be defined in `Service` templates inherited to the objects.
> **Note** > **Note**
> >
> Instead of assigning users to notifications, you can also add the `user_groups` > 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" { object User "icinga-oncall-2nd-level" {
display_name = "Icinga 2nd Level", display_name = "Icinga 2nd Level",
enable_notifications = 1, enable_notifications = true,
macros = { macros = {
"mobile" = "+49123456781" "mobile" = "+49123456781"
@ -163,10 +161,9 @@ notifications between start and end time.
object User "icinga-oncall-1st-level" { object User "icinga-oncall-1st-level" {
display_name = "Icinga 1st Level", display_name = "Icinga 1st Level",
enable_notifications = 1, enable_notifications = true,
macros = { macros.mobile = "+49123456782"
"mobile" = "+49123456782"
} }
} }
@ -198,33 +195,33 @@ 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 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). notified, but only for one hour (`2h` as `end` key for the `times` dictionary).
object Host "localhost" { apply Notification "mail" {
services["ping4"] = { import "generic-notification",
notifications["mail"] = { notification_command = "mail-notification",
templates = [ "generic-notification" ], users = [ "icingaadmin" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
},
notifications["escalation-sms-2nd-level"] = {
templates = [ "generic-notification" ],
notification_command = "sms-notification",
users = [ "icinga-oncall-2nd-level" ],
times = { assign where service.short_name == "ping4"
begin = 30m, }
end = 1h
}
},
notifications["escalation-sms-1st-level"] = {
templates = [ "generic-notification" ],
notification_command = "sms-notification",
users = [ "icinga-oncall-1st-level" ],
times = { apply Notification "escalation-sms-2nd-level" {
begin = 1h, import "generic-notification",
end = 2h notification_command = "sms-notification",
} users = [ "icinga-oncall-2nd-level" ],
}
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
} }
} }
@ -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 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. end time for this notification.
object Host "localhost" { apply Notification "mail" {
services["ping4"] = { import "generic-notification",
notifications["mail"] = { notification_command = "mail-notification",
templates = [ "generic-notification" ], users = [ "icingaadmin" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
times = { times.begin = 15m // delay first notification
begin = 15m // delay first notification
}
}
}
} }
> **Note** > **Note**

View File

@ -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 your hosts you can use templates to avoid having to copy & paste parts of your
configuration: configuration:
template Host "linux-server" { template Service "generic-service" {
services["ping"] = { max_check_attempts = 3,
check_command = "ping4" check_interval = 5m,
}, retry_interval = 1m,
enable_perfdata = true
check = "ping"
} }
object Host "my-server1" inherits "linux-server" { apply Service "ping4" {
macros["address"] = "10.0.0.1" import "generic-service",
check_command = "ping4",
assign where host.macros.address
} }
object Host "my-server2" inherits "linux-server" { apply Service "ping6" {
macros["address"] = "10.0.0.2" 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` In this example both `ping4` and `ping6` services inherit properties from the
service check. Each host gets its own host `check` defined as the `ping` template `generic-service`.
service too.
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 templates. Attributes inherited from a template can be overridden in the
object if necessary. 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" ]
}
}

View File

@ -37,17 +37,16 @@ Then add your hosts to this hostgroup
template Host "windows-mssql-template" { template Host "windows-mssql-template" {
groups = [ "windows" ], groups = [ "windows" ],
macros = { macros.mssql_port = 1433
"mssql_port" = 1433
} }
} }
object Host "mssql-srv1" { object Host "mssql-srv1" {
templates = [ "windows-mssql-template" ] import "windows-mssql-template"
} }
object Host "mssql-srv2" { 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 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" ] groups = [ "windows-mssql-admins" ]
} }
object User "win-mssql-noc" inherits "generic-windows-mssql-users" { object User "win-mssql-noc" {
macros = { import "generic-windows-mssql-users",
"email" = "noc@company.com"
} macros.email = "noc@example.com"
} }
object User "win-mssql-ops" inherits "generic-windows-mssql-users" { object User "win-mssql-ops" {
macros = { import "generic-windows-mssql-users",
"email" = "ops@company.com"
} macros.email = "ops@example.com"
} }
object Host "localhost" { apply Service "ping4" {
services["ping4"] = { import "generic-notification",
notifications["mail"] = { notification_command = "mail-notification",
templates = [ "generic-notification" ], user_groups = [ "windows-admins" ],
notification_command = "mail-notification",
user_groups = [ "windows-admins" ],
}
}
} }

View File

@ -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 on your configuration objects Icinga 2 assumes `24x7` as time period
as shown below. as shown below.
object TimePeriod "24x7" inherits "legacy-timeperiod" { object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod", display_name = "Icinga 2 24x7 TimePeriod",
ranges = { ranges = {
"monday" = "00:00-24:00", "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 create a new timeperiod named `workhours` defining a work day with
09:00 to 17:00. 09:00 to 17:00.
object TimePeriod "workhours" inherits "legacy-timeperiod" { object TimePeriod "workhours" {
import "legacy-timeperiod",
display_name = "Icinga 2 8x5 TimePeriod", display_name = "Icinga 2 8x5 TimePeriod",
ranges = { ranges = {
"monday" = "09:00-17:00", "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` Assign the timeperiod as `notification_period` to the `Notification`
object then. object then.
object Host "localhost" { apply Notification "mail" {
services["ping4"] = { import "generic-notification",
notifications["mail"] = {
templates = [ "generic-notification" ], notification_command = "mail-notification",
notification_command = "mail-notification", users = [ "icingaadmin" ],
users = [ "icingaadmin" ], notification_period = "workhours"
notification_period = "workhours"
} assign where host.name == "localhost"
}
} }

View File

@ -2,26 +2,19 @@
Icinga 2 supports three different types of logging: Icinga 2 supports three different types of logging:
* File logging (local Icinga 2 log file) * File logging
* Syslog facility logging (system's syslog application) * Syslog (on *NIX-based operating systems)
* Console logging (`STDOUT` on tty) * Console logging (`STDOUT` on tty)
> **Note** You can enable additional loggers using the `icinga2-enable-feature`
> and `icinga2-disable-feature` commands to configure loggers:
> You can define multiple logging objects at once.
The most common scenario will be logging Icinga 2's output to Feature | Description
syslog with severity `information`. ---------|------------
debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher)
object SyslogLogger "syslog" { mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher)
severity = "information" syslog | Syslog (severity: `warning` or higher)
}
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"
}
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.

View File

@ -17,5 +17,3 @@ on-demand in your Icinga 2 objects configuration.
spool_dir = "/data/check-results" spool_dir = "/data/check-results"
} }

View File

@ -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) 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. for specific use cases already around, for example monitoring Cisco routers.
The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and only defines The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and just
additional macros (note the `+=` operator) as command parameters for the `oid` overrides the `oid` macro. A service is created for all hosts which
(`community` is already set): have the `community` macro set.
object Host "remote-snmp-host" inherits "generic-host" { apply Service "uptime" {
... import "generic-service",
services["uptime"] = {
templates = [ "generic-service" ], templates = [ "generic-service" ],
check_command = "snmp", check_command = "snmp",
macros += { macros.oid = "1.3.6.1.2.1.1.3.0",
"oid" = "1.3.6.1.2.1.1.3.0"
} assign where host.macros.community
},
macros = {
"address" = "192.168.1.101"
}
} }
#### SSH #### 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 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). 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", command = [ "$plugindir$/check_by_ssh",
"-l", "remoteuser", "-l", "remoteuser",
"-H", "$address$", "-H", "$address$",
@ -52,21 +50,16 @@ its return code and output. `check_by_ssh` is available in the [Monitoring Plugi
] ]
} }
object Host "remote-ssh-host" inherits "generic-host" { apply Service "swap" {
... import "generic-service",
services["swap"] = { check_command = "check_by_ssh_swap",
templates = [ "generic-service" ], macros = {
check_command = "check_by_ssh_swap",
macros = {
"warn" = "50%", "warn" = "50%",
"crit" = "75%" "crit" = "75%"
}
},
macros = {
"address" = "192.168.1.102"
} }
}
assign where host.name == "remote-ssh-host"
}
#### NRPE #### NRPE
@ -77,37 +70,33 @@ remote client.
> **Note** > **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. > can be embedded into the Icinga 2 `CheckCommand` configuration syntax.
Example: Example:
object CheckCommand "check_nrpe" inherits "plugin-check-command" { object CheckCommand "check_nrpe" {
import "plugin-check-command",
command = [ "$plugindir$/check_nrpe", command = [ "$plugindir$/check_nrpe",
"-H", "$address$", "-H", "$address$",
"-c", "$remote_nrpe_command$", "-c", "$remote_nrpe_command$",
], ],
} }
object Host "remote-nrpe-host" inherits "generic-host" { apply Service "users" {
... import "generic-service",
services["users"] = {
templates = [ "generic-service" ], check_command = "check_nrpe",
check_command = "check_nrpe", macros.remote_nrpe_command = "check_users",
macros = {
"remote_nrpe_command" = "check_users" assign where host.name == "remote-nrpe-host"
}
},
macros = {
"address" = "192.168.1.103"
}
} }
nrpe.cfg: nrpe.cfg:
command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10 command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10
#### NSClient++ #### NSClient++
[NSClient++](http://nsclient.org) works on both Windows and Linux platforms and is well [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: Example:
object CheckCommand "check_nscp" inherits "plugin-check-command" { object CheckCommand "check_nscp" {
import "plugin-check-command",
command = [ "$plugindir$/check_nt", command = [ "$plugindir$/check_nt",
"-H", "$address$", "-H", "$address$",
"-p", "$port$", "-p", "$port$",
@ -138,21 +129,18 @@ Example:
} }
} }
object Host "remote-windows-host" inherits "generic-host" { apply Service "users" {
... import "generic-service",
services["users"] = {
templates = [ "generic-service" ], check_command = "check_nscp",
check_command = "check_nscp", macros += {
macros += { "remote_nscp_command" = "USEDDISKSPACE",
"remote_nscp_command" = "USEDDISKSPACE", "partition" = "c",
"partition" = "c", "warn" = "70",
"warn" = "70", "crit" = "80"
"crit" = "80"
}
},
macros = {
"address" = "192.168.1.104"
} }
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). 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 A dedicated Icinga 2 agent supporting all platforms and using the native
Icinga 2 communication protocol supported with SSL certificates, IPv4/IPv6 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 Meanwhile remote checkers in a [Cluster](#cluster) setup could act as
immediate replacement, but without any local configuration - or pushing immediate replacement, but without any local configuration - or pushing
their standalone configuration back to the master node including their check their standalone configuration back to the master node including their check
result messages. result messages.
### Passive Check Results and SNMP Traps ### Passive Check Results and SNMP Traps
> **Note** > **Note**

View File

@ -2,8 +2,8 @@
### <a id="object-definition"></a> Object Definition ### <a id="object-definition"></a> Object Definition
Icinga 2 features an object-based configuration format. In order to Icinga 2 features an object-based configuration format. You can define new
define objects the `object` keyword is used: objects using the `object` keyword:
object Host "host1.example.org" { object Host "host1.example.org" {
display_name = "host1", display_name = "host1",
@ -66,15 +66,15 @@ Example:
Certain characters need to be escaped. The following escape sequences Certain characters need to be escaped. The following escape sequences
are supported: are supported:
Character |Escape sequence Character | Escape sequence
------------------------------------|------------------------------------ --------------------------|------------------------------------
" |\\" " | \\"
\\ |\\\\ \\ | \\\\
\<TAB\> |\\t &lt;TAB&gt; | \\t
\<CARRIAGE-RETURN\> |\\r &lt;CARRIAGE-RETURN&gt; | \\r
\<LINE-FEED\> |\\n &lt;LINE-FEED&gt; | \\n
\<BEL\> |\\b &lt;BEL&gt; | \\b
\<FORM-FEED\> |\\f &lt;FORM-FEED&gt; | \\f
In addition to these pre-defined escape sequences you can specify In addition to these pre-defined escape sequences you can specify
arbitrary ASCII characters using the backslash character (\\) followed arbitrary ASCII characters using the backslash character (\\) followed
@ -154,7 +154,8 @@ The following operators are supported in expressions:
Operator | Examples (Result) | Description 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 + | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings
- | 3 - 1 (2) | Subtracts two numbers - | 3 - 1 (2) | Subtracts two numbers
* | 5m * 10 (3000) | Multiplies two numbers * | 5m * 10 (3000) | Multiplies two numbers
@ -295,6 +296,12 @@ The indexer syntax provides a convenient way to set dictionary elements.
Example: Example:
{
hello.key = "world"
}
Example (alternative syntax):
{ {
hello["key"] = "world" hello["key"] = "world"
} }
@ -307,60 +314,41 @@ This is equivalent to writing:
} }
} }
### <a id="object-inheritance"></a> Object Inheritance ### <a id="template-imports"></a> Template Imports
Objects can inherit attributes from other objects. Objects can import attributes from other objects.
Example: Example:
template Host "default-host" { template Host "default-host" {
macros["color"] = "red" macros.color = "red"
} }
template Host "test-host" inherits "default-host" { template Host "test-host" {
macros["color"] = "blue" import "default-host",
macros.color = "blue"
} }
object Host "localhost" inherits "test-host" { object Host "localhost" {
macros["address"] = "127.0.0.1", import "test-host",
macros["address6"] = "::1"
macros.address = "127.0.0.1",
macros.address6 = "::1"
} }
The `default-host` and `test-host` objects are marked as templates The `default-host` and `test-host` objects are marked as templates
using the `template` keyword. Unlike ordinary objects templates are not using the `template` keyword. Unlike ordinary objects templates are not
instantiated at run-time. Parent objects do not necessarily have to be 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** > **Note**
> >
> The final macros dictionary contains all three macros and the macro > The macros dictionary for the `localhost` object contains all three
> `color` has the value `"blue"`. > macros and the macro `color` has the value `"blue"`.
Parent objects are resolved in the order they're specified using the Parent objects are resolved in the order they're specified using the
`inherits` keyword. `import` keyword.
### <a id="disable-override-objects-attributes"></a> 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
### <a id="constants"></a> Constants ### <a id="constants"></a> Constants
@ -368,34 +356,59 @@ Global constants can be set using the `const` keyword:
const VarName = "some value" const VarName = "some value"
The value can be a string, number, array, or a dictionary. Once defined a constant can be access from any file. Constants cannot be changed
once they are set.
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.
### <a id="apply"></a> Apply ### <a id="apply"></a> Apply
The `apply` keyword can be used to associate a template with another group of The `apply` keyword can be used to create new objects which are associated with
objects. The exact effect of this association depends on the two object types. another group of objects.
template Service "ping-service" { apply Service "ping" {
short_name = "ping", import "generic-service",
check_command = "ping4"
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 Depending on the object type used in the `apply` expression additional local
evaluated for all objects of type Host and a new service is created for each variables may be available for use in the `where` condition:
matching host.
Depending on the object types used in the `apply` expression additional local Source Type | Target Type | Variables
variables may be available for use in the `where` condition. -----------------|-------------|--------------
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.
### <a id="boolean-values"></a> 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
### <a id="comments"></a> Comments ### <a id="comments"></a> Comments
@ -433,7 +446,7 @@ C/C++ compiler:
Note the use of angle brackets instead of double quotes. This causes the Note the use of angle brackets instead of double quotes. This causes the
config compiler to search the include search paths for the specified 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 paths. Additional include search paths can be added using
[command-line options](#cmdline). [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 The `library` directive can be used to manually load additional
libraries. Libraries can be used to provide additional object types and libraries. Libraries can be used to provide additional object types and
methods. functions.
Example: Example:
@ -467,8 +480,8 @@ Example:
> **Note** > **Note**
> >
> The `icinga` library is automatically loaded at startup. You don't need > The `icinga` and `methods` libraries is automatically loaded at startup.
> to load it manually. > You don't need to load them manually.
<!-- <!--
@ -480,18 +493,18 @@ you can specify which attributes are allowed in an object definition.
Example: Example:
type Pizza { %type Pizza {
%require "radius", %require "radius",
%attribute number "radius", %attribute %number "radius",
%attribute dictionary "ingredients" { %attribute %dictionary "ingredients" {
%validator "ValidateIngredients", %validator "ValidateIngredients",
%attribute string "*", %attribute %string "*",
%attribute dictionary "*" { %attribute %dictionary "*" {
%attribute number "quantity", %attribute %number "quantity",
%attribute string "name" %attribute %string "name"
} }
}, },
@ -512,7 +525,8 @@ The Pizza definition provides the following validation rules:
- If they're a dictionary they may contain attributes `quantity` (of - If they're a dictionary they may contain attributes `quantity` (of
type number) and `name` (of type string). type number) and `name` (of type string).
- The script function `ValidateIngredients` is run to perform further - The s
- cript function `ValidateIngredients` is run to perform further
validation of the ingredients dictionary. validation of the ingredients dictionary.
- Pizza objects may contain attribute matching the pattern - Pizza objects may contain attribute matching the pattern
@ -520,10 +534,11 @@ The Pizza definition provides the following validation rules:
Valid types for type rules include: Valid types for type rules include:
* any * %any
* number * %number
* string * %string
* scalar (an alias for string) * %scalar (an alias for string)
* dictionary * %dictionary
* %array
--> -->

View File

@ -4,7 +4,7 @@ Icinga 2 provides a number of special global constants. Some of them can be over
Variable |Description 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". 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". 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". IcingaPkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to IcingaPrefixDir + "/share/icinga2".

View File

@ -17,19 +17,6 @@ Example:
groups = [ "all-hosts" ], groups = [ "all-hosts" ],
services["ping"] = {
templates = [ "ping" ]
},
services["http"] = {
templates = [ "my-http" ],
macros = {
vhost = "test1.example.org",
port = 81
}
},
check = "ping" check = "ping"
} }
@ -40,8 +27,6 @@ Attributes:
display_name |**Optional.** A short description of the host. 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. 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. groups |**Optional.** A list of host groups this host belongs to.
services |**Optional.** Inline definition of services. Each dictionary item specifies a service.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the service.<br /><br />The new service's name is "hostname!service" - where "service" is the dictionary key in the services dictionary.<br /><br />The dictionary key is used as the service's short name.
dependencies |**Optional.** Inline definition of dependencies. Each dictionary item specifies a dependency.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.<br /><br />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. macros |**Optional.** A dictionary containing macros that are specific to this host.
### <a id="objecttype-hostgroup"></a> HostGroup ### <a id="objecttype-hostgroup"></a> HostGroup
@ -68,8 +53,8 @@ by Icinga 2.
> **Best Practice** > **Best Practice**
> >
> Rather than creating a `Service` object for a specific host it is usually easier > 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` > to just create a `Service` template and use the `apply` keyword to assign the
> object to associate these templates with a host. > service to a number of hosts.
Example: Example:
@ -115,8 +100,6 @@ Attributes:
flapping\_threshold|**Optional.** The flapping threshold in percent when a service is considered to be flapping. 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. 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. groups |**Optional.** The service groups this service belongs to.
notifications |**Optional.** Inline definition of notifications. Each dictionary item specifies a notification.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the notification object.<br /><br />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.<br /><br />The `templates` attribute can be used to specify an array of templates that should be inherited by the dependency object.<br /><br />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. 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. 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** > **Best Practice**
> >
> Rather than creating a `Notification` object for a specific service it is usually easier > 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` > to just create a `Notification` template and use the `apply` keyword to assign the
> object to associate these templates with a service. > notification to a number of services.
Example: Example:
@ -202,8 +185,8 @@ Dependency objects are used to specify dependencies between hosts and services.
> **Best Practice** > **Best Practice**
> >
> Rather than creating a `Dependency` object for a specific service it is usually easier > 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` > to just create a `Dependency` template and use the `apply` keyword to assign the
> object to associate these templates with a service. > dependency to a number of services.
Example: Example:
@ -327,7 +310,9 @@ when notifications should be sent out.
Example: Example:
object TimePeriod "24x7" inherits "legacy-timeperiod" { object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod", display_name = "Icinga 2 24x7 TimePeriod",
ranges = { ranges = {
"monday" = "00:00-24:00", "monday" = "00:00-24:00",
@ -345,7 +330,7 @@ Attributes:
Name |Description Name |Description
----------------|---------------- ----------------|----------------
display_name |**Optional.** A short description of the time period. 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. 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 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** > **Best Practice**
> >
> Rather than creating a `ScheduledDowntime` object for a specific service it is usually easier > 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` > to just create a `ScheduledDowntime` template and use the `apply` keyword to assign the
> object to associate these templates with a service. > scheduled downtime to a number of services.
Example: Example:
@ -431,7 +416,9 @@ defined here.
Example: 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$", command = "$plugindir$/check_snmp -H $address$ -C $community$ -o $oid$",
macros = { macros = {
@ -444,7 +431,7 @@ Attributes:
Name |Description 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. 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. 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. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
@ -457,7 +444,9 @@ A notification command definition.
Example: 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" ], command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [ export_macros = [
@ -480,7 +469,7 @@ Attributes:
Name |Description 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. 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. 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. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
@ -497,7 +486,9 @@ An event command definition.
Example: 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", command = "/opt/bin/restart-httpd.sh",
} }
@ -506,7 +497,7 @@ Attributes:
Name |Description 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. 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. 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. escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.

View File

@ -3,9 +3,11 @@
### <a id="best-practice-config-structure"></a> Configuration File and Directory Structure ### <a id="best-practice-config-structure"></a> Configuration File and Directory Structure
Icinga 2 does not care how you name your files and/or directories as long as 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 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 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. external addons not having write permissions to this file such as LConf.
@ -41,7 +43,6 @@ your configuration directory tree and files:
vienna/ vienna/
hosts.conf hosts.conf
If you're planning to create a [cluster](#cluster) setup with Icinga 2 and your 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, configuration master should deploy specific configuration parts to slave nodes,
it's reasonable not to confuse it with configuration below `conf.d`. Rather 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/ node2/
node99/ node99/
If you are preferring to control what several parties drop into the configuration If you are preferring to control what several parties drop into the configuration
pool (for example different departments with their own standalone configuration), pool (for example different departments with their own standalone configuration),
you can still deactivate the `conf.d` inclusion and use your own strategy. 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 Or rather inherit that template into a new template, and override/disable
unwanted values. unwanted values.
template Service "generic-service-disable-notifications" inherits "generic-service" { template Service "generic-service-disable-notifications" {
import "generic-service",
notifications["mail-icingaadmin"] = null notifications["mail-icingaadmin"] = null
} }
### <a id="best-practice-inline-objects-using-templates"></a> Inline Objects using Templates ### <a id="best-practice-inline-objects-using-templates"></a> Inline Objects using Templates
While it is reasonable to create single objects by your preferred configuration While it is reasonable to create single objects by your preferred configuration
tool, using templates and inheriting their attributes in inline objects will tool, using templates and the `apply` keyword will save you a lot of typing extra work.
save you a lot of typing extra work.
For instance, you can still create a host object, then a service object linking 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 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 get bloated and unreadable. You've already read that [using templates](#best-practice-use-templates)
will help here. will help here.
The `Notification` and `ScheduledDowntime` templates will be referenced in the service template and Using the `apply` keyword you can create services, notifications, scheduled downtimes and dependencies
inline definition (both locations are possible). for an arbitrary number of hosts and services respectively:
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.
template Notification "mail-notification" { apply Notification "mail-notification" {
notification_command = "mail-service-notification", notification_command = "mail-service-notification",
users = [ "user1", "user2" ] users = [ "user1", "user2" ]
assign where "generic-service" in service.templates
} }
template ScheduledDowntime "backup-downtime" { apply ScheduledDowntime "backup-downtime" {
author = "icingaadmin", author = "icingaadmin",
comment = "Some comment", comment = "Some comment",
@ -168,6 +165,8 @@ downtimes through the template automatism.
ranges = { ranges = {
"sunday" = "02:00-03:00" "sunday" = "02:00-03:00"
} }
assign where "generic-service" in service.templates
} }
template Service "generic-service" { template Service "generic-service" {
@ -175,35 +174,24 @@ downtimes through the template automatism.
check_interval = 5m, check_interval = 5m,
retry_interval = 1m, retry_interval = 1m,
enable_perfdata = true, enable_perfdata = true,
}
notifications["mail"] = { apply Service "ping4" {
templates = [ "mail-notification" ] import "generic-service",
}
check_command = "ping4",
assign where "linux-server" in host.templates
} }
template Host "linux-server" { template Host "linux-server" {
display_name = "The best host there is",
groups = [ "all-hosts" ], groups = [ "all-hosts" ],
host_dependencies = [ "router" ],
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4",
scheduled_downtimes["backup"] = {
templates = [ "backup-downtime" ]
}
},
check = "ping4" check = "ping4"
} }
object Host "localhost" inherits "linux-server" { object Host "localhost" {
import "linux-server",
display_name = "The best host there is",
} }

View File

@ -73,7 +73,7 @@ recurring downtimes for services.
Example: Example:
template ScheduledDowntime "backup-downtime" { apply ScheduledDowntime "backup-downtime" {
author = "icingaadmin", author = "icingaadmin",
comment = "Scheduled downtime for backup", comment = "Scheduled downtime for backup",
@ -86,17 +86,7 @@ Example:
saturday = "02:00-03:00", saturday = "02:00-03:00",
sunday = "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" ]
}
},
}

View File

@ -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 within the cluster, you must define `authorities` as additional service object
attribute. Required Endpoints must be defined as array. attribute. Required Endpoints must be defined as array.
object Host "dmz-host1" inherits "generic-host" { apply Service "dmz-oracledb" {
services["dmz-oracledb"] = { import "generic-service",
templates = [ "generic-service" ],
authorities = [ "icinga-node-1" ], authorities = [ "icinga-node-1" ],
}
assign where "oracle" in host.groups
} }
> **Tip** > **Tip**
@ -232,13 +233,14 @@ one or more configured nodes are not connected.
Example: Example:
object Host "icinga2a" inherits "generic-host" { apply Service "cluster" {
services["cluster"] = { import "generic-service",
templates = [ "generic-service" ],
check_interval = 1m, check_interval = 1m,
check_command = "cluster", check_command = "cluster",
authorities = [ "icinga2a" ] authorities = [ "icinga2a" ],
},
assign where host.name = "icinga2a"
} }
> **Note** > **Note**

View File

@ -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 a different state history. `icinga-node-dmz-2` still receives all cluster message updates
from the `icinga-node-dmz-1` endpoint. from the `icinga-node-dmz-1` endpoint.
object Host "dmz-host1" inherits "generic-host" { object Host "dmz-host1" {
import "generic-host",
services["dmz-oracledb"] = { services["dmz-oracledb"] = {
templates = [ "generic-service" ], templates = [ "generic-service" ],
domains = [ "dmz-db" ], domains = [ "dmz-db" ],

View File

@ -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 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. 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 router's firewall. In case the `dsl-router``ping4` service check fails, all
further checks for the `google-dns` `ping4` service should be suppressed. further checks for the `ping4` service on host `google-dns` service should
This is achieved by setting the `disable_checks` attribute to `true`. be suppressed. This is achieved by setting the `disable_checks` attribute to `true`.
object Host "dsl-router" { object Host "dsl-router" {
services["ping4"] = { macros.address = "192.168.1.1"
templates = "generic-service",
check_command = "ping4"
}
macros = {
address = "192.168.1.1",
},
} }
object Host "google-dns" { object Host "google-dns" {
services["ping4"] = { macros.address = "8.8.8.8",
templates = "generic-service", }
check_command = "ping4",
dependencies["dsl-router-ping4"] = { apply Service "ping4" {
parent_host = "dsl-router", import "generic-service",
parent_service = "ping4",
disable_checks = true check_command = "ping4"
}
} assign where host.macros.address
}
macros = {
address = "8.8.8.8", apply Dependency "internet" {
}, parent_host = "dsl-router",
disable_checks = true
dependencies["dsl-router"] = {
parent_host = "dsl-router" assign where host.name != "dsl-router"
},
} }

View File

@ -123,15 +123,17 @@ uses the `template` identifier:
template Service "ping4-template" { } template Service "ping4-template" { }
Icinga 1.x objects inherit from templates using the `use` attribute. Icinga 1.x objects inherit from templates using the `use` attribute.
Icinga 2 uses the keyword `inherits` after the object name and requires a Icinga 2 uses the keyword `import` with template names in double quotes.
comma-separated list with template names in double quotes.
define service { define service {
service_description testservice service_description testservice
use tmpl1,tmpl2,tmpl3 use tmpl1,tmpl2,tmpl3
} }
object Service "testservice" inherits "tmpl1", "tmpl2", "tmpl3" { object Service "testservice" {
import "tmpl1",
import "tmpl2",
import "tmpl3"
} }
## <a id="differences-1x-2-object-attributes"></a> Object attributes ## <a id="differences-1x-2-object-attributes"></a> 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 `hostgroup_name` or behavior changing regular expression. It's not possible
to define a service definition within a host definition. to define a service definition within a host definition.
The preferred way of associating hosts with services in Icinga 2 are services The preferred way of associating hosts with services in Icinga 2 is by
defined inline to the host object (or template) definition. Icinga 2 will using the `apply` keyword.
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.
## <a id="differences-1x-2-users"></a> Users ## <a id="differences-1x-2-users"></a> Users
@ -369,17 +367,22 @@ The preferred way of assigning objects to groups is by using a template:
template Host "dev-host" { template Host "dev-host" {
groups += [ "dev-hosts" ], 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 In order to associate a service with all hosts in a host group the `apply`
of that group. The example above shows how to use templates to accomplish keyword can be used:
the same effect.
apply Service "ping" {
import "generic-service",
check_command = "ping4",
assign where "group" in host.groups
}
## <a id="differences-1x-2-notifications"></a> Notifications ## <a id="differences-1x-2-notifications"></a> Notifications

View File

@ -1,51 +1,44 @@
/** /**
* Provides default settings for hosts. By convention * Provides default settings for hosts. By convention
* all hosts should inherit from this template. * all hosts should import this template.
*/ */
template Host "generic-host" { 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" ], 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" ], groups += [ "windows-servers" ],
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
} }
template Host "generic-printer" inherits "generic-host" { template Host "generic-printer" {
services["ping4"] = { import "generic-host",
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
} }
template Host "generic-switch" inherits "generic-host" { template Host "generic-switch" {
services["ping4"] = { import "generic-host",
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
} }

View File

@ -1,15 +1,18 @@
/** /**
* Provides default settings for services. By convention * Provides default settings for services. By convention
* all services should inherit from this template. * all services should import this template.
*/ */
template Service "generic-service" { template Service "generic-service" {
max_check_attempts = 3, max_check_attempts = 3,
check_interval = 5m, check_interval = 5m,
retry_interval = 1m, retry_interval = 1m,
enable_perfdata = true, enable_perfdata = true
}
notifications["mail-icingaadmin"] = {
templates = [ "mail-notification" ], apply Notification "mail-icingaadmin" {
user_groups = [ "icingaadmins" ] import "mail-notification",
}
user_groups = [ "icingaadmins"],
assign where "generic-service" in service.templates
} }

View File

@ -4,19 +4,5 @@
*/ */
template User "generic-user" { 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
} }

View File

@ -3,71 +3,72 @@
* in the conf.d directory (e.g. one per host). By default all *.conf * in the conf.d directory (e.g. one per host). By default all *.conf
* files in this directory are included. * files in this directory are included.
*/ */
object Host "localhost" inherits "linux-server" { object Host "localhost" {
display_name = "localhost", import "linux-server",
services["icinga"] = { macros.address = "127.0.0.1",
templates = [ "generic-service" ], macros.address6 = "::1"
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",
} }
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"
}

View File

@ -22,7 +22,9 @@ template Notification "mail-notification" {
notification_period = "24x7" 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" ], command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [ export_macros = [

View File

@ -3,7 +3,9 @@
* 'legacy-timeperiod' template from the ITL. * 'legacy-timeperiod' template from the ITL.
*/ */
object TimePeriod "24x7" inherits "legacy-timeperiod" { object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod", display_name = "Icinga 2 24x7 TimePeriod",
ranges = { ranges = {
"monday" = "00:00-24:00", "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", display_name = "Icinga 2 9to5 TimePeriod",
ranges = { ranges = {
"monday" = "09:00-17:00", "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", display_name = "Icinga 2 never TimePeriod",
ranges = { ranges = {
} }

View File

@ -3,7 +3,9 @@
* group 'icingaadmins'. * group 'icingaadmins'.
*/ */
object User "icingaadmin" inherits "generic-user" { object User "icingaadmin" {
import "generic-user",
display_name = "Icinga 2 Admin", display_name = "Icinga 2 Admin",
groups = [ "icingaadmins" ], groups = [ "icingaadmins" ],

View File

@ -89,7 +89,7 @@ static bool LoadConfigFiles(const String& appType, ValidationType validate)
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) { BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
std::ostringstream locbuf; std::ostringstream locbuf;
ShowCodeFragment(locbuf, message.Location); ShowCodeFragment(locbuf, message.Location, true);
String location = locbuf.str(); String location = locbuf.str();
String logmsg; String logmsg;

View File

@ -17,7 +17,9 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * 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 = [ command = [
"$plugindir$/check_ping", "$plugindir$/check_ping",
"-4", "-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 = [ command = [
"$plugindir$/check_ping", "$plugindir$/check_ping",
"-6", "-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 = [ command = [
"$plugindir$/check_dummy", "$plugindir$/check_dummy",
"$state$", "$state$",
@ -76,14 +82,18 @@ object CheckCommand "dummy" inherits "plugin-check-command" {
} }
} }
object CheckCommand "passive" inherits "dummy" { object CheckCommand "passive" {
import "dummy",
macros = { macros = {
state = 3, state = 3,
text = "No Passive Check Result Received." text = "No Passive Check Result Received."
} }
} }
object CheckCommand "tcp" inherits "plugin-check-command" { object CheckCommand "tcp" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_tcp", "$plugindir$/check_tcp",
"-H", "$address$", "-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 = [ command = [
"$plugindir$/check_udp", "$plugindir$/check_udp",
"-H", "$address$", "-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 = [ command = [
"$plugindir$/check_http", "$plugindir$/check_http",
"-H", "$vhost$" "-H", "$vhost$"
] ]
} }
object CheckCommand "http_ip" inherits "plugin-check-command" { object CheckCommand "http_ip" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_http", "$plugindir$/check_http",
"-H", "$address$" "-H", "$address$"
] ]
} }
object CheckCommand "https_vhost" inherits "plugin-check-command" { object CheckCommand "https_vhost" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_http", "$plugindir$/check_http",
"-H", "$vhost$", "-S" "-H", "$vhost$", "-S"
] ]
} }
object CheckCommand "https_ip" inherits "plugin-check-command" { object CheckCommand "https_ip" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_http", "$plugindir$/check_http",
"-I", "$address$", "-S" "-I", "$address$", "-S"
] ]
} }
object CheckCommand "smtp" inherits "plugin-check-command" { object CheckCommand "smtp" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_smtp", "$plugindir$/check_smtp",
"-H", "$address$" "-H", "$address$"
] ]
} }
object CheckCommand "ssmtp" inherits "plugin-check-command" { object CheckCommand "ssmtp" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_ssmtp", "$plugindir$/check_ssmtp",
"-H", "$address$", "-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 = [ command = [
"$plugindir$/check_ntp_time", "$plugindir$/check_ntp_time",
"-H", "$address$" "-H", "$address$"
] ]
} }
object CheckCommand "ssh" inherits "plugin-check-command" { object CheckCommand "ssh" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_ssh", "$plugindir$/check_ssh",
"$address$" "$address$"
] ]
} }
object CheckCommand "disk" inherits "plugin-check-command" { object CheckCommand "disk" {
import "plugin-check-command",
command = [ command = [
"$plugindir$/check_disk", "$plugindir$/check_disk",
"-w", "$wfree$%", "-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 = [ command = [
"$plugindir$/check_users", "$plugindir$/check_users",
"-w", "$wgreater$", "-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 = [ command = [
"$plugindir$/check_procs", "$plugindir$/check_procs",
"-w", "$wgreater$", "-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 = [ command = [
"$plugindir$/check_load", "$plugindir$/check_load",
"-w", "$wload1$,$wload5$,$wload15$", "-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 = [ command = [
"$plugindir$/check_snmp", "$plugindir$/check_snmp",
"-H", "$address$", "-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 += { macros += {
oid = "1.3.6.1.2.1.1.3.0" 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 = [ command = [
IcingaSysconfDir + "/icinga2/scripts/snmp-extend.sh", IcingaSysconfDir + "/icinga2/scripts/snmp-extend.sh",
"$HOSTADDRESS$", "$HOSTADDRESS$",

View File

@ -3,8 +3,9 @@ namespace icinga
abstract class DynamicObject abstract class DynamicObject
{ {
[config] String __name (Name); [config] String name (Name);
[config, get_protected] String __type (TypeName); [config, get_protected] String type (TypeName);
[config, get_protected] Array::Ptr templates;
[config] Dictionary::Ptr methods; [config] Dictionary::Ptr methods;
[config] Dictionary::Ptr custom; [config] Dictionary::Ptr custom;
[config] Array::Ptr domains; [config] Array::Ptr domains;

View File

@ -61,19 +61,22 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace
if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) { if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) {
result << std::endl; result << std::endl;
if (!stack)
stack = GetLastExceptionStack();
if (stack) if (stack)
result << *stack; result << *stack;
else
result << *GetLastExceptionStack();
} }
if (boost::get_error_info<ContextTraceErrorInfo>(ex) == NULL) { if (boost::get_error_info<ContextTraceErrorInfo>(ex) == NULL) {
result << std::endl; result << std::endl;
if (!context)
context = GetLastExceptionContext();
if (context) if (context)
result << *context; result << *context;
else
result << *GetLastExceptionContext();
} }
} }

View File

@ -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(field.Name, Serialize(input->GetField(i), attributeTypes));
} }
fields->Set("__type", type->GetName()); fields->Set("type", type->GetName());
return fields; return fields;
} }
@ -151,7 +151,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary
if (object) if (object)
type = object->GetReflectionType(); type = object->GetReflectionType();
else else
type = Type::GetByName(input->Get("__type")); type = Type::GetByName(input->Get("type"));
if (!type) if (!type)
return object; return object;
@ -165,6 +165,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary
instance = type->Instantiate(); instance = type->Instantiate();
} }
ObjectLock olock(input);
BOOST_FOREACH(const Dictionary::Pair& kv, input) { BOOST_FOREACH(const Dictionary::Pair& kv, input) {
if (kv.first.IsEmpty()) if (kv.first.IsEmpty())
continue; continue;
@ -230,7 +231,7 @@ Value icinga::Deserialize(const Object::Ptr& object, const Value& value, bool sa
ASSERT(dict != NULL); ASSERT(dict != NULL);
if (!dict->Contains("__type")) if (!dict->Contains("type"))
return DeserializeDictionary(dict, safe_mode, attributeTypes); return DeserializeDictionary(dict, safe_mode, attributeTypes);
return DeserializeObject(object, dict, safe_mode, attributeTypes); return DeserializeObject(object, dict, safe_mode, attributeTypes);

View File

@ -22,6 +22,7 @@
#include "base/utility.h" #include "base/utility.h"
#include "base/convert.h" #include "base/convert.h"
#include "base/application.h" #include "base/application.h"
#include "base/initialize.h"
#ifdef HAVE_BACKTRACE_SYMBOLS #ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h> # include <execinfo.h>
@ -29,7 +30,7 @@
using namespace icinga; using namespace icinga;
boost::once_flag StackTrace::m_OnceFlag = BOOST_ONCE_INIT; INITIALIZE_ONCE(&StackTrace::StaticInitialize);
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma optimize("", off) # pragma optimize("", off)
@ -37,8 +38,6 @@ boost::once_flag StackTrace::m_OnceFlag = BOOST_ONCE_INIT;
StackTrace::StackTrace(void) StackTrace::StackTrace(void)
{ {
boost::call_once(m_OnceFlag, &StackTrace::Initialize);
#ifdef HAVE_BACKTRACE_SYMBOLS #ifdef HAVE_BACKTRACE_SYMBOLS
m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0])); m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0]));
#else /* HAVE_BACKTRACE_SYMBOLS */ #else /* HAVE_BACKTRACE_SYMBOLS */
@ -57,8 +56,6 @@ StackTrace::StackTrace(void)
#ifdef _WIN32 #ifdef _WIN32
StackTrace::StackTrace(PEXCEPTION_POINTERS exi) StackTrace::StackTrace(PEXCEPTION_POINTERS exi)
{ {
boost::call_once(m_OnceFlag, &StackTrace::Initialize);
STACKFRAME64 frame; STACKFRAME64 frame;
int architecture; int architecture;
@ -91,7 +88,7 @@ StackTrace::StackTrace(PEXCEPTION_POINTERS exi)
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
void StackTrace::Initialize(void) void StackTrace::StaticInitialize(void)
{ {
#ifdef _WIN32 #ifdef _WIN32
(void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); (void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
@ -153,33 +150,11 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const
# endif /* HAVE_BACKTRACE_SYMBOLS */ # endif /* HAVE_BACKTRACE_SYMBOLS */
#else /* _WIN32 */ #else /* _WIN32 */
for (int i = ignoreFrames + 1; i < m_Count; i++) { for (int i = ignoreFrames + 1; i < m_Count; i++) {
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; fp << "\t(" << i - ignoreFrames - 1 << ") "
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; << Utility::GetSymbolSource(m_Frames[i])
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); << ": "
pSymbol->MaxNameLen = MAX_SYM_NAME; << Utility::GetSymbolName(m_Frames[i])
<< std::endl;
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;
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
} }

View File

@ -43,13 +43,11 @@ public:
void Print(std::ostream& fp, int ignoreFrames = 0) const; void Print(std::ostream& fp, int ignoreFrames = 0) const;
static void StaticInitialize(void);
private: private:
void *m_Frames[64]; void *m_Frames[64];
int m_Count; 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); I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);

View File

@ -128,7 +128,28 @@ String Utility::GetSymbolName(const void *addr)
return dli.dli_sname; return dli.dli_sname;
#endif /* HAVE_DLADDR */ #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) String Utility::GetSymbolSource(const void *addr)
@ -142,7 +163,23 @@ String Utility::GetSymbolSource(const void *addr)
} }
#endif /* HAVE_DLADDR */ #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)";
} }
/** /**

View File

@ -19,6 +19,7 @@
#include "config/aexpression.h" #include "config/aexpression.h"
#include "config/configerror.h" #include "config/configerror.h"
#include "config/configitem.h"
#include "base/array.h" #include "base/array.h"
#include "base/serializer.h" #include "base/serializer.h"
#include "base/context.h" #include "base/context.h"
@ -26,6 +27,8 @@
#include "base/scriptvariable.h" #include "base/scriptvariable.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/object.h"
#include "base/logger_fwd.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>
#include <boost/exception/errinfo_nested_exception.hpp> #include <boost/exception/errinfo_nested_exception.hpp>
@ -43,6 +46,14 @@ AExpression::AExpression(OpCallback op, const Value& operand1, const Value& oper
Value AExpression::Evaluate(const Dictionary::Ptr& locals) const Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
{ {
try { 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); return m_Operator(this, locals);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
if (boost::get_error_info<boost::errinfo_nested_exception>(ex)) if (boost::get_error_info<boost::errinfo_nested_exception>(ex))
@ -52,66 +63,6 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
} }
} }
void AExpression::ExtractPath(const std::vector<String>& 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<String> sub_path(path.begin() + 1, path.end());
exprl->ExtractPath(sub_path, result);
}
}
void AExpression::FindDebugInfoPath(const std::vector<String>& 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<String> sub_path(path.begin() + 1, path.end());
exprl->FindDebugInfoPath(sub_path, result);
}
}
}
void AExpression::MakeInline(void) void AExpression::MakeInline(void)
{ {
if (m_Operator == &AExpression::OpDict) if (m_Operator == &AExpression::OpDict)
@ -179,6 +130,11 @@ Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& loca
return ~(long)expr->EvaluateOperand1(locals); 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) Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(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); Value right = expr->EvaluateOperand2(locals);
if (!right.IsObjectType<Array>()) if (right.IsEmpty())
return false;
else if (!right.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right))); BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
Value left = expr->EvaluateOperand1(locals); 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 AExpression::OpSet(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
Value index = expr->EvaluateOperand1(locals);
Value right = expr->EvaluateOperand2(locals); Value right = expr->EvaluateOperand2(locals);
locals->Set(expr->m_Operand1, right); locals->Set(index, right);
return right; return right;
} }
Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals) 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; AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals; Dictionary::Ptr xlocals = locals;
@ -368,13 +328,14 @@ Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& loc
dict->Remove("__parent"); dict->Remove("__parent");
} }
locals->Set(expr->m_Operand1, result); locals->Set(index, result);
return result; return result;
} }
Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals) 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; AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals; Dictionary::Ptr xlocals = locals;
@ -394,13 +355,14 @@ Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& lo
dict->Remove("__parent"); dict->Remove("__parent");
} }
locals->Set(expr->m_Operand1, result); locals->Set(index, result);
return result; return result;
} }
Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals) 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; AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals; Dictionary::Ptr xlocals = locals;
@ -420,13 +382,14 @@ Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr&
dict->Remove("__parent"); dict->Remove("__parent");
} }
locals->Set(expr->m_Operand1, result); locals->Set(index, result);
return result; return result;
} }
Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals) 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; AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals; Dictionary::Ptr xlocals = locals;
@ -446,16 +409,49 @@ Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& l
dict->Remove("__parent"); dict->Remove("__parent");
} }
locals->Set(expr->m_Operand1, result); locals->Set(index, result);
return result; return result;
} }
Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals) Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
Dictionary::Ptr dict = OpVariable(expr, locals); Value value = expr->EvaluateOperand1(locals);
Value index = expr->EvaluateOperand2(locals);
if (!dict) if (value.IsObjectType<Dictionary>()) {
BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope.")); Dictionary::Ptr dict = value;
return dict->Get(index);
} else if (value.IsObjectType<Object>()) {
Object::Ptr object = value;
const Type *type = object->GetReflectionType();
return dict->Get(expr->m_Operand2); if (!type)
BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection"));
int field = type->GetFieldId(index);
if (field == -1)
BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'"));
return object->GetField(field);
} else if (value.IsEmpty()) {
return Empty;
} else {
BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'"));
}
}
Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value type = expr->EvaluateOperand1(locals);
Value name = expr->EvaluateOperand2(locals);
ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
if (!item)
BOOST_THROW_EXCEPTION(ConfigError("Import references unknown template: '" + name + "'"));
item->GetExpressionList()->Evaluate(locals);
return Empty;
} }

View File

@ -42,8 +42,6 @@ public:
AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di); AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di);
Value Evaluate(const Dictionary::Ptr& locals) const; Value Evaluate(const Dictionary::Ptr& locals) const;
void ExtractPath(const std::vector<String>& path, const Array::Ptr& result) const;
void FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const;
void MakeInline(void); void MakeInline(void);
@ -52,6 +50,7 @@ public:
static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals);
@ -79,6 +78,7 @@ public:
static Value OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals); static Value OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpImport(const AExpression *expr, const Dictionary::Ptr& locals);
private: private:
OpCallback m_Operator; OpCallback m_Operator;

View File

@ -18,19 +18,21 @@
******************************************************************************/ ******************************************************************************/
#include "config/applyrule.h" #include "config/applyrule.h"
#include "base/logger_fwd.h"
using namespace icinga; using namespace icinga;
ApplyRule::RuleMap ApplyRule::m_Rules; ApplyRule::RuleMap ApplyRule::m_Rules;
ApplyRule::CallbackMap ApplyRule::m_Callbacks; ApplyRule::CallbackMap ApplyRule::m_Callbacks;
ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) ApplyRule::ApplyRule(const String& name, const AExpression::Ptr& expression,
: m_Template(tmpl), m_Expression(expression), m_DebugInfo(di), m_Scope(scope) const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope)
: m_Name(name), m_Expression(expression), m_Filter(filter), m_DebugInfo(di), m_Scope(scope)
{ } { }
String ApplyRule::GetTemplate(void) const String ApplyRule::GetName(void) const
{ {
return m_Template; return m_Name;
} }
AExpression::Ptr ApplyRule::GetExpression(void) const AExpression::Ptr ApplyRule::GetExpression(void) const
@ -38,6 +40,11 @@ AExpression::Ptr ApplyRule::GetExpression(void) const
return m_Expression; return m_Expression;
} }
AExpression::Ptr ApplyRule::GetFilter(void) const
{
return m_Filter;
}
DebugInfo ApplyRule::GetDebugInfo(void) const DebugInfo ApplyRule::GetDebugInfo(void) const
{ {
return m_DebugInfo; return m_DebugInfo;
@ -48,30 +55,56 @@ Dictionary::Ptr ApplyRule::GetScope(void) const
return m_Scope; return m_Scope;
} }
void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) void ApplyRule::AddRule(const String& sourceType, const String& name,
const AExpression::Ptr& expression, const AExpression::Ptr& filter,
const DebugInfo& di, const Dictionary::Ptr& scope)
{ {
m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di, scope)); m_Rules[sourceType].push_back(ApplyRule(name, expression, filter, di, scope));
}
bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const
{
return m_Filter->Evaluate(scope);
} }
void ApplyRule::EvaluateRules(void) void ApplyRule::EvaluateRules(void)
{ {
std::pair<TypeCombination, Callback> kv; std::set<String> completedTypes;
BOOST_FOREACH(kv, m_Callbacks) {
RuleMap::const_iterator it = m_Rules.find(kv.first);
if (it == m_Rules.end()) while (completedTypes.size() < m_Callbacks.size()) {
continue; std::pair<String, std::pair<Callback, String> > kv;
BOOST_FOREACH(kv, m_Callbacks) {
const String& sourceType = kv.first;
kv.second(it->second); if (completedTypes.find(sourceType) != completedTypes.end())
continue;
const Callback& callback = kv.second.first;
const String& targetType = kv.second.second;
if (IsValidType(targetType) && completedTypes.find(targetType) == completedTypes.end())
continue;
completedTypes.insert(sourceType);
RuleMap::const_iterator it = m_Rules.find(kv.first);
if (it == m_Rules.end())
continue;
callback(it->second);
}
} }
m_Rules.clear();
} }
void ApplyRule::RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback) void ApplyRule::RegisterType(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback)
{ {
m_Callbacks[std::make_pair(sourceType, targetType)] = callback; m_Callbacks[sourceType] = make_pair(callback, targetType);
} }
bool ApplyRule::IsValidCombination(const String& sourceType, const String& targetType) bool ApplyRule::IsValidType(const String& sourceType)
{ {
return m_Callbacks.find(std::make_pair(sourceType, targetType)) != m_Callbacks.end(); return m_Callbacks.find(sourceType) != m_Callbacks.end();
} }

View File

@ -34,32 +34,37 @@ namespace icinga
class I2_CONFIG_API ApplyRule class I2_CONFIG_API ApplyRule
{ {
public: public:
typedef std::pair<String, String> TypeCombination;
typedef boost::function<void (const std::vector<ApplyRule>& rules)> Callback; typedef boost::function<void (const std::vector<ApplyRule>& rules)> Callback;
typedef std::map<TypeCombination, Callback> CallbackMap; typedef std::map<String, std::pair<Callback, String> > CallbackMap;
typedef std::map<TypeCombination, std::vector<ApplyRule> > RuleMap; typedef std::map<String, std::vector<ApplyRule> > RuleMap;
String GetTemplate(void) const; String GetName(void) const;
AExpression::Ptr GetExpression(void) const; AExpression::Ptr GetExpression(void) const;
AExpression::Ptr GetFilter(void) const;
DebugInfo GetDebugInfo(void) const; DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const; Dictionary::Ptr GetScope(void) const;
static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); bool EvaluateFilter(const Dictionary::Ptr& scope) const;
static void AddRule(const String& sourceType, const String& name, const AExpression::Ptr& expression,
const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope);
static void EvaluateRules(void); static void EvaluateRules(void);
static void RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback); static void RegisterType(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback);
static bool IsValidCombination(const String& sourceType, const String& targetType); static bool IsValidType(const String& sourceType);
private: private:
String m_Template; String m_Name;
AExpression::Ptr m_Expression; AExpression::Ptr m_Expression;
AExpression::Ptr m_Filter;
DebugInfo m_DebugInfo; DebugInfo m_DebugInfo;
Dictionary::Ptr m_Scope; Dictionary::Ptr m_Scope;
static CallbackMap m_Callbacks; static CallbackMap m_Callbacks;
static RuleMap m_Rules; static RuleMap m_Rules;
ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); ApplyRule(const String& tmpl, const AExpression::Ptr& expression,
const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope);
}; };
} }

View File

@ -17,40 +17,44 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type DynamicObject { %type DynamicObject {
%require "__name", %require "name",
%attribute string "__name", %attribute %string "name",
%require "__type", %require "type",
%attribute string "__type", %attribute %string "type",
%attribute dictionary "methods", %attribute %array "templates" {
%attribute %string "*"
%attribute dictionary "custom" {
%attribute string "*"
}, },
%attribute array "domains" { %attribute %dictionary "methods",
%attribute string "*"
%attribute %dictionary "custom" {
%attribute %string "*"
},
%attribute %array "domains" {
%attribute %string "*"
} }
} }
type Logger { %type Logger {
%attribute string "severity" %attribute %string "severity"
} }
type FileLogger inherits Logger { %type FileLogger %inherits Logger {
%require "path", %require "path",
%attribute string "path" %attribute %string "path"
} }
type SyslogLogger inherits Logger { %type SyslogLogger %inherits Logger {
} }
type Script { %type Script {
%require "language", %require "language",
%attribute string "language", %attribute %string "language",
%require "code", %require "code",
%attribute string "code" %attribute %string "code"
} }

View File

@ -197,33 +197,33 @@ static char *lb_steal(lex_buf *lb)
[ \t\r\n] /* ignore whitespace */ [ \t\r\n] /* ignore whitespace */
<INITIAL>{ <INITIAL>{
type return T_TYPE; %type return T_TYPE;
dictionary { yylval->type = TypeDictionary; return T_TYPE_DICTIONARY; } %dictionary { yylval->type = TypeDictionary; return T_TYPE_DICTIONARY; }
array { yylval->type = TypeArray; return T_TYPE_ARRAY; } %array { yylval->type = TypeArray; return T_TYPE_ARRAY; }
number { yylval->type = TypeNumber; return T_TYPE_NUMBER; } %number { yylval->type = TypeNumber; return T_TYPE_NUMBER; }
string { yylval->type = TypeString; return T_TYPE_STRING; } %string { yylval->type = TypeString; return T_TYPE_STRING; }
scalar { yylval->type = TypeScalar; return T_TYPE_SCALAR; } %scalar { yylval->type = TypeScalar; return T_TYPE_SCALAR; }
any { yylval->type = TypeAny; return T_TYPE_ANY; } %any { yylval->type = TypeAny; return T_TYPE_ANY; }
name { yylval->type = TypeName; return T_TYPE_NAME; } %name { yylval->type = TypeName; return T_TYPE_NAME; }
%validator { return T_VALIDATOR; } %validator { return T_VALIDATOR; }
%require { return T_REQUIRE; } %require { return T_REQUIRE; }
%attribute { return T_ATTRIBUTE; } %attribute { return T_ATTRIBUTE; }
%inherits return T_INHERITS;
object return T_OBJECT; object return T_OBJECT;
template return T_TEMPLATE; template return T_TEMPLATE;
include return T_INCLUDE; include return T_INCLUDE;
include_recursive return T_INCLUDE_RECURSIVE; include_recursive return T_INCLUDE_RECURSIVE;
library return T_LIBRARY; library return T_LIBRARY;
inherits return T_INHERITS;
null return T_NULL; null return T_NULL;
partial return T_PARTIAL; partial return T_PARTIAL;
true { yylval->num = 1; return T_NUMBER; } true { yylval->num = 1; return T_NUMBER; }
false { yylval->num = 0; return T_NUMBER; } false { yylval->num = 0; return T_NUMBER; }
set return T_VAR;
var return T_VAR;
const return T_CONST; const return T_CONST;
apply return T_APPLY; apply return T_APPLY;
to return T_TO;
where return T_WHERE; where return T_WHERE;
import return T_IMPORT;
assign return T_ASSIGN;
ignore return T_IGNORE;
\<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; } \<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; }
\>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; } \>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; }
\<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; } \<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; }

View File

@ -69,6 +69,13 @@ do { \
using namespace icinga; using namespace icinga;
static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *left, Value *right, DebugInfo& diLeft, DebugInfo& diRight)
{
*result = new Value(make_shared<AExpression>(op, static_cast<AExpression::Ptr>(*left), static_cast<AExpression::Ptr>(*right), DebugInfoRange(diLeft, diRight)));
delete left;
delete right;
}
%} %}
%pure-parser %pure-parser
@ -121,7 +128,6 @@ using namespace icinga;
%token <op> T_LESS_THAN "< (T_LESS_THAN)" %token <op> T_LESS_THAN "< (T_LESS_THAN)"
%token <op> T_GREATER_THAN "> (T_GREATER_THAN)" %token <op> T_GREATER_THAN "> (T_GREATER_THAN)"
%token T_VAR "var (T_VAR)"
%token T_CONST "const (T_CONST)" %token T_CONST "const (T_CONST)"
%token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)" %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)" %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
@ -142,8 +148,11 @@ using namespace icinga;
%token T_INHERITS "inherits (T_INHERITS)" %token T_INHERITS "inherits (T_INHERITS)"
%token T_PARTIAL "partial (T_PARTIAL)" %token T_PARTIAL "partial (T_PARTIAL)"
%token T_APPLY "apply (T_APPLY)" %token T_APPLY "apply (T_APPLY)"
%token T_TO "to (T_TO)"
%token T_WHERE "where (T_WHERE)" %token T_WHERE "where (T_WHERE)"
%token T_IMPORT "import (T_IMPORT)"
%token T_ASSIGN "assign (T_ASSIGN)"
%token T_IGNORE "ignore (T_IGNORE)"
%type <text> identifier %type <text> identifier
%type <array> rterm_items %type <array> rterm_items
%type <array> rterm_items_inner %type <array> rterm_items_inner
@ -151,27 +160,25 @@ using namespace icinga;
%type <array> lterm_items_inner %type <array> lterm_items_inner
%type <variant> typerulelist %type <variant> typerulelist
%type <op> lbinary_op %type <op> lbinary_op
%type <op> rbinary_op
%type <type> type %type <type> type
%type <num> partial_specifier %type <num> partial_specifier
%type <slist> object_inherits_list
%type <slist> object_inherits_specifier
%type <variant> rterm %type <variant> rterm
%type <variant> rterm_scope %type <variant> rterm_scope
%type <variant> lterm %type <variant> lterm
%type <num> variable_decl
%left T_LOGICAL_OR %left T_LOGICAL_OR
%left T_LOGICAL_AND %left T_LOGICAL_AND
%left T_BINARY_OR
%left T_BINARY_AND
%left T_IN %left T_IN
%left T_NOT_IN %left T_NOT_IN
%nonassoc T_EQUAL %left T_EQUAL T_NOT_EQUAL
%nonassoc T_NOT_EQUAL %left T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL
%left '+' '-' %left T_SHIFT_LEFT T_SHIFT_RIGHT
%left '*' '/' %left T_PLUS T_MINUS
%left '&' %left T_MULTIPLY T_DIVIDE_OP
%left '|' %right '!' '~'
%right '~' %left '.' '(' '['
%right '!'
%{ %{
int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
@ -192,6 +199,10 @@ static ConfigType::Ptr m_Type;
static Dictionary::Ptr m_ModuleScope; static Dictionary::Ptr m_ModuleScope;
static bool m_Apply;
static AExpression::Ptr m_Assign;
static AExpression::Ptr m_Ignore;
void ConfigCompiler::Compile(void) void ConfigCompiler::Compile(void)
{ {
m_ModuleScope = make_shared<Dictionary>(); m_ModuleScope = make_shared<Dictionary>();
@ -215,7 +226,7 @@ statements: /* empty */
| statements statement | statements statement
; ;
statement: object | type | include | include_recursive | library | variable | apply statement: object | type | include | include_recursive | library | constant | apply
{ } { }
| lterm | lterm
{ {
@ -265,7 +276,7 @@ library: T_LIBRARY T_STRING
} }
; ;
variable: variable_decl identifier T_SET rterm constant: T_CONST identifier T_SET rterm
{ {
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$4); AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$4);
delete $4; delete $4;
@ -277,16 +288,6 @@ variable: variable_decl identifier T_SET rterm
} }
; ;
variable_decl: T_VAR
{
$$ = true;
}
| T_CONST
{
$$ = false;
}
;
identifier: T_IDENTIFIER identifier: T_IDENTIFIER
| T_STRING | T_STRING
{ {
@ -411,9 +412,9 @@ object:
{ {
m_Abstract = false; m_Abstract = false;
} }
object_declaration identifier rterm object_inherits_specifier rterm_scope object_declaration identifier rterm rterm_scope
{ {
DebugInfo di = DebugInfoRange(@2, @6); DebugInfo di = DebugInfoRange(@2, @5);
ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(di); ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(di);
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$4); AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$4);
@ -444,16 +445,8 @@ object:
item->SetName(name); item->SetName(name);
if ($5) { AExpression::Ptr exprl = static_cast<AExpression::Ptr>(*$5);
BOOST_FOREACH(const String& parent, *$5) { delete $5;
item->AddParent(parent);
}
delete $5;
}
AExpression::Ptr exprl = static_cast<AExpression::Ptr>(*$6);
delete $6;
exprl->MakeInline(); exprl->MakeInline();
item->AddExpression(exprl); item->AddExpression(exprl);
@ -473,38 +466,6 @@ object_declaration: T_OBJECT
m_Abstract = true; m_Abstract = true;
} }
object_inherits_list:
{
$$ = NULL;
}
| T_STRING
{
$$ = new std::vector<String>();
$$->push_back($1);
free($1);
}
| object_inherits_list ',' T_STRING
{
if ($1)
$$ = $1;
else
$$ = new std::vector<String>();
$$->push_back($3);
free($3);
}
;
object_inherits_specifier:
{
$$ = NULL;
}
| T_INHERITS object_inherits_list
{
$$ = $2;
}
;
lbinary_op: T_SET lbinary_op: T_SET
| T_SET_PLUS | T_SET_PLUS
| T_SET_MINUS | T_SET_MINUS
@ -551,23 +512,71 @@ lterm_items_inner: /* empty */
lterm: identifier lbinary_op rterm lterm: identifier lbinary_op rterm
{ {
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$3); AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
$$ = new Value(make_shared<AExpression>($2, $1, aexpr, DebugInfoRange(@1, @3)));
free($1); free($1);
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$3);
$$ = new Value(make_shared<AExpression>($2, aindex, aexpr, DebugInfoRange(@1, @3)));
delete $3; delete $3;
} }
| identifier '[' T_STRING ']' lbinary_op rterm | identifier '[' rterm ']' lbinary_op rterm
{ {
AExpression::Ptr subexpr = make_shared<AExpression>($5, $3, static_cast<AExpression::Ptr>(*$6), DebugInfoRange(@1, @6)); AExpression::Ptr subexpr = make_shared<AExpression>($5, static_cast<AExpression::Ptr>(*$3), static_cast<AExpression::Ptr>(*$6), DebugInfoRange(@1, @6));
free($3); delete $3;
delete $6; delete $6;
Array::Ptr subexprl = make_shared<Array>(); Array::Ptr subexprl = make_shared<Array>();
subexprl->Add(subexpr); subexprl->Add(subexpr);
AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6)); AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6)));
free($1); free($1);
AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6));
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindex, expr, DebugInfoRange(@1, @6)));
}
| identifier '.' T_IDENTIFIER lbinary_op rterm
{
AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
AExpression::Ptr subexpr = make_shared<AExpression>($4, aindex, static_cast<AExpression::Ptr>(*$5), DebugInfoRange(@1, @5));
free($3);
delete $5;
Array::Ptr subexprl = make_shared<Array>();
subexprl->Add(subexpr);
AExpression::Ptr aindexl = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
free($1);
AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5));
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindexl, expr, DebugInfoRange(@1, @5)));
}
| T_IMPORT rterm
{
AExpression::Ptr avar = make_shared<AExpression>(&AExpression::OpVariable, "type", DebugInfoRange(@1, @2));
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$2);
delete $2;
$$ = new Value(make_shared<AExpression>(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2)));
}
| T_ASSIGN T_WHERE rterm
{
if (!m_Apply)
BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context."));
m_Assign = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Assign, static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3));
delete $3;
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
}
| T_IGNORE T_WHERE rterm
{
if (!m_Apply)
BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context."));
m_Ignore = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Ignore, static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3));
delete $3;
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
} }
| rterm | rterm
{ {
@ -575,29 +584,6 @@ lterm: identifier lbinary_op rterm
} }
; ;
rbinary_op: T_PLUS
| T_MINUS
| T_MULTIPLY
| T_DIVIDE_OP
| T_BINARY_AND
| T_BINARY_OR
| T_LESS_THAN
| T_GREATER_THAN
| T_LESS_THAN_OR_EQUAL
| T_GREATER_THAN_OR_EQUAL
| T_EQUAL
| T_NOT_EQUAL
| T_IN
| T_NOT_IN
| T_LOGICAL_AND
| T_LOGICAL_OR
| T_SHIFT_LEFT
| T_SHIFT_RIGHT
{
$$ = $1;
}
;
rterm_items: rterm_items_inner rterm_items: rterm_items_inner
{ {
$$ = $1; $$ = $1;
@ -630,12 +616,6 @@ rterm_items_inner: /* empty */
} }
; ;
rbinary_op: '+'
{
$$ = &AExpression::OpAdd;
}
;
rterm_scope: '{' lterm_items '}' rterm_scope: '{' lterm_items '}'
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3))); $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3)));
@ -655,6 +635,12 @@ rterm: T_STRING
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1)); $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1));
} }
| rterm '.' T_IDENTIFIER
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, static_cast<AExpression::Ptr>(*$1), make_shared<AExpression>(&AExpression::OpLiteral, $3, @3), DebugInfoRange(@1, @3)));
delete $1;
free($3);
}
| T_IDENTIFIER '(' rterm_items ')' | T_IDENTIFIER '(' rterm_items ')'
{ {
Array::Ptr arguments = Array::Ptr($3); Array::Ptr arguments = Array::Ptr($3);
@ -668,7 +654,7 @@ rterm: T_STRING
} }
| '!' rterm | '!' rterm
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2))); $$ = new Value(make_shared<AExpression>(&AExpression::OpLogicalNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2; delete $2;
} }
| '~' rterm | '~' rterm
@ -676,10 +662,10 @@ rterm: T_STRING
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2))); $$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2; delete $2;
} }
| identifier '[' T_STRING ']' | rterm '[' rterm ']'
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, $1, $3, DebugInfoRange(@1, @4))); $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @4)));
free($1); delete $1;
free($3); free($3);
} }
| '[' rterm_items ']' | '[' rterm_items ']'
@ -694,30 +680,56 @@ rterm: T_STRING
{ {
$$ = $2; $$ = $2;
} }
| rterm rbinary_op rterm | rterm T_LOGICAL_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_LOGICAL_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_BINARY_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_BINARY_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_NOT_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_NOT_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_LESS_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_GREATER_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_SHIFT_LEFT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_PLUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_MINUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_MULTIPLY rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
| rterm T_DIVIDE_OP rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
;
apply:
{ {
$$ = new Value(make_shared<AExpression>($2, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3))); m_Apply = true;
delete $1; m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
delete $3; m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
} }
; T_APPLY identifier rterm rterm
optional_template: /* empty */
| T_TEMPLATE
;
apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE rterm
{ {
if (!ApplyRule::IsValidCombination($3, $6)) { m_Apply = false;
BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'.") << errinfo_debuginfo(@1));
}
Array::Ptr arguments = make_shared<Array>(); AExpression::Ptr aname = static_cast<AExpression::Ptr>(*$4);
arguments->Add(*$8); delete $4;
delete $8; String type = $3;
free($3);
String name = aname->Evaluate(m_ModuleScope);
AExpression::Ptr aexpr = make_shared<AExpression>(&AExpression::OpFunctionCall, "bool", make_shared<AExpression>(&AExpression::OpLiteral, arguments, @8), @8); if (!ApplyRule::IsValidType(type))
BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
ApplyRule::AddRule($3, $4, $6, aexpr, DebugInfoRange(@1, @8), m_ModuleScope); AExpression::Ptr exprl = static_cast<AExpression::Ptr>(*$5);
delete $5;
exprl->MakeInline();
// assign && !ignore
AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
ApplyRule::AddRule(type, name, exprl, filter, DebugInfoRange(@2, @5), m_ModuleScope);
m_Assign.reset();
m_Ignore.reset();
} }
%% %%

View File

@ -38,6 +38,6 @@ std::string icinga::to_string(const errinfo_debuginfo& e)
{ {
std::ostringstream msgbuf; std::ostringstream msgbuf;
msgbuf << "Config location: " << e.value() << "\n"; msgbuf << "Config location: " << e.value() << "\n";
ShowCodeFragment(msgbuf, e.value()); ShowCodeFragment(msgbuf, e.value(), true);
return msgbuf.str(); return msgbuf.str();
} }

View File

@ -44,15 +44,13 @@ ConfigItem::ItemMap ConfigItem::m_Items;
* @param unit The unit of the item. * @param unit The unit of the item.
* @param abstract Whether the item is a template. * @param abstract Whether the item is a template.
* @param exprl Expression list for the item. * @param exprl Expression list for the item.
* @param parents Parent objects for the item.
* @param debuginfo Debug information. * @param debuginfo Debug information.
*/ */
ConfigItem::ConfigItem(const String& type, const String& name, ConfigItem::ConfigItem(const String& type, const String& name,
bool abstract, const AExpression::Ptr& exprl, bool abstract, const AExpression::Ptr& exprl,
const std::vector<String>& parents, const DebugInfo& debuginfo, const DebugInfo& debuginfo, const Dictionary::Ptr& scope)
const Dictionary::Ptr& scope)
: m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false), : m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false),
m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo), m_ExpressionList(exprl), m_DebugInfo(debuginfo),
m_Scope(scope) m_Scope(scope)
{ {
} }
@ -112,53 +110,19 @@ AExpression::Ptr ConfigItem::GetExpressionList(void) const
return m_ExpressionList; return m_ExpressionList;
} }
AExpression::Ptr ConfigItem::GetLinkedExpressionList(void)
{
ASSERT(OwnsLock());
if (m_LinkedExpressionList)
return m_LinkedExpressionList;
Array::Ptr subexprs = make_shared<Array>();
BOOST_FOREACH(const String& name, m_ParentNames) {
ConfigItem::Ptr parent = ConfigItem::GetObject(m_Type, name);
if (!parent) {
std::ostringstream message;
message << "Parent object '" << name << "' does not"
" exist (" << m_DebugInfo << ")";
ConfigCompilerContext::GetInstance()->AddMessage(true, message.str(), m_DebugInfo);
} else {
AExpression::Ptr pexprl;
{
ObjectLock olock(parent);
pexprl = parent->GetLinkedExpressionList();
}
subexprs->Add(pexprl);
}
}
subexprs->Add(m_ExpressionList);
m_LinkedExpressionList = make_shared<AExpression>(&AExpression::OpDict, subexprs, true, m_DebugInfo);
return m_LinkedExpressionList;
}
Dictionary::Ptr ConfigItem::GetProperties(void) Dictionary::Ptr ConfigItem::GetProperties(void)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
if (!m_Properties) { if (!m_Properties) {
m_Properties = make_shared<Dictionary>(); m_Properties = make_shared<Dictionary>();
m_Properties->Set("type", m_Type);
m_Properties->Set("name", m_Name);
m_Properties->Set("__parent", m_Scope); m_Properties->Set("__parent", m_Scope);
GetLinkedExpressionList()->Evaluate(m_Properties); GetExpressionList()->Evaluate(m_Properties);
m_Properties->Remove("__parent"); m_Properties->Remove("__parent");
VERIFY(m_Properties->Get("__type") == GetType() && m_Properties->Get("__name") == GetName()); VERIFY(m_Properties->Get("type") == GetType() && m_Properties->Get("name") == GetName());
} }
return m_Properties; return m_Properties;

View File

@ -45,8 +45,8 @@ public:
DECLARE_PTR_TYPEDEFS(ConfigItem); DECLARE_PTR_TYPEDEFS(ConfigItem);
ConfigItem(const String& type, const String& name, bool abstract, ConfigItem(const String& type, const String& name, bool abstract,
const AExpression::Ptr& exprl, const std::vector<String>& parents, const AExpression::Ptr& exprl, const DebugInfo& debuginfo,
const DebugInfo& debuginfo, const Dictionary::Ptr& scope); const Dictionary::Ptr& scope);
String GetType(void) const; String GetType(void) const;
String GetName(void) const; String GetName(void) const;
@ -54,7 +54,7 @@ public:
std::vector<ConfigItem::Ptr> GetParents(void) const; std::vector<ConfigItem::Ptr> GetParents(void) const;
AExpression::Ptr GetLinkedExpressionList(void); AExpression::Ptr GetExpressionList(void) const;
Dictionary::Ptr GetProperties(void); Dictionary::Ptr GetProperties(void);
DynamicObject::Ptr Commit(void); DynamicObject::Ptr Commit(void);
@ -74,8 +74,6 @@ public:
static void DiscardItems(void); static void DiscardItems(void);
private: private:
AExpression::Ptr GetExpressionList(void) const;
String m_Type; /**< The object type. */ String m_Type; /**< The object type. */
String m_Name; /**< The name. */ String m_Name; /**< The name. */
bool m_Abstract; /**< Whether this is a template. */ bool m_Abstract; /**< Whether this is a template. */
@ -88,8 +86,6 @@ private:
DebugInfo m_DebugInfo; /**< Debug information. */ DebugInfo m_DebugInfo; /**< Debug information. */
Dictionary::Ptr m_Scope; /**< variable scope. */ Dictionary::Ptr m_Scope; /**< variable scope. */
AExpression::Ptr m_LinkedExpressionList;
DynamicObject::Ptr m_Object; DynamicObject::Ptr m_Object;
static boost::mutex m_Mutex; static boost::mutex m_Mutex;

View File

@ -60,11 +60,6 @@ void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope)
m_Scope = scope; m_Scope = scope;
} }
void ConfigItemBuilder::AddParent(const String& parent)
{
m_Parents.push_back(parent);
}
void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr) void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr)
{ {
m_Expressions->Add(expr); m_Expressions->Add(expr);
@ -90,18 +85,19 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
} }
BOOST_FOREACH(const String& parent, m_Parents) {
if (parent == m_Name)
BOOST_THROW_EXCEPTION(std::invalid_argument("Configuration item '" + m_Name + "' of type '" + m_Type + "' must not inherit from itself."));
}
Array::Ptr exprs = make_shared<Array>(); Array::Ptr exprs = make_shared<Array>();
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__type", make_shared<AExpression>(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); Array::Ptr templateArray = make_shared<Array>();
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__name", make_shared<AExpression>(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); templateArray->Add(m_Name);
exprs->Add(make_shared<AExpression>(&AExpression::OpSetPlus,
make_shared<AExpression>(&AExpression::OpLiteral, "templates", m_DebugInfo),
make_shared<AExpression>(&AExpression::OpLiteral, templateArray, m_DebugInfo),
m_DebugInfo));
exprs->Add(make_shared<AExpression>(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); exprs->Add(make_shared<AExpression>(&AExpression::OpDict, m_Expressions, true, m_DebugInfo));
AExpression::Ptr exprl = make_shared<AExpression>(&AExpression::OpDict, exprs, true, m_DebugInfo); AExpression::Ptr exprl = make_shared<AExpression>(&AExpression::OpDict, exprs, true, m_DebugInfo);
return make_shared<ConfigItem>(m_Type, m_Name, m_Abstract, exprl, return make_shared<ConfigItem>(m_Type, m_Name, m_Abstract, exprl,
m_Parents, m_DebugInfo, m_Scope); m_DebugInfo, m_Scope);
} }

View File

@ -47,8 +47,6 @@ public:
void SetAbstract(bool abstract); void SetAbstract(bool abstract);
void SetScope(const Dictionary::Ptr& scope); void SetScope(const Dictionary::Ptr& scope);
void AddParent(const String& parent);
void AddExpression(const AExpression::Ptr& expr); void AddExpression(const AExpression::Ptr& expr);
ConfigItem::Ptr Compile(void); ConfigItem::Ptr Compile(void);
@ -57,8 +55,6 @@ private:
String m_Type; /**< The object type. */ String m_Type; /**< The object type. */
String m_Name; /**< The name. */ String m_Name; /**< The name. */
bool m_Abstract; /**< Whether the item is abstract. */ bool m_Abstract; /**< Whether the item is abstract. */
std::vector<String> m_Parents; /**< The names of parent configuration
items. */
Array::Ptr m_Expressions; /**< Expressions for this item. */ Array::Ptr m_Expressions; /**< Expressions for this item. */
DebugInfo m_DebugInfo; /**< Debug information. */ DebugInfo m_DebugInfo; /**< Debug information. */
Dictionary::Ptr m_Scope; /**< variable scope. */ Dictionary::Ptr m_Scope; /**< variable scope. */

View File

@ -180,7 +180,7 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
} }
if (overallResult == ValidationUnknownField) if (overallResult == ValidationUnknownField)
ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations)); ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) { else if (overallResult == ValidationInvalidType) {
String message = "Invalid value for attribute: " + LocationToString(locations); String message = "Invalid value for attribute: " + LocationToString(locations);

View File

@ -53,7 +53,7 @@ DebugInfo icinga::DebugInfoRange(const DebugInfo& start, const DebugInfo& end)
#define EXTRA_LINES 2 #define EXTRA_LINES 2
void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di) void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose)
{ {
if (di.Path.IsEmpty()) if (di.Path.IsEmpty())
return; return;
@ -61,41 +61,44 @@ void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di)
std::ifstream ifs; std::ifstream ifs;
ifs.open(di.Path.CStr(), std::ifstream::in); ifs.open(di.Path.CStr(), std::ifstream::in);
int lineno = 1; int lineno = 0;
char line[1024]; char line[1024];
while (ifs.good() && lineno <= di.LastLine + EXTRA_LINES) { while (ifs.good() && lineno <= di.LastLine + EXTRA_LINES) {
lineno++;
ifs.getline(line, sizeof(line)); ifs.getline(line, sizeof(line));
for (int i = 0; line[i]; i++) for (int i = 0; line[i]; i++)
if (line[i] == '\t') if (line[i] == '\t')
line[i] = ' '; line[i] = ' ';
if (lineno >= di.FirstLine - EXTRA_LINES && lineno <= di.LastLine + EXTRA_LINES) { int extra_lines = verbose ? EXTRA_LINES : 0;
String pathInfo = di.Path + "(" + Convert::ToString(lineno) + "): ";
out << pathInfo;
out << line << "\n";
if (lineno >= di.FirstLine && lineno <= di.LastLine) { if (lineno < di.FirstLine - extra_lines || lineno > di.LastLine + extra_lines)
int start, end; continue;
start = 0; String pathInfo = di.Path + "(" + Convert::ToString(lineno) + "): ";
end = strlen(line); out << pathInfo;
out << line << "\n";
if (lineno == di.FirstLine) if (lineno >= di.FirstLine && lineno <= di.LastLine) {
start = di.FirstColumn - 1; int start, end;
if (lineno == di.LastLine) start = 0;
end = di.LastColumn; end = strlen(line);
out << String(pathInfo.GetLength(), ' '); if (lineno == di.FirstLine)
out << String(start, ' '); start = di.FirstColumn - 1;
out << String(end - start, '^');
out << "\n"; if (lineno == di.LastLine)
} end = di.LastColumn;
out << String(pathInfo.GetLength(), ' ');
out << String(start, ' ');
out << String(end - start, '^');
out << "\n";
} }
lineno++;
} }
} }

View File

@ -64,7 +64,7 @@ I2_CONFIG_API std::ostream& operator<<(std::ostream& out, const DebugInfo& val);
I2_CONFIG_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end); I2_CONFIG_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end);
I2_CONFIG_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di); I2_CONFIG_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose);
} }

View File

@ -17,26 +17,26 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type DbConnection { %type DbConnection {
%attribute string "table_prefix", %attribute %string "table_prefix",
%attribute dictionary "cleanup" { %attribute %dictionary "cleanup" {
%attribute number "acknowledgements_age", %attribute %number "acknowledgements_age",
%attribute number "commenthistory_age", %attribute %number "commenthistory_age",
%attribute number "contactnotifications_age", %attribute %number "contactnotifications_age",
%attribute number "contactnotificationmethods_age", %attribute %number "contactnotificationmethods_age",
%attribute number "downtimehistory_age", %attribute %number "downtimehistory_age",
%attribute number "eventhandlers_age", %attribute %number "eventhandlers_age",
%attribute number "externalcommands_age", %attribute %number "externalcommands_age",
%attribute number "flappinghistory_age", %attribute %number "flappinghistory_age",
%attribute number "hostchecks_age", %attribute %number "hostchecks_age",
%attribute number "logentries_age", %attribute %number "logentries_age",
%attribute number "notifications_age", %attribute %number "notifications_age",
%attribute number "processevents_age", %attribute %number "processevents_age",
%attribute number "statehistory_age", %attribute %number "statehistory_age",
%attribute number "servicechecks_age", %attribute %number "servicechecks_age",
%attribute number "systemcommands_age", %attribute %number "systemcommands_age",
}, },
%attribute number "categories" %attribute %number "categories"
} }

View File

@ -17,5 +17,5 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type Hello { %type Hello {
} }

View File

@ -42,15 +42,15 @@ mkembedconfig_target(icinga-type.conf icinga-type.cpp)
add_library(icinga SHARED add_library(icinga SHARED
api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th
domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th dependency-apply.cpp domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
externalcommandprocessor.cpp host.cpp host.th host-apply.cpp hostgroup.cpp hostgroup.th externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th
icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
icingastatuswriter.th legacytimeperiod.cpp icingastatuswriter.th legacytimeperiod.cpp
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th
notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th notification.cpp notification.th notification-apply.cpp perfdatavalue.cpp perfdatavalue.th
pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-check.cpp pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th scheduleddowntime-apply.cpp
service-comment.cpp service.cpp service-dependency.cpp service-downtime.cpp service-event.cpp service-apply.cpp service-check.cpp service-comment.cpp service.cpp service-dependency.cpp
service-flapping.cpp service.th servicegroup.cpp servicegroup.th service-downtime.cpp service-event.cpp service-flapping.cpp service.th servicegroup.cpp servicegroup.th
service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th
usergroup.cpp usergroup.th icinga-type.cpp usergroup.cpp usergroup.th icinga-type.cpp
) )

View File

@ -0,0 +1,87 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "icinga/dependency.h"
#include "config/configitembuilder.h"
#include "base/initialize.h"
#include "base/dynamictype.h"
#include "base/convert.h"
#include "base/logger_fwd.h"
#include "base/context.h"
#include <boost/foreach.hpp>
using namespace icinga;
INITIALIZE_ONCE(&Dependency::RegisterApplyRuleHandler);
void Dependency::RegisterApplyRuleHandler(void)
{
ApplyRule::RegisterType("Dependency", "Service", &Dependency::EvaluateApplyRules);
}
void Dependency::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{
BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", service->GetHost());
locals->Set("service", service);
BOOST_FOREACH(const ApplyRule& rule, rules) {
DebugInfo di = rule.GetDebugInfo();
std::ostringstream msgbuf;
msgbuf << "Evaluating 'apply' rule (" << di << ")";
CONTEXT(msgbuf.str());
if (!rule.EvaluateFilter(locals))
continue;
std::ostringstream msgbuf2;
msgbuf2 << "Applying dependency '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di;
Log(LogDebug, "icinga", msgbuf2.str());
std::ostringstream namebuf;
namebuf << service->GetName() << "!" << rule.GetName();
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Dependency");
builder->SetName(name);
builder->SetScope(rule.GetScope());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "child_host", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetHost()->GetName(),
di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "child_service", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetShortName(), di), di));
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
}
}

View File

@ -23,6 +23,7 @@
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/dependency.th" #include "icinga/dependency.th"
#include "icinga/service.h" #include "icinga/service.h"
#include "config/applyrule.h"
#include "base/array.h" #include "base/array.h"
#include "base/dictionary.h" #include "base/dictionary.h"
@ -47,6 +48,9 @@ public:
bool IsAvailable(DependencyType dt) const; bool IsAvailable(DependencyType dt) const;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void OnStateLoaded(void); virtual void OnStateLoaded(void);
virtual void Stop(void); virtual void Stop(void);

View File

@ -57,8 +57,6 @@ void Host::OnConfigLoaded(void)
hg->AddMember(GetSelf()); hg->AddMember(GetSelf());
} }
} }
UpdateSlaveServices();
} }
void Host::Stop(void) void Host::Stop(void)
@ -92,78 +90,6 @@ bool Host::IsReachable(DependencyType dt, shared_ptr<Dependency> *failedDependen
return hc->IsReachable(dt, failedDependency); return hc->IsReachable(dt, failedDependency);
} }
void Host::UpdateSlaveServices(void)
{
ASSERT(!OwnsLock());
Dictionary::Ptr service_descriptions = GetServiceDescriptions();
if (!service_descriptions ||service_descriptions->GetLength() == 0)
return;
ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
ObjectLock olock(service_descriptions);
BOOST_FOREACH(const Dictionary::Pair& kv, service_descriptions) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<String> path;
path.push_back("services");
path.push_back(kv.first);
AExpression::Ptr exprl;
{
ObjectLock ilock(item);
exprl = item->GetLinkedExpressionList();
}
DebugInfo di;
exprl->FindDebugInfoPath(path, di);
if (di.Path.IsEmpty())
di = item->GetDebugInfo();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Service");
builder->SetName(name);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "display_name", make_shared<AExpression>(&AExpression::OpLiteral, kv.first, di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "short_name", make_shared<AExpression>(&AExpression::OpLiteral, kv.first, di), di));
if (!kv.second.IsObjectType<Dictionary>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary."));
Dictionary::Ptr service = kv.second;
Array::Ptr templates = service->Get("templates");
if (templates) {
ObjectLock olock(templates);
BOOST_FOREACH(const Value& tmpl, templates) {
builder->AddParent(tmpl);
}
}
/* Clone attributes from the service expression list. */
Array::Ptr svc_exprl = make_shared<Array>();
exprl->ExtractPath(path, svc_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, svc_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
}
std::set<Service::Ptr> Host::GetServices(void) const std::set<Service::Ptr> Host::GetServices(void) const
{ {
boost::mutex::scoped_lock lock(m_ServicesMutex); boost::mutex::scoped_lock lock(m_ServicesMutex);

View File

@ -102,9 +102,6 @@ public:
virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const; virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void Stop(void); virtual void Stop(void);
@ -114,8 +111,6 @@ private:
mutable boost::mutex m_ServicesMutex; mutable boost::mutex m_ServicesMutex;
std::map<String, shared_ptr<Service> > m_Services; std::map<String, shared_ptr<Service> > m_Services;
void UpdateSlaveServices(void);
static void RefreshServicesCache(void); static void RefreshServicesCache(void);
}; };

View File

@ -17,283 +17,228 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type Host { %type Host {
%attribute string "display_name", %attribute %string "display_name",
%attribute string "check", %attribute %string "check",
%attribute array "groups" { %attribute %array "groups" {
%attribute name(HostGroup) "*" %attribute %name(HostGroup) "*"
},
%attribute dictionary "services" {
%attribute dictionary "*" {
%attribute array "templates" {
%attribute name(Service) "*"
},
%attribute any "*"
}
}, },
%attribute dictionary "dependencies" { %attribute %dictionary "macros" {
%attribute dictionary "*" { %attribute %string "*"
%attribute array "templates" {
%attribute name(Dependency) "*"
},
%attribute any "*"
}
},
%attribute dictionary "macros" {
%attribute string "*"
} }
} }
type HostGroup { %type HostGroup {
%attribute string "display_name" %attribute %string "display_name"
} }
type IcingaApplication { %type IcingaApplication {
} }
type IcingaStatusWriter { %type IcingaStatusWriter {
%attribute string "status_path", %attribute %string "status_path",
%attribute number "update_interval" %attribute %number "update_interval"
} }
type Service { %type Service {
%require "host", %require "host",
%attribute name(Host) "host", %attribute %name(Host) "host",
%attribute string "short_name", %attribute %string "short_name",
%attribute string "display_name", %attribute %string "display_name",
%attribute dictionary "macros" { %attribute %dictionary "macros" {
%attribute string "*" %attribute %string "*"
}, },
%require "check_command", %require "check_command",
%attribute name(CheckCommand) "check_command", %attribute %name(CheckCommand) "check_command",
%attribute number "max_check_attempts", %attribute %number "max_check_attempts",
%attribute name(TimePeriod) "check_period", %attribute %name(TimePeriod) "check_period",
%attribute number "check_interval", %attribute %number "check_interval",
%attribute number "retry_interval", %attribute %number "retry_interval",
%attribute number "enable_notifications", %attribute %number "enable_notifications",
%attribute number "enable_active_checks", %attribute %number "enable_active_checks",
%attribute number "enable_passive_checks", %attribute %number "enable_passive_checks",
%attribute number "enable_event_handler", %attribute %number "enable_event_handler",
%attribute name(EventCommand) "event_command", %attribute %name(EventCommand) "event_command",
%attribute number "enable_flapping", %attribute %number "enable_flapping",
%attribute number "flapping_threshold", %attribute %number "flapping_threshold",
%attribute number "enable_perfdata", %attribute %number "enable_perfdata",
%attribute number "volatile", %attribute %number "volatile",
%attribute dictionary "dependencies" { %attribute %array "groups" {
%attribute dictionary "*" { %attribute %name(ServiceGroup) "*"
%attribute array "templates" {
%attribute name(Dependency) "*"
},
%attribute any "*"
}
}, },
%attribute array "groups" { %attribute %array "authorities" {
%attribute name(ServiceGroup) "*" %attribute %name(Endpoint) "*"
},
%attribute dictionary "notifications" {
%attribute dictionary "*" {
%attribute array "templates" {
%attribute name(Notification) "*"
},
%attribute any "*"
}
},
%attribute dictionary "scheduled_downtimes" {
%attribute dictionary "*" {
%attribute array "templates" {
%attribute name(ScheduledDowntime) "*"
},
%attribute any "*"
}
},
%attribute any "templates",
%attribute array "authorities" {
%attribute name(Endpoint) "*"
}, },
} }
type ServiceGroup { %type ServiceGroup {
%attribute string "display_name" %attribute %string "display_name"
} }
type Notification { %type Notification {
%require "host", %require "host",
%attribute name(Host) "host", %attribute %name(Host) "host",
%require "service", %require "service",
%attribute string "service", %attribute %string "service",
%attribute dictionary "macros" { %attribute %dictionary "macros" {
%attribute string "*" %attribute %string "*"
}, },
%attribute array "users" { %attribute %array "users" {
%attribute name(User) "*" %attribute %name(User) "*"
}, },
%attribute array "user_groups" { %attribute %array "user_groups" {
%attribute name(UserGroup) "*" %attribute %name(UserGroup) "*"
}, },
%attribute dictionary "times" { %attribute %dictionary "times" {
%attribute number "begin", %attribute %number "begin",
%attribute number "end", %attribute %number "end",
}, },
%require "notification_command", %require "notification_command",
%attribute name(NotificationCommand) "notification_command", %attribute %name(NotificationCommand) "notification_command",
%attribute number "notification_interval", %attribute %number "notification_interval",
%attribute name(TimePeriod) "notification_period", %attribute %name(TimePeriod) "notification_period",
%attribute number "notification_type_filter", %attribute %number "notification_%type_filter",
%attribute number "notification_state_filter", %attribute %number "notification_state_filter",
%attribute any "templates", %attribute %array "authorities" {
%attribute %name(Endpoint) "*"
%attribute array "authorities" {
%attribute name(Endpoint) "*"
}, },
} }
type User { %type User {
%attribute string "display_name", %attribute %string "display_name",
%attribute dictionary "macros" { %attribute %dictionary "macros" {
%attribute string "*" %attribute %string "*"
}, },
%attribute array "groups" { %attribute %array "groups" {
%attribute name(UserGroup) "*" %attribute %name(UserGroup) "*"
}, },
%attribute number "enable_notifications", %attribute %number "enable_notifications",
%attribute number "notification_type_filter", %attribute %number "notification_%type_filter",
%attribute number "notification_state_filter", %attribute %number "notification_state_filter",
%attribute name(TimePeriod) "notification_period" %attribute %name(TimePeriod) "notification_period"
} }
type UserGroup { %type UserGroup {
%attribute string "display_name" %attribute %string "display_name"
} }
type TimePeriod { %type TimePeriod {
%attribute string "display_name", %attribute %string "display_name",
%require "methods", %require "methods",
%attribute dictionary "methods" { %attribute %dictionary "methods" {
%require "update", %require "update",
%attribute string "update" %attribute %string "update"
}, },
/* %if (methods.update == "LegacyTimePeriod") { */ /* %if (methods.update == "LegacyTimePeriod") { */
// %require "ranges", // %require "ranges",
%attribute dictionary "ranges" { %attribute %dictionary "ranges" {
%attribute string "*" %attribute %string "*"
} }
/* } */ /* } */
} }
type Command { %type Command {
%require "methods", %require "methods",
%attribute dictionary "methods" { %attribute %dictionary "methods" {
%require "execute", %require "execute",
%attribute string "execute" %attribute %string "execute"
}, },
/* %if (methods.execute == "PluginNotification" || methods.execute == "PluginCheck" || methods.execute == "PluginEvent") { */ /* %if (methods.execute == "PluginNotification" || methods.execute == "PluginCheck" || methods.execute == "PluginEvent") { */
// %require "command", // %require "command",
%attribute string "command", %attribute %string "command",
%attribute array "command" { %attribute %array "command" {
%attribute string "*" %attribute %string "*"
}, },
%attribute array "export_macros" { %attribute %array "export_macros" {
%attribute string "*" %attribute %string "*"
}, },
%attribute array "escape_macros" { %attribute %array "escape_macros" {
%attribute string "*" %attribute %string "*"
}, },
%attribute dictionary "macros" { %attribute %dictionary "macros" {
%attribute string "*" %attribute %string "*"
}, },
%attribute number "timeout" %attribute %number "timeout"
/* } */ /* } */
} }
type CheckCommand inherits Command { %type CheckCommand %inherits Command {
} }
type NotificationCommand inherits Command { %type NotificationCommand %inherits Command {
} }
type EventCommand inherits Command { %type EventCommand %inherits Command {
} }
type Domain { %type Domain {
%attribute dictionary "acl" { %attribute %dictionary "acl" {
%attribute number "*" %attribute %number "*"
} }
} }
type ScheduledDowntime { %type ScheduledDowntime {
%require "host", %require "host",
%attribute name(Host) "host", %attribute %name(Host) "host",
%require "service", %require "service",
%attribute string "service", %attribute %string "service",
%require "author", %require "author",
%attribute string "author", %attribute %string "author",
%require "comment", %require "comment",
%attribute string "comment", %attribute %string "comment",
%attribute number "duration", %attribute %number "duration",
%attribute number "fixed", %attribute %number "fixed",
%require "ranges", %require "ranges",
%attribute dictionary "ranges" { %attribute %dictionary "ranges" {
%attribute string "*" %attribute %string "*"
}, },
%attribute any "templates"
} }
type Dependency { %type Dependency {
%require "parent_host", %require "parent_host",
%attribute name(Host) "parent_host", %attribute %name(Host) "parent_host",
%attribute string "parent_service", %attribute %string "parent_service",
%require "child_host", %require "child_host",
%attribute name(Host) "child_host", %attribute %name(Host) "child_host",
%attribute string "child_service", %attribute %string "child_service",
%attribute name(TimePeriod) "period", %attribute %name(TimePeriod) "period",
%attribute number "state_filter", %attribute %number "state_filter",
%attribute number "disable_checks", %attribute %number "disable_checks",
%attribute number "disable_notifications" %attribute %number "disable_notifications"
} }

View File

@ -0,0 +1,88 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "icinga/service.h"
#include "config/configitembuilder.h"
#include "base/initialize.h"
#include "base/dynamictype.h"
#include "base/convert.h"
#include "base/logger_fwd.h"
#include "base/context.h"
#include <boost/foreach.hpp>
using namespace icinga;
INITIALIZE_ONCE(&Notification::RegisterApplyRuleHandler);
void Notification::RegisterApplyRuleHandler(void)
{
ApplyRule::RegisterType("Notification", "Service", &Notification::EvaluateApplyRules);
}
void Notification::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{
BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", service->GetHost());
locals->Set("service", service);
BOOST_FOREACH(const ApplyRule& rule, rules) {
DebugInfo di = rule.GetDebugInfo();
std::ostringstream msgbuf;
msgbuf << "Evaluating 'apply' rule (" << di << ")";
CONTEXT(msgbuf.str());
if (!rule.EvaluateFilter(locals))
continue;
std::ostringstream msgbuf2;
msgbuf2 << "Applying notification '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di;
Log(LogDebug, "icinga", msgbuf2.str());
std::ostringstream namebuf;
namebuf << service->GetName() << "!" << rule.GetName();
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Notification");
builder->SetName(name);
builder->SetScope(rule.GetScope());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "host", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetHost()->GetName(), di),
di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "service", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetShortName(), di),
di));
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
}
}

View File

@ -25,6 +25,7 @@
#include "icinga/user.h" #include "icinga/user.h"
#include "icinga/usergroup.h" #include "icinga/usergroup.h"
#include "icinga/timeperiod.h" #include "icinga/timeperiod.h"
#include "config/applyrule.h"
#include "base/array.h" #include "base/array.h"
namespace icinga namespace icinga
@ -86,6 +87,9 @@ public:
static boost::signals2::signal<void (const Notification::Ptr&, double, const String&)> OnNextNotificationChanged; static boost::signals2::signal<void (const Notification::Ptr&, double, const String&)> OnNextNotificationChanged;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void Start(void); virtual void Start(void);
virtual void Stop(void); virtual void Stop(void);

View File

@ -0,0 +1,88 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "icinga/scheduleddowntime.h"
#include "config/configitembuilder.h"
#include "base/initialize.h"
#include "base/dynamictype.h"
#include "base/convert.h"
#include "base/logger_fwd.h"
#include "base/context.h"
#include <boost/foreach.hpp>
using namespace icinga;
INITIALIZE_ONCE(&ScheduledDowntime::RegisterApplyRuleHandler);
void ScheduledDowntime::RegisterApplyRuleHandler(void)
{
ApplyRule::RegisterType("ScheduledDowntime", "Service", &ScheduledDowntime::EvaluateApplyRules);
}
void ScheduledDowntime::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{
BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", service->GetHost());
locals->Set("service", service);
BOOST_FOREACH(const ApplyRule& rule, rules) {
DebugInfo di = rule.GetDebugInfo();
std::ostringstream msgbuf;
msgbuf << "Evaluating 'apply' rule (" << di << ")";
CONTEXT(msgbuf.str());
if (!rule.EvaluateFilter(locals))
continue;
std::ostringstream msgbuf2;
msgbuf2 << "Applying scheduled downtime '" << rule.GetName() << "' to service '" << service->GetName() << "' for rule " << di;
Log(LogDebug, "icinga", msgbuf2.str());
std::ostringstream namebuf;
namebuf << service->GetName() << "!" << rule.GetName();
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("ScheduledDowntime");
builder->SetName(name);
builder->SetScope(rule.GetScope());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "host", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetHost()->GetName(), di),
di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "service", di),
make_shared<AExpression>(&AExpression::OpLiteral, service->GetShortName(), di),
di));
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
}
}

View File

@ -23,6 +23,7 @@
#include "icinga/i2-icinga.h" #include "icinga/i2-icinga.h"
#include "icinga/scheduleddowntime.th" #include "icinga/scheduleddowntime.th"
#include "icinga/service.h" #include "icinga/service.h"
#include "config/applyrule.h"
#include <utility> #include <utility>
namespace icinga namespace icinga
@ -43,6 +44,9 @@ public:
Service::Ptr GetService(void) const; Service::Ptr GetService(void) const;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void Start(void); virtual void Start(void);

View File

@ -17,7 +17,7 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
#include "icinga/host.h" #include "icinga/service.h"
#include "config/configitembuilder.h" #include "config/configitembuilder.h"
#include "base/initialize.h" #include "base/initialize.h"
#include "base/dynamictype.h" #include "base/dynamictype.h"
@ -28,59 +28,55 @@
using namespace icinga; using namespace icinga;
INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler); INITIALIZE_ONCE(&Service::RegisterApplyRuleHandler);
void Host::RegisterApplyRuleHandler(void) void Service::RegisterApplyRuleHandler(void)
{ {
ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules); ApplyRule::RegisterType("Service", "Host", &Service::EvaluateApplyRules);
} }
void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules) void Service::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{ {
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) { BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>(); Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", host->GetName()); locals->Set("host", host);
Array::Ptr groups = host->GetGroups();
if (!groups)
groups = make_shared<Array>();
locals->Set("hostgroups", groups);
BOOST_FOREACH(const ApplyRule& rule, rules) { BOOST_FOREACH(const ApplyRule& rule, rules) {
DebugInfo di = rule.GetDebugInfo();
std::ostringstream msgbuf; std::ostringstream msgbuf;
msgbuf << "Evaluating 'apply' rule (" << rule.GetDebugInfo() << ")"; msgbuf << "Evaluating 'apply' rule (" << di << ")";
CONTEXT(msgbuf.str()); CONTEXT(msgbuf.str());
Value result = rule.GetExpression()->Evaluate(locals); if (!rule.EvaluateFilter(locals))
try {
if (!static_cast<bool>(result))
continue;
} catch (...) {
std::ostringstream msgbuf;
msgbuf << "Apply rule (" << rule.GetDebugInfo() << ") returned invalid data type, expected bool: " + JsonSerialize(result);
Log(LogCritical, "icinga", msgbuf.str());
continue; continue;
}
std::ostringstream msgbuf2; std::ostringstream msgbuf2;
msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << rule.GetDebugInfo(); msgbuf2 << "Applying service '" << rule.GetName() << "' to host '" << host->GetName() << "' for rule " << di;
Log(LogDebug, "icinga", msgbuf2.str()); Log(LogDebug, "icinga", msgbuf2.str());
std::ostringstream namebuf; std::ostringstream namebuf;
namebuf << host->GetName() << "!apply!" << rule.GetTemplate(); namebuf << host->GetName() << "!" << rule.GetName();
String name = namebuf.str(); String name = namebuf.str();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(rule.GetDebugInfo()); ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Service"); builder->SetType("Service");
builder->SetName(name); builder->SetName(name);
builder->SetScope(rule.GetScope()); builder->SetScope(rule.GetScope());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, host->GetName(), rule.GetDebugInfo()), rule.GetDebugInfo()));
builder->AddParent(rule.GetTemplate()); builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "host", di),
make_shared<AExpression>(&AExpression::OpLiteral, host->GetName(), di),
di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet,
make_shared<AExpression>(&AExpression::OpLiteral, "short_name", di),
make_shared<AExpression>(&AExpression::OpLiteral, rule.GetName(), di),
di));
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile(); ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register(); serviceItem->Register();

View File

@ -154,89 +154,3 @@ std::set<Service::Ptr> Service::GetChildServices(void) const
return parents; return parents;
} }
void Service::UpdateSlaveDependencies(void)
{
/*
* pass == 0 -> steal host's dependency definitions
* pass == 1 -> service's dependencies
*/
for (int pass = 0; pass < 2; pass++) {
/* Service dependency descs */
Dictionary::Ptr descs;
if (pass == 0 && !IsHostCheck())
continue;
if (pass == 0)
descs = GetHost()->GetDependencyDescriptions();
else
descs = GetDependencyDescriptions();
if (!descs || descs->GetLength() == 0)
continue;
ConfigItem::Ptr item;
if (pass == 0)
item = ConfigItem::GetObject("Host", GetHost()->GetName());
else
item = ConfigItem::GetObject("Service", GetName());
ObjectLock olock(descs);
BOOST_FOREACH(const Dictionary::Pair& kv, descs) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<String> path;
path.push_back("dependencies");
path.push_back(kv.first);
AExpression::Ptr exprl;
{
ObjectLock ilock(item);
exprl = item->GetLinkedExpressionList();
}
DebugInfo di;
exprl->FindDebugInfoPath(path, di);
if (di.Path.IsEmpty())
di = item->GetDebugInfo();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Dependency");
builder->SetName(name);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "child_host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "child_service", make_shared<AExpression>(&AExpression::OpLiteral, GetShortName(), di), di));
Dictionary::Ptr dependency = kv.second;
Array::Ptr templates = dependency->Get("templates");
if (templates) {
ObjectLock tlock(templates);
BOOST_FOREACH(const Value& tmpl, templates) {
builder->AddParent(tmpl);
}
}
/* Clone attributes from the scheduled downtime expression list. */
Array::Ptr sd_exprl = make_shared<Array>();
exprl->ExtractPath(path, sd_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, sd_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr dependencyItem = builder->Compile();
dependencyItem->Register();
DynamicObject::Ptr dobj = dependencyItem->Commit();
dobj->OnConfigLoaded();
}
}
}

View File

@ -321,70 +321,3 @@ int Service::GetDowntimeDepth(void) const
return downtime_depth; return downtime_depth;
} }
void Service::UpdateSlaveScheduledDowntimes(void)
{
/* Service scheduled downtime descs */
Dictionary::Ptr descs = GetScheduledDowntimeDescriptions();
if (!descs || descs->GetLength() == 0)
return;
ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
ObjectLock olock(descs);
BOOST_FOREACH(const Dictionary::Pair& kv, descs) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<String> path;
path.push_back("scheduled_downtimes");
path.push_back(kv.first);
AExpression::Ptr exprl;
{
ObjectLock ilock(item);
exprl = item->GetLinkedExpressionList();
}
DebugInfo di;
exprl->FindDebugInfoPath(path, di);
if (di.Path.IsEmpty())
di = item->GetDebugInfo();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("ScheduledDowntime");
builder->SetName(name);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "service", make_shared<AExpression>(&AExpression::OpLiteral, GetShortName(), di), di));
Dictionary::Ptr scheduledDowntime = kv.second;
Array::Ptr templates = scheduledDowntime->Get("templates");
if (templates) {
ObjectLock tlock(templates);
BOOST_FOREACH(const Value& tmpl, templates) {
builder->AddParent(tmpl);
}
}
/* Clone attributes from the scheduled downtime expression list. */
Array::Ptr sd_exprl = make_shared<Array>();
exprl->ExtractPath(path, sd_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, sd_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr scheduledDowntimeItem = builder->Compile();
scheduledDowntimeItem->Register();
DynamicObject::Ptr dobj = scheduledDowntimeItem->Commit();
dobj->OnConfigLoaded();
}
}

View File

@ -100,74 +100,6 @@ void Service::RemoveNotification(const Notification::Ptr& notification)
m_Notifications.erase(notification); m_Notifications.erase(notification);
} }
void Service::UpdateSlaveNotifications(void)
{
/* Service notification descs */
Dictionary::Ptr descs = GetNotificationDescriptions();
if (!descs || descs->GetLength() == 0)
return;
ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
ObjectLock olock(descs);
BOOST_FOREACH(const Dictionary::Pair& kv, descs) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<String> path;
path.push_back("notifications");
path.push_back(kv.first);
AExpression::Ptr exprl;
{
ObjectLock ilock(item);
exprl = item->GetLinkedExpressionList();
}
DebugInfo di;
exprl->FindDebugInfoPath(path, di);
if (di.Path.IsEmpty())
di = item->GetDebugInfo();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Notification");
builder->SetName(name);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "service", make_shared<AExpression>(&AExpression::OpLiteral, GetShortName(), di), di));
Dictionary::Ptr notification = kv.second;
Array::Ptr templates = notification->Get("templates");
if (templates) {
ObjectLock tlock(templates);
BOOST_FOREACH(const Value& tmpl, templates) {
builder->AddParent(tmpl);
}
}
/* Clone attributes from the notification expression list. */
Array::Ptr nfc_exprl = make_shared<Array>();
exprl->ExtractPath(path, nfc_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, nfc_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Register();
DynamicObject::Ptr dobj = notificationItem->Commit();
dobj->OnConfigLoaded();
}
}
bool Service::GetEnableNotifications(void) const bool Service::GetEnableNotifications(void) const
{ {
if (!GetOverrideEnableNotifications().IsEmpty()) if (!GetOverrideEnableNotifications().IsEmpty())

View File

@ -76,10 +76,6 @@ void Service::OnConfigLoaded(void)
if (m_Host) if (m_Host)
m_Host->AddService(GetSelf()); m_Host->AddService(GetSelf());
UpdateSlaveNotifications();
UpdateSlaveScheduledDowntimes();
UpdateSlaveDependencies();
SetSchedulingOffset(Utility::Random()); SetSchedulingOffset(Utility::Random());
} }

View File

@ -220,8 +220,6 @@ public:
bool IsInDowntime(void) const; bool IsInDowntime(void) const;
bool IsAcknowledged(void); bool IsAcknowledged(void);
void UpdateSlaveScheduledDowntimes(void);
/* Comments */ /* Comments */
static int GetNextCommentID(void); static int GetNextCommentID(void);
@ -251,8 +249,6 @@ public:
void ResetNotificationNumbers(void); void ResetNotificationNumbers(void);
void UpdateSlaveNotifications(void);
/* Event Handler */ /* Event Handler */
void ExecuteEventHandler(void); void ExecuteEventHandler(void);
@ -284,7 +280,8 @@ public:
void RemoveReverseDependency(const shared_ptr<Dependency>& dep); void RemoveReverseDependency(const shared_ptr<Dependency>& dep);
std::set<shared_ptr<Dependency> > GetReverseDependencies(void) const; std::set<shared_ptr<Dependency> > GetReverseDependencies(void) const;
void UpdateSlaveDependencies(void); static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void Start(void); virtual void Start(void);

View File

@ -17,26 +17,26 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/ ******************************************************************************/
type Endpoint { %type Endpoint {
%require "host", %require "host",
%attribute string "host", %attribute %string "host",
%require "port", %require "port",
%attribute string "port", %attribute %string "port",
%attribute array "config_files" { %attribute %array "config_files" {
%attribute string "*" %attribute %string "*"
}, },
%attribute array "config_files_recursive" { %attribute %array "config_files_recursive" {
%attribute string "*", %attribute %string "*",
%attribute dictionary "*" { %attribute %dictionary "*" {
%attribute string "path", %attribute %string "path",
%attribute string "pattern" %attribute %string "pattern"
} }
}, },
%attribute array "accept_config" { %attribute %array "accept_config" {
%attribute name(Endpoint) "*" %attribute %name(Endpoint) "*"
} }
} }

View File

@ -1,4 +1,6 @@
object EventCommand "test_event" inherits "plugin-event-command" { object EventCommand "test_event" {
import "plugin-event-command",
command = {{{echo "\ command = {{{echo "\
$$HOSTNAME$HOSTNAME$\ $$HOSTNAME$HOSTNAME$\
|HOSTNAME=$HOSTNAME$\ |HOSTNAME=$HOSTNAME$\

View File

@ -24,7 +24,9 @@ template Notification "mail-notification" {
/** /**
* 1:1 copy of the default command * 1:1 copy of the default command
*/ */
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { object NotificationCommand "mail-service-notification" {
import "plugin-notification-command",
command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ], command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ],
export_macros = [ export_macros = [