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 */