]> granicus.if.org Git - icinga2/commitdiff
Implement attributes for some well-known macros and allow macro recursion.
authorGunnar Beutner <gunnar.beutner@netways.de>
Tue, 8 Apr 2014 11:23:24 +0000 (13:23 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 8 Apr 2014 11:23:24 +0000 (13:23 +0200)
Refs #5856
Fixes #5959

22 files changed:
components/livestatus/hoststable.cpp
components/livestatus/servicestable.cpp
components/perfdata/perfdatawriter.cpp
components/perfdata/perfdatawriter.ti
doc/3.03-custom-attributes-runtime-macros.md
etc/icinga2/conf.d/localhost.conf
lib/icinga/checkable.ti
lib/icinga/host.cpp
lib/icinga/host.ti
lib/icinga/icinga-type.conf
lib/icinga/icingaapplication.cpp
lib/icinga/macroprocessor.cpp
lib/icinga/macroprocessor.h
lib/icinga/macroresolver.cpp
lib/icinga/macroresolver.h
lib/icinga/service.cpp
lib/icinga/user.cpp
lib/icinga/user.h
lib/icinga/user.ti
lib/methods/pluginchecktask.cpp
lib/methods/plugineventtask.cpp
lib/methods/pluginnotificationtask.cpp

index bc1ffe5492ac7c96956077a74c5a009a9ece08e8..0fc7ff2da2203659f8a2bac3a2c581e4c7ec2e62 100644 (file)
@@ -295,10 +295,9 @@ Value HostsTable::NotesExpandedAccessor(const Value& row)
        if (!host)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-
-       resolvers.push_back(host);
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(host, "notes");
 
@@ -322,10 +321,9 @@ Value HostsTable::NotesUrlExpandedAccessor(const Value& row)
        if (!host)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-
-       resolvers.push_back(host);
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(host, "notes_url");
 
@@ -349,10 +347,9 @@ Value HostsTable::ActionUrlExpandedAccessor(const Value& row)
        if (!host)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-
-       resolvers.push_back(host);
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(host, "action_url");
 
@@ -399,10 +396,9 @@ Value HostsTable::IconImageExpandedAccessor(const Value& row)
        if (!host)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-
-       resolvers.push_back(host);
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(host, "icon_image");
 
index 429b640d16014fd5ed73e5715a51f221c820973d..b521287d286904daf94ccf70b2763b8f8fda2887 100644 (file)
@@ -310,10 +310,10 @@ Value ServicesTable::NotesExpandedAccessor(const Value& row)
        if (!service)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-       resolvers.push_back(service);
-       resolvers.push_back(service->GetHost());
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", service->GetHost()));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(service, "notes");
 
@@ -337,10 +337,10 @@ Value ServicesTable::NotesUrlExpandedAccessor(const Value& row)
        if (!service)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-       resolvers.push_back(service);
-       resolvers.push_back(service->GetHost());
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", service->GetHost()));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(service, "notes_url");
 
@@ -364,10 +364,10 @@ Value ServicesTable::ActionUrlExpandedAccessor(const Value& row)
        if (!service)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-       resolvers.push_back(service);
-       resolvers.push_back(service->GetHost());
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", service->GetHost()));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(service, "action_url");
 
@@ -391,10 +391,10 @@ Value ServicesTable::IconImageExpandedAccessor(const Value& row)
        if (!service)
                return Empty;
 
-       std::vector<MacroResolver::Ptr> resolvers;
-       resolvers.push_back(service);
-       resolvers.push_back(service->GetHost());
-       resolvers.push_back(IcingaApplication::GetInstance());
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", service->GetHost()));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value value = CompatUtility::GetCustomAttributeConfig(service, "icon_image");
 
index 8cd227a19f18729974faeb9b0c7ccca8c5e0c173..8cdb2c36b3c9ac244f668b23bc397b0001036e08 100644 (file)
@@ -79,11 +79,11 @@ void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const C
        else
                host = static_pointer_cast<Host>(checkable);
 
-       std::vector<MacroResolver::Ptr> resolvers;
+       MacroProcessor::ResolverList resolvers;
        if (service)
-               resolvers.push_back(service);
-       resolvers.push_back(host);
-       resolvers.push_back(IcingaApplication::GetInstance());
+               resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        if (service) {
                String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr);
index dca86e492b4f3e297a3c65a563761fc2bc6a8e57..95f9cfc39934480145827b849b541dac4194c900 100644 (file)
@@ -24,9 +24,9 @@ class PerfdataWriter : DynamicObject
                            "TIMET::$icinga.timet$\t"
                            "HOSTNAME::$host.name$\t"
                            "HOSTPERFDATA::$host.perfdata$\t"
-                           "HOSTCHECKCOMMAND::$host.checkcommand$\t"
+                           "HOSTCHECKCOMMAND::$host.check_command$\t"
                            "HOSTSTATE::$host.state$\t"
-                           "HOSTSTATETYPE::$host.statetype$";
+                           "HOSTSTATETYPE::$host.state_type$";
                }}}
        };
        [config] String service_format_template {
@@ -34,13 +34,13 @@ class PerfdataWriter : DynamicObject
                        return "DATATYPE::SERVICEPERFDATA\t"
                            "TIMET::$icinga.timet$\t"
                            "HOSTNAME::$host.name$\t"
-                           "SERVICEDESC::$service.description$\t"
+                           "SERVICEDESC::$service.name$\t"
                            "SERVICEPERFDATA::$service.perfdata$\t"
-                           "SERVICECHECKCOMMAND::$service.checkcommand$\t"
+                           "SERVICECHECKCOMMAND::$service.check_command$\t"
                            "HOSTSTATE::$host.state$\t"
-                           "HOSTSTATETYPE::$host.statetype$\t"
+                           "HOSTSTATETYPE::$host.state_type$\t"
                            "SERVICESTATE::$service.state$\t"
-                           "SERVICESTATETYPE::$service.statetype$";
+                           "SERVICESTATETYPE::$service.state_type$";
                }}}
        };
 
