Merge branch 'feature/apply-5789' into next

Fixes #5789
This commit is contained in:
Gunnar Beutner 2014-03-19 12:48:47 +01:00
commit c146ca272f
32 changed files with 692 additions and 226 deletions

View File

@ -113,7 +113,7 @@ If you require default macro definitions, you can add a macro dictionary as show
`CheckCommand` object. `CheckCommand` object.
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { 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 = [ export_macros = [
"NOTIFICATIONTYPE", "NOTIFICATIONTYPE",

View File

@ -273,7 +273,7 @@ Example:
... ...
{ {
check_interval = (MyCheckInterval / 2.5) check_interval = MyCheckInterval / 2.5
} }
More details in the chapter [Constant Expressions](#constant-expressions). More details in the chapter [Constant Expressions](#constant-expressions).

View File

@ -25,11 +25,11 @@ The user `icingaadmin` in the example below will get notified only on `WARNING`
object User "icingaadmin" { object User "icingaadmin" {
display_name = "Icinga 2 Admin", display_name = "Icinga 2 Admin",
enable_notifications = 1, enable_notifications = 1,
notification_state_filter = (StateFilterOK | notification_state_filter = StateFilterOK |
StateFilterWarning | StateFilterWarning |
StateFilterCritical), StateFilterCritical,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterRecovery), NotificationFilterRecovery,
macros = { macros = {
"email" = "icinga@localhost", "email" = "icinga@localhost",
"pager" = "+49123456789" "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. The example below may or may not fit your needs.
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { 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 = [ export_macros = [
"NOTIFICATIONTYPE", "NOTIFICATIONTYPE",
@ -91,18 +91,18 @@ to the defined notifications. That way you'll save duplicated attributes in each
notification_command = "mail-service-notification", notification_command = "mail-service-notification",
notification_state_filter = (StateFilterWarning | notification_state_filter = StateFilterWarning |
StateFilterCritical | StateFilterCritical |
StateFilterUnknown), StateFilterUnknown,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement | NotificationFilterAcknowledgement |
NotificationFilterRecovery | NotificationFilterRecovery |
NotificationFilterCustom | NotificationFilterCustom |
NotificationFilterFlappingStart | NotificationFilterFlappingStart |
NotificationFilterFlappingEnd | NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart | NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd | NotificationFilterDowntimeEnd |
NotificationFilterDowntimeRemoved), NotificationFilterDowntimeRemoved,
notification_period = "24x7" notification_period = "24x7"
} }
@ -274,18 +274,18 @@ Available state and type filters for notifications are:
template Notification "generic-notification" { template Notification "generic-notification" {
notification_state_filter = (StateFilterWarning | notification_state_filter = StateFilterWarning |
StateFilterCritical | StateFilterCritical |
StateFilterUnknown), StateFilterUnknown,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement | NotificationFilterAcknowledgement |
NotificationFilterRecovery | NotificationFilterRecovery |
NotificationFilterCustom | NotificationFilterCustom |
NotificationFilterFlappingStart | NotificationFilterFlappingStart |
NotificationFilterFlappingEnd | NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart | NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd | NotificationFilterDowntimeEnd |
NotificationFilterDowntimeRemoved), NotificationFilterDowntimeRemoved,
} }
> **Note** > **Note**

View File

@ -317,14 +317,14 @@ Constants cannot be changed once they are set.
Simple calculations can be performed using the constant expression syntax: 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: overridden by grouping expressions using parentheses:
{ {
check_interval ((15 * 60) / 2) check_interval = (30 + 60) / 2
} }
Global constants may be used in constant expressions. 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** > **Note**
> >
> Constant expressions are evaluated as soon as they're encountered in > Constant expressions in attributes and variable definitions are evaluated as
> the configuration file. > soon as they're encountered in the configuration file.
### <a id="apply"></a> Apply
The `apply` keyword can be used to associate a template with another group of
objects. The exact effect of this association depends on the two object types.
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.
### <a id="comments"></a> Comments ### <a id="comments"></a> Comments

View File

@ -214,7 +214,7 @@ Example:
parent_host = "internet", parent_host = "internet",
parent_service = "ping4", parent_service = "ping4",
state_filter = (StateFilterOK), state_filter = StateFilterOK,
disable_checks = true disable_checks = true
} }
@ -230,7 +230,7 @@ Attributes:
disable_checks |**Optional.** Whether to disable checks when this dependency fails. Defaults to false. 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. disable_notifications|**Optional.** Whether to disable notifications when this dependency fails. Defaults to true.
period |**Optional.** Time period during which this dependency is enabled. 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 &#124; StateFilterWarning). state_filter |**Optional.** A set of type filters when this dependency should be OK. Defaults to StateFilterOK &#124; StateFilterWarning.
Available state filters: Available state filters:
@ -252,12 +252,12 @@ Example:
enable_notifications = 1, enable_notifications = 1,
notification_period = "24x7", notification_period = "24x7",
notification_state_filter = (StateFilterOK | notification_state_filter = StateFilterOK |
StateFilterWarning | StateFilterWarning |
StateFilterCritical | StateFilterCritical |
StateFilterUnknown), StateFilterUnknown,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterRecovery), NotificationFilterRecovery,
macros = { macros = {
"name" = "Icinga 2 Admin", "name" = "Icinga 2 Admin",
"email" = "icinga@localhost", "email" = "icinga@localhost",
@ -458,7 +458,7 @@ A notification command definition.
Example: Example:
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { 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 = [ export_macros = [
"NOTIFICATIONTYPE", "NOTIFICATIONTYPE",
@ -588,7 +588,7 @@ Example:
logentries_age = 31d, logentries_age = 31d,
}, },
categories = (DbCatConfig | DbCatState) categories = DbCatConfig | DbCatState
} }
Attributes: Attributes:
@ -672,7 +672,7 @@ Example:
logentries_age = 31d, logentries_age = 31d,
}, },
categories = (DbCatConfig | DbCatState) categories = DbCatConfig | DbCatState
} }
Attributes: Attributes:
@ -877,7 +877,7 @@ a defined JSON file.
Example: Example:
object IcingaStatusWriter "status" { object IcingaStatusWriter "status" {
status_path = (IcingaLocalStateDir + "/cache/icinga2/status.json"), status_path = IcingaLocalStateDir + "/cache/icinga2/status.json",
update_interval = 15s update_interval = 15s
} }
@ -962,8 +962,8 @@ Example:
object Domain "dmz-1" { object Domain "dmz-1" {
acl = { acl = {
node1 = (DomainPrivCheckResult), node1 = DomainPrivCheckResult,
node2 = (DomainPrivReadWrite) node2 = DomainPrivReadWrite
} }
} }
@ -980,5 +980,5 @@ Domain ACLs:
DomainPrivRead | Endpoint reads local messages and relays them to remote nodes. DomainPrivRead | Endpoint reads local messages and relays them to remote nodes.
DomainPrivCheckResult | Endpoint accepts check result messages from remote nodes. DomainPrivCheckResult | Endpoint accepts check result messages from remote nodes.
DomainPrivCommand | Endpoint accepts command messages from remote nodes. DomainPrivCommand | Endpoint accepts command messages from remote nodes.
DomainPrevReadOnly | Endpoint reads local messages and relays them to remote nodes. DomainPrevReadOnly | Equivalent to DomainPrivRead.
DomainPrivReadWrite | Combination of (DomainPrivRead | DomainPrivCheckResult | DomainPrivCommand) DomainPrivReadWrite | Equivalent to DomainPrivRead &#124; DomainPrivCheckResult &#124; DomainPrivCommand.

