Implement dictionary support for apply+for

fixes #7561
This commit is contained in:
Gunnar Beutner 2014-11-04 11:01:00 +01:00
parent 8c9ba23cdc
commit a1c905bf62
14 changed files with 476 additions and 273 deletions

View File

@ -28,10 +28,10 @@ ApplyRule::RuleMap ApplyRule::m_Rules;
ApplyRule::CallbackMap ApplyRule::m_Callbacks; ApplyRule::CallbackMap ApplyRule::m_Callbacks;
ApplyRule::ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression, ApplyRule::ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression,
const Expression::Ptr& filter, const String& fvar, const Expression::Ptr& fterm, const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm,
const DebugInfo& di, const Dictionary::Ptr& scope) const DebugInfo& di, const Dictionary::Ptr& scope)
: m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_FVar(fvar), : m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_FKVar(fkvar),
m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope) m_FVVar(fvvar), m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope)
{ } { }
String ApplyRule::GetTargetType(void) const String ApplyRule::GetTargetType(void) const
@ -54,9 +54,14 @@ Expression::Ptr ApplyRule::GetFilter(void) const
return m_Filter; return m_Filter;
} }
String ApplyRule::GetFVar(void) const String ApplyRule::GetFKVar(void) const
{ {
return m_FVar; return m_FKVar;
}
String ApplyRule::GetFVVar(void) const
{
return m_FVVar;
} }
Expression::Ptr ApplyRule::GetFTerm(void) const Expression::Ptr ApplyRule::GetFTerm(void) const
@ -75,10 +80,10 @@ Dictionary::Ptr ApplyRule::GetScope(void) const
} }
void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name, void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name,
const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fvar, const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fkvar,
const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope) const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope)
{ {
m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, fvar, fterm, di, scope)); m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, fkvar, fvvar, fterm, di, scope));
} }
bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const

View File

@ -42,7 +42,8 @@ public:
String GetName(void) const; String GetName(void) const;
Expression::Ptr GetExpression(void) const; Expression::Ptr GetExpression(void) const;
Expression::Ptr GetFilter(void) const; Expression::Ptr GetFilter(void) const;
String GetFVar(void) const; String GetFKVar(void) const;
String GetFVVar(void) const;
Expression::Ptr GetFTerm(void) const; Expression::Ptr GetFTerm(void) const;
DebugInfo GetDebugInfo(void) const; DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const; Dictionary::Ptr GetScope(void) const;
@ -50,7 +51,7 @@ public:
bool EvaluateFilter(const Dictionary::Ptr& scope) const; bool EvaluateFilter(const Dictionary::Ptr& scope) const;
static void AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression, static void AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression,
const Expression::Ptr& filter, const String& fvar, const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope); const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope);
static void EvaluateRules(bool clear); static void EvaluateRules(bool clear);
static void RegisterType(const String& sourceType, const std::vector<String>& targetTypes, const ApplyRule::Callback& callback); static void RegisterType(const String& sourceType, const std::vector<String>& targetTypes, const ApplyRule::Callback& callback);
@ -63,7 +64,8 @@ private:
String m_Name; String m_Name;
Expression::Ptr m_Expression; Expression::Ptr m_Expression;
Expression::Ptr m_Filter; Expression::Ptr m_Filter;
String m_FVar; String m_FKVar;
String m_FVVar;
Expression::Ptr m_FTerm; Expression::Ptr m_FTerm;
DebugInfo m_DebugInfo; DebugInfo m_DebugInfo;
Dictionary::Ptr m_Scope; Dictionary::Ptr m_Scope;
@ -72,7 +74,7 @@ private:
static RuleMap m_Rules; static RuleMap m_Rules;
ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression, ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression,
const Expression::Ptr& filter, const String& fvar, const Expression::Ptr& fterm, const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm,
const DebugInfo& di, const Dictionary::Ptr& scope); const DebugInfo& di, const Dictionary::Ptr& scope);
}; };

View File

