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::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)
: m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_FVar(fvar),
m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope)
: m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_FKVar(fkvar),
m_FVVar(fvvar), m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope)
{ }
String ApplyRule::GetTargetType(void) const
@ -54,9 +54,14 @@ Expression::Ptr ApplyRule::GetFilter(void) const
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
@ -75,10 +80,10 @@ Dictionary::Ptr ApplyRule::GetScope(void) const
}
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& fterm, const DebugInfo& di, const Dictionary::Ptr& scope)
const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fkvar,
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

View File

@ -42,7 +42,8 @@ public:
String GetName(void) const;
Expression::Ptr GetExpression(void) const;
Expression::Ptr GetFilter(void) const;
String GetFVar(void) const;
String GetFKVar(void) const;
String GetFVVar(void) const;
Expression::Ptr GetFTerm(void) const;
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const;
@ -50,7 +51,7 @@ public:
bool EvaluateFilter(const Dictionary::Ptr& scope) const;
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 RegisterType(const String& sourceType, const std::vector<String>& targetTypes, const ApplyRule::Callback& callback);
@ -63,7 +64,8 @@ private:
String m_Name;
Expression::Ptr m_Expression;
Expression::Ptr m_Filter;
String m_FVar;
String m_FKVar;
String m_FVVar;
Expression::Ptr m_FTerm;
DebugInfo m_DebugInfo;
Dictionary::Ptr m_Scope;
@ -72,7 +74,7 @@ private:
static RuleMap m_Rules;
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);
};

View File

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

View File

@ -228,9 +228,11 @@ where return T_WHERE;
import return T_IMPORT;
assign return T_ASSIGN;
ignore return T_IGNORE;
for return T_APPLY_FOR;
__function return T_FUNCTION;
__return return T_RETURN;
__for return T_FOR;
=\> return T_FOLLOWS;
\<\< { yylval->op = &Expression::OpShiftLeft; return T_SHIFT_LEFT; }
\>\> { yylval->op = &Expression::OpShiftRight; return T_SHIFT_RIGHT; }
\<= { 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_ASSIGN "assign (T_ASSIGN)"
%token T_IGNORE "ignore (T_IGNORE)"
%token T_APPLY_FOR "for (T_APPLY_FOR)"
%token T_FUNCTION "function (T_FUNCTION)"
%token T_RETURN "return (T_RETURN)"
%token T_FOR "for (T_FOR)"
%token T_FOLLOWS "=> (T_FOLLOWS)"
%type <text> identifier
%type <array> rterm_items
@ -177,6 +179,7 @@ static void MakeRBinaryOp(Value** result, Expression::OpCallback& op, Value *lef
%type <variant> lterm
%type <variant> object
%type <variant> apply
%type <variant> optional_rterm
%type <text> target_type_specifier
%left T_LOGICAL_OR
@ -218,7 +221,8 @@ static std::stack<bool> m_ObjectAssign;
static std::stack<bool> m_SeenAssign;
static std::stack<Expression::Ptr> m_Assign;
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;
void ConfigCompiler::Compile(void)
@ -233,7 +237,8 @@ void ConfigCompiler::Compile(void)
m_SeenAssign = std::stack<bool>();
m_Assign = 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>();
try {
@ -812,6 +817,25 @@ rterm: T_STRING
$$ = 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
{
Array::Ptr arr = make_shared<Array>();
@ -819,6 +843,8 @@ rterm: T_STRING
arr->Add($3);
free($3);
arr->Add(Empty);
Expression::Ptr aexpr = *$5;
delete $5;
arr->Add(aexpr);
@ -841,26 +867,50 @@ target_type_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);
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;
delete $5;
}
;
optional_rterm: /* empty */
{
$$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfo()));
}
| rterm
{
$$ = $1;
}
;
apply:
{
m_Apply.push(true);
m_SeenAssign.push(false);
m_Assign.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());
}
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();
@ -912,8 +962,11 @@ apply:
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign.top(), rex, DebugInfoRange(@2, @5));
m_Assign.pop();
String fvar = m_FVar.top();
m_FVar.pop();
String fkvar = m_FKVar.top();
m_FKVar.pop();
String fvvar = m_FVVar.top();
m_FVVar.pop();
Expression::Ptr fterm = m_FTerm.top();
m_FTerm.pop();
@ -923,7 +976,8 @@ apply:
args->Add(target);
args->Add(aname);
args->Add(filter);
args->Add(fvar);
args->Add(fkvar);
args->Add(fvvar);
args->Add(fterm);
$$ = 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);
Expression::Ptr aname = left->Get(2);
Expression::Ptr filter = left->Get(3);
String fvar = left->Get(4);
Expression::Ptr fterm = left->Get(5);
String fkvar = left->Get(4);
String fvvar = left->Get(5);
Expression::Ptr fterm = left->Get(6);
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;
}
@ -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)
{
Array::Ptr left = expr->m_Operand1;
String varname = left->Get(0);
Expression::Ptr aexpr = left->Get(1);
String kvar = left->Get(0);
String vvar = left->Get(1);
Expression::Ptr aexpr = left->Get(2);
Expression::Ptr ascope = expr->m_Operand2;
Array::Ptr arr = aexpr->Evaluate(locals, dhint);
Value value = aexpr->Evaluate(locals, dhint);
ObjectLock olock(arr);
BOOST_FOREACH(const Value& value, arr) {
Dictionary::Ptr xlocals = make_shared<Dictionary>();
xlocals->Set("__parent", locals);
xlocals->Set(varname, value);
if (value.IsObjectType<Array>()) {
if (!vvar.IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Cannot use dictionary iterator for array.") << errinfo_debuginfo(expr->m_DebugInfo));
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;
}

View File

@ -42,6 +42,57 @@ void Dependency::RegisterApplyRuleHandler(void)
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)
{
DebugInfo di = rule.GetDebugInfo();
@ -63,69 +114,46 @@ bool Dependency::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const App
if (!rule.EvaluateFilter(locals))
return false;
Array::Ptr instances;
Value vinstances;
if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
vinstances = rule.GetFTerm()->Evaluate(locals);
} else {
instances = make_shared<Array>();
Array::Ptr instances = make_shared<Array>();
instances->Add("");
vinstances = instances;
}
ObjectLock olock(instances);
BOOST_FOREACH(const String& instance, instances) {
String objName = rule.GetName();
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) {
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance;
Array::Ptr arr = vinstances;
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")
<< "Applying dependency '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
ObjectLock olock(dict);
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);
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));
EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
}
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;