index 02bfc13389c572af4542804a518d693db7e9a91a..c60b6c5bd204b0edcbdd04bca240cad03f3b5713 100644 (file)
@@ -119,56 +119,64 @@ external commands).
 The following host custom attributes are available in all commands that are executed for
 hosts or services:
 
-  Name                       | Description
-  ---------------------------|--------------
-  host.name                  | The name of the host object.
-  host.displayname           | The value of the `display_name` attribute.
-  host.state                 | The host's current state. Can be one of `UNREACHABLE`, `UP` and `DOWN`.
-  host.stateid               | The host's current state. Can be one of `0` (up), `1` (down) and `2` (unreachable).
-  host.statetype             | The host's current state type. Can be one of `SOFT` and `HARD`.
-  host.attempt               | The current check attempt number.
-  host.maxattempt            | The maximum number of checks which are executed before changing to a hard state.
-  host.laststate             | The host's previous state. Can be one of `UNREACHABLE`, `UP` and `DOWN`.
-  host.laststateid           | The host's previous state. Can be one of `0` (up), `1` (down) and `2` (unreachable).
-  host.laststatetype         | The host's previous state type. Can be one of `SOFT` and `HARD`.
-  host.laststatechange       | The last state change's timestamp.
-  host.durationsec           | The time since the last state change.
-  host.latency               | The host's check latency.
-  host.executiontime         | The host's check execution time.
-  host.output                | The last check's output.
-  host.perfdata              | The last check's performance data.
-  host.lastcheck             | The timestamp when the last check was executed.
-  host.totalservices         | Number of services associated with the host.
-  host.totalservicesok       | Number of services associated with the host which are in an `OK` state.
-  host.totalserviceswarning  | Number of services associated with the host which are in a `WARNING` state.
-  host.totalservicesunknown  | Number of services associated with the host which are in an `UNKNOWN` state.
-  host.totalservicescritical | Number of services associated with the host which are in a `CRITICAL` state.
+  Name                         | Description
+  -----------------------------|--------------
+  host.name                    | The name of the host object.
+  host.display_name            | The value of the `display_name` attribute.
+  host.state                   | The host's current state. Can be one of `UNREACHABLE`, `UP` and `DOWN`.
+  host.stateid                 | The host's current state. Can be one of `0` (up), `1` (down) and `2` (unreachable).
+  host.statetype               | The host's current state type. Can be one of `SOFT` and `HARD`.
+  host.check_attempt           | The current check attempt number.
+  host.max_check_attempts      | The maximum number of checks which are executed before changing to a hard state.
+  host.last_state              | The host's previous state. Can be one of `UNREACHABLE`, `UP` and `DOWN`.
+  host.last_state_id           | The host's previous state. Can be one of `0` (up), `1` (down) and `2` (unreachable).
+  host.last_state_type         | The host's previous state type. Can be one of `SOFT` and `HARD`.
+  host.last_state_change       | The last state change's timestamp.
+  host.duration_sec            | The time since the last state change.
+  host.latency                 | The host's check latency.
+  host.execution_time          | The host's check execution time.
+  host.output                  | The last check's output.
+  host.perfdata                | The last check's performance data.
+  host.last_check              | The timestamp when the last check was executed.
+  host.total_services          | Number of services associated with the host.
+  host.total_services_ok       | Number of services associated with the host which are in an `OK` state.
+  host.total_services_warning  | Number of services associated with the host which are in a `WARNING` state.
+  host.total_services_unknown  | Number of services associated with the host which are in an `UNKNOWN` state.
+  host.total_services_critical | Number of services associated with the host which are in a `CRITICAL` state.
 
 ### <a id="service-runtime-macros"></a> Service Runtime Macros
 
 The following service macros are available in all commands that are executed for
 services:
 
