diff --git a/doc/3.02-commands.md b/doc/3.02-commands.md
index 584a8405e..4f3cddc40 100644
--- a/doc/3.02-commands.md
+++ b/doc/3.02-commands.md
@@ -113,7 +113,7 @@ If you require default macro definitions, you can add a macro dictionary as show
`CheckCommand` object.
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
- command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ],
+ command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
"NOTIFICATIONTYPE",
diff --git a/doc/3.03-macros.md b/doc/3.03-macros.md
index 4c55fa915..6c1b67cdb 100644
--- a/doc/3.03-macros.md
+++ b/doc/3.03-macros.md
@@ -273,7 +273,7 @@ Example:
...
{
- check_interval = (MyCheckInterval / 2.5)
+ check_interval = MyCheckInterval / 2.5
}
More details in the chapter [Constant Expressions](#constant-expressions).
diff --git a/doc/3.04-notifications.md b/doc/3.04-notifications.md
index 6f1b09a1d..86b8d820f 100644
--- a/doc/3.04-notifications.md
+++ b/doc/3.04-notifications.md
@@ -25,11 +25,11 @@ The user `icingaadmin` in the example below will get notified only on `WARNING`
object User "icingaadmin" {
display_name = "Icinga 2 Admin",
enable_notifications = 1,
- notification_state_filter = (StateFilterOK |
- StateFilterWarning |
- StateFilterCritical),
- notification_type_filter = (NotificationFilterProblem |
- NotificationFilterRecovery),
+ notification_state_filter = StateFilterOK |
+ StateFilterWarning |
+ StateFilterCritical,
+ notification_type_filter = NotificationFilterProblem |
+ NotificationFilterRecovery,
macros = {
"email" = "icinga@localhost",
"pager" = "+49123456789"
@@ -59,7 +59,7 @@ There are various macros available at runtime execution of the `NotificationComm
The example below may or may not fit your needs.
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
- command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ],
+ command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
"NOTIFICATIONTYPE",
@@ -91,18 +91,18 @@ to the defined notifications. That way you'll save duplicated attributes in each
notification_command = "mail-service-notification",
- notification_state_filter = (StateFilterWarning |
- StateFilterCritical |
- StateFilterUnknown),
- notification_type_filter = (NotificationFilterProblem |
- NotificationFilterAcknowledgement |
- NotificationFilterRecovery |
- NotificationFilterCustom |
- NotificationFilterFlappingStart |
- NotificationFilterFlappingEnd |
- NotificationFilterDowntimeStart |
- NotificationFilterDowntimeEnd |
- NotificationFilterDowntimeRemoved),
+ notification_state_filter = StateFilterWarning |
+ StateFilterCritical |
+ StateFilterUnknown,
+ notification_type_filter = NotificationFilterProblem |
+ NotificationFilterAcknowledgement |
+ NotificationFilterRecovery |
+ NotificationFilterCustom |
+ NotificationFilterFlappingStart |
+ NotificationFilterFlappingEnd |
+ NotificationFilterDowntimeStart |
+ NotificationFilterDowntimeEnd |
+ NotificationFilterDowntimeRemoved,
notification_period = "24x7"
}
@@ -274,18 +274,18 @@ Available state and type filters for notifications are:
template Notification "generic-notification" {
- notification_state_filter = (StateFilterWarning |
- StateFilterCritical |
- StateFilterUnknown),
- notification_type_filter = (NotificationFilterProblem |
- NotificationFilterAcknowledgement |
- NotificationFilterRecovery |
- NotificationFilterCustom |
- NotificationFilterFlappingStart |
- NotificationFilterFlappingEnd |
- NotificationFilterDowntimeStart |
- NotificationFilterDowntimeEnd |
- NotificationFilterDowntimeRemoved),
+ notification_state_filter = StateFilterWarning |
+ StateFilterCritical |
+ StateFilterUnknown,
+ notification_type_filter = NotificationFilterProblem |
+ NotificationFilterAcknowledgement |
+ NotificationFilterRecovery |
+ NotificationFilterCustom |
+ NotificationFilterFlappingStart |
+ NotificationFilterFlappingEnd |
+ NotificationFilterDowntimeStart |
+ NotificationFilterDowntimeEnd |
+ NotificationFilterDowntimeRemoved,
}
> **Note**
diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md
index 59969d2f1..d3bdf2311 100644
--- a/doc/4.1-configuration-syntax.md
+++ b/doc/4.1-configuration-syntax.md
@@ -317,14 +317,14 @@ Constants cannot be changed once they are set.
Simple calculations can be performed using the constant expression syntax:
{
- check_interval = (15 * 60)
+ check_interval = 30 + 60
}
-Valid operators include ~, +, -, * and /. The default precedence rules can be
+Valid operators include ~, !, +, -, *, /, ==, !=, in and !in. The default precedence rules can be
overridden by grouping expressions using parentheses:
{
- check_interval ((15 * 60) / 2)
+ check_interval = (30 + 60) / 2
}
Global constants may be used in constant expressions.
@@ -334,13 +334,32 @@ Global constants may be used in constant expressions.
...
{
- check_interval = (MyCheckInterval / 2.5)
+ check_interval = MyCheckInterval / 2.5
}
> **Note**
>
-> Constant expressions are evaluated as soon as they're encountered in
-> the configuration file.
+> Constant expressions in attributes and variable definitions are evaluated as
+> soon as they're encountered in the configuration file.
+
+### 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.
+
+ template Service "ping-service" {
+ short_name = "ping",
+ check_command = "ping4"
+ }
+
+ apply template Service "ping-service" to Host where (host == "localhost")
+
+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 types used in the `apply` expression additional local
+variables may be available for use in the `where` condition.
### Comments
diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md
index 68847254e..0af7c07de 100644
--- a/doc/4.3-object-types.md
+++ b/doc/4.3-object-types.md
@@ -214,7 +214,7 @@ Example:
parent_host = "internet",
parent_service = "ping4",
- state_filter = (StateFilterOK),
+ state_filter = StateFilterOK,
disable_checks = true
}
@@ -230,7 +230,7 @@ Attributes:
disable_checks |**Optional.** Whether to disable checks when this dependency fails. Defaults to false.
disable_notifications|**Optional.** Whether to disable notifications when this dependency fails. Defaults to true.
period |**Optional.** Time period during which this dependency is enabled.
- state_filter |**Optional.** A set of type filters when this dependency should be OK. Defaults to (StateFilterOK | StateFilterWarning).
+ state_filter |**Optional.** A set of type filters when this dependency should be OK. Defaults to StateFilterOK | StateFilterWarning.
Available state filters:
@@ -252,12 +252,12 @@ Example:
enable_notifications = 1,
notification_period = "24x7",
- notification_state_filter = (StateFilterOK |
- StateFilterWarning |
- StateFilterCritical |
- StateFilterUnknown),
- notification_type_filter = (NotificationFilterProblem |
- NotificationFilterRecovery),
+ notification_state_filter = StateFilterOK |
+ StateFilterWarning |
+ StateFilterCritical |
+ StateFilterUnknown,
+ notification_type_filter = NotificationFilterProblem |
+ NotificationFilterRecovery,
macros = {
"name" = "Icinga 2 Admin",
"email" = "icinga@localhost",
@@ -458,7 +458,7 @@ A notification command definition.
Example:
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
- command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ],
+ command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
"NOTIFICATIONTYPE",
@@ -588,7 +588,7 @@ Example:
logentries_age = 31d,
},
- categories = (DbCatConfig | DbCatState)
+ categories = DbCatConfig | DbCatState
}
Attributes:
@@ -672,7 +672,7 @@ Example:
logentries_age = 31d,
},
- categories = (DbCatConfig | DbCatState)
+ categories = DbCatConfig | DbCatState
}
Attributes:
@@ -877,7 +877,7 @@ a defined JSON file.
Example:
object IcingaStatusWriter "status" {
- status_path = (IcingaLocalStateDir + "/cache/icinga2/status.json"),
+ status_path = IcingaLocalStateDir + "/cache/icinga2/status.json",
update_interval = 15s
}
@@ -962,8 +962,8 @@ Example:
object Domain "dmz-1" {
acl = {
- node1 = (DomainPrivCheckResult),
- node2 = (DomainPrivReadWrite)
+ node1 = DomainPrivCheckResult,
+ node2 = DomainPrivReadWrite
}
}
@@ -980,5 +980,5 @@ Domain ACLs:
DomainPrivRead | Endpoint reads local messages and relays them to remote nodes.
DomainPrivCheckResult | Endpoint accepts check result messages from remote nodes.
DomainPrivCommand | Endpoint accepts command messages from remote nodes.
- DomainPrevReadOnly | Endpoint reads local messages and relays them to remote nodes.
- DomainPrivReadWrite | Combination of (DomainPrivRead | DomainPrivCheckResult | DomainPrivCommand)
+ DomainPrevReadOnly | Equivalent to DomainPrivRead.
+ DomainPrivReadWrite | Equivalent to DomainPrivRead | DomainPrivCheckResult | DomainPrivCommand.
diff --git a/doc/6.04-cluster.md b/doc/6.04-cluster.md
index 9284d79ec..d720c75b8 100644
--- a/doc/6.04-cluster.md
+++ b/doc/6.04-cluster.md
@@ -129,7 +129,7 @@ In order to load configuration files which were received from a remote Icinga 2
instance you will have to add the following include directive to your
`icinga2.conf` configuration file:
- include (IcingaLocalStateDir + "/lib/icinga2/cluster/config/*/*")
+ include IcingaLocalStateDir + "/lib/icinga2/cluster/config/*/*"
### Initial Cluster Sync
diff --git a/doc/6.05-domains.md b/doc/6.05-domains.md
index 3e79ae35b..157816c75 100644
--- a/doc/6.05-domains.md
+++ b/doc/6.05-domains.md
@@ -25,7 +25,7 @@ from the `icinga-node-dmz-1` endpoint.
object Domain "dmz-db" {
acl = {
- icinga-node-dmz-1 = (DomainPrivReadOnly),
- icinga-node-dmz-2 = (DomainPrivReadWrite)
+ icinga-node-dmz-1 = DomainPrivReadOnly,
+ icinga-node-dmz-2 = DomainPrivReadWrite
}
}
\ No newline at end of file
diff --git a/doc/8-differences-between-icinga-1x-and-2.md b/doc/8-differences-between-icinga-1x-and-2.md
index e8f4187d4..82e7f60f4 100644
--- a/doc/8-differences-between-icinga-1x-and-2.md
+++ b/doc/8-differences-between-icinga-1x-and-2.md
@@ -463,8 +463,8 @@ All state and type filter use long names or'd with a pipe together
notification_options w,u,c,r,f,s
- notification_state_filter = (StateFilterWarning | StateFilterUnknown | StateFilterCritical),
- notification_type_filter = (NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd | NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved)
+ notification_state_filter = StateFilterWarning | StateFilterUnknown | StateFilterCritical,
+ notification_type_filter = NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd | NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved
> **Note**
>
diff --git a/etc/icinga2/conf.d/generic-user.conf b/etc/icinga2/conf.d/generic-user.conf
index a2dae8d8b..66f78cd88 100644
--- a/etc/icinga2/conf.d/generic-user.conf
+++ b/etc/icinga2/conf.d/generic-user.conf
@@ -7,10 +7,10 @@ template User "generic-user" {
enable_notifications = true,
notification_period = "24x7",
- notification_state_filter = (StateFilterWarning |
+ notification_state_filter = StateFilterWarning |
StateFilterCritical |
- StateFilterUnknown),
- notification_type_filter = (NotificationFilterProblem |
+ StateFilterUnknown,
+ notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement |
NotificationFilterRecovery |
NotificationFilterCustom |
@@ -18,5 +18,5 @@ template User "generic-user" {
NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd |
- NotificationFilterDowntimeRemoved)
+ NotificationFilterDowntimeRemoved
}
diff --git a/etc/icinga2/conf.d/notifications.conf b/etc/icinga2/conf.d/notifications.conf
index e74ae8f1b..5bd59810c 100644
--- a/etc/icinga2/conf.d/notifications.conf
+++ b/etc/icinga2/conf.d/notifications.conf
@@ -5,11 +5,11 @@
template Notification "mail-notification" {
notification_command = "mail-service-notification",
- notification_state_filter = (StateFilterOK |
+ notification_state_filter = StateFilterOK |
StateFilterWarning |
StateFilterCritical |
- StateFilterUnknown),
- notification_type_filter = (NotificationFilterProblem |
+ StateFilterUnknown,
+ notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement |
NotificationFilterRecovery |
NotificationFilterCustom |
@@ -17,13 +17,13 @@ template Notification "mail-notification" {
NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd |
- NotificationFilterDowntimeRemoved),
+ NotificationFilterDowntimeRemoved,
notification_period = "24x7"
}
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" {
- command = [ (IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh") ],
+ command = [ IcingaSysconfDir + "/icinga2/scripts/mail-notification.sh" ],
export_macros = [
"NOTIFICATIONTYPE",
diff --git a/etc/icinga2/features-available/debuglog.conf b/etc/icinga2/features-available/debuglog.conf
index 656b8f7be..86947cbec 100644
--- a/etc/icinga2/features-available/debuglog.conf
+++ b/etc/icinga2/features-available/debuglog.conf
@@ -6,6 +6,6 @@
object FileLogger "debug-file" {
severity = "debug",
- path = (IcingaLocalStateDir + "/log/icinga2/debug.log")
+ path = IcingaLocalStateDir + "/log/icinga2/debug.log"
}
diff --git a/etc/icinga2/features-available/mainlog.conf b/etc/icinga2/features-available/mainlog.conf
index 848f7398a..2d237a451 100644
--- a/etc/icinga2/features-available/mainlog.conf
+++ b/etc/icinga2/features-available/mainlog.conf
@@ -4,6 +4,6 @@
object FileLogger "main-log" {
severity = "information",
- path = (IcingaLocalStateDir + "/log/icinga2/icinga2.log")
+ path = IcingaLocalStateDir + "/log/icinga2/icinga2.log"
}
diff --git a/lib/base/qstring.cpp b/lib/base/qstring.cpp
index 0ba16b699..5aba2f808 100644
--- a/lib/base/qstring.cpp
+++ b/lib/base/qstring.cpp
@@ -136,6 +136,11 @@ std::string& String::GetData(void)
return m_Data;
}
+const std::string& String::GetData(void) const
+{
+ return m_Data;
+}
+
size_t String::Find(const String& str, size_t pos) const
{
return m_Data.find(str, pos);
diff --git a/lib/base/qstring.h b/lib/base/qstring.h
index 7464c2e68..b85800312 100644
--- a/lib/base/qstring.h
+++ b/lib/base/qstring.h
@@ -80,6 +80,7 @@ public:
size_t GetLength(void) const;
std::string& GetData(void);
+ const std::string& GetData(void) const;
size_t Find(const String& str, size_t pos = 0) const;
size_t RFind(const String& str, size_t pos = NPos) const;
diff --git a/lib/base/value.cpp b/lib/base/value.cpp
index 19ad822a2..a9028c28c 100644
--- a/lib/base/value.cpp
+++ b/lib/base/value.cpp
@@ -196,7 +196,7 @@ ValueType Value::GetType(void) const
return static_cast(m_Value.which());
}
-bool Value::operator==(bool rhs)
+bool Value::operator==(bool rhs) const
{
if (!IsScalar())
return false;
@@ -204,12 +204,12 @@ bool Value::operator==(bool rhs)
return static_cast(*this) == rhs;
}
-bool Value::operator!=(bool rhs)
+bool Value::operator!=(bool rhs) const
{
return !(*this == rhs);
}
-bool Value::operator==(int rhs)
+bool Value::operator==(int rhs) const
{
if (!IsScalar())
return false;
@@ -217,12 +217,12 @@ bool Value::operator==(int rhs)
return static_cast(*this) == rhs;
}
-bool Value::operator!=(int rhs)
+bool Value::operator!=(int rhs) const
{
return !(*this == rhs);
}
-bool Value::operator==(double rhs)
+bool Value::operator==(double rhs) const
{
if (!IsScalar())
return false;
@@ -230,32 +230,32 @@ bool Value::operator==(double rhs)
return static_cast(*this) == rhs;
}
-bool Value::operator!=(double rhs)
+bool Value::operator!=(double rhs) const
{
return !(*this == rhs);
}
-bool Value::operator==(const char *rhs)
+bool Value::operator==(const char *rhs) const
{
return static_cast(*this) == rhs;
}
-bool Value::operator!=(const char *rhs)
+bool Value::operator!=(const char *rhs) const
{
return !(*this == rhs);
}
-bool Value::operator==(const String& rhs)
+bool Value::operator==(const String& rhs) const
{
return static_cast(*this) == rhs;
}
-bool Value::operator!=(const String& rhs)
+bool Value::operator!=(const String& rhs) const
{
return !(*this == rhs);
}
-bool Value::operator==(const Value& rhs)
+bool Value::operator==(const Value& rhs) const
{
if (IsEmpty() != rhs.IsEmpty())
return false;
@@ -275,7 +275,7 @@ bool Value::operator==(const Value& rhs)
return static_cast(*this) == static_cast(rhs);
}
-bool Value::operator!=(const Value& rhs)
+bool Value::operator!=(const Value& rhs) const
{
return !(*this == rhs);
}
diff --git a/lib/base/value.h b/lib/base/value.h
index 162767e9b..f8d8aa551 100644
--- a/lib/base/value.h
+++ b/lib/base/value.h
@@ -73,23 +73,23 @@ public:
operator double(void) const;
operator String(void) const;
- bool operator==(bool rhs);
- bool operator!=(bool rhs);
+ bool operator==(bool rhs) const;
+ bool operator!=(bool rhs) const;
- bool operator==(int rhs);
- bool operator!=(int rhs);
+ bool operator==(int rhs) const;
+ bool operator!=(int rhs) const;
- bool operator==(double rhs);
- bool operator!=(double rhs);
+ bool operator==(double rhs) const;
+ bool operator!=(double rhs) const;
- bool operator==(const char *rhs);
- bool operator!=(const char *rhs);
+ bool operator==(const char *rhs) const;
+ bool operator!=(const char *rhs) const;
- bool operator==(const String& rhs);
- bool operator!=(const String& rhs);
+ bool operator==(const String& rhs) const;
+ bool operator!=(const String& rhs) const;
- bool operator==(const Value& rhs);
- bool operator!=(const Value& rhs);
+ bool operator==(const Value& rhs) const;
+ bool operator!=(const Value& rhs) const;
template
operator shared_ptr(void) const
diff --git a/lib/config/CMakeLists.txt b/lib/config/CMakeLists.txt
index ab0f302db..6f9dbeb50 100644
--- a/lib/config/CMakeLists.txt
+++ b/lib/config/CMakeLists.txt
@@ -27,7 +27,7 @@ mkembedconfig_target(base-type.conf base-type.cpp)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
add_library(config SHARED
- aexpression.cpp avalue.cpp base-type.conf base-type.cpp
+ aexpression.cpp applyrule.cpp avalue.cpp base-type.conf base-type.cpp
configcompilercontext.cpp configcompiler.cpp configitembuilder.cpp
configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS}
configtype.cpp expression.cpp expressionlist.cpp typerule.cpp typerulelist.cpp
diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp
index 94aab4355..40dbadea8 100644
--- a/lib/config/aexpression.cpp
+++ b/lib/config/aexpression.cpp
@@ -18,28 +18,44 @@
******************************************************************************/
#include "config/aexpression.h"
+#include "base/array.h"
+#include "base/serializer.h"
+#include "base/context.h"
+#include "base/scriptfunction.h"
+#include
using namespace icinga;
-AExpression::AExpression(AOperator op, const AValue& operand1)
- : m_Operator(op), m_Operand1(operand1)
+AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di)
+ : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di)
{
ASSERT(op == AEReturn);
}
-AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2)
- : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2)
+AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di)
+ : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
{
ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide ||
- op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight);
+ op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight ||
+ op == AEEqual || op == AENotEqual || op == AEIn || op == AENotIn ||
+ op == AELogicalAnd || op == AELogicalOr || op == AEFunctionCall);
}
-Value AExpression::Evaluate(const Object::Ptr& thisRef) const
+Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
{
Value left, right;
+ Array::Ptr arr, arr2;
+ bool found;
+ String funcName;
+ ScriptFunction::Ptr func;
+ std::vector arguments;
- left = m_Operand1.Evaluate(thisRef);
- right = m_Operand2.Evaluate(thisRef);
+ left = m_Operand1.Evaluate(locals);
+ right = m_Operand2.Evaluate(locals);
+
+ std::ostringstream msgbuf;
+ msgbuf << "Evaluating AExpression " << m_DebugInfo << "; left=" << JsonSerialize(left) << "; right=" << JsonSerialize(right);
+ CONTEXT(msgbuf.str());
switch (m_Operator) {
case AEReturn:
@@ -65,8 +81,65 @@ Value AExpression::Evaluate(const Object::Ptr& thisRef) const
return (long)left << (long)right;
case AEShiftRight:
return (long)left >> (long)right;
+ case AEEqual:
+ return left == right;
+ case AENotEqual:
+ return left != right;
+ case AEIn:
+ if (!right.IsObjectType())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
+
+ arr = right;
+ found = false;
+ BOOST_FOREACH(const Value& value, arr) {
+ if (value == left) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+ case AENotIn:
+ if (!right.IsObjectType())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
+
+ arr = right;
+ found = false;
+ BOOST_FOREACH(const Value& value, arr) {
+ if (value == left) {
+ found = true;
+ break;
+ }
+ }
+
+ return !found;
+ case AELogicalAnd:
+ return (long)left && (long)right;
+ case AELogicalOr:
+ return (long)left || (long)right;
+ case AEFunctionCall:
+ funcName = left;
+ func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName);
+
+ if (!func)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist."));
+
+ arr = right;
+ BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
+ arguments.push_back(aexpr->Evaluate(locals));
+ }
+
+ return func->Invoke(arguments);
+ case AEArray:
+ arr = left;
+ arr2 = make_shared();
+
+ BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
+ arr2->Add(aexpr->Evaluate(locals));
+ }
+
+ return arr2;
default:
ASSERT(!"Invalid operator.");
}
}
-
diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h
index 34b827f98..a2dd99c12 100644
--- a/lib/config/aexpression.h
+++ b/lib/config/aexpression.h
@@ -22,7 +22,8 @@
#include "config/i2-config.h"
#include "config/avalue.h"
-#include "base/object.h"
+#include "config/debuginfo.h"
+#include "base/dictionary.h"
namespace icinga
{
@@ -41,7 +42,15 @@ enum AOperator
AEBinaryAnd,
AEBinaryOr,
AEShiftLeft,
- AEShiftRight
+ AEShiftRight,
+ AEEqual,
+ AENotEqual,
+ AEIn,
+ AENotIn,
+ AELogicalAnd,
+ AELogicalOr,
+ AEFunctionCall,
+ AEArray
};
/**
@@ -52,15 +61,16 @@ class I2_CONFIG_API AExpression : public Object
public:
DECLARE_PTR_TYPEDEFS(AExpression);
- AExpression(AOperator op, const AValue& operand1);
- AExpression(AOperator op, const AValue& operand1, const AValue& operand2);
+ AExpression(AOperator op, const AValue& operand1, const DebugInfo& di);
+ AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di);
- Value Evaluate(const Object::Ptr& thisRef) const;
+ Value Evaluate(const Dictionary::Ptr& locals) const;
private:
AOperator m_Operator;
AValue m_Operand1;
AValue m_Operand2;
+ DebugInfo m_DebugInfo;
};
}
diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp
new file mode 100644
index 000000000..23247db27
--- /dev/null
+++ b/lib/config/applyrule.cpp
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * 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 "config/applyrule.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)
+ : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di)
+{ }
+
+String ApplyRule::GetTemplate(void) const
+{
+ return m_Template;
+}
+
+AExpression::Ptr ApplyRule::GetExpression(void) const
+{
+ return m_Expression;
+}
+
+DebugInfo ApplyRule::GetDebugInfo(void) const
+{
+ return m_DebugInfo;
+}
+
+void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di)
+{
+ m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di));
+}
+
+void ApplyRule::EvaluateRules(void)
+{
+ std::pair kv;
+ BOOST_FOREACH(kv, m_Callbacks) {
+ RuleMap::const_iterator it = m_Rules.find(kv.first);
+
+ if (it == m_Rules.end())
+ continue;
+
+ kv.second(it->second);
+ }
+}
+
+void ApplyRule::RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback)
+{
+ m_Callbacks[std::make_pair(sourceType, targetType)] = callback;
+}
+
+bool ApplyRule::IsValidCombination(const String& sourceType, const String& targetType)
+{
+ return m_Callbacks.find(std::make_pair(sourceType, targetType)) != m_Callbacks.end();
+}
diff --git a/lib/config/applyrule.h b/lib/config/applyrule.h
new file mode 100644
index 000000000..e08ad98fb
--- /dev/null
+++ b/lib/config/applyrule.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * 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. *
+ ******************************************************************************/
+
+#ifndef APPLYRULE_H
+#define APPLYRULE_H
+
+#include "config/i2-config.h"
+#include "config/aexpression.h"
+#include "config/debuginfo.h"
+#include "base/dynamictype.h"
+
+namespace icinga
+{
+
+/**
+ * @ingroup config
+ */
+class I2_CONFIG_API ApplyRule
+{
+public:
+ typedef std::pair TypeCombination;
+ typedef boost::function& rules)> Callback;
+ typedef std::map CallbackMap;
+ typedef std::map > RuleMap;
+
+ String GetTemplate(void) const;
+ AExpression::Ptr GetExpression(void) const;
+ DebugInfo GetDebugInfo(void) const;
+
+ static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di);
+ 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);
+
+private:
+ String m_Template;
+ AExpression::Ptr m_Expression;
+ DebugInfo m_DebugInfo;
+
+ static CallbackMap m_Callbacks;
+ static RuleMap m_Rules;
+
+ ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di);
+};
+
+}
+
+#endif /* APPLYRULE_H */
diff --git a/lib/config/avalue.cpp b/lib/config/avalue.cpp
index 8f604a9e2..742bbca22 100644
--- a/lib/config/avalue.cpp
+++ b/lib/config/avalue.cpp
@@ -35,17 +35,20 @@ AValue::AValue(AValueType type, const Value& value)
: m_Type(type), m_Value(value)
{ }
-Value AValue::Evaluate(const Object::Ptr& thisRef) const
+Value AValue::Evaluate(const Dictionary::Ptr& locals) const
{
switch (m_Type) {
case ATSimple:
return m_Value;
case ATVariable:
- return ScriptVariable::Get(m_Value);
+ if (locals && locals->Contains(m_Value))
+ return locals->Get(m_Value);
+ else
+ return ScriptVariable::Get(m_Value);
case ATThisRef:
VERIFY(!"Not implemented.");
case ATExpression:
- return m_Expression->Evaluate(thisRef);
+ return m_Expression->Evaluate(locals);
default:
ASSERT(!"Invalid type.");
}
diff --git a/lib/config/avalue.h b/lib/config/avalue.h
index 5ddea3483..37969ca3f 100644
--- a/lib/config/avalue.h
+++ b/lib/config/avalue.h
@@ -22,7 +22,7 @@
#include "config/i2-config.h"
#include "base/value.h"
-#include "base/object.h"
+#include "base/dictionary.h"
namespace icinga
{
@@ -50,7 +50,7 @@ public:
AValue(const shared_ptr& expr);
AValue(AValueType type, const Value& value);
- Value Evaluate(const Object::Ptr& thisRef) const;
+ Value Evaluate(const Dictionary::Ptr& locals) const;
private:
AValueType m_Type;
diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll
index ce4bfa942..f397a5ab7 100644
--- a/lib/config/config_lexer.ll
+++ b/lib/config/config_lexer.ll
@@ -222,8 +222,17 @@ 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;
\<\< return T_SHIFT_LEFT;
\>\> return T_SHIFT_RIGHT;
+== return T_EQUAL;
+!= return T_NOT_EQUAL;
+!in return T_NOT_IN;
+in return T_IN;
+&& return T_LOGICAL_AND;
+\|\| return T_LOGICAL_OR;
[a-zA-Z_][:a-zA-Z0-9\-_]* { yylval->text = strdup(yytext); return T_IDENTIFIER; }
\<[^\>]*\> { yytext[yyleng-1] = '\0'; yylval->text = strdup(yytext + 1); return T_STRING_ANGLE; }
-?[0-9]+(\.[0-9]+)?ms { yylval->num = strtod(yytext, NULL) / 1000; return T_NUMBER; }
@@ -232,7 +241,7 @@ const return T_CONST;
-?[0-9]+(\.[0-9]+)?m { yylval->num = strtod(yytext, NULL) * 60; return T_NUMBER; }
-?[0-9]+(\.[0-9]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-?[0-9]+(\.[0-9]+)? { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-= { yylval->op = OperatorSet; return T_EQUAL; }
+= { yylval->op = OperatorSet; return T_SET; }
\+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; }
-= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; }
\*= { yylval->op = OperatorMultiply; return T_MULTIPLY_EQUAL; }
diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy
index 3a5209dec..f508747a6 100644
--- a/lib/config/config_parser.yy
+++ b/lib/config/config_parser.yy
@@ -27,11 +27,13 @@
#include "config/typerule.h"
#include "config/typerulelist.h"
#include "config/aexpression.h"
+#include "config/applyrule.h"
#include "base/value.h"
#include "base/utility.h"
#include "base/array.h"
#include "base/scriptvariable.h"
#include "base/exception.h"
+#include "base/dynamictype.h"
#include
#include
#include
@@ -69,7 +71,7 @@ using namespace icinga;
%token T_NUMBER
%token T_NULL
%token T_IDENTIFIER
-%token T_EQUAL "= (T_EQUAL)"
+%token T_SET "= (T_SET)"
%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
%token T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
@@ -78,6 +80,12 @@ using namespace icinga;
%token T_CONST "const (T_CONST)"
%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
+%token T_EQUAL "== (T_EQUAL)"
+%token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
+%token T_IN "in (T_IN)"
+%token T_NOT_IN "!in (T_NOT_IN)"
+%token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
+%token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
%token T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
@@ -96,11 +104,12 @@ using namespace icinga;
%token T_LIBRARY "library (T_LIBRARY)"
%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)"
%type identifier
-%type array
%type array_items
%type array_items_inner
-%type simplevalue
%type value
%type expression
%type expressions
@@ -112,13 +121,20 @@ using namespace icinga;
%type partial_specifier
%type object_inherits_list
%type object_inherits_specifier
-%type aterm
%type aexpression
%type variable_decl
+%left T_LOGICAL_OR
+%left T_LOGICAL_AND
+%left T_IN
+%left T_NOT_IN
+%nonassoc T_EQUAL
+%nonassoc T_NOT_EQUAL
%left '+' '-'
%left '*' '/'
%left '&'
%left '|'
+%right '~'
+%right '!'
%{
int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
@@ -156,7 +172,7 @@ statements: /* empty */
| statements statement
;
-statement: object | type | include | include_recursive | library | variable
+statement: object | type | include | include_recursive | library | variable | apply
;
include: T_INCLUDE value
@@ -191,7 +207,7 @@ library: T_LIBRARY T_STRING
}
;
-variable: variable_decl identifier T_EQUAL value
+variable: variable_decl identifier T_SET value
{
Value *value = $4;
if (value->IsObjectType()) {
@@ -480,7 +496,7 @@ expression: identifier operator value
}
;
-operator: T_EQUAL
+operator: T_SET
| T_PLUS_EQUAL
| T_MINUS_EQUAL
| T_MULTIPLY_EQUAL
@@ -490,12 +506,6 @@ operator: T_EQUAL
}
;
-array: '[' array_items ']'
- {
- $$ = $2;
- }
- ;
-
array_items: array_items_inner
{
$$ = $1;
@@ -509,153 +519,176 @@ array_items_inner: /* empty */
{
$$ = NULL;
}
- | value
+ | aexpression
{
$$ = new Array();
-
- if ($1->IsObjectType()) {
- ExpressionList::Ptr exprl = *$1;
- Dictionary::Ptr dict = make_shared();
- exprl->Execute(dict);
- delete $1;
- $1 = new Value(dict);
- }
-
$$->Add(*$1);
delete $1;
}
- | array_items_inner ',' value
+ | array_items_inner ',' aexpression
{
if ($1)
$$ = $1;
else
$$ = new Array();
- if ($3->IsObjectType()) {
- ExpressionList::Ptr exprl = *$3;
- Dictionary::Ptr dict = make_shared();
- exprl->Execute(dict);
- delete $3;
- $3 = new Value(dict);
- }
-
$$->Add(*$3);
delete $3;
}
;
-simplevalue: T_STRING
+aexpression: T_STRING
{
- $$ = new Value($1);
+ $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), yylloc));
free($1);
}
| T_NUMBER
{
- $$ = new Value($1);
+ $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), yylloc));
}
| T_NULL
{
- $$ = new Value();
+ $$ = new Value(make_shared(AEReturn, AValue(ATSimple, Empty), yylloc));
}
- | array
+ | T_IDENTIFIER '(' array_items ')'
{
- if ($1 == NULL)
- $1 = new Array();
-
- Array::Ptr array = Array::Ptr($1);
- $$ = new Value(array);
- }
- ;
-
-aterm: '(' aexpression ')'
- {
- $$ = $2;
- }
-
-aexpression: T_STRING
- {
- $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1)));
+ Array::Ptr arguments = Array::Ptr($3);
+ $$ = new Value(make_shared(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc));
free($1);
}
- | T_NUMBER
- {
- $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1)));
- }
| T_IDENTIFIER
{
- $$ = new Value(make_shared(AEReturn, AValue(ATVariable, $1)));
+ $$ = new Value(make_shared(AEReturn, AValue(ATVariable, $1), yylloc));
free($1);
}
+ | '!' aexpression
+ {
+ $$ = new Value(make_shared(AENegate, static_cast(*$2), yylloc));
+ delete $2;
+ }
| '~' aexpression
{
- $$ = new Value(make_shared(AENegate, static_cast(*$2)));
+ $$ = new Value(make_shared(AENegate, static_cast(*$2), yylloc));
delete $2;
}
- | aexpression '+' aexpression
+ | '[' array_items ']'
{
- $$ = new Value(make_shared(AEAdd, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression '-' aexpression
- {
- $$ = new Value(make_shared(AESubtract, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression '*' aexpression
- {
- $$ = new Value(make_shared(AEMultiply, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression '/' aexpression
- {
- $$ = new Value(make_shared(AEDivide, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression '&' aexpression
- {
- $$ = new Value(make_shared(AEBinaryAnd, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression '|' aexpression
- {
- $$ = new Value(make_shared(AEBinaryOr, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression T_SHIFT_LEFT aexpression
- {
- $$ = new Value(make_shared(AEShiftLeft, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
- }
- | aexpression T_SHIFT_RIGHT aexpression
- {
- $$ = new Value(make_shared(AEShiftRight, static_cast(*$1), static_cast(*$3)));
- delete $1;
- delete $3;
+ $$ = new Value(make_shared(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc));
}
| '(' aexpression ')'
{
$$ = $2;
}
+ | aexpression '+' aexpression
+ {
+ $$ = new Value(make_shared(AEAdd, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression '-' aexpression
+ {
+ $$ = new Value(make_shared(AESubtract, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression '*' aexpression
+ {
+ $$ = new Value(make_shared(AEMultiply, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression '/' aexpression
+ {
+ $$ = new Value(make_shared(AEDivide, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression '&' aexpression
+ {
+ $$ = new Value(make_shared(AEBinaryAnd, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression '|' aexpression
+ {
+ $$ = new Value(make_shared(AEBinaryOr, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_IN aexpression
+ {
+ $$ = new Value(make_shared(AEIn, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_NOT_IN aexpression
+ {
+ $$ = new Value(make_shared(AENotIn, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_EQUAL aexpression
+ {
+ $$ = new Value(make_shared(AEEqual, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_NOT_EQUAL aexpression
+ {
+ $$ = new Value(make_shared(AENotEqual, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_SHIFT_LEFT aexpression
+ {
+ $$ = new Value(make_shared(AEShiftLeft, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_SHIFT_RIGHT aexpression
+ {
+ $$ = new Value(make_shared(AEShiftRight, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_LOGICAL_AND aexpression
+ {
+ $$ = new Value(make_shared(AELogicalAnd, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
+ | aexpression T_LOGICAL_OR aexpression
+ {
+ $$ = new Value(make_shared(AELogicalOr, static_cast(*$1), static_cast(*$3), yylloc));
+ delete $1;
+ delete $3;
+ }
;
-value: simplevalue
- | expressionlist
+value: expressionlist
{
ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
$$ = new Value(exprl);
}
- | aterm
+ | aexpression
{
AExpression::Ptr aexpr = *$1;
- $$ = new Value(aexpr->Evaluate(Object::Ptr()));
+ $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
delete $1;
}
;
+
+optional_template: /* empty */
+ | T_TEMPLATE
+ ;
+
+apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE aexpression
+ {
+ if (!ApplyRule::IsValidCombination($3, $6)) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'."));
+ }
+
+ ApplyRule::AddRule($3, $4, $6, *$8, yylloc);
+ delete $8;
+ }
%%
diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp
index 8e7635776..841075dff 100644
--- a/lib/config/configitem.cpp
+++ b/lib/config/configitem.cpp
@@ -19,6 +19,7 @@
#include "config/configitem.h"
#include "config/configcompilercontext.h"
+#include "config/applyrule.h"
#include "base/application.h"
#include "base/dynamictype.h"
#include "base/objectlock.h"
@@ -303,6 +304,9 @@ bool ConfigItem::ActivateItems(bool validateOnly)
upq.Join();
+ Log(LogInformation, "config", "Evaluating 'apply' rules...");
+ ApplyRule::EvaluateRules();
+
Log(LogInformation, "config", "Validating config items (step 2)...");
BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
diff --git a/lib/icinga/CMakeLists.txt b/lib/icinga/CMakeLists.txt
index 8dab566a8..5ea9d54ff 100644
--- a/lib/icinga/CMakeLists.txt
+++ b/lib/icinga/CMakeLists.txt
@@ -43,7 +43,7 @@ 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 hostgroup.cpp hostgroup.th
+ externalcommandprocessor.cpp host.cpp host.th host-apply.cpp hostgroup.cpp hostgroup.th
icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
icingastatuswriter.th legacytimeperiod.cpp
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th
diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp
new file mode 100644
index 000000000..46b1beb48
--- /dev/null
+++ b/lib/icinga/host-apply.cpp
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * 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/host.h"
+#include "config/configitembuilder.h"
+#include "base/initialize.h"
+#include "base/dynamictype.h"
+#include "base/convert.h"
+#include "base/logger_fwd.h"
+#include "base/context.h"
+#include
+
+using namespace icinga;
+
+INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler);
+
+void Host::RegisterApplyRuleHandler(void)
+{
+ ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules);
+}
+
+void Host::EvaluateApplyRules(const std::vector& rules)
+{
+ BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects()) {
+ CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'");
+
+ Dictionary::Ptr locals = make_shared();
+ locals->Set("host", host->GetName());
+
+ Array::Ptr groups = host->GetGroups();
+ if (!groups)
+ groups = make_shared();
+ locals->Set("hostgroups", groups);
+
+ BOOST_FOREACH(const ApplyRule& rule, rules) {
+ std::ostringstream msgbuf;
+ msgbuf << "Evaluating 'apply' rule (" << rule.GetDebugInfo() << ")";
+ CONTEXT(msgbuf.str());
+
+ Value result = rule.GetExpression()->Evaluate(locals);
+
+ try {
+ if (!static_cast(result))
+ continue;
+ } catch (...) {
+ std::ostringstream msgbuf;
+ msgbuf << "Apply rule (" << rule.GetDebugInfo() << ") returned invalid data type, expected bool: " + JsonSerialize(result);
+ Log(LogCritical, "icinga", msgbuf.str());
+
+ continue;
+ }
+
+ std::ostringstream msgbuf2;
+ msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << rule.GetDebugInfo();
+ Log(LogDebug, "icinga", msgbuf2.str());
+
+ std::ostringstream namebuf;
+ namebuf << host->GetName() << "!apply!" << rule.GetTemplate();
+ String name = namebuf.str();
+
+ ConfigItemBuilder::Ptr builder = make_shared(rule.GetDebugInfo());
+ builder->SetType("Service");
+ builder->SetName(name);
+ builder->AddExpression("host", OperatorSet, host->GetName());
+
+ builder->AddParent(rule.GetTemplate());
+
+ ConfigItem::Ptr serviceItem = builder->Compile();
+ serviceItem->Register();
+ DynamicObject::Ptr dobj = serviceItem->Commit();
+ dobj->OnConfigLoaded();
+ }
+ }
+}
diff --git a/lib/icinga/host.h b/lib/icinga/host.h
index 21c6d7f34..c49fab286 100644
--- a/lib/icinga/host.h
+++ b/lib/icinga/host.h
@@ -24,6 +24,7 @@
#include "icinga/host.th"
#include "icinga/macroresolver.h"
#include "icinga/checkresult.h"
+#include "config/applyrule.h"
#include "base/array.h"
#include "base/dictionary.h"
@@ -101,6 +102,9 @@ public:
virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const;
+ static void RegisterApplyRuleHandler(void);
+ static void EvaluateApplyRules(const std::vector& rules);
+
protected:
virtual void Stop(void);
diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt
index a689d4e9d..281c0a88d 100644
--- a/lib/methods/CMakeLists.txt
+++ b/lib/methods/CMakeLists.txt
@@ -18,7 +18,7 @@
add_library(methods SHARED
icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp
pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.cpp
- randomchecktask.cpp timeperiodtask.cpp
+ randomchecktask.cpp timeperiodtask.cpp utilityfuncs.cpp
)
target_link_libraries(methods ${Boost_LIBRARIES} base config icinga)
diff --git a/lib/methods/utilityfuncs.cpp b/lib/methods/utilityfuncs.cpp
new file mode 100644
index 000000000..298b597e8
--- /dev/null
+++ b/lib/methods/utilityfuncs.cpp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * 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 "methods/utilityfuncs.h"
+#include "base/scriptfunction.h"
+#include "base/utility.h"
+#include
+
+using namespace icinga;
+
+REGISTER_SCRIPTFUNCTION(regex, &UtilityFuncs::Regex);
+REGISTER_SCRIPTFUNCTION(match, &Utility::Match);
+
+bool UtilityFuncs::Regex(const String& pattern, const String& text)
+{
+ boost::regex expr(pattern.GetData());
+ boost::smatch what;
+ return boost::regex_search(text.GetData(), what, expr);
+}
diff --git a/lib/methods/utilityfuncs.h b/lib/methods/utilityfuncs.h
new file mode 100644
index 000000000..7612672be
--- /dev/null
+++ b/lib/methods/utilityfuncs.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * 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. *
+ ******************************************************************************/
+
+#ifndef UTILITYFUNCS_H
+#define UTILITYFUNCS_H
+
+#include "methods/i2-methods.h"
+#include "base/qstring.h"
+
+namespace icinga
+{
+
+/**
+ * @ingroup methods
+ */
+class I2_METHODS_API UtilityFuncs
+{
+public:
+ static bool Regex(const String& pattern, const String& text);
+
+private:
+ UtilityFuncs(void);
+};
+
+}
+
+#endif /* UTILITYFUNCS_H */