@ -32,12 +32,7 @@
%attribute %dictionary "methods", %attribute %dictionary "methods",
%attribute %dictionary "vars" { %attribute %dictionary "vars"
%attribute %string "*",
%attribute %array "*" {
%attribute %string "*"
}
},
} }
%type Logger { %type Logger {

View File

@ -228,9 +228,11 @@ where return T_WHERE;
import return T_IMPORT; import return T_IMPORT;
assign return T_ASSIGN; assign return T_ASSIGN;
ignore return T_IGNORE; ignore return T_IGNORE;
for return T_APPLY_FOR;
__function return T_FUNCTION; __function return T_FUNCTION;
__return return T_RETURN; __return return T_RETURN;
__for return T_FOR; __for return T_FOR;
=\> return T_FOLLOWS;
\<\< { yylval->op = &Expression::OpShiftLeft; return T_SHIFT_LEFT; } \<\< { yylval->op = &Expression::OpShiftLeft; return T_SHIFT_LEFT; }
\>\> { yylval->op = &Expression::OpShiftRight; return T_SHIFT_RIGHT; } \>\> { yylval->op = &Expression::OpShiftRight; return T_SHIFT_RIGHT; }
\<= { yylval->op = &Expression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; } \<= { yylval->op = &Expression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; }

View File

@ -157,9 +157,11 @@ static void MakeRBinaryOp(Value** result, Expression::OpCallback& op, Value *lef
%token T_IMPORT "import (T_IMPORT)" %token T_IMPORT "import (T_IMPORT)"
%token T_ASSIGN "assign (T_ASSIGN)" %token T_ASSIGN "assign (T_ASSIGN)"
%token T_IGNORE "ignore (T_IGNORE)" %token T_IGNORE "ignore (T_IGNORE)"
%token T_APPLY_FOR "for (T_APPLY_FOR)"
%token T_FUNCTION "function (T_FUNCTION)" %token T_FUNCTION "function (T_FUNCTION)"
%token T_RETURN "return (T_RETURN)" %token T_RETURN "return (T_RETURN)"
%token T_FOR "for (T_FOR)" %token T_FOR "for (T_FOR)"
%token T_FOLLOWS "=> (T_FOLLOWS)"
%type <text> identifier %type <text> identifier
%type <array> rterm_items %type <array> rterm_items
@ -177,6 +179,7 @@ static void MakeRBinaryOp(Value** result, Expression::OpCallback& op, Value *lef
%type <variant> lterm %type <variant> lterm
%type <variant> object %type <variant> object
%type <variant> apply %type <variant> apply
%type <variant> optional_rterm
%type <text> target_type_specifier %type <text> target_type_specifier
%left T_LOGICAL_OR %left T_LOGICAL_OR
@ -218,7 +221,8 @@ static std::stack<bool> m_ObjectAssign;
static std::stack<bool> m_SeenAssign; static std::stack<bool> m_SeenAssign;
static std::stack<Expression::Ptr> m_Assign; static std::stack<Expression::Ptr> m_Assign;
static std::stack<Expression::Ptr> m_Ignore; static std::stack<Expression::Ptr> m_Ignore;
static std::stack<String> m_FVar; static std::stack<String> m_FKVar;
static std::stack<String> m_FVVar;
static std::stack<Expression::Ptr> m_FTerm; static std::stack<Expression::Ptr> m_FTerm;
void ConfigCompiler::Compile(void) void ConfigCompiler::Compile(void)
@ -233,7 +237,8 @@ void ConfigCompiler::Compile(void)
m_SeenAssign = std::stack<bool>(); m_SeenAssign = std::stack<bool>();
m_Assign = std::stack<Expression::Ptr>(); m_Assign = std::stack<Expression::Ptr>();
m_Ignore = std::stack<Expression::Ptr>(); m_Ignore = std::stack<Expression::Ptr>();
m_FVar = std::stack<String>(); m_FKVar = std::stack<String>();
m_FVVar = std::stack<String>();
m_FTerm = std::stack<Expression::Ptr>(); m_FTerm = std::stack<Expression::Ptr>();
try { try {
@ -812,6 +817,25 @@ rterm: T_STRING
$$ = new Value(make_shared<Expression>(&Expression::OpFunction, arr, Array::Ptr($3), DebugInfoRange(@1, @5))); $$ = new Value(make_shared<Expression>(&Expression::OpFunction, arr, Array::Ptr($3), DebugInfoRange(@1, @5)));
} }
| T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' rterm_scope
{
Array::Ptr arr = make_shared<Array>();
arr->Add($3);
free($3);
arr->Add($5);
free($5);
Expression::Ptr aexpr = *$7;
delete $7;
arr->Add(aexpr);
Expression::Ptr ascope = *$9;
delete $9;
$$ = new Value(make_shared<Expression>(&Expression::OpFor, arr, ascope, DebugInfoRange(@1, @9)));
}
| T_FOR '(' identifier T_IN rterm ')' rterm_scope | T_FOR '(' identifier T_IN rterm ')' rterm_scope
{ {
Array::Ptr arr = make_shared<Array>(); Array::Ptr arr = make_shared<Array>();
@ -819,6 +843,8 @@ rterm: T_STRING
arr->Add($3); arr->Add($3);
free($3); free($3);
arr->Add(Empty);
Expression::Ptr aexpr = *$5; Expression::Ptr aexpr = *$5;
delete $5; delete $5;
arr->Add(aexpr); arr->Add(aexpr);
@ -841,26 +867,50 @@ target_type_specifier: /* empty */
; ;
apply_for_specifier: /* empty */ apply_for_specifier: /* empty */
| T_FOR '(' identifier T_IN rterm ')' | T_APPLY_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')'
{ {
m_FVar.top() = $3; m_FKVar.top() = $3;
free($3); free($3);
m_FVVar.top() = $5;
free($5);
m_FTerm.top() = *$7;
delete $7;
}
| T_APPLY_FOR '(' identifier T_IN rterm ')'
{
m_FKVar.top() = $3;
free($3);
m_FVVar.top() = "";
m_FTerm.top() = *$5; m_FTerm.top() = *$5;
delete $5; delete $5;
} }
; ;
optional_rterm: /* empty */
{
$$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfo()));
}
| rterm
{
$$ = $1;
}
;
apply: apply:
{ {
m_Apply.push(true); m_Apply.push(true);
m_SeenAssign.push(false); m_SeenAssign.push(false);
m_Assign.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo())); m_Assign.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
m_Ignore.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo())); m_Ignore.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
m_FVar.push(""); m_FKVar.push("");
m_FVVar.push("");
m_FTerm.push(Expression::Ptr()); m_FTerm.push(Expression::Ptr());
} }
T_APPLY identifier rterm apply_for_specifier target_type_specifier rterm T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier rterm
{ {
m_Apply.pop(); m_Apply.pop();
@ -912,8 +962,11 @@ apply:
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign.top(), rex, DebugInfoRange(@2, @5)); Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign.top(), rex, DebugInfoRange(@2, @5));
m_Assign.pop(); m_Assign.pop();
String fvar = m_FVar.top(); String fkvar = m_FKVar.top();
m_FVar.pop(); m_FKVar.pop();
String fvvar = m_FVVar.top();
m_FVVar.pop();
Expression::Ptr fterm = m_FTerm.top(); Expression::Ptr fterm = m_FTerm.top();
m_FTerm.pop(); m_FTerm.pop();
@ -923,7 +976,8 @@ apply:
args->Add(target); args->Add(target);
args->Add(aname); args->Add(aname);
args->Add(filter); args->Add(filter);
args->Add(fvar); args->Add(fkvar);
args->Add(fvvar);
args->Add(fterm); args->Add(fterm);
$$ = new Value(make_shared<Expression>(&Expression::OpApply, args, exprl, DebugInfoRange(@2, @5))); $$ = new Value(make_shared<Expression>(&Expression::OpApply, args, exprl, DebugInfoRange(@2, @5)));