-  Name                    | Description
-  ------------------------|--------------
-  service.description     | The short name of the service object.
-  service.displayname     | The value of the `display_name` attribute.
-  service.checkcommand    | This is an alias for the `SERVICEDISPLAYNAME` macro.
-  service.state           | The service's current state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`.
-  service.stateid         | The service's current state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown).
-  service.statetype       | The service's current state type. Can be one of `SOFT` and `HARD`.
-  service.attempt         | The current check attempt number.
-  service.maxattempt      | The maximum number of checks which are executed before changing to a hard state.
-  service.laststate       | The service's previous state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`.
-  service.laststateid     | The service's previous state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown).
-  service.laststatetype   | The service's previous state type. Can be one of `SOFT` and `HARD`.
-  service.laststatechange | The last state change's timestamp.
-  service.durationsec     | The time since the last state change.
-  service.latency         | The service's check latency.
-  service.executiontime   | The service's check execution time.
-  service.output          | The last check's output.
-  service.perfdata        | The last check's performance data.
-  service.lastcheck       | The timestamp when the last check was executed.
+  Name                       | Description
+  ---------------------------|--------------
+  service.name               | The short name of the service object.
+  service.display_name       | The value of the `display_name` attribute.
+  service.check_command      | This is an alias for the `SERVICEDISPLAYNAME` macro.
+  service.state              | The service's current state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`.
+  service.state_id           | The service's current state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown).
+  service.state_type         | The service's current state type. Can be one of `SOFT` and `HARD`.
+  service.check_attempt      | The current check attempt number.
+  service.max_check_attempts | The maximum number of checks which are executed before changing to a hard state.
+  service.last_state         | The service's previous state. Can be one of `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`.
+  service.last_state_id      | The service's previous state. Can be one of `0` (ok), `1` (warning), `2` (critical) and `3` (unknown).
+  service.last_state_type    | The service's previous state type. Can be one of `SOFT` and `HARD`.
+  service.last_state_change  | The last state change's timestamp.
+  service.duration_sec       | The time since the last state change.
+  service.latency            | The service's check latency.
+  service.execution_time     | The service's check execution time.
+  service.output             | The last check's output.
+  service.perfdata           | The last check's performance data.
+  service.last_check         | The timestamp when the last check was executed.
+
+### <a id="command-runtime-macros"></a> Command Runtime Macros
+
+The following custom attributes are available in all commands:
+
+  Name                   | Description
+  -----------------------|--------------
+  command.name           | The name of the command object.
 
 ### <a id="user-runtime-macros"></a> User Runtime Macros
 
@@ -178,8 +186,7 @@ users:
   Name                   | Description
   -----------------------|--------------
   user.name              | The name of the user object.
-  user.displayname       | The value of the display_name attribute.
-
+  user.display_name      | The value of the display_name attribute.
 
 ### <a id="notification-runtime-macros"></a> Notification Runtime Macros
 
@@ -196,7 +203,7 @@ The following macros are available in all executed commands:
   Name                   | Description
   -----------------------|--------------
   icinga.timet           | Current UNIX timestamp.
-  icinga.longdatetime    | Current date and time including timezone information. Example: `2014-01-03 11:23:08 +0000`
-  icinga.shortdatetime   | Current date and time. Example: `2014-01-03 11:23:08`
+  icinga.long_date_time  | Current date and time including timezone information. Example: `2014-01-03 11:23:08 +0000`
+  icinga.short_date_time | Current date and time. Example: `2014-01-03 11:23:08`
   icinga.date            | Current date. Example: `2014-01-03`
   icinga.time            | Current time including timezone information. Example: `11:23:08 +0000`
index 7c80e6929e7face51434bf6098e10cf1b78b4fb2..f4b2083476f2d0780214dee81c9bdc2b7d6f5730 100644 (file)
@@ -6,8 +6,8 @@
 object Host "localhost" {
   import "linux-server"
 
-  vars.address = "127.0.0.1"
-  vars.address6 = "::1"
+  address = "127.0.0.1"
+  address6 = "::1"
 }
 
 object Service "icinga" {
index 9f5493cf7df3f17de3b6ae039a11d5e2592b702e..dd2fade3900883edd4b997a8701e39f2e28350ff 100644 (file)
@@ -56,6 +56,12 @@ abstract class Checkable : DynamicObject
                default {{{ return true; }}}
        };
 