View File

@ -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 instance you will have to add the following include directive to your
`icinga2.conf` configuration file: `icinga2.conf` configuration file:
include (IcingaLocalStateDir + "/lib/icinga2/cluster/config/*/*") include IcingaLocalStateDir + "/lib/icinga2/cluster/config/*/*"
### <a id="initial-cluster-sync"></a> Initial Cluster Sync ### <a id="initial-cluster-sync"></a> Initial Cluster Sync

View File

@ -25,7 +25,7 @@ from the `icinga-node-dmz-1` endpoint.
object Domain "dmz-db" { object Domain "dmz-db" {
acl = { acl = {
icinga-node-dmz-1 = (DomainPrivReadOnly), icinga-node-dmz-1 = DomainPrivReadOnly,
icinga-node-dmz-2 = (DomainPrivReadWrite) icinga-node-dmz-2 = DomainPrivReadWrite
} }
} }

View File

@ -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_options w,u,c,r,f,s
notification_state_filter = (StateFilterWarning | StateFilterUnknown | StateFilterCritical), notification_state_filter = StateFilterWarning | StateFilterUnknown | StateFilterCritical,
notification_type_filter = (NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd | NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved) notification_type_filter = NotificationProblem | NotificationRecovery | NotificationFlappingStart | NotificationFlappingEnd | NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved
> **Note** > **Note**
> >