View File

@ -551,12 +551,13 @@ Value Expression::OpApply(const Expression* expr, const Dictionary::Ptr& locals,
String target = left->Get(1); String target = left->Get(1);
Expression::Ptr aname = left->Get(2); Expression::Ptr aname = left->Get(2);
Expression::Ptr filter = left->Get(3); Expression::Ptr filter = left->Get(3);
String fvar = left->Get(4); String fkvar = left->Get(4);
Expression::Ptr fterm = left->Get(5); String fvvar = left->Get(5);
Expression::Ptr fterm = left->Get(6);
String name = aname->Evaluate(locals, dhint); String name = aname->Evaluate(locals, dhint);
ApplyRule::AddRule(type, target, name, exprl, filter, fvar, fterm, expr->m_DebugInfo, locals); ApplyRule::AddRule(type, target, name, exprl, filter, fkvar, fvvar, fterm, expr->m_DebugInfo, locals);
return Empty; return Empty;
} }
@ -618,20 +619,44 @@ Value Expression::OpObject(const Expression* expr, const Dictionary::Ptr& locals
Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint) Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint)
{ {
Array::Ptr left = expr->m_Operand1; Array::Ptr left = expr->m_Operand1;
String varname = left->Get(0); String kvar = left->Get(0);
Expression::Ptr aexpr = left->Get(1); String vvar = left->Get(1);
Expression::Ptr aexpr = left->Get(2);
Expression::Ptr ascope = expr->m_Operand2; Expression::Ptr ascope = expr->m_Operand2;
Array::Ptr arr = aexpr->Evaluate(locals, dhint); Value value = aexpr->Evaluate(locals, dhint);
ObjectLock olock(arr); if (value.IsObjectType<Array>()) {
BOOST_FOREACH(const Value& value, arr) { if (!vvar.IsEmpty())
Dictionary::Ptr xlocals = make_shared<Dictionary>(); BOOST_THROW_EXCEPTION(ConfigError("Cannot use dictionary iterator for array.") << errinfo_debuginfo(expr->m_DebugInfo));
xlocals->Set("__parent", locals);
xlocals->Set(varname, value);
ascope->Evaluate(xlocals, dhint); Array::Ptr arr = value;
}
ObjectLock olock(arr);
BOOST_FOREACH(const Value& value, arr) {
Dictionary::Ptr xlocals = make_shared<Dictionary>();
xlocals->Set("__parent", locals);
xlocals->Set(kvar, value);
ascope->Evaluate(xlocals, dhint);
}
} else if (value.IsObjectType<Dictionary>()) {
if (vvar.IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Cannot use array iterator for dictionary.") << errinfo_debuginfo(expr->m_DebugInfo));
Dictionary::Ptr dict = value;
ObjectLock olock(dict);
BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
Dictionary::Ptr xlocals = make_shared<Dictionary>();
xlocals->Set("__parent", locals);
xlocals->Set(kvar, kv.first);
xlocals->Set(vvar, kv.second);
ascope->Evaluate(xlocals, dhint);
}
} else
BOOST_THROW_EXCEPTION(ConfigError("Invalid type in __for expression: " + value.GetTypeName()) << errinfo_debuginfo(expr->m_DebugInfo));
return Empty; return Empty;
} }