View File

@ -60,6 +60,7 @@ private:
Checkable::Ptr m_Parent;
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 void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);

View File

@ -42,6 +42,52 @@ void Notification::RegisterApplyRuleHandler(void)
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)
{
DebugInfo di = rule.GetDebugInfo();
@ -63,64 +109,46 @@ bool Notification::EvaluateApplyRuleOne(const Checkable::Ptr& checkable, const A
if (!rule.EvaluateFilter(locals))
return false;
Array::Ptr instances;
Value vinstances;
if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
vinstances = rule.GetFTerm()->Evaluate(locals);
} else {
instances = make_shared<Array>();
Array::Ptr instances = make_shared<Array>();
instances->Add("");
vinstances = instances;
}
ObjectLock olock(instances);
BOOST_FOREACH(const String& instance, instances) {
String objName = rule.GetName();
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) {
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance;
Array::Ptr arr = vinstances;
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")
<< "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
ObjectLock olock(dict);
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);
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));
EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
}
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;

View File

@ -113,6 +113,7 @@ protected:
private:
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 void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);

View File

@ -41,7 +41,52 @@ void ScheduledDowntime::RegisterApplyRuleHandler(void)
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();
@ -62,115 +107,106 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const
if (!rule.EvaluateFilter(locals))
return false;
Array::Ptr instances;
Value vinstances;
if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
vinstances = rule.GetFTerm()->Evaluate(locals);
} else {
instances = make_shared<Array>();
Array::Ptr instances = make_shared<Array>();
instances->Add("");
vinstances = instances;
}
ObjectLock olock(instances);
BOOST_FOREACH(const String& instance, instances) {
String objName = rule.GetName();
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) {
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance;
Array::Ptr arr = vinstances;
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")
<< "Applying scheduled downtime '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
ObjectLock olock(dict);
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);
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));
EvaluateApplyRuleOneInstance(checkable, rule.GetName() + kv.first, locals, rule);
}
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;
}
void ScheduledDowntime::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
void ScheduledDowntime::EvaluateApplyRule(const ApplyRule& rule)
{
int apply_count = 0;
BOOST_FOREACH(const ApplyRule& rule, rules) {
if (rule.GetTargetType() == "Host") {
apply_count = 0;
if (rule.GetTargetType() == "Host") {
apply_count = 0;
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
try {
if (EvaluateApplyRule(host, 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());
}
try {
if (EvaluateApplyRuleOne(host, 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 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);
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);
};

View File

@ -40,6 +40,45 @@ void Service::RegisterApplyRuleHandler(void)
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)
{
DebugInfo di = rule.GetDebugInfo();
@ -55,62 +94,46 @@ bool Service::EvaluateApplyRuleOne(const Host::Ptr& host, const ApplyRule& rule)
if (!rule.EvaluateFilter(locals))
return false;
Array::Ptr instances;
Value vinstances;
if (rule.GetFTerm()) {
Value vinstances = rule.GetFTerm()->Evaluate(locals);
if (!vinstances.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
instances = vinstances;
vinstances = rule.GetFTerm()->Evaluate(locals);
} else {
instances = make_shared<Array>();
Array::Ptr instances = make_shared<Array>();
instances->Add("");
vinstances = instances;
}
ObjectLock olock(instances);
BOOST_FOREACH(const String& instance, instances) {
String objName = rule.GetName();
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ConfigError("Array iterator requires value to be an array.") << errinfo_debuginfo(di));
if (!rule.GetFVar().IsEmpty()) {
locals->Set(rule.GetFVar(), instance);
objName += "-" + instance;
Array::Ptr arr = vinstances;
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")
<< "Applying service '" << objName << "' to host '" << host->GetName() << "' for rule " << di;
ObjectLock olock(dict);
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);
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));
EvaluateApplyRuleOneInstance(host, rule.GetName() + kv.first, locals, rule);
}
builder->AddExpression(rule.GetExpression());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
}
return true;

View File

@ -59,6 +59,7 @@ protected:
private:
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 void EvaluateApplyRule(const ApplyRule& rule);
static void EvaluateApplyRules(const std::vector<ApplyRule>& rules);