View File

@ -7,10 +7,10 @@ template User "generic-user" {
enable_notifications = true, enable_notifications = true,
notification_period = "24x7", notification_period = "24x7",
notification_state_filter = (StateFilterWarning | notification_state_filter = StateFilterWarning |
StateFilterCritical | StateFilterCritical |
StateFilterUnknown), StateFilterUnknown,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement | NotificationFilterAcknowledgement |
NotificationFilterRecovery | NotificationFilterRecovery |
NotificationFilterCustom | NotificationFilterCustom |
@ -18,5 +18,5 @@ template User "generic-user" {
NotificationFilterFlappingEnd | NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart | NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd | NotificationFilterDowntimeEnd |
NotificationFilterDowntimeRemoved) NotificationFilterDowntimeRemoved
} }

View File

@ -5,11 +5,11 @@
template Notification "mail-notification" { template Notification "mail-notification" {
notification_command = "mail-service-notification", notification_command = "mail-service-notification",
notification_state_filter = (StateFilterOK | notification_state_filter = StateFilterOK |
StateFilterWarning | StateFilterWarning |
StateFilterCritical | StateFilterCritical |
StateFilterUnknown), StateFilterUnknown,
notification_type_filter = (NotificationFilterProblem | notification_type_filter = NotificationFilterProblem |
NotificationFilterAcknowledgement | NotificationFilterAcknowledgement |
NotificationFilterRecovery | NotificationFilterRecovery |
NotificationFilterCustom | NotificationFilterCustom |
@ -17,13 +17,13 @@ template Notification "mail-notification" {
NotificationFilterFlappingEnd | NotificationFilterFlappingEnd |
NotificationFilterDowntimeStart | NotificationFilterDowntimeStart |
NotificationFilterDowntimeEnd | NotificationFilterDowntimeEnd |
NotificationFilterDowntimeRemoved), NotificationFilterDowntimeRemoved,
notification_period = "24x7" notification_period = "24x7"
} }
object NotificationCommand "mail-service-notification" inherits "plugin-notification-command" { 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 = [ export_macros = [
"NOTIFICATIONTYPE", "NOTIFICATIONTYPE",

View File

@ -6,6 +6,6 @@
object FileLogger "debug-file" { object FileLogger "debug-file" {
severity = "debug", severity = "debug",
path = (IcingaLocalStateDir + "/log/icinga2/debug.log") path = IcingaLocalStateDir + "/log/icinga2/debug.log"
} }

View File

@ -4,6 +4,6 @@
object FileLogger "main-log" { object FileLogger "main-log" {
severity = "information", severity = "information",
path = (IcingaLocalStateDir + "/log/icinga2/icinga2.log") path = IcingaLocalStateDir + "/log/icinga2/icinga2.log"
} }

View File

@ -136,6 +136,11 @@ std::string& String::GetData(void)
return m_Data; return m_Data;
} }
const std::string& String::GetData(void) const
{
return m_Data;
}
size_t String::Find(const String& str, size_t pos) const size_t String::Find(const String& str, size_t pos) const
{ {
return m_Data.find(str, pos); return m_Data.find(str, pos);

View File

@ -80,6 +80,7 @@ public:
size_t GetLength(void) const; size_t GetLength(void) const;
std::string& GetData(void); std::string& GetData(void);
const std::string& GetData(void) const;
size_t Find(const String& str, size_t pos = 0) const; size_t Find(const String& str, size_t pos = 0) const;
size_t RFind(const String& str, size_t pos = NPos) const; size_t RFind(const String& str, size_t pos = NPos) const;

View File

@ -196,7 +196,7 @@ ValueType Value::GetType(void) const
return static_cast<ValueType>(m_Value.which()); return static_cast<ValueType>(m_Value.which());
} }
bool Value::operator==(bool rhs) bool Value::operator==(bool rhs) const
{ {
if (!IsScalar()) if (!IsScalar())
return false; return false;
@ -204,12 +204,12 @@ bool Value::operator==(bool rhs)
return static_cast<double>(*this) == rhs; return static_cast<double>(*this) == rhs;
} }
bool Value::operator!=(bool rhs) bool Value::operator!=(bool rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
bool Value::operator==(int rhs) bool Value::operator==(int rhs) const
{ {
if (!IsScalar()) if (!IsScalar())
return false; return false;
@ -217,12 +217,12 @@ bool Value::operator==(int rhs)
return static_cast<double>(*this) == rhs; return static_cast<double>(*this) == rhs;
} }
bool Value::operator!=(int rhs) bool Value::operator!=(int rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
bool Value::operator==(double rhs) bool Value::operator==(double rhs) const
{ {
if (!IsScalar()) if (!IsScalar())
return false; return false;
@ -230,32 +230,32 @@ bool Value::operator==(double rhs)
return static_cast<double>(*this) == rhs; return static_cast<double>(*this) == rhs;
} }
bool Value::operator!=(double rhs) bool Value::operator!=(double rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
bool Value::operator==(const char *rhs) bool Value::operator==(const char *rhs) const
{ {
return static_cast<String>(*this) == rhs; return static_cast<String>(*this) == rhs;
} }
bool Value::operator!=(const char *rhs) bool Value::operator!=(const char *rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
bool Value::operator==(const String& rhs) bool Value::operator==(const String& rhs) const
{ {
return static_cast<String>(*this) == rhs; return static_cast<String>(*this) == rhs;
} }
bool Value::operator!=(const String& rhs) bool Value::operator!=(const String& rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
bool Value::operator==(const Value& rhs) bool Value::operator==(const Value& rhs) const
{ {
if (IsEmpty() != rhs.IsEmpty()) if (IsEmpty() != rhs.IsEmpty())
return false; return false;
@ -275,7 +275,7 @@ bool Value::operator==(const Value& rhs)
return static_cast<String>(*this) == static_cast<String>(rhs); return static_cast<String>(*this) == static_cast<String>(rhs);
} }
bool Value::operator!=(const Value& rhs) bool Value::operator!=(const Value& rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }

View File

@ -73,23 +73,23 @@ public:
operator double(void) const; operator double(void) const;
operator String(void) const; operator String(void) const;
bool operator==(bool rhs); bool operator==(bool rhs) const;
bool operator!=(bool rhs); bool operator!=(bool rhs) const;
bool operator==(int rhs); bool operator==(int rhs) const;
bool operator!=(int rhs); bool operator!=(int rhs) const;
bool operator==(double rhs); bool operator==(double rhs) const;
bool operator!=(double rhs); bool operator!=(double rhs) const;
bool operator==(const char *rhs); bool operator==(const char *rhs) const;
bool operator!=(const char *rhs); bool operator!=(const char *rhs) const;
bool operator==(const String& rhs); bool operator==(const String& rhs) const;
bool operator!=(const String& rhs); bool operator!=(const String& rhs) const;
bool operator==(const Value& rhs); bool operator==(const Value& rhs) const;
bool operator!=(const Value& rhs); bool operator!=(const Value& rhs) const;
template<typename T> template<typename T>
operator shared_ptr<T>(void) const operator shared_ptr<T>(void) const

View File

@ -27,7 +27,7 @@ mkembedconfig_target(base-type.conf base-type.cpp)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
add_library(config SHARED 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 configcompilercontext.cpp configcompiler.cpp configitembuilder.cpp
configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS} configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS}
configtype.cpp expression.cpp expressionlist.cpp typerule.cpp typerulelist.cpp configtype.cpp expression.cpp expressionlist.cpp typerule.cpp typerulelist.cpp

View File

@ -18,28 +18,44 @@
******************************************************************************/ ******************************************************************************/
#include "config/aexpression.h" #include "config/aexpression.h"
#include "base/array.h"
#include "base/serializer.h"
#include "base/context.h"
#include "base/scriptfunction.h"
#include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
AExpression::AExpression(AOperator op, const AValue& operand1) AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1) : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di)
{ {
ASSERT(op == AEReturn); ASSERT(op == AEReturn);
} }
AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2) AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1), m_Operand2(operand2) : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
{ {
ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide || 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; Value left, right;
Array::Ptr arr, arr2;
bool found;
String funcName;
ScriptFunction::Ptr func;
std::vector<Value> arguments;
left = m_Operand1.Evaluate(thisRef); left = m_Operand1.Evaluate(locals);
right = m_Operand2.Evaluate(thisRef); 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) { switch (m_Operator) {
case AEReturn: case AEReturn:
@ -65,8 +81,65 @@ Value AExpression::Evaluate(const Object::Ptr& thisRef) const
return (long)left << (long)right; return (long)left << (long)right;
case AEShiftRight: case AEShiftRight:
return (long)left >> (long)right; return (long)left >> (long)right;
case AEEqual:
return left == right;
case AENotEqual:
return left != right;
case AEIn:
if (!right.IsObjectType<Array>())
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<Array>())
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<Array>();
BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
arr2->Add(aexpr->Evaluate(locals));
}
return arr2;
default: default:
ASSERT(!"Invalid operator."); ASSERT(!"Invalid operator.");
} }
} }