View File

@ -42,6 +42,57 @@ void Dependency::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("Dependency", targets, &Dependency::EvaluateApplyRules); ApplyRule::RegisterType("Dependency", targets, &Dependency::EvaluateApplyRules);
} }
void Dependency::EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule)
{
DebugInfo di = rule.GetDebugInfo();
Log(LogDebug, "Dependency")
<< "Applying dependency '" << name << "' to object '" << checkable->GetName() << "' for rule " << di;
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Dependency");
builder->SetName(name);
builder->SetScope(locals);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "parent_host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "child_host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "child_service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
}
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr dependencyItem = builder->Compile();
dependencyItem->Register();
DynamicObject::Ptr dobj = dependencyItem->Commit();
dobj->OnConfigLoaded();
}
bool Dependency::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule) bool Dependency::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule)
{ {
DebugInfo di = rule.GetDebugInfo(); DebugInfo di = rule.GetDebugInfo();
@ -63,69 +114,46 @@ bool Dependency::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const App
if (!rule.EvaluateFilter(locals)) if (!rule.EvaluateFilter(locals))
return false; return false;
Array::Ptr instances; Value vinstances;
if (rule.GetFTerm()) { if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals); vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
} else { } else {
instances = make_shared<Array>(); Array::Ptr instances = make_shared<Array>();
instances->Add(""); instances->Add("");
vinstances = instances;
} }
ObjectLock olock(instances); if (vinstances.IsObjectType<Array>()) {
BOOST_FOREACH(const String& instance, instances) { if (!rule.GetFVVar().IsEmpty())
String objName = rule.GetName(); BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) { Array::Ptr arr = vinstances;
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance; ObjectLock olock(arr);
BOOST_FOREACH(const String& instance, arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
locals->Set(rule.GetFKVar(), instance);
name += instance;
}
EvaluateApplyRuleOneInstance(checkable, name, locals, rule);
} }
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Dictionary iterator requires value to be a dictionary.") << errinfo_debuginfo(di));
Dictionary::Ptr dict = vinstances;
Log(LogDebug, "Dependency") ObjectLock olock(dict);
<< "Applying dependency '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di; BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
locals->Set(rule.GetFKVar(), kv.first);
locals->Set(rule.GetFVVar(), kv.second);
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di); EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
builder->SetType("Dependency");
builder->SetName(objName);
builder->SetScope(locals);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "parent_host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "child_host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "child_service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
} }
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr dependencyItem = builder->Compile();
dependencyItem->Register();
DynamicObject::Ptr dobj = dependencyItem->Commit();
dobj->OnConfigLoaded();
} }
return true; return true;

