diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index e6d847ea0..0521c17c3 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -18,17 +18,21 @@ ******************************************************************************/ #include "config/aexpression.h" +#include "base/array.h" +#include "base/serializer.h" +#include "base/context.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); @@ -37,10 +41,16 @@ AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& ope Value AExpression::Evaluate(const Dictionary::Ptr& locals) const { Value left, right; + Array::Ptr arr; + bool found; 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: return left; @@ -69,6 +79,26 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const 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: + return left != right; + case AELogicalAnd: + return (long)left && (long)right; + case AELogicalOr: + return (long)left || (long)right; default: ASSERT(!"Invalid operator."); } diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index dd60cfd96..f78afe598 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -22,6 +22,7 @@ #include "config/i2-config.h" #include "config/avalue.h" +#include "config/debuginfo.h" #include "base/dictionary.h" namespace icinga @@ -44,6 +45,10 @@ enum AOperator AEShiftRight, AEEqual, AENotEqual, + AEIn, + AENotIn, + AELogicalAnd, + AELogicalOr }; /** @@ -54,8 +59,8 @@ 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 Dictionary::Ptr& locals) const; @@ -63,6 +68,7 @@ private: AOperator m_Operator; AValue m_Operand1; AValue m_Operand2; + DebugInfo m_DebugInfo; }; } diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 1e6aa4d34..f397a5ab7 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -227,6 +227,12 @@ 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; } @@ -235,8 +241,6 @@ where return T_WHERE; -?[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 = OperatorEqual; return T_EQUAL; } -!= { yylval->op = OperatorNotEqual; return T_NOT_EQUAL; } = { yylval->op = OperatorSet; return T_SET; } \+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; } -= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index f0370bfac..57118d03c 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -71,8 +71,6 @@ using namespace icinga; %token T_NUMBER %token T_NULL %token T_IDENTIFIER -%token T_EQUAL "== (T_EQUAL)" -%token T_NOT_EQUAL "!= (T_NOT_EQUAL)" %token T_SET "= (T_SET)" %token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)" %token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)" @@ -82,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)" @@ -122,6 +126,12 @@ using namespace icinga; %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 '&' @@ -581,82 +591,106 @@ aterm: '(' aexpression ')' aexpression: simplevalue { - $$ = new Value(make_shared(AEReturn, AValue(ATSimple, *$1))); + $$ = new Value(make_shared(AEReturn, AValue(ATSimple, *$1), yylloc)); delete $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))); + $$ = new Value(make_shared(AENegate, static_cast(*$2), yylloc)); delete $2; } - | aexpression T_EQUAL aexpression + | '(' aexpression ')' { - $$ = new Value(make_shared(AEEqual, static_cast(*$1), static_cast(*$3))); - delete $1; - delete $3; - } - | aexpression T_NOT_EQUAL aexpression - { - $$ = new Value(make_shared(AENotEqual, static_cast(*$1), static_cast(*$3))); - delete $1; - delete $3; + $$ = $2; } | aexpression '+' aexpression { - $$ = new Value(make_shared(AEAdd, static_cast(*$1), static_cast(*$3))); + $$ = 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))); + $$ = 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))); + $$ = 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))); + $$ = 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))); + $$ = 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))); + $$ = 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))); + $$ = 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))); + $$ = new Value(make_shared(AEShiftRight, static_cast(*$1), static_cast(*$3), yylloc)); delete $1; delete $3; } - | '(' aexpression ')' + | aexpression T_LOGICAL_AND aexpression { - $$ = $2; + $$ = 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; } ; diff --git a/lib/config/expression.h b/lib/config/expression.h index 4b77210a3..1c0881019 100644 --- a/lib/config/expression.h +++ b/lib/config/expression.h @@ -43,9 +43,7 @@ enum ExpressionOperator OperatorPlus, OperatorMinus, OperatorMultiply, - OperatorDivide, - OperatorEqual, /* Not used for Expressions */ - OperatorNotEqual, /* Not used for Expressions */ + OperatorDivide }; class ExpressionList; diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp index d2796cb2d..0d381f21d 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -43,6 +43,11 @@ void Host::EvaluateApplyRules(const std::vector& rules) 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() << ")"; @@ -79,8 +84,6 @@ void Host::EvaluateApplyRules(const std::vector& rules) serviceItem->Register(); DynamicObject::Ptr dobj = serviceItem->Commit(); dobj->OnConfigLoaded(); - - Log(LogInformation, "icinga", "Rule result: " + Convert::ToString(result)); } } }