+       [config] String notes;
+       [config] String notes_url;
+       [config] String action_url;
+       [config] String icon_image;
+       [config] String icon_image_alt;
+
        [state] double next_check (NextCheckRaw);
        [state] int check_attempt {
                default {{{ return 1; }}}
index 32c6b775e2ce11801043bbb66eab52d11539ff4b..aaf427d9501f7ad317705dbcaabf89897751cd72 100644 (file)
@@ -221,154 +221,72 @@ String Host::StateTypeToString(StateType type)
 
 bool Host::ResolveMacro(const String& macro, const CheckResult::Ptr&, String *result) const
 {
-       String key;
-       Dictionary::Ptr vars;
-
-       /* special treatment for address macros providing name fallback */
-       if (macro == "address" || macro == "address6") {
-               vars = GetVars();
-
-               String value;
-               if (vars && vars->Contains(macro))
-                       value = vars->Get(macro);
-
-               if (value.IsEmpty()) {
-                       *result = GetName();
-                       return true;
-               } else {
-                       *result = value;
-                       return true;
-               }
-       }
-       else if (macro == "host.vars.address" || macro == "host.vars.address6") {
-               key = macro.SubStr(10);
-               vars = GetVars();
-
-               String value;
-               if (vars && vars->Contains(key))
-                       value = vars->Get(key);
+       if (macro == "state") {
+               *result = StateToString(GetState());
+               return true;
+       } else if (macro == "state_id") {
+               *result = Convert::ToString(GetState());
+               return true;
+       } else if (macro == "state_type") {
+               *result = StateTypeToString(GetStateType());
+               return true;
+       } else if (macro == "last_state") {
+               *result = StateToString(GetLastState());
+               return true;
+       } else if (macro == "last_state_id") {
+               *result = Convert::ToString(GetLastState());
+               return true;
+       } else if (macro == "last_state_type") {
+               *result = StateTypeToString(GetLastStateType());
+               return true;
+       } else if (macro == "last_state_change") {
+               *result = Convert::ToString((long)GetLastStateChange());
+               return true;
+       } else if (macro == "duration_sec") {
+               *result = Convert::ToString((long)(Utility::GetTime() - GetLastStateChange()));
+               return true;
+       } else if (macro == "total_services" || macro == "total_services_ok" || macro == "total_services_warning"
+                   || macro == "total_services_unknown" || macro == "total_services_critical") {
+                       int filter = -1;
+                       int count = 0;
+
+                       if (macro == "total_services_ok")
+                               filter = ServiceOK;
+                       else if (macro == "total_services_warning")
+                               filter = ServiceWarning;
+                       else if (macro == "total_services_unknown")
+                               filter = ServiceUnknown;
+                       else if (macro == "total_services_critical")
+                               filter = ServiceCritical;
+
+                       BOOST_FOREACH(const Service::Ptr& service, GetServices()) {
+                               if (filter != -1 && service->GetState() != filter)
+                                       continue;
+
+                               count++;
+                       }
 
-               if (value.IsEmpty()) {
-                       *result = GetName();
+                       *result = Convert::ToString(count);
                        return true;
-               } else {
-                       *result = value;
-                       return true;
-               }
        }
 
-       /* require prefix for object macros */
-       if (macro.SubStr(0, 5) == "host.") {
-               key = macro.SubStr(5);
-
-               if (key.SubStr(0, 5) == "vars.") {
-                       vars = GetVars();
-                       String vars_key = key.SubStr(5);
-
-                       if (vars && vars->Contains(vars_key)) {
-                               *result = vars->Get(vars_key);
-                               return true;
-                       }
-               }
-               else if (key == "name") {
-                       *result = GetName();
-                       return true;
-               }
-               else if (key == "displaymane") {
-                       *result = GetDisplayName();
-                       return true;
-               }
-
-               CheckResult::Ptr cr = GetLastCheckResult();
+       CheckResult::Ptr cr = GetLastCheckResult();
 
-               if (key == "state") {
-                       *result = StateToString(GetState());
-                       return true;
-               } else if (key == "stateid") {
-                       *result = Convert::ToString(GetState());
-                       return true;
-               } else if (key == "statetype") {
-                       *result = StateTypeToString(GetStateType());
-                       return true;
-               } else if (key == "attempt") {
-                       *result = Convert::ToString(GetCheckAttempt());
-                       return true;
-               } else if (key == "maxattempt") {
-                       *result = Convert::ToString(GetMaxCheckAttempts());
-                       return true;
-               } else if (key == "laststate") {
-                       *result = StateToString(GetLastState());
-                       return true;
-               } else if (key == "laststateid") {
-                       *result = Convert::ToString(GetLastState());
-                       return true;
-               } else if (key == "laststatetype") {
-                       *result = StateTypeToString(GetLastStateType());
+       if (cr) {
+               if (macro == "latency") {
+                       *result = Convert::ToString(Service::CalculateLatency(cr));
                        return true;
-               } else if (key == "laststatechange") {
-                       *result = Convert::ToString((long)GetLastStateChange());
+               } else if (macro == "execution_time") {
+                       *result = Convert::ToString(Service::CalculateExecutionTime(cr));
                        return true;
-               } else if (key == "durationsec") {
-                       *result = Convert::ToString((long)(Utility::GetTime() - GetLastStateChange()));
+               } else if (macro == "output") {
+                       *result = cr->GetOutput();
                        return true;
-               } else if (key == "checkcommand") {
-                       CheckCommand::Ptr commandObj = GetCheckCommand();
-
-                       if (commandObj)
-                               *result = commandObj->GetName();
-                       else
-                               *result = "";
-
+               } else if (macro == "perfdata") {
+                       *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData());
                        return true;
-               } else if (key == "totalservices" || key == "totalservicesok" || key == "totalserviceswarning"
-                           || key == "totalservicesunknown" || key == "totalservicescritical") {
-                               int filter = -1;
-                               int count = 0;
-
-                               if (key == "totalservicesok")
-                                       filter = ServiceOK;
-                               else if (key == "totalserviceswarning")
-                                       filter = ServiceWarning;
-                               else if (key == "totalservicesunknown")
-                                       filter = ServiceUnknown;
-                               else if (key == "totalservicescritical")
-                                       filter = ServiceCritical;
-
-                               BOOST_FOREACH(const Service::Ptr& service, GetServices()) {
-                                       if (filter != -1 && service->GetState() != filter)
-                                               continue;
-
-                                       count++;
-                               }
-
-                               *result = Convert::ToString(count);
-                               return true;
-                       }
-
-
-               if (cr) {
-                       if (key == "latency") {
-                               *result = Convert::ToString(Service::CalculateLatency(cr));
-                               return true;
-                       } else if (key == "executiontime") {
-                               *result = Convert::ToString(Service::CalculateExecutionTime(cr));
-                               return true;
-                       } else if (key == "output") {
-                               *result = cr->GetOutput();
-                               return true;
-                       } else if (key == "perfdata") {
-                               *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData());
-                               return true;
-                       } else if (key == "lastcheck") {
-                               *result = Convert::ToString((long)cr->GetScheduleStart());
-                               return true;
-                       }
-               }
-       } else {
-               vars = GetVars();
-
-               if (vars && vars->Contains(macro)) {
-                       *result = vars->Get(macro);
+               } else if (macro == "last_check") {
+                       *result = Convert::ToString((long)cr->GetScheduleStart());
                        return true;
                }
        }
index c0ec1891c7f9419a66e950cec63ca9136d57c0d9..a45493258f90c23248dff48bce2410d7f5c7efeb 100644 (file)
@@ -15,6 +15,9 @@ class Host : Checkable
                }}}
        };
        [config] Array::Ptr groups;
