#include "base/socket.hpp"
#include "base/utility.hpp"
#include "base/json.hpp"
+#include "base/objectlock.hpp"
#include <mmatch.h>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/replace.hpp>
#include <ios>
#include <fstream>
#include <iostream>
return result;
}
+String Utility::Join(const Array::Ptr& tokens, char separator)
+{
+ String result;
+ bool first = true;
+
+ ObjectLock olock(tokens);
+ BOOST_FOREACH(const Value& vtoken, tokens) {
+ String token = Convert::ToString(vtoken);
+ boost::algorithm::replace_all(token, "\\", "\\\\");
+
+ char sep_before[2], sep_after[3];
+ sep_before[0] = separator;
+ sep_before[1] = '\0';
+ sep_after[0] = '\\';
+ sep_after[1] = separator;
+ sep_after[2] = '\0';
+ boost::algorithm::replace_all(token, sep_before, sep_after);
+
+ if (first)
+ first = false;
+ else
+ result += String(1, separator);
+
+ result += token;
+ }
+
+ return result;
+}
+
String Utility::FormatDuration(double duration)
{
std::vector<String> tokens;
#include "base/i2-base.hpp"
#include "base/string.hpp"
+#include "base/array.hpp"
#include <typeinfo>
#include <boost/function.hpp>
#include <boost/thread/tss.hpp>
static void QueueAsyncCallback(const boost::function<void (void)>& callback, SchedulerPolicy policy = DefaultScheduler);
static String NaturalJoin(const std::vector<String>& tokens);
+ static String Join(const Array::Ptr& tokens, char separator);
static String FormatDuration(double duration);
static String FormatDateTime(const char *format, double ts);
ObjectLock olock(vars);
BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
- if (!kv.first.IsEmpty()) {
- fp << "\t";
+ if (kv.first.IsEmpty())
+ continue;
- if (!CompatUtility::IsLegacyAttribute(object, kv.first))
- fp << "_";
+ String value;
- fp << kv.first << "\t" << kv.second << "\n";
- }
+ if (kv.second.IsObjectType<Array>())
+ value = Utility::Join(kv.second, ';');
+ else
+ value = kv.second;
+
+ fp << "\t";
+
+ if (!CompatUtility::IsLegacyAttribute(object, kv.first))
+ fp << "_";
+
+ fp << kv.first << "\t" << value << "\n";
}
}
ApplyRule::CallbackMap ApplyRule::m_Callbacks;
ApplyRule::ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression,
- const Expression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope)
- : m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_DebugInfo(di), m_Scope(scope)
+ const Expression::Ptr& filter, const String& fvar, 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)
{ }
String ApplyRule::GetTargetType(void) const
return m_Filter;
}
+String ApplyRule::GetFVar(void) const
+{
+ return m_FVar;
+}
+
+Expression::Ptr ApplyRule::GetFTerm(void) const
+{
+ return m_FTerm;
+}
+
DebugInfo ApplyRule::GetDebugInfo(void) const
{
return m_DebugInfo;
}
void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name,
- const Expression::Ptr& expression, const Expression::Ptr& filter,
- const DebugInfo& di, const Dictionary::Ptr& scope)
+ const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fvar,
+ const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope)
{
- m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, di, scope));
+ m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, fvar, fterm, di, scope));
}
bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const
String GetName(void) const;
Expression::Ptr GetExpression(void) const;
Expression::Ptr GetFilter(void) const;
+ String GetFVar(void) const;
+ Expression::Ptr GetFTerm(void) const;
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const;
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 DebugInfo& di, const Dictionary::Ptr& scope);
+ const Expression::Ptr& filter, const String& fvar, 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);
String m_Name;
Expression::Ptr m_Expression;
Expression::Ptr m_Filter;
+ String m_FVar;
+ Expression::Ptr m_FTerm;
DebugInfo m_DebugInfo;
Dictionary::Ptr m_Scope;
static RuleMap m_Rules;
ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression,
- const Expression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope);
+ const Expression::Ptr& filter, const String& fvar, const Expression::Ptr& fterm,
+ const DebugInfo& di, const Dictionary::Ptr& scope);
};
}
%attribute %dictionary "methods",
%attribute %dictionary "vars" {
- %attribute %string "*"
+ %attribute %string "*",
+ %attribute %array "*" {
+ %attribute %string "*"
+ }
},
}
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<Expression::Ptr> m_FTerm;
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_FTerm = std::stack<Expression::Ptr>();
try {
yyparse(this);
}
;
+apply_for_specifier: /* empty */
+ | T_FOR '(' identifier T_IN rterm ')'
+ {
+ m_FVar.top() = $3;
+ free($3);
+
+ m_FTerm.top() = *$5;
+ delete $5;
+ }
+ ;
+
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_FTerm.push(Expression::Ptr());
}
- T_APPLY identifier rterm target_type_specifier rterm
+ T_APPLY identifier rterm apply_for_specifier target_type_specifier rterm
{
m_Apply.pop();
free($3);
Expression::Ptr aname = *$4;
delete $4;
- String target = $5;
- free($5);
+ String target = $6;
+ free($6);
if (!ApplyRule::IsValidSourceType(type))
BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
BOOST_THROW_EXCEPTION(ConfigError("'apply' target type '" + target + "' is invalid") << errinfo_debuginfo(DebugInfoRange(@2, @5)));
}
- Expression::Ptr exprl = *$6;
- delete $6;
+ Expression::Ptr exprl = *$7;
+ delete $7;
exprl->MakeInline();
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();
+
+ Expression::Ptr fterm = m_FTerm.top();
+ m_FTerm.pop();
+
Array::Ptr args = make_shared<Array>();
args->Add(type);
args->Add(target);
args->Add(aname);
args->Add(filter);
+ args->Add(fvar);
+ args->Add(fterm);
$$ = new Value(make_shared<Expression>(&Expression::OpApply, args, exprl, DebugInfoRange(@2, @5)));
}
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 name = aname->Evaluate(locals, dhint);
- ApplyRule::AddRule(type, target, name, exprl, filter, expr->m_DebugInfo, locals);
+ ApplyRule::AddRule(type, target, name, exprl, filter, fvar, fterm, expr->m_DebugInfo, locals);
return Empty;
}
ObjectLock olock (vars);
BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
- if (!kv.first.IsEmpty()) {
- int overridden = custom_var_object->IsVarOverridden(kv.first) ? 1 : 0;
-
- Log(LogDebug, "DbObject")
- << "object customvar key: '" << kv.first << "' value: '" << kv.second
- << "' overridden: " << overridden;
-
- Dictionary::Ptr fields = make_shared<Dictionary>();
- fields->Set("varname", Convert::ToString(kv.first));
- fields->Set("varvalue", Convert::ToString(kv.second));
- fields->Set("config_type", 1);
- fields->Set("has_been_modified", overridden);
- fields->Set("object_id", obj);
- fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-
- DbQuery query;
- query.Table = "customvariables";
- query.Type = DbQueryInsert;
- query.Category = DbCatConfig;
- query.Fields = fields;
- OnQuery(query);
- }
+ if (kv.first.IsEmpty())
+ continue;
+
+ String value;
+
+ if (kv.second.IsObjectType<Array>())
+ value = Utility::Join(kv.second, ';');
+ else
+ value = kv.second;
+
+ int overridden = custom_var_object->IsVarOverridden(kv.first) ? 1 : 0;
+
+ Log(LogDebug, "DbObject")
+ << "object customvar key: '" << kv.first << "' value: '" << kv.second
+ << "' overridden: " << overridden;
+
+ Dictionary::Ptr fields = make_shared<Dictionary>();
+ fields->Set("varname", kv.first);
+ fields->Set("varvalue", value);
+ fields->Set("config_type", 1);
+ fields->Set("has_been_modified", overridden);
+ fields->Set("object_id", obj);
+ fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
+
+ DbQuery query;
+ query.Table = "customvariables";
+ query.Type = DbQueryInsert;
+ query.Category = DbCatConfig;
+ query.Fields = fields;
+ OnQuery(query);
}
}
}
ObjectLock olock (vars);
BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
- if (!kv.first.IsEmpty()) {
- int overridden = custom_var_object->IsVarOverridden(kv.first) ? 1 : 0;
-
- Log(LogDebug, "DbObject")
- << "object customvar key: '" << kv.first << "' value: '" << kv.second
- << "' overridden: " << overridden;
-
- Dictionary::Ptr fields = make_shared<Dictionary>();
- fields->Set("varname", Convert::ToString(kv.first));
- fields->Set("varvalue", Convert::ToString(kv.second));
- fields->Set("has_been_modified", overridden);
- fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
- fields->Set("object_id", obj);
- fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-
- DbQuery query;
- query.Table = "customvariablestatus";
- query.Type = DbQueryInsert | DbQueryUpdate;
- query.Category = DbCatState;
- query.Fields = fields;
-
- query.WhereCriteria = make_shared<Dictionary>();
- query.WhereCriteria->Set("object_id", obj);
- query.WhereCriteria->Set("varname", Convert::ToString(kv.first));
- query.Object = GetSelf();
-
- OnQuery(query);
- }
+ if (kv.first.IsEmpty() || kv.second.IsObject())
+ continue;
+
+ int overridden = custom_var_object->IsVarOverridden(kv.first) ? 1 : 0;
+
+ Log(LogDebug, "DbObject")
+ << "object customvar key: '" << kv.first << "' value: '" << kv.second
+ << "' overridden: " << overridden;
+
+ Dictionary::Ptr fields = make_shared<Dictionary>();
+ fields->Set("varname", Convert::ToString(kv.first));
+ fields->Set("varvalue", Convert::ToString(kv.second));
+ fields->Set("has_been_modified", overridden);
+ fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
+ fields->Set("object_id", obj);
+ fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
+
+ DbQuery query;
+ query.Table = "customvariablestatus";
+ query.Type = DbQueryInsert | DbQueryUpdate;
+ query.Category = DbCatState;
+ query.Fields = fields;
+
+ query.WhereCriteria = make_shared<Dictionary>();
+ query.WhereCriteria->Set("object_id", obj);
+ query.WhereCriteria->Set("varname", Convert::ToString(kv.first));
+ query.Object = GetSelf();
+
+ OnQuery(query);
}
-
}
}
if (!rule.EvaluateFilter(locals))
return false;
- Log(LogDebug, "Dependency")
- << "Applying dependency '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
+ Array::Ptr instances;
- ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
- builder->SetType("Dependency");
- builder->SetName(rule.GetName());
- builder->SetScope(locals);
+ if (rule.GetFTerm()) {
+ Value vinstances = rule.GetFTerm()->Evaluate(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));
+ if (!vinstances.IsObjectType<Array>())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
- 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));
+ instances = vinstances;
+ } else {
+ instances = make_shared<Array>();
+ instances->Add("");
}
- String zone = checkable->GetZone();
+ ObjectLock olock(instances);
+ BOOST_FOREACH(const String& instance, instances) {
+ String objName = rule.GetName();
+
+ if (!rule.GetFVar().IsEmpty()) {
+ locals->Set(rule.GetFVar(), instance);
+ objName += "-" + instance;
+ }
+
+ Log(LogDebug, "Dependency")
+ << "Applying dependency '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
+
+ ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
+ builder->SetType("Dependency");
+ builder->SetName(objName);
+ builder->SetScope(locals);
- 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));
- }
+ make_shared<Expression>(&Expression::OpLiteral, "parent_host_name", di),
+ make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
+ di));
- builder->AddExpression(rule.GetExpression());
+ 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));
+ }
- ConfigItem::Ptr dependencyItem = builder->Compile();
- dependencyItem->Register();
- DynamicObject::Ptr dobj = dependencyItem->Commit();
- dobj->OnConfigLoaded();
+ 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;
}
if (!rule.EvaluateFilter(locals))
return false;
- Log(LogDebug, "Notification")
- << "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
+ Array::Ptr instances;
- ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
- builder->SetType("Notification");
- builder->SetName(rule.GetName());
- builder->SetScope(locals);
+ if (rule.GetFTerm()) {
+ Value vinstances = rule.GetFTerm()->Evaluate(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 (!vinstances.IsObjectType<Array>())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
- 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));
+ instances = vinstances;
+ } else {
+ instances = make_shared<Array>();
+ instances->Add("");
}
- String zone = checkable->GetZone();
+ ObjectLock olock(instances);
+ BOOST_FOREACH(const String& instance, instances) {
+ String objName = rule.GetName();
+
+ if (!rule.GetFVar().IsEmpty()) {
+ locals->Set(rule.GetFVar(), instance);
+ objName += "-" + instance;
+ }
+
+ Log(LogDebug, "Notification")
+ << "Applying notification '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
+
+ ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
+ builder->SetType("Notification");
+ builder->SetName(objName);
+ builder->SetScope(locals);
- 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));
- }
+ 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();
- builder->AddExpression(rule.GetExpression());
+ 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();
+ ConfigItem::Ptr notificationItem = builder->Compile();
+ notificationItem->Register();
+ DynamicObject::Ptr dobj = notificationItem->Commit();
+ dobj->OnConfigLoaded();
+ }
return true;
}
if (!rule.EvaluateFilter(locals))
return false;
- Log(LogDebug, "ScheduledDowntime")
- << "Applying scheduled downtime '" << rule.GetName() << "' to object '" << checkable->GetName() << "' for rule " << di;
+ Array::Ptr instances;
- ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
- builder->SetType("ScheduledDowntime");
- builder->SetName(rule.GetName());
- builder->SetScope(locals);
+ if (rule.GetFTerm()) {
+ Value vinstances = rule.GetFTerm()->Evaluate(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 (!vinstances.IsObjectType<Array>())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
- 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));
+ instances = vinstances;
+ } else {
+ instances = make_shared<Array>();
+ instances->Add("");
}
- String zone = checkable->GetZone();
+ ObjectLock olock(instances);
+ BOOST_FOREACH(const String& instance, instances) {
+ String objName = rule.GetName();
+
+ if (!rule.GetFVar().IsEmpty()) {
+ locals->Set(rule.GetFVar(), instance);
+ objName += "-" + instance;
+ }
+
+ 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(objName);
+ builder->SetScope(locals);
- 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));
- }
+ 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();
- builder->AddExpression(rule.GetExpression());
+ 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));
+ }
- ConfigItem::Ptr downtimeItem = builder->Compile();
- downtimeItem->Register();
- DynamicObject::Ptr dobj = downtimeItem->Commit();
- dobj->OnConfigLoaded();
+ builder->AddExpression(rule.GetExpression());
+
+ ConfigItem::Ptr downtimeItem = builder->Compile();
+ downtimeItem->Register();
+ DynamicObject::Ptr dobj = downtimeItem->Commit();
+ dobj->OnConfigLoaded();
+ }
return true;
}
if (!rule.EvaluateFilter(locals))
return false;
- Log(LogDebug, "Service")
- << "Applying service '" << rule.GetName() << "' to host '" << host->GetName() << "' for rule " << di;
+ Array::Ptr instances;
- ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
- builder->SetType("Service");
- builder->SetName(rule.GetName());
- builder->SetScope(locals);
+ if (rule.GetFTerm()) {
+ Value vinstances = rule.GetFTerm()->Evaluate(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 (!vinstances.IsObjectType<Array>())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("for expression must be an array"));
- builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
- make_shared<Expression>(&Expression::OpLiteral, "name", di),
- make_shared<Expression>(&Expression::OpLiteral, rule.GetName(), di),
- di));
+ instances = vinstances;
+ } else {
+ instances = make_shared<Array>();
+ instances->Add("");
+ }
+
+ ObjectLock olock(instances);
+ BOOST_FOREACH(const String& instance, instances) {
+ String objName = rule.GetName();
+
+ if (!rule.GetFVar().IsEmpty()) {
+ locals->Set(rule.GetFVar(), instance);
+ objName += "-" + instance;
+ }
- String zone = host->GetZone();
+ Log(LogDebug, "Service")
+ << "Applying service '" << objName << "' to host '" << host->GetName() << "' for rule " << di;
+
+ ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(di);
+ builder->SetType("Service");
+ builder->SetName(objName);
+ builder->SetScope(locals);
- if (!zone.IsEmpty()) {
builder->AddExpression(make_shared<Expression>(&Expression::OpSet,
- make_shared<Expression>(&Expression::OpLiteral, "zone", di),
- make_shared<Expression>(&Expression::OpLiteral, zone, di),
+ make_shared<Expression>(&Expression::OpLiteral, "host_name", di),
+ make_shared<Expression>(&Expression::OpLiteral, host->GetName(), di),
di));
- }
- builder->AddExpression(rule.GetExpression());
+ 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();
+ ConfigItem::Ptr serviceItem = builder->Compile();
+ serviceItem->Register();
+ DynamicObject::Ptr dobj = serviceItem->Commit();
+ dobj->OnConfigLoaded();
+ }
return true;
}