Implement the new syntax for the "apply" keyword.

Refs #5878
This commit is contained in:
Gunnar Beutner 2014-03-28 13:25:40 +01:00
parent b289987500
commit 7ee1278118
7 changed files with 116 additions and 62 deletions

View File

@ -121,6 +121,11 @@ Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& loca
return ~(long)expr->EvaluateOperand1(locals);
}
Value AExpression::OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals)
{
return !expr->EvaluateOperand1(locals).ToBool();
}
Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals)
{
return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals);

View File

@ -50,6 +50,7 @@ public:
static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpLogicalNegate(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals);
static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals);

View File

@ -18,19 +18,21 @@
******************************************************************************/
#include "config/applyrule.h"
#include "base/logger_fwd.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, const Dictionary::Ptr& scope)
: m_Template(tmpl), m_Expression(expression), m_DebugInfo(di), m_Scope(scope)
ApplyRule::ApplyRule(const String& name, const AExpression::Ptr& expression,
const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope)
: m_Name(name), m_Expression(expression), m_Filter(filter), m_DebugInfo(di), m_Scope(scope)
{ }
String ApplyRule::GetTemplate(void) const
String ApplyRule::GetName(void) const
{
return m_Template;
return m_Name;
}
AExpression::Ptr ApplyRule::GetExpression(void) const
@ -38,6 +40,11 @@ AExpression::Ptr ApplyRule::GetExpression(void) const
return m_Expression;
}
AExpression::Ptr ApplyRule::GetFilter(void) const
{
return m_Filter;
}
DebugInfo ApplyRule::GetDebugInfo(void) const
{
return m_DebugInfo;
@ -48,30 +55,37 @@ Dictionary::Ptr ApplyRule::GetScope(void) const
return m_Scope;
}
void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope)
void ApplyRule::AddRule(const String& sourceType, const String& name,
const AExpression::Ptr& expression, const AExpression::Ptr& filter,
const DebugInfo& di, const Dictionary::Ptr& scope)
{
m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di, scope));
m_Rules[sourceType].push_back(ApplyRule(name, expression, filter, di, scope));
}
bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const
{
return m_Filter->Evaluate(scope);
}
void ApplyRule::EvaluateRules(void)
{
std::pair<TypeCombination, Callback> kv;
std::pair<String, std::pair<Callback, int> > 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);
kv.second.first(it->second);
}
}
void ApplyRule::RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback)
void ApplyRule::RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority)
{
m_Callbacks[std::make_pair(sourceType, targetType)] = callback;
m_Callbacks[sourceType] = make_pair(callback, priority);
}
bool ApplyRule::IsValidCombination(const String& sourceType, const String& targetType)
bool ApplyRule::IsValidType(const String& sourceType)
{
return m_Callbacks.find(std::make_pair(sourceType, targetType)) != m_Callbacks.end();
return m_Callbacks.find(sourceType) != m_Callbacks.end();
}

View File

@ -34,32 +34,37 @@ namespace icinga
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;
typedef std::map<String, std::pair<Callback, int> > CallbackMap;
typedef std::map<String, std::vector<ApplyRule> > RuleMap;
String GetTemplate(void) const;
String GetName(void) const;
AExpression::Ptr GetExpression(void) const;
AExpression::Ptr GetFilter(void) const;
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const;
static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope);
bool EvaluateFilter(const Dictionary::Ptr& scope) const;
static void AddRule(const String& sourceType, const String& name, const AExpression::Ptr& expression,
const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope);
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);
static void RegisterType(const String& sourceType, const ApplyRule::Callback& callback, int priority);
static bool IsValidType(const String& sourceType);
private:
String m_Template;
String m_Name;
AExpression::Ptr m_Expression;
AExpression::Ptr m_Filter;
DebugInfo m_DebugInfo;
Dictionary::Ptr m_Scope;
static CallbackMap m_Callbacks;
static RuleMap m_Rules;
ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope);
ApplyRule(const String& tmpl, const AExpression::Ptr& expression,
const AExpression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope);
};
}

View File

@ -222,9 +222,10 @@ set return T_VAR;
var return T_VAR;
const return T_CONST;
apply return T_APPLY;
to return T_TO;
where return T_WHERE;
import return T_IMPORT;
assign return T_ASSIGN;
ignore return T_IGNORE;
\<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; }
\>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; }
\<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; }

View File