+
+       [config] String address;
+       [config] String address6;
 };
 
 }
index 5acc3b87b9202b9986e3a1b02af07f62ef3ec144..7bf57db97eda001b608dce670975b16a07d22233 100644 (file)
        %attribute %array "authorities" {
                %attribute %name(Endpoint) "*"
        },
+
+       %attribute %string "notes",
+       %attribute %string "notes_url",
+       %attribute %string "action_url",
+       %attribute %string "icon_image",
+       %attribute %string "icon_image_alt",
 }
 
 %type Host %inherits Checkable {
@@ -59,6 +65,9 @@
        %attribute %array "groups" {
                %attribute %name(HostGroup) "*"
        },
+
+       %attribute %string "address",
+       %attribute %string "address6",
 }
 
 %type HostGroup {
        %attribute %array "notification_state_filter" {
                %attribute %number "*"
        },
-       %attribute %name(TimePeriod) "notification_period"
+       %attribute %name(TimePeriod) "notification_period",
+
+       %attribute %string "email",
+       %attribute %string "pager",
 }
 
 %type UserGroup {
index b65cf2e8037d5cdba4a0471e3212f2db21c0151f..bc161e0b5ff33287b203a0a7639ef3b37b026563 100644 (file)
@@ -133,29 +133,23 @@ String IcingaApplication::GetNodeName(void) const
 
 bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr&, String *result) const
 {
-       /* require icinga prefix for application macros */
-       if (macro.SubStr(0, 7) == "icinga.") {
-               String key = macro.SubStr(7);
-
-               double now = Utility::GetTime();
-
-               if (key == "timet") {
-                       *result = Convert::ToString((long)now);
-                       return true;
-               } else if (key == "longdatetime") {
-                       *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now);
-                       return true;
-               } else if (key == "shortdatetime") {
-                       *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now);
-                       return true;
-               } else if (key == "date") {
-                       *result = Utility::FormatDateTime("%Y-%m-%d", now);
-                       return true;
-               } else if (key == "time") {
-                       *result = Utility::FormatDateTime("%H:%M:%S %z", now);
-                       return true;
-               }
+       double now = Utility::GetTime();
 
+       if (macro == "timet") {
+               *result = Convert::ToString((long)now);
+               return true;
+       } else if (macro == "long_date_time") {
+               *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", now);
+               return true;
+       } else if (macro == "short_date_time") {
+               *result = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", now);
+               return true;
+       } else if (macro == "date") {
+               *result = Utility::FormatDateTime("%Y-%m-%d", now);
+               return true;
+       } else if (macro == "time") {
+               *result = Utility::FormatDateTime("%H:%M:%S %z", now);
+               return true;
        }
 
        Dictionary::Ptr vars = GetVars();
index 0cf1d9e01ebf56ab4e633c84f1515bec93048eaf..103c4cc18b97710611904070c9ff90c3ce72dfcb 100644 (file)
 #include "base/objectlock.h"
 #include "base/logger_fwd.h"
 #include "base/context.h"
+#include "base/dynamicobject.h"
 #include <boost/foreach.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/classification.hpp>
 
 using namespace icinga;
 