View File

@ -22,7 +22,8 @@
#include "config/i2-config.h" #include "config/i2-config.h"
#include "config/avalue.h" #include "config/avalue.h"
#include "base/object.h" #include "config/debuginfo.h"
#include "base/dictionary.h"
namespace icinga namespace icinga
{ {
@ -41,7 +42,15 @@ enum AOperator
AEBinaryAnd, AEBinaryAnd,
AEBinaryOr, AEBinaryOr,
AEShiftLeft, AEShiftLeft,
AEShiftRight AEShiftRight,
AEEqual,
AENotEqual,
AEIn,
AENotIn,
AELogicalAnd,
AELogicalOr,
AEFunctionCall,
AEArray
}; };
/** /**
@ -52,15 +61,16 @@ class I2_CONFIG_API AExpression : public Object
public: public:
DECLARE_PTR_TYPEDEFS(AExpression); DECLARE_PTR_TYPEDEFS(AExpression);
AExpression(AOperator op, const AValue& operand1); AExpression(AOperator op, const AValue& operand1, const DebugInfo& di);
AExpression(AOperator op, const AValue& operand1, const AValue& operand2); 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: private:
AOperator m_Operator; AOperator m_Operator;
AValue m_Operand1; AValue m_Operand1;
AValue m_Operand2; AValue m_Operand2;
DebugInfo m_DebugInfo;
}; };
} }

72
lib/config/applyrule.cpp Normal file
View File

@ -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<TypeCombination, Callback> 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();
}

65
lib/config/applyrule.h Normal file
View File

@ -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<String, String> TypeCombination;
typedef boost::function<void (const std::vector<ApplyRule>& rules)> Callback;
typedef std::map<TypeCombination, Callback> CallbackMap;
typedef std::map<TypeCombination, std::vector<ApplyRule> > RuleMap;
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 */