View File

@ -60,6 +60,7 @@ private:
Checkable::Ptr m_Parent; Checkable::Ptr m_Parent;
Checkable::Ptr m_Child; Checkable::Ptr m_Child;
static void EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule);
static bool EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule); static bool EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule);
static void EvaluateApplyRule(const ApplyRule& rule); static void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules); static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);

View File

@ -42,6 +42,52 @@ void Notification::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("Notification", targets, &Notification::EvaluateApplyRules); ApplyRule::RegisterType("Notification", targets, &Notification::EvaluateApplyRules);
} }
void Notification::EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule)
{
DebugInfo di = rule.GetDebugInfo();
Log(LogDebug, "Notification")
<< "Applying notification '" << name << "' to object '" << checkable->GetName() << "' for rule " << di;
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Notification");
builder->SetName(name);
builder->SetScope(locals);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
}
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Register();
DynamicObject::Ptr dobj = notificationItem->Commit();
dobj->OnConfigLoaded();
}
bool Notification::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule) bool Notification::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule)
{ {
DebugInfo di = rule.GetDebugInfo(); DebugInfo di = rule.GetDebugInfo();
@ -63,64 +109,46 @@ bool Notification::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const A
if (!rule.EvaluateFilter(locals)) if (!rule.EvaluateFilter(locals))
return false; return false;
Array::Ptr instances; Value vinstances;
if (rule.GetFTerm()) { if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals); vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
} else { } else {
instances = make_shared<Array>(); Array::Ptr instances = make_shared<Array>();
instances->Add(""); instances->Add("");
vinstances = instances;
} }
ObjectLock olock(instances); if (vinstances.IsObjectType<Array>()) {
BOOST_FOREACH(const String& instance, instances) { if (!rule.GetFVVar().IsEmpty())
String objName = rule.GetName(); BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) { Array::Ptr arr = vinstances;
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance; ObjectLock olock(arr);
BOOST_FOREACH(const String& instance, arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
locals->Set(rule.GetFKVar(), instance);
name += instance;
}
EvaluateApplyRuleOneInstance(checkable, name, locals, rule);
} }
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Dictionary iterator requires value to be a dictionary.") << errinfo_debuginfo(di));
Dictionary::Ptr dict = vinstances;
Log(LogDebug, "Notification") ObjectLock olock(dict);
<< "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di; BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
locals->Set(rule.GetFKVar(), kv.first);
locals->Set(rule.GetFVVar(), kv.second);
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di); EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
builder->SetType("Notification");
builder->SetName(objName);
builder->SetScope(locals);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
} }
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Register();
DynamicObject::Ptr dobj = notificationItem->Commit();
dobj->OnConfigLoaded();
} }
return true; return true;

View File

@ -113,6 +113,7 @@ protected:
private: private:
void ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const CheckResult::Ptr& cr, bool force, const String& author = "", const String& text = ""); void ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const CheckResult::Ptr& cr, bool force, const String& author = "", const String& text = "");
static void EvaluateApplyRuleOneInstance(const shared_ptr<Checkable>& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule);
static bool EvaluateApplyRuleOne(const shared_ptr<Checkable>& checkable, const ApplyRule& rule); static bool EvaluateApplyRuleOne(const shared_ptr<Checkable>& checkable, const ApplyRule& rule);
static void EvaluateApplyRule(const ApplyRule& rule); static void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules); static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);

View File

