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
* files in this directory are included.
*/
object Host "nsca-ng" inherits "generic-host" {
object Host "nsca-ng" {
import "generic-host",
display_name = "nsca-ng test",
services["PassiveService1"] = {
@ -15,4 +17,4 @@ object Host "nsca-ng" inherits "generic-host" {
templates = [ "generic-service" ],
check_command = "passive",
},
}
}

View File

@ -17,5 +17,5 @@
* 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. *
******************************************************************************/
type ClusterListener {
%attribute string "cert_path",
%type ClusterListener {
%attribute %string "cert_path",
%require "cert_path",
%attribute string "key_path",
%attribute %string "key_path",
%require "key_path",
%attribute string "ca_path",
%attribute %string "ca_path",
%require "ca_path",
%attribute string "crl_path",
%attribute %string "crl_path",
%attribute string "bind_host",
%attribute string "bind_port",
%attribute %string "bind_host",
%attribute %string "bind_port",
%attribute array "peers" {
%attribute %array "peers" {
%attribute name(Endpoint) "*"
}
}

View File

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

View File

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

View File

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

View File

@ -17,5 +17,5 @@
* 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. *
******************************************************************************/
type LivestatusListener {
%type LivestatusListener {
%validator "ValidateSocketType",
%attribute string "socket_type",
%attribute %string "socket_type",
%attribute string "socket_path",
%attribute string "bind_host",
%attribute string "bind_port",
%attribute %string "socket_path",
%attribute %string "bind_host",
%attribute %string "bind_port",
%attribute string "compat_log_path",
%attribute %string "compat_log_path",
}

View File

@ -17,5 +17,5 @@
* 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. *
******************************************************************************/
type PerfdataWriter {
%attribute string "perfdata_path",
%attribute string "format_template",
%attribute number "rotation_interval"
%type PerfdataWriter {
%attribute %string "perfdata_path",
%attribute %string "format_template",
%attribute %number "rotation_interval"
}
type GraphiteWriter {
%attribute string "host",
%attribute string "port",
%type GraphiteWriter {
%attribute %string "host",
%attribute %string "port",
}

View File

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

View File

@ -106,22 +106,23 @@ def process_host(host_element):
hosts[name] = { "name": name, "address": address, "services": services }
def print_host(host):
print "object Host \"%s\" inherits \"discovered-host\" {" % (host["name"])
print "\tmacros[\"address\"] = \"%s\"," % (host["address"])
for serv, service in host["services"].iteritems():
print ""
print "\tservices[\"%s\"] = {" % (serv)
print "\t\ttemplates = [ \"discovered-service\" ],"
print ""
print "\t\tcheck_command = \"%s\"," % (service["command"])
print ""
print "\t\tmacros[\"port\"] = %s" % (service["port"])
print "\t},"
print "object Host \"%s\" {" % (host["name"])
print "\timport \"discovered-host\","
print ""
print "\tmacros.address = \"%s\"," % (host["address"])
print "}"
print ""
for serv, service in host["services"].iteritems():
print "apply Service \"%s\" {" % (serv)
print "\timport \"discovered-service\","
print ""
print "\tcheck_command = \"%s\"," % (service["command"])
print ""
print "\tmacros.port = %s" % (service["port"])
print "}"
print ""
for arg in sys.argv[1:]:
# Expects XML output from 'nmap -oX'
dom = parse(arg)

View File

@ -2,10 +2,11 @@
## <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
and any conceivable network resource, notifies the user of errors and recoveries and generates
performance data for reporting. Scalable and extensible, Icinga 2 can monitor complex, large
environments across dispersed locations.
Icinga 2 is an open source monitoring system which checks the availability of your
network resources, notifies users of outages and generates performance data for reporting.
Scalable and extensible, Icinga 2 can monitor complex, large environments across
multiple locations.
## <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
operating system and distribution you are running.
Distribution |Repository URL
Distribution | Repository URL
------------------------|---------------------------
Debian |http://packages.icinga.org/debian/
Ubuntu |http://packages.icinga.org/ubuntu/
RHEL/CentOS 5 |http://packages.icinga.org/epel/5/release/
RHEL/CentOS 6 |http://packages.icinga.org/epel/6/release/
OpenSUSE 12.3 |http://packages.icinga.org/openSUSE/12.3/release/
SLES 11 SP3 |http://packages.icinga.org/SUSE/sles11-sp3/release/
Debian | http://packages.icinga.org/debian/
Ubuntu | http://packages.icinga.org/ubuntu/
RHEL/CentOS 5 | http://packages.icinga.org/epel/5/release/
RHEL/CentOS 6 | http://packages.icinga.org/epel/6/release/
OpenSUSE 12.3 | http://packages.icinga.org/openSUSE/12.3/release/
SLES 11 SP3 | http://packages.icinga.org/SUSE/sles11-sp3/release/
Packages for distributions other than the ones listed above may also be
available. Please check http://packages.icinga.org/ to see if packages
@ -29,8 +29,7 @@ to install the `icinga2` package.
> **Note**
>
> On RHEL/CentOS and SLES you will need to use `chkconfig` to enable the
`icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2
start`.
> `icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2 start`.
Some parts of Icinga 2's functionality are available as separate packages:
@ -114,7 +113,7 @@ The `conf.d/macros.conf` file can be used to define global macros:
/**
* Global macros
*/
set IcingaMacros = {
const IcingaMacros = {
plugindir = "/usr/local/icinga/libexec"
}
@ -131,70 +130,86 @@ The `conf.d/localhost.conf` file contains our first host definition:
* files in this directory are included.
*/
object Host "localhost" {
services["ping4"] = {
templates = [ "generic-service" ],
import "linux-server",
check_command = "ping4"
},
services["ping6"] = {
templates = [ "generic-service" ],
check_command = "ping6"
},
services["http"] = {
templates = [ "generic-service" ],
check_command = "http_ip"
},
services["ssh"] = {
templates = [ "generic-service" ],
check_command = "ssh"
},
services["load"] = {
templates = [ "generic-service" ],
check_command = "load"
},
services["processes"] = {
templates = [ "generic-service" ],
check_command = "processes"
},
services["users"] = {
templates = [ "generic-service" ],
check_command = "users"
},
services["disk"] = {
templates = [ "generic-service" ],
check_command = "disk"
},
macros = {
address = "127.0.0.1",
address6 = "::1",
},
check = "ping4",
macros.address = "127.0.0.1",
macros.address6 = "::1"
}
This defines a host named "localhost" which has a couple of services. Services
may inherit from one or more service templates.
The command objects `ping4`, `ping6`, `http_ip`, `ssh`, `load`, `processes`, `users`
and `disk` are all provided by the Icinga Template Library (short ITL) which
we enabled earlier by including the `itl/itl.conf` configuration file.
This defines the host `localhost`. The `import` keyword is used to import
the `linux-server` template which takes care of setting up the `ping4` and
`ping6` services for the host as well as adding the host to the `linux-servers`
host group.
The `macros` attribute can be used to define macros that are available for all
services which belong to this host. Most of the templates in the Icinga Template
Library require an `address` macro.
apply Service "icinga" {
import "generic-service",
check_command = "icinga",
assign where host.name == "localhost"
}
apply Service "http" {
import "generic-service",
check_command = "http_ip",
assign where host.name == "localhost"
}
apply Service "ssh" {
import "generic-service",
check_command = "ssh",
assign where host.name == "localhost"
}
apply Service "load" {
import "generic-service",
check_command = "load",
assign where host.name == "localhost"
}
apply ScheduledDowntime "backup-downtime" {
import "backup-downtime",
assign where service.host == "localhost" && service.short_name == "load"
}
apply Service "processes" {
import "generic-service",
check_command = "processes",
assign where host.name == "localhost"
}
apply Service "users" {
import "generic-service",
check_command = "users",
assign where host.name == "localhost"
}
apply Service "disk" {
import "generic-service",
check_command = "disk",
assign where host.name == "localhost"
}
The `apply` keyword can be used to dynamically create services for all hosts based
on rules.
The command objects `http_ip`, `ssh`, `load`, `processes`, `users`
and `disk` are all provided by the Icinga Template Library (short ITL) which
we enabled earlier by including the `itl/itl.conf` configuration file.

View File

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

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
-l [ --library ] arg load a library
-I [ --include ] arg add include search directory
-D [ --define] args define a constant
-D [ --define] args define a constant
-c [ --config ] arg parse a configuration file
-C [ --validate ] exit after validating the configuration
-Z [ --no-validate ] skip validating the configuration

View File

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

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

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:
object CheckCommand "my-ping" inherits "plugin-check-command" {
object CheckCommand "my-ping" {
import "plugin-check-command",
command = [
"$plugindir$/check_ping",
"-4",
@ -73,14 +75,12 @@ values for some of the latency thresholds and timeouts.
When using the `my-ping` command you can override all or some of the macros
in the service definition like this:
object Host "my-server1" {
services["ping"] = {
check_command = "my-ping",
apply Service "ping" {
check_command = "my-ping",
macros["packets"] = 10 // Overrides the default value of 5 given in the command
},
macros.packets = 10 // Overrides the default value of 5 given in the command
macros["address"] = "10.0.0.1"
assign where host.name == "my-server1"
}
If a macro isn't defined anywhere an empty value is used and a warning is
@ -126,8 +126,10 @@ Node 2:
CheckCommand definition:
object CheckCommand "whatever" inherits "plugin-check-command" {
command = "$plugindir$/check_whatever"
object CheckCommand "whatever" {
import "plugin-check-command",
command = "$plugindir$/check_whatever"
}
On Node 1, this will be evaluated into `/usr/lib/icinga/plugins/check_whatever`.
@ -246,18 +248,20 @@ be exported as environment variables prior to executing the command.
This is useful for example for hiding sensitive information on the command line output
when passing credentials to database checks:
object CheckCommand "mysql-health" inherits "plugin-check-command" {
command = "$plugindir$/check_mysql -H $address$ -d $db$",
/* default macro values */
macros = {
"MYSQLUSER" = "icinga_check",
"MYSQLPASS" = "1c1ng42r0xx"
},
object CheckCommand "mysql-health" {
import "plugin-check-command",
export_macros = [
"MYSQLUSER",
"MYSQLPASS"
]
command = "$plugindir$/check_mysql -H $address$ -d $db$",
/* default macro values */
macros = {
"MYSQLUSER" = "icinga_check",
"MYSQLPASS" = "1c1ng42r0xx"
},
export_macros = [
"MYSQLUSER",
"MYSQLPASS"
]
}
### <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`.
The example below may or may not fit your needs.
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
object NotificationCommand "mail-service-notification" {
import "plugin-notification-command",
command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
@ -111,21 +113,17 @@ to the defined notifications. That way you'll save duplicated attributes in each
>
> The `TimePeriod` `24x7` is shipped as example configuration with Icinga 2.
Use the `generic-notification` template for the `mail` notification defined
inline to the host's service `ping4` and assign the `icingaadmin` user.
Use the `apply` keyword to create `Notification` objects for your services:
object Host "localhost" {
services["ping4"] = {
notifications["mail"] = {
templates = [ "generic-notification" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
}
}
apply Notification "mail" {
import "generic-notification",
notification_command = "mail-notification",
users = [ "icingaadmin" ],
assign where service.short_name == "ping4"
}
Notifications can be defined in `Service` templates inherited to the objects.
> **Note**
>
> Instead of assigning users to notifications, you can also add the `user_groups`
@ -154,7 +152,7 @@ notifications between start and end time.
object User "icinga-oncall-2nd-level" {
display_name = "Icinga 2nd Level",
enable_notifications = 1,
enable_notifications = true,
macros = {
"mobile" = "+49123456781"
@ -163,10 +161,9 @@ notifications between start and end time.
object User "icinga-oncall-1st-level" {
display_name = "Icinga 1st Level",
enable_notifications = 1,
enable_notifications = true,
macros = {
"mobile" = "+49123456782"
macros.mobile = "+49123456782"
}
}
@ -198,35 +195,35 @@ If the problem does not get resolved or acknowledged preventing further notifica
the `escalation-sms-1st-level` user will be escalated `1h` after the initial problem was
notified, but only for one hour (`2h` as `end` key for the `times` dictionary).
object Host "localhost" {
services["ping4"] = {
notifications["mail"] = {
templates = [ "generic-notification" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
},
notifications["escalation-sms-2nd-level"] = {
templates = [ "generic-notification" ],
notification_command = "sms-notification",
users = [ "icinga-oncall-2nd-level" ],
apply Notification "mail" {
import "generic-notification",
notification_command = "mail-notification",
users = [ "icingaadmin" ],
assign where service.short_name == "ping4"
}
apply Notification "escalation-sms-2nd-level" {
import "generic-notification",
notification_command = "sms-notification",
users = [ "icinga-oncall-2nd-level" ],
times = {
begin = 30m,
end = 1h
}
},
notifications["escalation-sms-1st-level"] = {
templates = [ "generic-notification" ],
notification_command = "sms-notification",
users = [ "icinga-oncall-1st-level" ],
times = {
begin = 1h,
end = 2h
}
}
times = {
begin = 30m,
end = 1h
}
}
apply Notification "escalation-sms-1st-level" {
import "generic-notification",
notification_command = "sms-notification",
users = [ "icinga-oncall-1st-level" ],
times = {
begin = 1h,
end = 2h
}
}
> **Note**
>
@ -243,18 +240,12 @@ dictionary and set `begin = 15m` as key and value if you want to suppress notifi
in the first 15 minutes. Leave out the `end` key - if not set, Icinga 2 will not check against any
end time for this notification.
object Host "localhost" {
services["ping4"] = {
notifications["mail"] = {
templates = [ "generic-notification" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
apply Notification "mail" {
import "generic-notification",
notification_command = "mail-notification",
users = [ "icingaadmin" ],
times = {
begin = 15m // delay first notification
}
}
}
times.begin = 15m // delay first notification
}
> **Note**

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
configuration:
template Host "linux-server" {
services["ping"] = {
check_command = "ping4"
},
check = "ping"
template Service "generic-service" {
max_check_attempts = 3,
check_interval = 5m,
retry_interval = 1m,
enable_perfdata = true
}
object Host "my-server1" inherits "linux-server" {
macros["address"] = "10.0.0.1"
apply Service "ping4" {
import "generic-service",
check_command = "ping4",
assign where host.macros.address
}
object Host "my-server2" inherits "linux-server" {
macros["address"] = "10.0.0.2"
apply Service "ping6" {
import "generic-service",
check_command = "ping6",
assign where host.macros.address6
}
In this example both `my-server1` and `my-server2` each get their own `ping`
service check. Each host gets its own host `check` defined as the `ping`
service too.
In this example both `ping4` and `ping6` services inherit properties from the
template `generic-service`.
Objects as well as templates themselves can inherit from an arbitrary number of
Objects as well as templates themselves can import an arbitrary number of
templates. Attributes inherited from a template can be overridden in the
object if necessary.
Templates can also be used in service and notification definitions using the
`templates` attribute:
template Service "weekend-service" {
check_interval = 0.5m,
check_period = "weekend"
}
object Host "my-server1" {
services["backup"] {
check_command = "backup-check",
templates = [ "weekend-service" ]
}
}

View File

@ -37,17 +37,16 @@ Then add your hosts to this hostgroup
template Host "windows-mssql-template" {
groups = [ "windows" ],
macros = {
"mssql_port" = 1433
macros.mssql_port = 1433
}
}
object Host "mssql-srv1" {
templates = [ "windows-mssql-template" ]
import "windows-mssql-template"
}
object Host "mssql-srv2" {
templates = [ "windows-mssql-template" ]
import "windows-mssql-template"
}
This can be done for service and user groups the same way. Additionally
@ -61,24 +60,20 @@ the user groups are associated as attributes in `Notification` objects.
groups = [ "windows-mssql-admins" ]
}
object User "win-mssql-noc" inherits "generic-windows-mssql-users" {
macros = {
"email" = "noc@company.com"
}
object User "win-mssql-noc" {
import "generic-windows-mssql-users",
macros.email = "noc@example.com"
}
object User "win-mssql-ops" inherits "generic-windows-mssql-users" {
macros = {
"email" = "ops@company.com"
}
object User "win-mssql-ops" {
import "generic-windows-mssql-users",
macros.email = "ops@example.com"
}
object Host "localhost" {
services["ping4"] = {
notifications["mail"] = {
templates = [ "generic-notification" ],
notification_command = "mail-notification",
user_groups = [ "windows-admins" ],
}
}
apply Service "ping4" {
import "generic-notification",
notification_command = "mail-notification",
user_groups = [ "windows-admins" ],
}

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
as shown below.
object TimePeriod "24x7" inherits "legacy-timeperiod" {
object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod",
ranges = {
"monday" = "00:00-24:00",
@ -48,7 +50,9 @@ If your operation staff should only be notified during workhours
create a new timeperiod named `workhours` defining a work day with
09:00 to 17:00.
object TimePeriod "workhours" inherits "legacy-timeperiod" {
object TimePeriod "workhours" {
import "legacy-timeperiod",
display_name = "Icinga 2 8x5 TimePeriod",
ranges = {
"monday" = "09:00-17:00",
@ -62,13 +66,12 @@ create a new timeperiod named `workhours` defining a work day with
Assign the timeperiod as `notification_period` to the `Notification`
object then.
object Host "localhost" {
services["ping4"] = {
notifications["mail"] = {
templates = [ "generic-notification" ],
notification_command = "mail-notification",
users = [ "icingaadmin" ],
notification_period = "workhours"
}
}
apply Notification "mail" {
import "generic-notification",
notification_command = "mail-notification",
users = [ "icingaadmin" ],
notification_period = "workhours"
assign where host.name == "localhost"
}

View File

@ -2,26 +2,19 @@
Icinga 2 supports three different types of logging:
* File logging (local Icinga 2 log file)
* Syslog facility logging (system's syslog application)
* File logging
* Syslog (on *NIX-based operating systems)
* Console logging (`STDOUT` on tty)
> **Note**
>
> You can define multiple logging objects at once.
You can enable additional loggers using the `icinga2-enable-feature`
and `icinga2-disable-feature` commands to configure loggers:
The most common scenario will be logging Icinga 2's output to
syslog with severity `information`.
object SyslogLogger "syslog" {
severity = "information"
}
For debugging purposes you can install a `FileLogger` object
and forward the `debug` severity into an Icinga 2 debug file.
object FileLogger "debug-file" {
severity = "debug",
path = "/var/log/icinga2/debug.log"
}
Feature | Description
---------|------------
debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher)
mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher)
syslog | Syslog (severity: `warning` or higher)
By default file the `mainlog` feature is enabled. When running Icinga 2
on a terminal log messages with severity `information` or higher are
written to the console.

View File

@ -17,5 +17,3 @@ on-demand in your Icinga 2 objects configuration.
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)
for specific use cases already around, for example monitoring Cisco routers.
The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and only defines
additional macros (note the `+=` operator) as command parameters for the `oid`
(`community` is already set):
The following example uses the [SNMP ITL](#itl-snmp) `CheckCommand` and just
overrides the `oid` macro. A service is created for all hosts which
have the `community` macro set.
object Host "remote-snmp-host" inherits "generic-host" {
...
services["uptime"] = {
templates = [ "generic-service" ],
check_command = "snmp",
macros += {
"oid" = "1.3.6.1.2.1.1.3.0"
}
},
macros = {
"address" = "192.168.1.101"
}
apply Service "uptime" {
import "generic-service",
templates = [ "generic-service" ],
check_command = "snmp",
macros.oid = "1.3.6.1.2.1.1.3.0",
assign where host.macros.community
}
#### SSH
@ -44,7 +40,9 @@ additional macros (note the `+=` operator) as command parameters for the `oid`
Calling a plugin using the SSH protocol to execute a plugin on the remote server fetching
its return code and output. `check_by_ssh` is available in the [Monitoring Plugins package](#setting-up-check-plugins).
object CheckCommand "check_by_ssh_swap" inherits "plugin-check-command" {
object CheckCommand "check_by_ssh_swap" {
import "plugin-check-command",
command = [ "$plugindir$/check_by_ssh",
"-l", "remoteuser",
"-H", "$address$",
@ -52,22 +50,17 @@ its return code and output. `check_by_ssh` is available in the [Monitoring Plugi
]
}
object Host "remote-ssh-host" inherits "generic-host" {
...
services["swap"] = {
templates = [ "generic-service" ],
check_command = "check_by_ssh_swap",
macros = {
apply Service "swap" {
import "generic-service",
check_command = "check_by_ssh_swap",
macros = {
"warn" = "50%",
"crit" = "75%"
}
},
macros = {
"address" = "192.168.1.102"
}
assign where host.name == "remote-ssh-host"
}
#### NRPE
[NRPE](http://docs.icinga.org/latest/en/nrpe.html) runs as daemon on the remote client including
@ -77,37 +70,33 @@ remote client.
> **Note**
>
> The NRPE daemon uses its own proprietary configuration format in nrpe.cfg while `check_nrpe`
> The NRPE daemon uses its own configuration format in nrpe.cfg while `check_nrpe`
> can be embedded into the Icinga 2 `CheckCommand` configuration syntax.
Example:
object CheckCommand "check_nrpe" inherits "plugin-check-command" {
object CheckCommand "check_nrpe" {
import "plugin-check-command",
command = [ "$plugindir$/check_nrpe",
"-H", "$address$",
"-c", "$remote_nrpe_command$",
],
}
object Host "remote-nrpe-host" inherits "generic-host" {
...
services["users"] = {
templates = [ "generic-service" ],
check_command = "check_nrpe",
macros = {
"remote_nrpe_command" = "check_users"
}
},
macros = {
"address" = "192.168.1.103"
}
apply Service "users" {
import "generic-service",
check_command = "check_nrpe",
macros.remote_nrpe_command = "check_users",
assign where host.name == "remote-nrpe-host"
}
nrpe.cfg:
command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10
#### NSClient++
[NSClient++](http://nsclient.org) works on both Windows and Linux platforms and is well
@ -122,7 +111,9 @@ the required output and performance counters.
Example:
object CheckCommand "check_nscp" inherits "plugin-check-command" {
object CheckCommand "check_nscp" {
import "plugin-check-command",
command = [ "$plugindir$/check_nt",
"-H", "$address$",
"-p", "$port$",
@ -138,21 +129,18 @@ Example:
}
}
object Host "remote-windows-host" inherits "generic-host" {
...
services["users"] = {
templates = [ "generic-service" ],
check_command = "check_nscp",
macros += {
"remote_nscp_command" = "USEDDISKSPACE",
"partition" = "c",
"warn" = "70",
"crit" = "80"
}
},
macros = {
"address" = "192.168.1.104"
apply Service "users" {
import "generic-service",
check_command = "check_nscp",
macros += {
"remote_nscp_command" = "USEDDISKSPACE",
"partition" = "c",
"warn" = "70",
"crit" = "80"
}
assign where host.name == "remote-windows-host"
}
For details on the `NSClient++` configuration please refer to the [official documentation](http://www.nsclient.org/nscp/wiki/doc/configuration/0.4.x).
@ -166,13 +154,12 @@ For details on the `NSClient++` configuration please refer to the [official docu
A dedicated Icinga 2 agent supporting all platforms and using the native
Icinga 2 communication protocol supported with SSL certificates, IPv4/IPv6
support, etc is on the [development roadmap](https://dev.icinga.org/projects/i2?jump=issues).
support, etc. is on the [development roadmap](https://dev.icinga.org/projects/i2?jump=issues).
Meanwhile remote checkers in a [Cluster](#cluster) setup could act as
immediate replacement, but without any local configuration - or pushing
their standalone configuration back to the master node including their check
result messages.
### Passive Check Results and SNMP Traps
> **Note**

View File

@ -2,8 +2,8 @@
### <a id="object-definition"></a> Object Definition
Icinga 2 features an object-based configuration format. In order to
define objects the `object` keyword is used:
Icinga 2 features an object-based configuration format. You can define new
objects using the `object` keyword:
object Host "host1.example.org" {
display_name = "host1",
@ -66,15 +66,15 @@ Example:
Certain characters need to be escaped. The following escape sequences
are supported:
Character |Escape sequence
------------------------------------|------------------------------------
" |\\"
\\ |\\\\
\<TAB\> |\\t
\<CARRIAGE-RETURN\> |\\r
\<LINE-FEED\> |\\n
\<BEL\> |\\b
\<FORM-FEED\> |\\f
Character | Escape sequence
--------------------------|------------------------------------
" | \\"
\\ | \\\\
&lt;TAB&gt; | \\t
&lt;CARRIAGE-RETURN&gt; | \\r
&lt;LINE-FEED&gt; | \\n
&lt;BEL&gt; | \\b
&lt;FORM-FEED&gt; | \\f
In addition to these pre-defined escape sequences you can specify
arbitrary ASCII characters using the backslash character (\\) followed
@ -154,7 +154,8 @@ The following operators are supported in expressions:
Operator | Examples (Result) | Description
---------|-----------------------------------------------|--------------------------------
!, ~ | ~true (false) | Bitwise negation of the operand
! | !"Hello" (false), !false (true) | Logical negation of the operand
~ | ~true (false) | Bitwise negation of the operand
+ | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings
- | 3 - 1 (2) | Subtracts two numbers
* | 5m * 10 (3000) | Multiplies two numbers
@ -295,6 +296,12 @@ The indexer syntax provides a convenient way to set dictionary elements.
Example:
{
hello.key = "world"
}
Example (alternative syntax):
{
hello["key"] = "world"
}
@ -307,60 +314,41 @@ This is equivalent to writing:
}
}
### <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:
template Host "default-host" {
macros["color"] = "red"
macros.color = "red"
}
template Host "test-host" inherits "default-host" {
macros["color"] = "blue"
template Host "test-host" {
import "default-host",
macros.color = "blue"
}
object Host "localhost" inherits "test-host" {
macros["address"] = "127.0.0.1",
macros["address6"] = "::1"
object Host "localhost" {
import "test-host",
macros.address = "127.0.0.1",
macros.address6 = "::1"
}
The `default-host` and `test-host` objects are marked as templates
using the `template` keyword. Unlike ordinary objects templates are not
instantiated at run-time. Parent objects do not necessarily have to be
templates though in general they are.
templates, however in general they are.
> **Note**
>
> The final macros dictionary contains all three macros and the macro
> `color` has the value `"blue"`.
> The macros dictionary for the `localhost` object contains all three
> macros and the macro `color` has the value `"blue"`.
Parent objects are resolved in the order they're specified using the
`inherits` keyword.
### <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
`import` keyword.
### <a id="constants"></a> Constants
@ -368,34 +356,59 @@ Global constants can be set using the `const` keyword:
const VarName = "some value"
The value can be a string, number, array, or a dictionary.
Constants cannot be changed once they are set.
> **Note**
>
> The `set` and `var` keywords are an alias for `const` and are available
> in order to provide compatibility with older versions. Their use is
> deprecated.
Once defined a constant can be access from any file. Constants cannot be changed
once they are set.
### <a id="apply"></a> Apply
The `apply` keyword can be used to associate a template with another group of
objects. The exact effect of this association depends on the two object types.
The `apply` keyword can be used to create new objects which are associated with
another group of objects.
template Service "ping-service" {
short_name = "ping",
check_command = "ping4"
apply Service "ping" {
import "generic-service",
check_command = "ping4",
assign where host.name == "localhost"
}
apply template Service "ping-service" to Host where host == "localhost"
In this example the `assign where` condition is a boolean expression which is
evaluated for all objects of type `Host` and a new service with name "ping"
is created for each matching host.
In this example the `where` condition is a constant expression which is
evaluated for all objects of type Host and a new service is created for each
matching host.
Depending on the object type used in the `apply` expression additional local
variables may be available for use in the `where` condition:
Depending on the object types used in the `apply` expression additional local
variables may be available for use in the `where` condition.
Source Type | Target Type | Variables
-----------------|-------------|--------------
Service | Host | host
Dependency | Service | host, service
Notification | Service | host, service
ScheduledDowntime| Service | host, service
> **Note**
>
> Any valid config attribute can be accessed using the `host` and `service`
> variables. For example, `host.macros.address` would return the host's
> "address" macro - or null if it doesn't have that macro.
### <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
@ -433,7 +446,7 @@ C/C++ compiler:
Note the use of angle brackets instead of double quotes. This causes the
config compiler to search the include search paths for the specified
file. By default $PREFIX/icinga2 is included in the list of search
file. By default $PREFIX/share/icinga2 is included in the list of search
paths. Additional include search paths can be added using
[command-line options](#cmdline).
@ -459,7 +472,7 @@ When no pattern is specified the default pattern "*.conf" is used.
The `library` directive can be used to manually load additional
libraries. Libraries can be used to provide additional object types and
methods.
functions.
Example:
@ -467,8 +480,8 @@ Example:
> **Note**
>
> The `icinga` library is automatically loaded at startup. You don't need
> to load it manually.
> The `icinga` and `methods` libraries is automatically loaded at startup.
> You don't need to load them manually.
<!--
@ -480,18 +493,18 @@ you can specify which attributes are allowed in an object definition.
Example:
type Pizza {
%type Pizza {
%require "radius",
%attribute number "radius",
%attribute %number "radius",
%attribute dictionary "ingredients" {
%attribute %dictionary "ingredients" {
%validator "ValidateIngredients",
%attribute string "*",
%attribute %string "*",
%attribute dictionary "*" {
%attribute number "quantity",
%attribute string "name"
%attribute %dictionary "*" {
%attribute %number "quantity",
%attribute %string "name"
}
},
@ -512,7 +525,8 @@ The Pizza definition provides the following validation rules:
- If they're a dictionary they may contain attributes `quantity` (of
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.
- 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:
* any
* number
* string
* scalar (an alias for string)
* dictionary
* %any
* %number
* %string
* %scalar (an alias for string)
* %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
--------------------------|-------------------
IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to /usr/local
IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to "/usr/local".
IcingaSysconfDir |**Read-only.** Contains the path of the sysconf directory. Defaults to IcingaPrefixDir + "/etc".
IcingaLocalStateDir |**Read-only.** Contains the path of the local state directory. Defaults to IcingaPrefixDir + "/var".
IcingaPkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to IcingaPrefixDir + "/share/icinga2".

View File

@ -17,19 +17,6 @@ Example:
groups = [ "all-hosts" ],
services["ping"] = {
templates = [ "ping" ]
},
services["http"] = {
templates = [ "my-http" ],
macros = {
vhost = "test1.example.org",
port = 81
}
},
check = "ping"
}
@ -40,8 +27,6 @@ Attributes:
display_name |**Optional.** A short description of the host.
check |**Optional.** A service that is used to determine whether the host is up or down. This must be a service short name of a service that belongs to the host.
groups |**Optional.** A list of host groups this host belongs to.
services |**Optional.** Inline definition of services. Each dictionary item specifies a service.<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.
### <a id="objecttype-hostgroup"></a> HostGroup
@ -68,8 +53,8 @@ by Icinga 2.
> **Best Practice**
>
> Rather than creating a `Service` object for a specific host it is usually easier
> to just create a `Service` template and use the `services` attribute in the `Host`
> object to associate these templates with a host.
> to just create a `Service` template and use the `apply` keyword to assign the
> service to a number of hosts.
Example:
@ -115,8 +100,6 @@ Attributes:
flapping\_threshold|**Optional.** The flapping threshold in percent when a service is considered to be flapping.
volatile |**Optional.** The volatile setting enables always `HARD` state types if `NOT-OK` state changes occur.
groups |**Optional.** The service groups this service belongs to.
notifications |**Optional.** Inline definition of notifications. Each dictionary item specifies a notification.<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.
domains |**Optional.** A list of Domains for this service object in a cluster scenario.
@ -144,8 +127,8 @@ of service state changes and other events.
> **Best Practice**
>
> Rather than creating a `Notification` object for a specific service it is usually easier
> to just create a `Notification` template and use the `notifications` attribute in the `Service`
> object to associate these templates with a service.
> to just create a `Notification` template and use the `apply` keyword to assign the
> notification to a number of services.
Example:
@ -202,8 +185,8 @@ Dependency objects are used to specify dependencies between hosts and services.
> **Best Practice**
>
> Rather than creating a `Dependency` object for a specific service it is usually easier
> to just create a `Dependency` template and using the `dependencies` attribute in the `Service`
> object to associate these templates with a service.
> to just create a `Dependency` template and use the `apply` keyword to assign the
> dependency to a number of services.
Example:
@ -327,7 +310,9 @@ when notifications should be sent out.
Example:
object TimePeriod "24x7" inherits "legacy-timeperiod" {
object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod",
ranges = {
"monday" = "00:00-24:00",
@ -345,7 +330,7 @@ Attributes:
Name |Description
----------------|----------------
display_name |**Optional.** A short description of the time period.
methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should just inherit from the "legacy-timeperiod" template to take care of this setting.
methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should import the "legacy-timeperiod" template to take care of this setting.
ranges |**Required.** A dictionary containing information which days and durations apply to this timeperiod.
The `/etc/icinga2/conf.d/timeperiods.conf` file is usually used to define
@ -358,8 +343,8 @@ ScheduledDowntime objects can be used to set up recurring downtimes for services
> **Best Practice**
>
> Rather than creating a `ScheduledDowntime` object for a specific service it is usually easier
> to just create a `ScheduledDowntime` template and use the `scheduled_downtimes` attribute in the `Service`
> object to associate these templates with a service.
> to just create a `ScheduledDowntime` template and use the `apply` keyword to assign the
> scheduled downtime to a number of services.
Example:
@ -431,7 +416,9 @@ defined here.
Example:
object CheckCommand "check_snmp" inherits "plugin-check-command" {
object CheckCommand "check_snmp" {
import "plugin-check-command",
command = "$plugindir$/check_snmp -H $address$ -C $community$ -o $oid$",
macros = {
@ -444,7 +431,7 @@ Attributes:
Name |Description
----------------|----------------
methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should just inherit from the "plugin-check-command" template to take care of this setting.
methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should import the "plugin-check-command" template to take care of this setting.
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
@ -457,7 +444,9 @@ A notification command definition.
Example:
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
object NotificationCommand "mail-service-notification" {
import "plugin-notification-command",
command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
@ -480,7 +469,7 @@ Attributes:
Name |Description
----------------|----------------
methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should just inherit from the "plugin-notification-command" template to take care of this setting.
methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should import the "plugin-notification-command" template to take care of this setting.
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
@ -497,7 +486,9 @@ An event command definition.
Example:
object EventCommand "restart-httpd-event" inherits "plugin-event-command" {
object EventCommand "restart-httpd-event" {
import "plugin-event-command",
command = "/opt/bin/restart-httpd.sh",
}
@ -506,7 +497,7 @@ Attributes:
Name |Description
----------------|----------------
methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should just inherit from the "plugin-event-command" template to take care of this setting.
methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should import the "plugin-event-command" template to take care of this setting.
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.

View File

@ -3,9 +3,11 @@
### <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
you'll include them accordingly in the [icinga2.conf](#icinga2-conf) file.
you include them in the [icinga2.conf](#icinga2-conf) file.
By default, the `conf.d` directory is included recursively looking for files
which match the pattern `*.conf`.
By default, `conf.d` is included recursively looking for `*.conf` file endings.
If you're putting/generating your configuration structure in there, you do not
need to touch the [icinga2.conf](#icinga2-conf) file. This becomes useful with
external addons not having write permissions to this file such as LConf.
@ -41,7 +43,6 @@ your configuration directory tree and files:
vienna/
hosts.conf
If you're planning to create a [cluster](#cluster) setup with Icinga 2 and your
configuration master should deploy specific configuration parts to slave nodes,
it's reasonable not to confuse it with configuration below `conf.d`. Rather
@ -54,8 +55,6 @@ create a dedicated directory and put all nodes into their own directories:
node2/
node99/
If you are preferring to control what several parties drop into the configuration
pool (for example different departments with their own standalone configuration),
you can still deactivate the `conf.d` inclusion and use your own strategy.
@ -81,15 +80,16 @@ does not fit everyone, split it into two.
Or rather inherit that template into a new template, and override/disable
unwanted values.
template Service "generic-service-disable-notifications" inherits "generic-service" {
template Service "generic-service-disable-notifications" {
import "generic-service",
notifications["mail-icingaadmin"] = null
}
### <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
tool, using templates and inheriting their attributes in inline objects will
save you a lot of typing extra work.
tool, using templates and the `apply` keyword will save you a lot of typing extra work.
For instance, you can still create a host object, then a service object linking
to it, after that a notification object referencing the service object, and last
@ -145,20 +145,17 @@ By doing that everytime for such a series of linked objects, your configuration
will get bloated and unreadable. You've already read that [using templates](#best-practice-use-templates)
will help here.
The `Notification` and `ScheduledDowntime` templates will be referenced in the service template and
inline definition (both locations are possible).
The `Service` template is referenced within the inline service array for the `Host` template. In the end
the `Host` object inherits from the `Host` template named `linux-server`.
That way similar hosts may just inherit the host template and get all services, notifications, scheduled
downtimes through the template automatism.
Using the `apply` keyword you can create services, notifications, scheduled downtimes and dependencies
for an arbitrary number of hosts and services respectively:
template Notification "mail-notification" {
apply Notification "mail-notification" {
notification_command = "mail-service-notification",
users = [ "user1", "user2" ]
assign where "generic-service" in service.templates
}
template ScheduledDowntime "backup-downtime" {
apply ScheduledDowntime "backup-downtime" {
author = "icingaadmin",
comment = "Some comment",
@ -168,6 +165,8 @@ downtimes through the template automatism.
ranges = {
"sunday" = "02:00-03:00"
}
assign where "generic-service" in service.templates
}
template Service "generic-service" {
@ -175,35 +174,24 @@ downtimes through the template automatism.
check_interval = 5m,
retry_interval = 1m,
enable_perfdata = true,
}
notifications["mail"] = {
templates = [ "mail-notification" ]
}
apply Service "ping4" {
import "generic-service",
check_command = "ping4",
assign where "linux-server" in host.templates
}
template Host "linux-server" {
display_name = "The best host there is",
groups = [ "all-hosts" ],
host_dependencies = [ "router" ],
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4",
scheduled_downtimes["backup"] = {
templates = [ "backup-downtime" ]
}
},
check = "ping4"
}
object Host "localhost" inherits "linux-server" {
object Host "localhost" {
import "linux-server",
display_name = "The best host there is",
}

View File

@ -73,7 +73,7 @@ recurring downtimes for services.
Example:
template ScheduledDowntime "backup-downtime" {
apply ScheduledDowntime "backup-downtime" {
author = "icingaadmin",
comment = "Scheduled downtime for backup",
@ -86,17 +86,7 @@ Example:
saturday = "02:00-03:00",
sunday = "02:00-03:00"
}
assign where "backup" in service.groups
}
object Host "localhost" inherits "generic-host" {
...
services["load"] = {
templates = [ "generic-service" ],
check_command = "load",
scheduled_downtimes["backup"] = {
templates = [ "backup-downtime" ]
}
},
}

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

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
from the `icinga-node-dmz-1` endpoint.
object Host "dmz-host1" inherits "generic-host" {
object Host "dmz-host1" {
import "generic-host",
services["dmz-oracledb"] = {
templates = [ "generic-service" ],
domains = [ "dmz-db" ],
@ -28,4 +30,4 @@ from the `icinga-node-dmz-1` endpoint.
icinga-node-dmz-1 = DomainPrivReadOnly,
icinga-node-dmz-2 = DomainPrivReadWrite
}
}
}

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
defines a host dependency which acts implicit as parent relation too.
Furthermore the host may be reachable but ping samples are dropped by the
Furthermore the host may be reachable but ping probes are dropped by the
router's firewall. In case the `dsl-router``ping4` service check fails, all
further checks for the `google-dns` `ping4` service should be suppressed.
This is achieved by setting the `disable_checks` attribute to `true`.
further checks for the `ping4` service on host `google-dns` service should
be suppressed. This is achieved by setting the `disable_checks` attribute to `true`.
object Host "dsl-router" {
services["ping4"] = {
templates = "generic-service",
check_command = "ping4"
}
macros = {
address = "192.168.1.1",
},
macros.address = "192.168.1.1"
}
object Host "google-dns" {
services["ping4"] = {
templates = "generic-service",
check_command = "ping4",
dependencies["dsl-router-ping4"] = {
parent_host = "dsl-router",
parent_service = "ping4",
disable_checks = true
}
}
macros.address = "8.8.8.8",
}
macros = {
address = "8.8.8.8",
},
apply Service "ping4" {
import "generic-service",
dependencies["dsl-router"] = {
parent_host = "dsl-router"
},
check_command = "ping4"
}
assign where host.macros.address
}
apply Dependency "internet" {
parent_host = "dsl-router",
disable_checks = true
assign where host.name != "dsl-router"
}

View File

@ -123,15 +123,17 @@ uses the `template` identifier:
template Service "ping4-template" { }
Icinga 1.x objects inherit from templates using the `use` attribute.
Icinga 2 uses the keyword `inherits` after the object name and requires a
comma-separated list with template names in double quotes.
Icinga 2 uses the keyword `import` with template names in double quotes.
define service {
service_description testservice
use tmpl1,tmpl2,tmpl3
}
object Service "testservice" inherits "tmpl1", "tmpl2", "tmpl3" {
object Service "testservice" {
import "tmpl1",
import "tmpl2",
import "tmpl3"
}
## <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 define a service definition within a host definition.
The preferred way of associating hosts with services in Icinga 2 are services
defined inline to the host object (or template) definition. Icinga 2 will
implicitely create a new service object on configuration activation. These
inline service definitions can reference service templates.
Linking a service to a host is still possible with the 'host' attribute in
a service object in Icinga 2.
The preferred way of associating hosts with services in Icinga 2 is by
using the `apply` keyword.
## <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" {
groups += [ "dev-hosts" ],
services["http"] = {
check_command = [ "http-ip" ]
}
}
object Host "web-dev" inherits "dev-host" { }
object Host "web-dev" {
import "dev-host"
}
Host groups in Icinga 2 cannot be used to associate services with all members
of that group. The example above shows how to use templates to accomplish
the same effect.
In order to associate a service with all hosts in a host group the `apply`
keyword can be used:
apply Service "ping" {
import "generic-service",
check_command = "ping4",
assign where "group" in host.groups
}
## <a id="differences-1x-2-notifications"></a> Notifications

View File

@ -1,51 +1,44 @@
/**
* Provides default settings for hosts. By convention
* all hosts should inherit from this template.
* all hosts should import this template.
*/
template Host "generic-host" {
check = "ping4"
}
template Host "linux-server" inherits "generic-host" {
apply Service "ping4" {
import "generic-service",
check_command = "ping4",
assign where "generic-host" in host.templates
}
apply Service "ping6" {
import "generic-service",
check_command = "ping6",
assign where "generic-host" in host.templates,
ignore where !host.macros.address6
}
template Host "linux-server" {
import "generic-host",
groups += [ "linux-servers" ],
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
}
template Host "windows-server" inherits "generic-host" {
template Host "windows-server" {
import "generic-host",
groups += [ "windows-servers" ],
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
}
template Host "generic-printer" inherits "generic-host" {
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
template Host "generic-printer" {
import "generic-host",
}
template Host "generic-switch" inherits "generic-host" {
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
check = "ping4"
template Host "generic-switch" {
import "generic-host",
}

View File

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

View File

@ -4,19 +4,5 @@
*/
template User "generic-user" {
enable_notifications = true,
notification_period = "24x7",
notification_state_filter = StateFilterWarning |
StateFilterCritical |
StateFilterUnknown,
notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement |
NotificationFilterRecovery |
NotificationFilterCustom |
NotificationFilterFlappingStart |
NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd |
NotificationFilterDowntimeRemoved
}

View File

@ -3,71 +3,72 @@
* in the conf.d directory (e.g. one per host). By default all *.conf
* files in this directory are included.
*/
object Host "localhost" inherits "linux-server" {
display_name = "localhost",
object Host "localhost" {
import "linux-server",
services["icinga"] = {
templates = [ "generic-service" ],
check_command = "icinga"
},
services["ping4"] = {
templates = [ "generic-service" ],
check_command = "ping4"
},
services["ping6"] = {
templates = [ "generic-service" ],
check_command = "ping6"
},
services["http"] = {
templates = [ "generic-service" ],
check_command = "http_ip"
},
services["ssh"] = {
templates = [ "generic-service" ],
check_command = "ssh"
},
services["load"] = {
templates = [ "generic-service" ],
check_command = "load",
scheduled_downtimes["backup"] = {
templates = [ "backup-downtime" ]
}
},
services["processes"] = {
templates = [ "generic-service" ],
check_command = "processes"
},
services["users"] = {
templates = [ "generic-service" ],
check_command = "users"
},
services["disk"] = {
templates = [ "generic-service" ],
check_command = "disk"
},
macros = {
address = "127.0.0.1",
address6 = "::1",
},
check = "ping4",
macros.address = "127.0.0.1",
macros.address6 = "::1"
}
apply Service "icinga" {
import "generic-service",
check_command = "icinga",
assign where host.name == "localhost"
}
apply Service "http" {
import "generic-service",
check_command = "http_ip",
assign where host.name == "localhost"
}
apply Service "ssh" {
import "generic-service",
check_command = "ssh",
assign where host.name == "localhost"
}
apply Service "load" {
import "generic-service",
check_command = "load",
assign where host.name == "localhost"
}
apply ScheduledDowntime "backup-downtime" {
import "backup-downtime",
assign where service.host == "localhost" && service.short_name == "load"
}
apply Service "processes" {
import "generic-service",
check_command = "processes",
assign where host.name == "localhost"
}
apply Service "users" {
import "generic-service",
check_command = "users",
assign where host.name == "localhost"
}
apply Service "disk" {
import "generic-service",
check_command = "disk",
assign where host.name == "localhost"
}

View File

@ -22,7 +22,9 @@ template Notification "mail-notification" {
notification_period = "24x7"
}
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
object NotificationCommand "mail-service-notification" {
import "plugin-notification-command",
command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [

View File

@ -3,7 +3,9 @@
* 'legacy-timeperiod' template from the ITL.
*/
object TimePeriod "24x7" inherits "legacy-timeperiod" {
object TimePeriod "24x7" {
import "legacy-timeperiod",
display_name = "Icinga 2 24x7 TimePeriod",
ranges = {
"monday" = "00:00-24:00",
@ -16,7 +18,9 @@ object TimePeriod "24x7" inherits "legacy-timeperiod" {
}
}
object TimePeriod "9to5" inherits "legacy-timeperiod" {
object TimePeriod "9to5" {
import "legacy-timeperiod",
display_name = "Icinga 2 9to5 TimePeriod",
ranges = {
"monday" = "09:00-17:00",
@ -27,7 +31,9 @@ object TimePeriod "9to5" inherits "legacy-timeperiod" {
}
}
object TimePeriod "never" inherits "legacy-timeperiod" {
object TimePeriod "never" {
import "legacy-timeperiod",
display_name = "Icinga 2 never TimePeriod",
ranges = {
}

View File

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

View File

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

View File

@ -17,7 +17,9 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
object CheckCommand "ping4" inherits "plugin-check-command" {
object CheckCommand "ping4" {
import "plugin-check-command",
command = [
"$plugindir$/check_ping",
"-4",
@ -40,7 +42,9 @@ object CheckCommand "ping4" inherits "plugin-check-command" {
}
}
object CheckCommand "ping6" inherits "plugin-check-command" {
object CheckCommand "ping6" {
import "plugin-check-command",
command = [
"$plugindir$/check_ping",
"-6",
@ -63,7 +67,9 @@ object CheckCommand "ping6" inherits "plugin-check-command" {
}
}
object CheckCommand "dummy" inherits "plugin-check-command" {
object CheckCommand "dummy" {
import "plugin-check-command",
command = [
"$plugindir$/check_dummy",
"$state$",
@ -76,14 +82,18 @@ object CheckCommand "dummy" inherits "plugin-check-command" {
}
}
object CheckCommand "passive" inherits "dummy" {
object CheckCommand "passive" {
import "dummy",
macros = {
state = 3,
text = "No Passive Check Result Received."
}
}
object CheckCommand "tcp" inherits "plugin-check-command" {
object CheckCommand "tcp" {
import "plugin-check-command",
command = [
"$plugindir$/check_tcp",
"-H", "$address$",
@ -91,7 +101,9 @@ object CheckCommand "tcp" inherits "plugin-check-command" {
]
}
object CheckCommand "udp" inherits "plugin-check-command" {
object CheckCommand "udp" {
import "plugin-check-command",
command = [
"$plugindir$/check_udp",
"-H", "$address$",
@ -99,42 +111,54 @@ object CheckCommand "udp" inherits "plugin-check-command" {
]
}
object CheckCommand "http_vhost" inherits "plugin-check-command" {
object CheckCommand "http_vhost" {
import "plugin-check-command",
command = [
"$plugindir$/check_http",
"-H", "$vhost$"
]
}
object CheckCommand "http_ip" inherits "plugin-check-command" {
object CheckCommand "http_ip" {
import "plugin-check-command",
command = [
"$plugindir$/check_http",
"-H", "$address$"
]
}
object CheckCommand "https_vhost" inherits "plugin-check-command" {
object CheckCommand "https_vhost" {
import "plugin-check-command",
command = [
"$plugindir$/check_http",
"-H", "$vhost$", "-S"
]
}
object CheckCommand "https_ip" inherits "plugin-check-command" {
object CheckCommand "https_ip" {
import "plugin-check-command",
command = [
"$plugindir$/check_http",
"-I", "$address$", "-S"
]
}
object CheckCommand "smtp" inherits "plugin-check-command" {
object CheckCommand "smtp" {
import "plugin-check-command",
command = [
"$plugindir$/check_smtp",
"-H", "$address$"
]
}
object CheckCommand "ssmtp" inherits "plugin-check-command" {
object CheckCommand "ssmtp" {
import "plugin-check-command",
command = [
"$plugindir$/check_ssmtp",
"-H", "$address$",
@ -146,21 +170,27 @@ object CheckCommand "ssmtp" inherits "plugin-check-command" {
}
}
object CheckCommand "ntp_time" inherits "plugin-check-command" {
object CheckCommand "ntp_time" {
import "plugin-check-command",
command = [
"$plugindir$/check_ntp_time",
"-H", "$address$"
]
}
object CheckCommand "ssh" inherits "plugin-check-command" {
object CheckCommand "ssh" {
import "plugin-check-command",
command = [
"$plugindir$/check_ssh",
"$address$"
]
}
object CheckCommand "disk" inherits "plugin-check-command" {
object CheckCommand "disk" {
import "plugin-check-command",
command = [
"$plugindir$/check_disk",
"-w", "$wfree$%",
@ -173,7 +203,9 @@ object CheckCommand "disk" inherits "plugin-check-command" {
}
}
object CheckCommand "users" inherits "plugin-check-command" {
object CheckCommand "users"{
import "plugin-check-command",
command = [
"$plugindir$/check_users",
"-w", "$wgreater$",
@ -186,7 +218,9 @@ object CheckCommand "users" inherits "plugin-check-command" {
}
}
object CheckCommand "processes" inherits "plugin-check-command" {
object CheckCommand "processes"{
import "plugin-check-command",
command = [
"$plugindir$/check_procs",
"-w", "$wgreater$",
@ -199,7 +233,9 @@ object CheckCommand "processes" inherits "plugin-check-command" {
}
}
object CheckCommand "load" inherits "plugin-check-command" {
object CheckCommand "load"{
import "plugin-check-command",
command = [
"$plugindir$/check_load",
"-w", "$wload1$,$wload5$,$wload15$",
@ -217,7 +253,9 @@ object CheckCommand "load" inherits "plugin-check-command" {
}
}
object CheckCommand "snmp" inherits "plugin-check-command" {
object CheckCommand "snmp"{
import "plugin-check-command",
command = [
"$plugindir$/check_snmp",
"-H", "$address$",
@ -230,19 +268,27 @@ object CheckCommand "snmp" inherits "plugin-check-command" {
}
}
object CheckCommand "snmp-uptime" inherits "snmp" {
object CheckCommand "snmp-uptime"{
import "snmp",
macros += {
oid = "1.3.6.1.2.1.1.3.0"
}
}
object CheckCommand "icinga" inherits "icinga-check-command" {
object CheckCommand "icinga"{
import "icinga-check-command",
}
object CheckCommand "cluster" inherits "cluster-check-command" {
object CheckCommand "cluster"{
import "cluster-check-command",
}
object CheckCommand "snmp-extend" inherits "plugin-check-command" {
object CheckCommand "snmp-extend"{
import "plugin-check-command",
command = [
IcingaSysconfDir + "/icinga2/scripts/snmp-extend.sh",
"$HOSTADDRESS$",

View File

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

View File

@ -61,19 +61,22 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace
if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (!stack)
stack = GetLastExceptionStack();
if (stack)
result << *stack;
else
result << *GetLastExceptionStack();
}
if (boost::get_error_info<ContextTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (!context)
context = GetLastExceptionContext();
if (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("__type", type->GetName());
fields->Set("type", type->GetName());
return fields;
}
@ -151,7 +151,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary
if (object)
type = object->GetReflectionType();
else
type = Type::GetByName(input->Get("__type"));
type = Type::GetByName(input->Get("type"));
if (!type)
return object;
@ -165,6 +165,7 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary
instance = type->Instantiate();
}
ObjectLock olock(input);
BOOST_FOREACH(const Dictionary::Pair& kv, input) {
if (kv.first.IsEmpty())
continue;
@ -230,7 +231,7 @@ Value icinga::Deserialize(const Object::Ptr& object, const Value& value, bool sa
ASSERT(dict != NULL);
if (!dict->Contains("__type"))
if (!dict->Contains("type"))
return DeserializeDictionary(dict, safe_mode, attributeTypes);
return DeserializeObject(object, dict, safe_mode, attributeTypes);

View File

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

View File

@ -43,13 +43,11 @@ public:
void Print(std::ostream& fp, int ignoreFrames = 0) const;
static void StaticInitialize(void);
private:
void *m_Frames[64];
int m_Count;
static boost::once_flag m_OnceFlag;
static void Initialize(void);
};
I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);

View File

@ -128,7 +128,28 @@ String Utility::GetSymbolName(const void *addr)
return dli.dli_sname;
#endif /* HAVE_DLADDR */
return "";
#ifdef _WIN32
char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 dwAddress = (DWORD64)addr;
DWORD64 dwDisplacement;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement, pSymbol)) {
char output[256];
if (UnDecorateSymbolName(pSymbol->Name, output, sizeof(output), UNDNAME_COMPLETE))
return String(output) + "+" + Convert::ToString(dwDisplacement);
else
return String(pSymbol->Name) + "+" + Convert::ToString(dwDisplacement);
}
#endif /* _WIN32 */
return "(unknown function)";
}
String Utility::GetSymbolSource(const void *addr)
@ -142,7 +163,23 @@ String Utility::GetSymbolSource(const void *addr)
}
#endif /* HAVE_DLADDR */
return "";
#ifdef _WIN32
char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 dwAddress = (DWORD64)addr;
DWORD dwDisplacement;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(GetCurrentProcess(), dwAddress, &dwDisplacement, &line))
return String(line.FileName) + ":" + Convert::ToString(line.LineNumber);
#endif /* _WIN32 */
return "(unknown file/line)";
}
/**

View File

@ -19,6 +19,7 @@
#include "config/aexpression.h"
#include "config/configerror.h"
#include "config/configitem.h"
#include "base/array.h"
#include "base/serializer.h"
#include "base/context.h"
@ -26,6 +27,8 @@
#include "base/scriptvariable.h"
#include "base/utility.h"
#include "base/objectlock.h"
#include "base/object.h"
#include "base/logger_fwd.h"
#include <boost/foreach.hpp>
#include <boost/exception_ptr.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
{
try {
#ifdef _DEBUG
if (m_Operator != &AExpression::OpLiteral) {
std::ostringstream msgbuf;
ShowCodeFragment(msgbuf, m_DebugInfo, false);
Log(LogDebug, "config", "Executing:\n" + msgbuf.str());
}
#endif /* _DEBUG */
return m_Operator(this, locals);
} catch (const std::exception& ex) {
if (boost::get_error_info<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)
{
if (m_Operator == &AExpression::OpDict)
@ -179,6 +130,11 @@ Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& loca
return ~(long)expr->EvaluateOperand1(locals);
}
Value AExpression::OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals)
{
return !expr->EvaluateOperand1(locals).ToBool();
}
Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals)
{
return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals);
@ -253,7 +209,9 @@ Value AExpression::OpIn(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value right = expr->EvaluateOperand2(locals);
if (!right.IsObjectType<Array>())
if (right.IsEmpty())
return false;
else if (!right.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
Value left = expr->EvaluateOperand1(locals);
@ -341,14 +299,16 @@ Value AExpression::OpDict(const AExpression *expr, const Dictionary::Ptr& locals
Value AExpression::OpSet(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value index = expr->EvaluateOperand1(locals);
Value right = expr->EvaluateOperand2(locals);
locals->Set(expr->m_Operand1, right);
locals->Set(index, right);
return right;
}
Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value left = locals->Get(expr->m_Operand1);
Value index = expr->EvaluateOperand1(locals);
Value left = locals->Get(index);
AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals;
@ -368,13 +328,14 @@ Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& loc
dict->Remove("__parent");
}
locals->Set(expr->m_Operand1, result);
locals->Set(index, result);
return result;
}
Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value left = locals->Get(expr->m_Operand1);
Value index = expr->EvaluateOperand1(locals);
Value left = locals->Get(index);
AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals;
@ -394,13 +355,14 @@ Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& lo
dict->Remove("__parent");
}
locals->Set(expr->m_Operand1, result);
locals->Set(index, result);
return result;
}
Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value left = locals->Get(expr->m_Operand1);
Value index = expr->EvaluateOperand1(locals);
Value left = locals->Get(index);
AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals;
@ -420,13 +382,14 @@ Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr&
dict->Remove("__parent");
}
locals->Set(expr->m_Operand1, result);
locals->Set(index, result);
return result;
}
Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value left = locals->Get(expr->m_Operand1);
Value index = expr->EvaluateOperand1(locals);
Value left = locals->Get(index);
AExpression::Ptr exp_right = expr->m_Operand2;
Dictionary::Ptr xlocals = locals;
@ -446,16 +409,49 @@ Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& l
dict->Remove("__parent");
}
locals->Set(expr->m_Operand1, result);
locals->Set(index, result);
return result;
}
Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals)
{
Dictionary::Ptr dict = OpVariable(expr, locals);
if (!dict)
BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope."));
return dict->Get(expr->m_Operand2);
Value value = expr->EvaluateOperand1(locals);
Value index = expr->EvaluateOperand2(locals);
if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value;
return dict->Get(index);
} else if (value.IsObjectType<Object>()) {
Object::Ptr object = value;
const Type *type = object->GetReflectionType();
if (!type)
BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection"));
int field = type->GetFieldId(index);
if (field == -1)
BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'"));
return object->GetField(field);
} else if (value.IsEmpty()) {
return Empty;
} else {
BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'"));
}
}
Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals)
{
Value type = expr->EvaluateOperand1(locals);
Value name = expr->EvaluateOperand2(locals);
ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
if (!item)
BOOST_THROW_EXCEPTION(ConfigError("Import references unknown template: '" + name + "'"));
item->GetExpressionList()->Evaluate(locals);
return Empty;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,15 +44,13 @@ ConfigItem::ItemMap ConfigItem::m_Items;
* @param unit The unit of the item.
* @param abstract Whether the item is a template.
* @param exprl Expression list for the item.
* @param parents Parent objects for the item.
* @param debuginfo Debug information.
*/
ConfigItem::ConfigItem(const String& type, const String& name,
bool abstract, const AExpression::Ptr& exprl,
const std::vector<String>& parents, const DebugInfo& debuginfo,
const Dictionary::Ptr& scope)
const DebugInfo& debuginfo, const Dictionary::Ptr& scope)
: m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false),
m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo),
m_ExpressionList(exprl), m_DebugInfo(debuginfo),
m_Scope(scope)
{
}
@ -112,53 +110,19 @@ AExpression::Ptr ConfigItem::GetExpressionList(void) const
return m_ExpressionList;
}
AExpression::Ptr ConfigItem::GetLinkedExpressionList(void)
{
ASSERT(OwnsLock());
if (m_LinkedExpressionList)
return m_LinkedExpressionList;
Array::Ptr subexprs = make_shared<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)
{
ASSERT(OwnsLock());
if (!m_Properties) {
m_Properties = make_shared<Dictionary>();
m_Properties->Set("type", m_Type);
m_Properties->Set("name", m_Name);
m_Properties->Set("__parent", m_Scope);
GetLinkedExpressionList()->Evaluate(m_Properties);
GetExpressionList()->Evaluate(m_Properties);
m_Properties->Remove("__parent");
VERIFY(m_Properties->Get("__type") == GetType() && m_Properties->Get("__name") == GetName());
VERIFY(m_Properties->Get("type") == GetType() && m_Properties->Get("name") == GetName());
}
return m_Properties;

View File

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

View File

@ -60,11 +60,6 @@ void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope)
m_Scope = scope;
}
void ConfigItemBuilder::AddParent(const String& parent)
{
m_Parents.push_back(parent);
}
void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr)
{
m_Expressions->Add(expr);
@ -90,18 +85,19 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
}
BOOST_FOREACH(const String& parent, m_Parents) {
if (parent == m_Name)
BOOST_THROW_EXCEPTION(std::invalid_argument("Configuration item '" + m_Name + "' of type '" + m_Type + "' must not inherit from itself."));
}
Array::Ptr exprs = make_shared<Array>();
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__type", make_shared<AExpression>(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo));
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__name", make_shared<AExpression>(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo));
Array::Ptr templateArray = make_shared<Array>();
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));
AExpression::Ptr exprl = make_shared<AExpression>(&AExpression::OpDict, exprs, true, m_DebugInfo);
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 SetScope(const Dictionary::Ptr& scope);
void AddParent(const String& parent);
void AddExpression(const AExpression::Ptr& expr);
ConfigItem::Ptr Compile(void);
@ -57,8 +55,6 @@ private:
String m_Type; /**< The object type. */
String m_Name; /**< The name. */
bool m_Abstract; /**< Whether the item is abstract. */
std::vector<String> m_Parents; /**< The names of parent configuration
items. */
Array::Ptr m_Expressions; /**< Expressions for this item. */
DebugInfo m_DebugInfo; /**< Debug information. */
Dictionary::Ptr m_Scope; /**< variable scope. */

View File

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

View File

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

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 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. *
******************************************************************************/
type DbConnection {
%attribute string "table_prefix",
%type DbConnection {
%attribute %string "table_prefix",
%attribute dictionary "cleanup" {
%attribute number "acknowledgements_age",
%attribute number "commenthistory_age",
%attribute number "contactnotifications_age",
%attribute number "contactnotificationmethods_age",
%attribute number "downtimehistory_age",
%attribute number "eventhandlers_age",
%attribute number "externalcommands_age",
%attribute number "flappinghistory_age",
%attribute number "hostchecks_age",
%attribute number "logentries_age",
%attribute number "notifications_age",
%attribute number "processevents_age",
%attribute number "statehistory_age",
%attribute number "servicechecks_age",
%attribute number "systemcommands_age",
%attribute %dictionary "cleanup" {
%attribute %number "acknowledgements_age",
%attribute %number "commenthistory_age",
%attribute %number "contactnotifications_age",
%attribute %number "contactnotificationmethods_age",
%attribute %number "downtimehistory_age",
%attribute %number "eventhandlers_age",
%attribute %number "externalcommands_age",
%attribute %number "flappinghistory_age",
%attribute %number "hostchecks_age",
%attribute %number "logentries_age",
%attribute %number "notifications_age",
%attribute %number "processevents_age",
%attribute %number "statehistory_age",
%attribute %number "servicechecks_age",
%attribute %number "systemcommands_age",
},
%attribute number "categories"
%attribute %number "categories"
}

View File

@ -17,5 +17,5 @@
* 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
api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th
domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
externalcommandprocessor.cpp host.cpp host.th host-apply.cpp hostgroup.cpp hostgroup.th
dependency-apply.cpp domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th
icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
icingastatuswriter.th legacytimeperiod.cpp
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th
notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th
pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-check.cpp
service-comment.cpp service.cpp service-dependency.cpp service-downtime.cpp service-event.cpp
service-flapping.cpp service.th servicegroup.cpp servicegroup.th
notification.cpp notification.th notification-apply.cpp perfdatavalue.cpp perfdatavalue.th
pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th scheduleddowntime-apply.cpp
service-apply.cpp service-check.cpp service-comment.cpp service.cpp service-dependency.cpp
service-downtime.cpp service-event.cpp service-flapping.cpp service.th servicegroup.cpp servicegroup.th
service-notification.cpp timeperiod.cpp timeperiod.th user.cpp user.th
usergroup.cpp usergroup.th icinga-type.cpp
)

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

View File

@ -57,8 +57,6 @@ void Host::OnConfigLoaded(void)
hg->AddMember(GetSelf());
}
}
UpdateSlaveServices();
}
void Host::Stop(void)
@ -92,78 +90,6 @@ bool Host::IsReachable(DependencyType dt, shared_ptr<Dependency> *failedDependen
return hc->IsReachable(dt, failedDependency);
}
void Host::UpdateSlaveServices(void)
{
ASSERT(!OwnsLock());
Dictionary::Ptr service_descriptions = GetServiceDescriptions();
if (!service_descriptions ||service_descriptions->GetLength() == 0)
return;
ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
ObjectLock olock(service_descriptions);
BOOST_FOREACH(const Dictionary::Pair& kv, service_descriptions) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<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
{
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;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected:
virtual void Stop(void);
@ -114,8 +111,6 @@ private:
mutable boost::mutex m_ServicesMutex;
std::map<String, shared_ptr<Service> > m_Services;
void UpdateSlaveServices(void);
static void RefreshServicesCache(void);
};

View File

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

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/usergroup.h"
#include "icinga/timeperiod.h"
#include "config/applyrule.h"
#include "base/array.h"
namespace icinga
@ -86,6 +87,9 @@ public:
static boost::signals2::signal<void (const Notification::Ptr&, double, const String&)> OnNextNotificationChanged;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected:
virtual void Start(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/scheduleddowntime.th"
#include "icinga/service.h"
#include "config/applyrule.h"
#include <utility>
namespace icinga
@ -43,6 +44,9 @@ public:
Service::Ptr GetService(void) const;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected:
virtual void Start(void);

View File

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

View File

@ -154,89 +154,3 @@ std::set<Service::Ptr> Service::GetChildServices(void) const
return parents;
}
void Service::UpdateSlaveDependencies(void)
{
/*
* pass == 0 -> steal host's dependency definitions
* pass == 1 -> service's dependencies
*/
for (int pass = 0; pass < 2; pass++) {
/* Service dependency descs */
Dictionary::Ptr descs;
if (pass == 0 && !IsHostCheck())
continue;
if (pass == 0)
descs = GetHost()->GetDependencyDescriptions();
else
descs = GetDependencyDescriptions();
if (!descs || descs->GetLength() == 0)
continue;
ConfigItem::Ptr item;
if (pass == 0)
item = ConfigItem::GetObject("Host", GetHost()->GetName());
else
item = ConfigItem::GetObject("Service", GetName());
ObjectLock olock(descs);
BOOST_FOREACH(const Dictionary::Pair& kv, descs) {
std::ostringstream namebuf;
namebuf << GetName() << "!" << kv.first;
String name = namebuf.str();
std::vector<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;
}
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);
}
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
{
if (!GetOverrideEnableNotifications().IsEmpty())

View File

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

View File

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

View File

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

View File

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

View File

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