View File

@ -35,17 +35,20 @@ AValue::AValue(AValueType type, const Value& value)
: m_Type(type), m_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) { switch (m_Type) {
case ATSimple: case ATSimple:
return m_Value; return m_Value;
case ATVariable: 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: case ATThisRef:
VERIFY(!"Not implemented."); VERIFY(!"Not implemented.");
case ATExpression: case ATExpression:
return m_Expression->Evaluate(thisRef); return m_Expression->Evaluate(locals);
default: default:
ASSERT(!"Invalid type."); ASSERT(!"Invalid type.");
} }

View File

@ -22,7 +22,7 @@
#include "config/i2-config.h" #include "config/i2-config.h"
#include "base/value.h" #include "base/value.h"
#include "base/object.h" #include "base/dictionary.h"
namespace icinga namespace icinga
{ {
@ -50,7 +50,7 @@ public:
AValue(const shared_ptr<AExpression>& expr); AValue(const shared_ptr<AExpression>& expr);
AValue(AValueType type, const Value& value); AValue(AValueType type, const Value& value);
Value Evaluate(const Object::Ptr& thisRef) const; Value Evaluate(const Dictionary::Ptr& locals) const;
private: private:
AValueType m_Type; AValueType m_Type;

View File

@ -222,8 +222,17 @@ false { yylval->num = 0; return T_NUMBER; }
set return T_VAR; set return T_VAR;
var return T_VAR; var return T_VAR;
const return T_CONST; const return T_CONST;
apply return T_APPLY;
to return T_TO;
where return T_WHERE;
\<\< return T_SHIFT_LEFT; \<\< return T_SHIFT_LEFT;
\>\> return T_SHIFT_RIGHT; \>\> 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; } [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; } \<[^\>]*\> { 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; } -?[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]+)?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]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-?[0-9]+(\.[0-9]+)? { 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 = OperatorPlus; return T_PLUS_EQUAL; }
-= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; } -= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; }
\*= { yylval->op = OperatorMultiply; return T_MULTIPLY_EQUAL; } \*= { yylval->op = OperatorMultiply; return T_MULTIPLY_EQUAL; }