@ -41,7 +41,52 @@ void ScheduledDowntime::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("ScheduledDowntime", targets, &ScheduledDowntime::EvaluateApplyRules); ApplyRule::RegisterType("ScheduledDowntime", targets, &ScheduledDowntime::EvaluateApplyRules);
} }
bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule) void ScheduledDowntime::EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule)
{
DebugInfo di = rule.GetDebugInfo();
Log(LogDebug, "ScheduledDowntime")
<< "Applying scheduled downtime '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("ScheduledDowntime");
builder->SetName(name);
builder->SetScope(locals);
Host::Ptr host;
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
}
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr downtimeItem = builder->Compile();
downtimeItem->Register();
DynamicObject::Ptr dobj = downtimeItem->Commit();
dobj->OnConfigLoaded();
}
bool ScheduledDowntime::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule)
{ {
DebugInfo di = rule.GetDebugInfo(); DebugInfo di = rule.GetDebugInfo();
@ -62,115 +107,106 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const
if (!rule.EvaluateFilter(locals)) if (!rule.EvaluateFilter(locals))
return false; return false;
Array::Ptr instances; Value vinstances;
if (rule.GetFTerm()) { if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals); vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
} else { } else {
instances = make_shared<Array>(); Array::Ptr instances = make_shared<Array>();
instances->Add(""); instances->Add("");
vinstances = instances;
} }
ObjectLock olock(instances); if (vinstances.IsObjectType<Array>()) {
BOOST_FOREACH(const String& instance, instances) { if (!rule.GetFVVar().IsEmpty())
String objName = rule.GetName(); BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) { Array::Ptr arr = vinstances;
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance; ObjectLock olock(arr);
BOOST_FOREACH(const String& instance, arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
locals->Set(rule.GetFKVar(), instance);
name += instance;
}
EvaluateApplyRuleOneInstance(checkable, name, locals, rule);
} }
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Dictionary iterator requires value to be a dictionary.") << errinfo_debuginfo(di));
Dictionary::Ptr dict = vinstances;
Log(LogDebug, "ScheduledDowntime") ObjectLock olock(dict);
<< "Applying scheduled downtime '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di; BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
locals->Set(rule.GetFKVar(), kv.first);
locals->Set(rule.GetFVVar(), kv.second);
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di); EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
builder->SetType("ScheduledDowntime");
builder->SetName(objName);
builder->SetScope(locals);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
if (service) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "service_name", di),
make_shared<Expression>(&Expression::OpLiteral, service->GetShortName(), di),
di));
} }
String zone = checkable->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr downtimeItem = builder->Compile();
downtimeItem->Register();
DynamicObject::Ptr dobj = downtimeItem->Commit();
dobj->OnConfigLoaded();
} }
return true; return true;
} }
void ScheduledDowntime::EvaluateApplyRules(const std::vector<ApplyRule>& rules) void ScheduledDowntime::EvaluateApplyRule(const ApplyRule& rule)
{ {
int apply_count = 0; int apply_count = 0;
BOOST_FOREACH(const ApplyRule& rule, rules) { if (rule.GetTargetType() == "Host") {
if (rule.GetTargetType() == "Host") { apply_count = 0;
apply_count = 0;
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) { BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
try { try {
if (EvaluateApplyRule(host, rule)) if (EvaluateApplyRuleOne(host, rule))
apply_count++; apply_count++;
} catch (const ConfigError& ex) { } catch (const ConfigError& ex) {
const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex); const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
}
} }
if (apply_count == 0)
Log(LogWarning, "ScheduledDowntime")
<< "Apply rule '" << rule.GetName() << "' for host does not match anywhere!";
} else if (rule.GetTargetType() == "Service") {
apply_count = 0;
BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjectsByType<Service>()) {
CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
try {
if(EvaluateApplyRule(service, rule))
apply_count++;
} catch (const ConfigError& ex) {
const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
}
}
if (apply_count == 0)
Log(LogWarning, "ScheduledDowntime")
<< "Apply rule '" << rule.GetName() << "' for service does not match anywhere!";
} else {
Log(LogWarning, "ScheduledDowntime")
<< "Wrong target type for apply rule '" << rule.GetName() << "'!";
} }
if (apply_count == 0)
Log(LogWarning, "ScheduledDowntime")
<< "Apply rule '" << rule.GetName() << "' for host does not match anywhere!";
} else if (rule.GetTargetType() == "Service") {
apply_count = 0;
BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjectsByType<Service>()) {
CONTEXT("Evaluating 'apply' rules for Service '" + service->GetName() + "'");
try {
if(EvaluateApplyRuleOne(service, rule))
apply_count++;
} catch (const ConfigError& ex) {
const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
}
}
if (apply_count == 0)
Log(LogWarning, "ScheduledDowntime")
<< "Apply rule '" << rule.GetName() << "' for service does not match anywhere!";
} else {
Log(LogWarning, "ScheduledDowntime")
<< "Wrong target type for apply rule '" << rule.GetName() << "'!";
} }
} }
void ScheduledDowntime::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
{
ParallelWorkQueue upq;
BOOST_FOREACH(const ApplyRule& rule, rules) {
upq.Enqueue(boost::bind(&ScheduledDowntime::EvaluateApplyRule, boost::cref(rule)));
}
upq.Join();
}