@ -142,9 +142,10 @@ using namespace icinga;
%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)"
%token T_IMPORT "import (T_IMPORT)"
%token T_ASSIGN "assign (T_ASSIGN)"
%token T_IGNORE "ignore (T_IGNORE)"
%type <text> identifier
%type <array> rterm_items
%type <array> rterm_items_inner
@ -192,6 +193,10 @@ static ConfigType::Ptr m_Type;
static Dictionary::Ptr m_ModuleScope;
static bool m_Apply;
static AExpression::Ptr m_Assign;
static AExpression::Ptr m_Ignore;
void ConfigCompiler::Compile(void)
{
m_ModuleScope = make_shared<Dictionary>();
@ -542,6 +547,34 @@ lterm: identifier lbinary_op rterm
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @5)));
free($1);
}
| T_IMPORT rterm
{
AExpression::Ptr avar = make_shared<AExpression>(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2));
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$2);
delete $2;
$$ = new Value(make_shared<AExpression>(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2)));
}
| T_ASSIGN T_WHERE rterm
{
if (!m_Apply)
BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context."));
m_Assign = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Assign, static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3));
delete $3;
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
}
| T_IGNORE T_WHERE rterm
{
if (!m_Apply)
BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context."));
m_Ignore = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Ignore, static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3));
delete $3;
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
}
| rterm
{
$$ = $1;
@ -640,13 +673,6 @@ rterm: T_STRING
$$ = new Value(make_shared<AExpression>(&AExpression::OpFunctionCall, $1, make_shared<AExpression>(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4)));
free($1);
}
| T_IMPORT rterm
{
AExpression::Ptr avar = make_shared<AExpression>(&AExpression::OpVariable, "__type", DebugInfoRange(@1, @2));
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$2);
delete $2;
$$ = new Value(make_shared<AExpression>(&AExpression::OpImport, avar, aexpr, DebugInfoRange(@1, @2)));
}
| T_IDENTIFIER
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpVariable, $1, @1));
@ -654,7 +680,7 @@ rterm: T_STRING
}
| '!' rterm
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
$$ = new Value(make_shared<AExpression>(&AExpression::OpLogicalNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2;
}
| '~' rterm
@ -688,22 +714,36 @@ rterm: T_STRING
}
;
optional_template: /* empty */
| T_TEMPLATE
;
apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE rterm
apply:
{
if (!ApplyRule::IsValidCombination($3, $6)) {
BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'.") << errinfo_debuginfo(@1));
}
m_Apply = true;
m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
}
T_APPLY identifier rterm rterm
{
m_Apply = false;
Array::Ptr arguments = make_shared<Array>();
arguments->Add(*$8);
delete $8;
AExpression::Ptr aname = static_cast<AExpression::Ptr>(*$4);
delete $4;
String type = $3;
free($3);
String name = aname->Evaluate(m_ModuleScope);
AExpression::Ptr aexpr = make_shared<AExpression>(&AExpression::OpFunctionCall, "bool", make_shared<AExpression>(&AExpression::OpLiteral, arguments, @8), @8);
if (!ApplyRule::IsValidType(type))
BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(@2));
ApplyRule::AddRule($3, $4, $6, aexpr, DebugInfoRange(@1, @8), m_ModuleScope);
AExpression::Ptr exprl = static_cast<AExpression::Ptr>(*$5);
delete $5;
exprl->MakeInline();
// assign && !ignore
AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
ApplyRule::AddRule(type, name, exprl, filter, DebugInfoRange(@1, @5), m_ModuleScope);
m_Assign.reset();
m_Ignore.reset();
}
%%

View File

@ -32,7 +32,7 @@ INITIALIZE_ONCE(&Host::RegisterApplyRuleHandler);
void Host::RegisterApplyRuleHandler(void)
{
ApplyRule::RegisterCombination("Service", "Host", &Host::EvaluateApplyRules);
ApplyRule::RegisterType("Service", &Host::EvaluateApplyRules, 1);
}
void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
@ -50,25 +50,15 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
msgbuf << "Evaluating 'apply' rule (" << di << ")";
CONTEXT(msgbuf.str());
Value result = rule.GetExpression()->Evaluate(locals);
try {
if (!static_cast<bool>(result))
continue;
} catch (...) {
std::ostringstream msgbuf;
msgbuf << "Apply rule (" << di << ") returned invalid data type, expected bool: " + JsonSerialize(result);
Log(LogCritical, "icinga", msgbuf.str());
if (!rule.EvaluateFilter(locals))
continue;
}
std::ostringstream msgbuf2;
msgbuf2 << "Applying service template '" << rule.GetTemplate() << "' to host '" << host->GetName() << "' for rule " << di;
msgbuf2 << "Applying service '" << rule.GetName() << "' to host '" << host->GetName() << "' for rule " << di;
Log(LogDebug, "icinga", msgbuf2.str());
std::ostringstream namebuf;
namebuf << host->GetName() << "!apply!" << rule.GetTemplate();
namebuf << host->GetName() << "!" << rule.GetName();
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
@ -76,11 +66,9 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
builder->SetName(name);
builder->SetScope(rule.GetScope());
AExpression::Ptr atype = make_shared<AExpression>(&AExpression::OpLiteral, "Service", di);
AExpression::Ptr atmpl = make_shared<AExpression>(&AExpression::OpLiteral, rule.GetTemplate(), di);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpImport, atype, atmpl, di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, host->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "short_name", make_shared<AExpression>(&AExpression::OpLiteral, rule.GetName(), di), di));
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();