View File

@ -27,11 +27,13 @@
#include "config/typerule.h" #include "config/typerule.h"
#include "config/typerulelist.h" #include "config/typerulelist.h"
#include "config/aexpression.h" #include "config/aexpression.h"
#include "config/applyrule.h"
#include "base/value.h" #include "base/value.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/array.h" #include "base/array.h"
#include "base/scriptvariable.h" #include "base/scriptvariable.h"
#include "base/exception.h" #include "base/exception.h"
#include "base/dynamictype.h"
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -69,7 +71,7 @@ using namespace icinga;
%token <num> T_NUMBER %token <num> T_NUMBER
%token T_NULL %token T_NULL
%token <text> T_IDENTIFIER %token <text> T_IDENTIFIER
%token <op> T_EQUAL "= (T_EQUAL)" %token <op> T_SET "= (T_SET)"
%token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)" %token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
%token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)" %token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
%token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)" %token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
@ -78,6 +80,12 @@ using namespace icinga;
%token T_CONST "const (T_CONST)" %token T_CONST "const (T_CONST)"
%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)" %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)" %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 <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)" %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)" %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)" %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
@ -96,11 +104,12 @@ using namespace icinga;
%token T_LIBRARY "library (T_LIBRARY)" %token T_LIBRARY "library (T_LIBRARY)"
%token T_INHERITS "inherits (T_INHERITS)" %token T_INHERITS "inherits (T_INHERITS)"
%token T_PARTIAL "partial (T_PARTIAL)" %token T_PARTIAL "partial (T_PARTIAL)"
%token T_APPLY "apply (T_APPLY)"
%token T_TO "to (T_TO)"
%token T_WHERE "where (T_WHERE)"
%type <text> identifier %type <text> identifier
%type <array> array
%type <array> array_items %type <array> array_items
%type <array> array_items_inner %type <array> array_items_inner
%type <variant> simplevalue
%type <variant> value %type <variant> value
%type <expr> expression %type <expr> expression
%type <exprl> expressions %type <exprl> expressions
@ -112,13 +121,20 @@ using namespace icinga;
%type <num> partial_specifier %type <num> partial_specifier
%type <slist> object_inherits_list %type <slist> object_inherits_list
%type <slist> object_inherits_specifier %type <slist> object_inherits_specifier
%type <aexpr> aterm
%type <aexpr> aexpression %type <aexpr> aexpression
%type <num> variable_decl %type <num> 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 '*' '/'
%left '&' %left '&'
%left '|' %left '|'
%right '~'
%right '!'
%{ %{
int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
@ -156,7 +172,7 @@ statements: /* empty */
| statements statement | statements statement
; ;
statement: object | type | include | include_recursive | library | variable statement: object | type | include | include_recursive | library | variable | apply
; ;
include: T_INCLUDE value 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; Value *value = $4;
if (value->IsObjectType<ExpressionList>()) { if (value->IsObjectType<ExpressionList>()) {
@ -480,7 +496,7 @@ expression: identifier operator value
} }
; ;
operator: T_EQUAL operator: T_SET
| T_PLUS_EQUAL | T_PLUS_EQUAL
| T_MINUS_EQUAL | T_MINUS_EQUAL
| T_MULTIPLY_EQUAL | T_MULTIPLY_EQUAL
@ -490,12 +506,6 @@ operator: T_EQUAL
} }
; ;
array: '[' array_items ']'
{
$$ = $2;
}
;
array_items: array_items_inner array_items: array_items_inner
{ {
$$ = $1; $$ = $1;
@ -509,153 +519,176 @@ array_items_inner: /* empty */
{ {
$$ = NULL; $$ = NULL;
} }
| value | aexpression
{ {
$$ = new Array(); $$ = new Array();
if ($1->IsObjectType<ExpressionList>()) {
ExpressionList::Ptr exprl = *$1;
Dictionary::Ptr dict = make_shared<Dictionary>();
exprl->Execute(dict);
delete $1;
$1 = new Value(dict);
}
$$->Add(*$1); $$->Add(*$1);
delete $1; delete $1;
} }
| array_items_inner ',' value | array_items_inner ',' aexpression
{ {
if ($1) if ($1)
$$ = $1; $$ = $1;
else else
$$ = new Array(); $$ = new Array();
if ($3->IsObjectType<ExpressionList>()) {
ExpressionList::Ptr exprl = *$3;
Dictionary::Ptr dict = make_shared<Dictionary>();
exprl->Execute(dict);
delete $3;
$3 = new Value(dict);
}
$$->Add(*$3); $$->Add(*$3);
delete $3; delete $3;
} }
; ;
simplevalue: T_STRING aexpression: T_STRING
{ {
$$ = new Value($1); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
free($1); free($1);
} }
| T_NUMBER | T_NUMBER
{ {
$$ = new Value($1); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
} }
| T_NULL | T_NULL
{ {
$$ = new Value(); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, Empty), yylloc));
} }
| array | T_IDENTIFIER '(' array_items ')'
{ {
if ($1 == NULL) Array::Ptr arguments = Array::Ptr($3);
$1 = new Array(); $$ = new Value(make_shared<AExpression>(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc));
Array::Ptr array = Array::Ptr($1);
$$ = new Value(array);
}
;
aterm: '(' aexpression ')'
{
$$ = $2;
}
aexpression: T_STRING
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
free($1); free($1);
} }
| T_NUMBER
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
}
| T_IDENTIFIER | T_IDENTIFIER
{ {
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1))); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
free($1); free($1);
} }
| '!' aexpression
{
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
delete $2;
}
| '~' aexpression | '~' aexpression
{ {
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2))); $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
delete $2; delete $2;
} }
| aexpression '+' aexpression | '[' array_items ']'
{ {
$$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3))); $$ = new Value(make_shared<AExpression>(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc));
delete $1;
delete $3;
}
| aexpression '-' aexpression
{
$$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression '*' aexpression
{
$$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression '/' aexpression
{
$$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression '&' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression '|' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression T_SHIFT_LEFT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression T_SHIFT_RIGHT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
} }
| '(' aexpression ')' | '(' aexpression ')'
{ {
$$ = $2; $$ = $2;
} }
| aexpression '+' aexpression
{
$$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '-' aexpression
{
$$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '*' aexpression
{
$$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '/' aexpression
{
$$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '&' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '|' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_NOT_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_NOT_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_SHIFT_LEFT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_SHIFT_RIGHT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_LOGICAL_AND aexpression
{
$$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_LOGICAL_OR aexpression
{
$$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
; ;
value: simplevalue value: expressionlist
| expressionlist
{ {
ExpressionList::Ptr exprl = ExpressionList::Ptr($1); ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
$$ = new Value(exprl); $$ = new Value(exprl);
} }
| aterm | aexpression
{ {
AExpression::Ptr aexpr = *$1; AExpression::Ptr aexpr = *$1;
$$ = new Value(aexpr->Evaluate(Object::Ptr())); $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
delete $1; 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;
}
%% %%

View File

@ -19,6 +19,7 @@
#include "config/configitem.h" #include "config/configitem.h"
#include "config/configcompilercontext.h" #include "config/configcompilercontext.h"
#include "config/applyrule.h"
#include "base/application.h" #include "base/application.h"
#include "base/dynamictype.h" #include "base/dynamictype.h"
#include "base/objectlock.h" #include "base/objectlock.h"
@ -303,6 +304,9 @@ bool ConfigItem::ActivateItems(bool validateOnly)
upq.Join(); upq.Join();
Log(LogInformation, "config", "Evaluating 'apply' rules...");
ApplyRule::EvaluateRules();
Log(LogInformation, "config", "Validating config items (step 2)..."); Log(LogInformation, "config", "Validating config items (step 2)...");
BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {

View File

@ -43,7 +43,7 @@ add_library(icinga SHARED
api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th api.cpp api.h checkcommand.cpp checkcommand.th checkresult.cpp checkresult.th
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp dependency.cpp dependency.th
domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th 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 icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
icingastatuswriter.th legacytimeperiod.cpp icingastatuswriter.th legacytimeperiod.cpp
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th

90
lib/icinga/host-apply.cpp Normal file
View File

@ -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 <boost/foreach.hpp>
using namespace icinga;
INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler);
void Host::RegisterApplyRuleHandler(void)
{
ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules);
}
void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjects<Host>()) {
CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", host->GetName());
Array::Ptr groups = host->GetGroups();
if (!groups)
groups = make_shared<Array>();
locals->Set("hostgroups", groups);
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<bool>(result))
continue;
} catch (...) {
std::ostringstream msgbuf;
msgbuf << "Apply rule (" << rule.GetDebugInfo() << ") returned invalid data type, expected bool: " + JsonSerialize(result);
Log(LogCritical, "icinga", msgbuf.str());
continue;
}
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<ConfigItemBuilder>(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();
}
}
}

View File

@ -24,6 +24,7 @@
#include "icinga/host.th" #include "icinga/host.th"
#include "icinga/macroresolver.h" #include "icinga/macroresolver.h"
#include "icinga/checkresult.h" #include "icinga/checkresult.h"
#include "config/applyrule.h"
#include "base/array.h" #include "base/array.h"
#include "base/dictionary.h" #include "base/dictionary.h"
@ -101,6 +102,9 @@ public:
virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const; virtual bool ResolveMacro(const String& macro, const CheckResult::Ptr& cr, String *result) const;
static void RegisterApplyRuleHandler(void);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
protected: protected:
virtual void Stop(void); virtual void Stop(void);

View File

@ -18,7 +18,7 @@
add_library(methods SHARED add_library(methods SHARED
icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp
pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.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) target_link_libraries(methods ${Boost_LIBRARIES} base config icinga)

View File

@ -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 <boost/regex.hpp>
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);
}

View File

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