View File

@ -56,7 +56,9 @@ private:
std::pair<double, double> FindNextSegment(void); std::pair<double, double> FindNextSegment(void);
void CreateNextDowntime(void); void CreateNextDowntime(void);
static bool EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule); static void EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule);
static bool EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const ApplyRule& rule);
static void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules); static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);
}; };

View File

@ -40,6 +40,45 @@ void Service::RegisterApplyRuleHandler(void)
ApplyRule::RegisterType("Service", targets, &Service::EvaluateApplyRules); ApplyRule::RegisterType("Service", targets, &Service::EvaluateApplyRules);
} }
void Service::EvaluateApplyRuleOneInstance(const Host::Ptr& host, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule)
{
DebugInfo di = rule.GetDebugInfo();
Log(LogDebug, "Service")
<< "Applying service '" << name << "' to host '" << host->GetName() << "' for rule " << di;
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
builder->SetType("Service");
builder->SetName(name);
builder->SetScope(locals);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "name", di),
make_shared<Expression>(&Expression::OpLiteral, name, di),
di));
String zone = host->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
bool Service::EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule) bool Service::EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule)
{ {
DebugInfo di = rule.GetDebugInfo(); DebugInfo di = rule.GetDebugInfo();
@ -55,62 +94,46 @@ bool Service::EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule)
if (!rule.EvaluateFilter(locals)) if (!rule.EvaluateFilter(locals))
return false; return false;
Array::Ptr instances; Value vinstances;
if (rule.GetFTerm()) { if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals); vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
} else { } else {
instances = make_shared<Array>(); Array::Ptr instances = make_shared<Array>();
instances->Add(""); instances->Add("");
vinstances = instances;
} }
ObjectLock olock(instances); if (vinstances.IsObjectType<Array>()) {
BOOST_FOREACH(const String& instance, instances) { if (!rule.GetFVVar().IsEmpty())
String objName = rule.GetName(); BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) { Array::Ptr arr = vinstances;
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance; ObjectLock olock(arr);
BOOST_FOREACH(const String& instance, arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
locals->Set(rule.GetFKVar(), instance);
name += instance;
}
EvaluateApplyRuleOneInstance(host, name, locals, rule);
} }
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Dictionary iterator requires value to be a dictionary.") << errinfo_debuginfo(di));
Dictionary::Ptr dict = vinstances;
Log(LogDebug, "Service") ObjectLock olock(dict);
<< "Applying service '" << objName << "' to host '" << host->GetName() << "' for rule " << di; BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
locals->Set(rule.GetFKVar(), kv.first);
locals->Set(rule.GetFVVar(), kv.second);
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di); EvaluateApplyRuleOneInstance(host, rule.GetName() + kv.first, locals, rule);
builder->SetType("Service");
builder->SetName(objName);
builder->SetScope(locals);
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "name", di),
make_shared<Expression>(&Expression::OpLiteral, objName, di),
di));
String zone = host->GetZone();
if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
make_shared<Expression>(&Expression::OpLiteral, "zone", di),
make_shared<Expression>(&Expression::OpLiteral, zone, di),
di));
} }
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
} }
return true; return true;

View File

@ -59,6 +59,7 @@ protected:
private: private:
Host::Ptr m_Host; Host::Ptr m_Host;
static void EvaluateApplyRuleOneInstance(const Host::Ptr& host, const String& name, const Dictionary::Ptr& locals, const ApplyRule& rule);
static bool EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule); static bool EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule);
static void EvaluateApplyRule(const ApplyRule& rule); static void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules); static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);