-Value MacroProcessor::ResolveMacros(const Value& str, const std::vector<MacroResolver::Ptr>& resolvers,
+Value MacroProcessor::ResolveMacros(const Value& str, const ResolverList& resolvers,
        const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn)
 {
        Value result;
@@ -57,25 +61,93 @@ Value MacroProcessor::ResolveMacros(const Value& str, const std::vector<MacroRes
        return result;
 }
 
-bool MacroProcessor::ResolveMacro(const String& macro, const std::vector<MacroResolver::Ptr>& resolvers,
+bool MacroProcessor::ResolveMacro(const String& macro, const ResolverList& resolvers,
     const CheckResult::Ptr& cr, String *result)
 {
        CONTEXT("Resolving macro '" + macro + "'");
 
-       BOOST_FOREACH(const MacroResolver::Ptr& resolver, resolvers) {
-               if (resolver->ResolveMacro(macro, cr, result))
+       std::vector<String> tokens;
+       boost::algorithm::split(tokens, macro, boost::is_any_of("."));
+
+       String objName;
+       if (tokens.size() > 1) {
+               objName = tokens[0];
+               tokens.erase(tokens.begin());
+       }
+
+       BOOST_FOREACH(const ResolverSpec& resolver, resolvers) {
+               if (!objName.IsEmpty() && objName != resolver.first)
+                       continue;
+
+               if (objName.IsEmpty()) {
+                       DynamicObject::Ptr dobj = dynamic_pointer_cast<DynamicObject>(resolver.second);
+
+                       if (dobj) {
+                               Dictionary::Ptr vars = dobj->GetVars();
+
+                               if (vars && vars->Contains(macro)) {
+                                       *result = vars->Get(macro);
+                                       return true;
+                               }
+                       }
+               }
+
+               MacroResolver::Ptr mresolver = dynamic_pointer_cast<MacroResolver>(resolver.second);
+
+               if (mresolver && mresolver->ResolveMacro(boost::algorithm::join(tokens, "."), cr, result))
                        return true;
+
+               Value ref = resolver.second;
+               bool valid = true;
+
+               BOOST_FOREACH(const String& token, tokens) {
+                       if (ref.IsObjectType<Dictionary>()) {
+                               Dictionary::Ptr dict = ref;
+                               if (dict->Contains(token)) {
+                                       ref = dict->Get(token);
+                                       continue;
+                               } else {
+                                       valid = false;
+                                       break;
+                               }
+                       } else if (ref.IsObject()) {
+                               Object::Ptr object = ref;
+
+                               const Type *type = object->GetReflectionType();
+
+                               if (!type) {
+                                       valid = false;
+                                       break;
+                               }
+
+                               int field = type->GetFieldId(token);
+
+                               if (field == -1) {
+                                       valid = false;
+                                       break;
+                               }
+
+                               ref = object->GetField(field);
+                       }
+               }
+
+               if (valid) {
+                       *result = ref;
+                       return true;
+               }
        }
 
        return false;
 }
 
-
-String MacroProcessor::InternalResolveMacros(const String& str, const std::vector<MacroResolver::Ptr>& resolvers,
-       const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn)
+String MacroProcessor::InternalResolveMacros(const String& str, const ResolverList& resolvers,
+       const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, int recursionLevel)
 {
        CONTEXT("Resolving macros for string '" + str + "'");
 
+       if (recursionLevel > 15)
+               BOOST_THROW_EXCEPTION(std::runtime_error("Infinite recursion detected while resolving macros"));
+
        size_t offset, pos_first, pos_second;
        offset = 0;
 
@@ -100,6 +172,9 @@ String MacroProcessor::InternalResolveMacros(const String& str, const std::vecto
                if (!found)
                        Log(LogWarning, "icinga", "Macro '" + name + "' is not defined.");
 
+               /* recursively resolve macros in the macro */
+               resolved_macro = InternalResolveMacros(resolved_macro, resolvers, cr, EscapeCallback(), recursionLevel + 1);
+
                if (escapeFn)
                        resolved_macro = escapeFn(resolved_macro);
 
index cd7fead0199c066a0c5edf58f766675ca7a606f2..61cea23bafde024049825402da48a275331fad3d 100644 (file)
@@ -25,7 +25,7 @@
 #include "base/dictionary.h"
 #include "base/array.h"
 #include <boost/function.hpp>
-#include <vector>
+#include <map>
 
 namespace icinga
 {
@@ -39,18 +39,20 @@ class I2_ICINGA_API MacroProcessor
 {
 public:
        typedef boost::function<String (const String&)> EscapeCallback;
+       typedef std::pair<String, Object::Ptr> ResolverSpec;
+       typedef std::vector<ResolverSpec> ResolverList;
 
-       static Value ResolveMacros(const Value& str, const std::vector<MacroResolver::Ptr>& resolvers,
+       static Value ResolveMacros(const Value& str, const ResolverList& resolvers,
                const CheckResult::Ptr& cr, const EscapeCallback& escapeFn = EscapeCallback());
-       static bool ResolveMacro(const String& macro, const std::vector<MacroResolver::Ptr>& resolvers,
+       static bool ResolveMacro(const String& macro, const ResolverList& resolvers,
                const CheckResult::Ptr& cr, String *result);
 
 private:
        MacroProcessor(void);
 
        static String InternalResolveMacros(const String& str,
-               const std::vector<MacroResolver::Ptr>& resolvers, const CheckResult::Ptr& cr,
-           const EscapeCallback& escapeFn);
+           const ResolverList& resolvers, const CheckResult::Ptr& cr,
+           const EscapeCallback& escapeFn, int recursionLevel = 0);
 };
 
 }
index 99d837cfba6953a466ba7ac56bed6db1834763dd..830fad6b5ddea0cbe60c8eb74a18f4290fd1373e 100644 (file)
 #include "icinga/macroresolver.h"
 
 using namespace icinga;
-
-StaticMacroResolver::StaticMacroResolver(void)
-       : m_Macros(make_shared<Dictionary>())
-{ }
-
-void StaticMacroResolver::Add(const String& macro, const String& value)
-{
-       m_Macros->Set(macro, value);
-}
-
-bool StaticMacroResolver::ResolveMacro(const String& macro, const CheckResult::Ptr&, String *result) const
-{
-       if (m_Macros->Contains(macro)) {
-               *result = m_Macros->Get(macro);
-               return true;
-       }
-
-       return false;
-}
index 18b269416ad0c8613ff4a9e11f71db2fc08ee665..8637d4bf9406fec7d14fe7997655c35ca16813ef 100644 (file)
@@ -41,21 +41,6 @@ public:
        virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const = 0;
 };
 
-class I2_ICINGA_API StaticMacroResolver : public Object, public MacroResolver
-{
-public:
-       DECLARE_PTR_TYPEDEFS(StaticMacroResolver);
-
-       StaticMacroResolver(void);
-
-       void Add(const String& macro, const String& value);
-
-       virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const;
-
-private:
-       Dictionary::Ptr m_Macros;
-};
-
 }
 
 #endif /* MACRORESOLVER_H */
index 0fc2a17dff2f50cc183f6733892c44ec4752225b..0fcaecac3505ab366442d8eb7e1473d20dadd9cb 100644 (file)
@@ -135,93 +135,47 @@ String Service::StateTypeToString(StateType type)
 
 bool Service::ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const
 {
-       String key;
-       Dictionary::Ptr vars;
-
-       /* require prefix for object macros */
-       if (macro.SubStr(0, 8) == "service.") {
-               key = macro.SubStr(8);
-
-               if (key.SubStr(0, 5) == "vars.") {
-                       vars = GetVars();
-                       String vars_key = key.SubStr(5);
-
-                       if (vars && vars->Contains(vars_key)) {
-                               *result = vars->Get(vars_key);
-                               return true;
-                       }
-               } else if (key == "description") {
-                       *result = GetShortName();
-                       return true;
-               } else if (key == "displayname") {
-                       *result = GetDisplayName();
-                       return true;
-               } else if (key == "checkcommand") {
-                       CheckCommand::Ptr commandObj = GetCheckCommand();
-
-                       if (commandObj)
-                               *result = commandObj->GetName();
-                       else
-                               *result = "";
-
-                       return true;
-               }
+       if (macro == "state") {
+               *result = StateToString(GetState());
+               return true;
+       } else if (macro == "state_id") {
+               *result = Convert::ToString(GetState());
+               return true;
+       } else if (macro == "state_type") {
+               *result = StateTypeToString(GetStateType());
+               return true;
+       } else if (macro == "last_state") {
+               *result = StateToString(GetLastState());
+               return true;
+       } else if (macro == "last_state_id") {
+               *result = Convert::ToString(GetLastState());
+               return true;
+       } else if (macro == "last_state_type") {
+               *result = StateTypeToString(GetLastStateType());
+               return true;
+       } else if (macro == "last_state_change") {
+               *result = Convert::ToString((long)GetLastStateChange());
+               return true;
+       } else if (macro == "duration_sec") {
+               *result = Convert::ToString((long)(Utility::GetTime() - GetLastStateChange()));
+               return true;
+       }
 
-               if (key == "state") {
-                       *result = StateToString(GetState());
-                       return true;
-               } else if (key == "stateid") {
-                       *result = Convert::ToString(GetState());
-                       return true;
-               } else if (key == "statetype") {
-                       *result = StateTypeToString(GetStateType());
+       if (cr) {
+               if (macro == "latency") {
+                       *result = Convert::ToString(Service::CalculateLatency(cr));
                        return true;
-               } else if (key == "attempt") {
-                       *result = Convert::ToString(GetCheckAttempt());
+               } else if (macro == "execution_time") {
+                       *result = Convert::ToString(Service::CalculateExecutionTime(cr));
                        return true;
-               } else if (key == "maxattempt") {
-                       *result = Convert::ToString(GetMaxCheckAttempts());
+               } else if (macro == "output") {
+                       *result = cr->GetOutput();
                        return true;
-               } else if (key == "laststate") {
-                       *result = StateToString(GetLastState());
+               } else if (macro == "perfdata") {
+                       *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData());
                        return true;
-               } else if (key == "laststateid") {
-                       *result = Convert::ToString(GetLastState());
-                       return true;
-               } else if (key == "laststatetype") {
-                       *result = StateTypeToString(GetLastStateType());
-                       return true;
-               } else if (key == "laststatechange") {
-                       *result = Convert::ToString((long)GetLastStateChange());
-                       return true;
-               } else if (key == "durationsec") {
-                       *result = Convert::ToString((long)(Utility::GetTime() - GetLastStateChange()));
-                       return true;
-               }
-
-               if (cr) {
-                       if (key == "latency") {
-                               *result = Convert::ToString(Service::CalculateLatency(cr));
-                               return true;
-                       } else if (key == "executiontime") {
-                               *result = Convert::ToString(Service::CalculateExecutionTime(cr));
-                               return true;
-                       } else if (key == "output") {
-                               *result = cr->GetOutput();
-                               return true;
-                       } else if (key == "perfdata") {
-                               *result = PluginUtility::FormatPerfdata(cr->GetPerformanceData());
-                               return true;
-                       } else if (key == "lastcheck") {
-                               *result = Convert::ToString((long)cr->GetExecutionEnd());
-                               return true;
-                       }
-               }
-       } else {
-               vars = GetVars();
-
-               if (vars && vars->Contains(macro)) {
-                       *result = vars->Get(macro);
+               } else if (macro == "last_check") {
+                       *result = Convert::ToString((long)cr->GetExecutionEnd());
                        return true;
                }
        }
index 16fffb2680771c43fb2f354343e973e475aac55c..4231a02e06b6ad93bd1762c4585f9884c7acd37e 100644 (file)
@@ -91,39 +91,3 @@ void User::ValidateFilters(const String& location, const Dictionary::Ptr& attrs)
                    location + ": Type filter is invalid.");
        }
 }
-
-bool User::ResolveMacro(const String& macro, const CheckResult::Ptr&, String *result) const
-{
-       String key;
-       Dictionary::Ptr vars;
-
-       /* require prefix for object macros */
-       if (macro.SubStr(0, 5) == "user.") {
-               key = macro.SubStr(5);
-
-               if (key.SubStr(0, 5) == "vars.") {
-                       vars = GetVars();
-                       String vars_key = key.SubStr(5);
-
-                       if (vars && vars->Contains(vars_key)) {
-                               *result = vars->Get(vars_key);
-                               return true;
-                       }
-               } else if (key == "name") {
-                       *result = GetName();
-                       return true;
-               } else if (key == "displayname") {
-                       *result = GetDisplayName();
-                       return true;
-               }
-       } else {
-               vars = GetVars();
-
-               if (vars && vars->Contains(macro)) {
-                       *result = vars->Get(macro);
-                       return true;
-               }
-       }
-
-       return false;
-}
index 22509f07531c88a12acdbfb9feb004d963853f78..4cff8709eaae222dd9b26611207c18dbda5ecb32 100644 (file)
@@ -34,7 +34,7 @@ namespace icinga
  *
  * @ingroup icinga
  */
-class I2_ICINGA_API User : public ObjectImpl<User>, public MacroResolver
+class I2_ICINGA_API User : public ObjectImpl<User>
 {
 public:
        DECLARE_PTR_TYPEDEFS(User);
@@ -43,8 +43,6 @@ public:
        /* Notifications */
        TimePeriod::Ptr GetNotificationPeriod(void) const;
 
-       virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const;
-
        static void ValidateFilters(const String& location, const Dictionary::Ptr& attrs);
 
 protected:
index 896abf2cfdc587f872a537582857f6b049f10434..74e9d74a33d438eb373d6e5d17e2178eef5cbfb7 100644 (file)
@@ -19,6 +19,10 @@ class User : DynamicObject
        [config] Array::Ptr notification_type_filter (NotificationTypeFilterRaw);
        int notification_type_filter_real (NotificationTypeFilter);
        [config] Array::Ptr notification_state_filter (NotificationStateFilterRaw);
+
+       [config] String email;
+       [config] String pager;
+
        int notification_state_filter_real (NotificationStateFilter);
        [state] bool enable_notifications;
        [state] double last_notification;
index 5e2431fe936c68f268c9dc1ffed14a1088bc7ff2..a5e4db767e6911bb9f7a78b2800120be00120403 100644 (file)
@@ -44,12 +44,12 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
        Service::Ptr service;
        tie(host, service) = GetHostService(checkable);
 
-       std::vector<MacroResolver::Ptr> resolvers;
+       MacroProcessor::ResolverList resolvers;
        if (service)
-               resolvers.push_back(service);
-       resolvers.push_back(host);
-       resolvers.push_back(commandObj);
-       resolvers.push_back(IcingaApplication::GetInstance());
+               resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("command", commandObj));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value command = MacroProcessor::ResolveMacros(raw_command, resolvers, checkable->GetLastCheckResult(), Utility::EscapeShellCmd);
 
index 37976d8d0312ff8686a31468b4fc8c956620865f..355db7efd4f829f1cef74df4877f1e7959c2b62a 100644 (file)
@@ -41,12 +41,12 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable)
        Service::Ptr service;
        tie(host, service) = GetHostService(checkable);
 
-       std::vector<MacroResolver::Ptr> resolvers;
+       MacroProcessor::ResolverList resolvers;
        if (service)
-               resolvers.push_back(service);
-       resolvers.push_back(host);
-       resolvers.push_back(commandObj);
-       resolvers.push_back(IcingaApplication::GetInstance());
+               resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("command", commandObj));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value command = MacroProcessor::ResolveMacros(raw_command, resolvers, checkable->GetLastCheckResult(), Utility::EscapeShellCmd);
 
index 88d7b148ec6baa68d273cfa21598533316fce779..cccfb0059f1f7319c1f3b1d2df58ca801188e612 100644 (file)
@@ -44,24 +44,24 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, c
 
        Value raw_command = commandObj->GetCommandLine();
 
-       StaticMacroResolver::Ptr notificationMacroResolver = make_shared<StaticMacroResolver>();
-       notificationMacroResolver->Add("notification.type", Notification::NotificationTypeToString(type));
-       notificationMacroResolver->Add("notification.author", author);
-       notificationMacroResolver->Add("notification.comment", comment);
+       Dictionary::Ptr notificationExtra = make_shared<Dictionary>();
+       notificationExtra->Set("type", Notification::NotificationTypeToString(type));
+       notificationExtra->Set("author", author);
+       notificationExtra->Set("comment", comment);
 
        Host::Ptr host;
        Service::Ptr service;
        tie(host, service) = GetHostService(checkable);
 
-       std::vector<MacroResolver::Ptr> resolvers;
-       resolvers.push_back(user);
-       resolvers.push_back(notificationMacroResolver);
-       resolvers.push_back(notification);
+       MacroProcessor::ResolverList resolvers;
+       resolvers.push_back(std::make_pair("user", user));
+       resolvers.push_back(std::make_pair("notification", notificationExtra));
+       resolvers.push_back(std::make_pair("notification", notification));
        if (service)
-               resolvers.push_back(service);
-       resolvers.push_back(host);;
-       resolvers.push_back(commandObj);
-       resolvers.push_back(IcingaApplication::GetInstance());
+               resolvers.push_back(std::make_pair("service", service));
+       resolvers.push_back(std::make_pair("host", host));
+       resolvers.push_back(std::make_pair("command", commandObj));
+       resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
 
        Value command = MacroProcessor::ResolveMacros(raw_command, resolvers, cr, Utility::EscapeShellCmd);