diff --git a/components/compat/compatlog.cpp b/components/compat/compatlog.cpp index af6394cde..27faf0b7c 100644 --- a/components/compat/compatlog.cpp +++ b/components/compat/compatlog.cpp @@ -577,7 +577,7 @@ void CompatLog::ValidateRotationMethod(const String& location, const Dictionary: if (!rotation_method.IsEmpty() && rotation_method != "HOURLY" && rotation_method != "DAILY" && rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") { - ConfigCompilerContext::GetInstance()->AddError(false, "Validation failed for " + + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": Rotation method '" + rotation_method + "' is invalid."); } } diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 90efd84d3..f85182433 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -58,50 +58,23 @@ static bool LoadConfigFiles(bool validateOnly) ConfigCompiler::CompileText(name, fragment); } - bool hasError = false; - - BOOST_FOREACH(const ConfigCompilerError& error, ConfigCompilerContext::GetInstance()->GetErrors()) { - if (!error.Warning) { - hasError = true; - break; - } - } - - /* Don't link or validate if we have already encountered at least one error. */ - if (!hasError) { - ConfigItem::LinkItems(); - ConfigItem::ValidateItems(); - } - - hasError = false; - - BOOST_FOREACH(const ConfigCompilerError& error, ConfigCompilerContext::GetInstance()->GetErrors()) { - if (error.Warning) { - Log(LogWarning, "icinga-app", "Config warning: " + error.Message); - } else { - hasError = true; - Log(LogCritical, "icinga-app", "Config error: " + error.Message); - } - } - - if (hasError) - return false; - - if (validateOnly) - return true; - - if (Application::GetInstance()) { - Log(LogCritical, "icinga-app", "You must not manually create an Application object."); - return false; - } - ConfigItemBuilder::Ptr builder = boost::make_shared(); builder->SetType(Application::GetApplicationType()); builder->SetName("application"); ConfigItem::Ptr item = builder->Compile(); item->Register(); - ConfigItem::ActivateItems(); + bool result = ConfigItem::ActivateItems(validateOnly); + + BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) { + if (message.Error) + Log(LogCritical, "config", "Config error: " + message.Text); + else + Log(LogWarning, "config", "Config warning: " + message.Text); + } + + if (!result) + return false; ConfigItem::DiscardItems(); ConfigType::DiscardTypes(); diff --git a/lib/config/config_lexer.cc b/lib/config/config_lexer.cc index b5bdcedba..7492f11d5 100644 --- a/lib/config/config_lexer.cc +++ b/lib/config/config_lexer.cc @@ -1061,7 +1061,7 @@ YY_RULE_SETUP { std::ostringstream msgbuf; msgbuf << "Unterminated string found: " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); BEGIN(INITIAL); } YY_BREAK @@ -1078,7 +1078,7 @@ YY_RULE_SETUP /* error, constant is out-of-bounds */ std::ostringstream msgbuf; msgbuf << "Constant is out-of-bounds: " << yytext << " " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); } lb_append_char(&string_buf, result); @@ -1093,7 +1093,7 @@ YY_RULE_SETUP */ std::ostringstream msgbuf; msgbuf << "Bad escape sequence found: " << yytext << " " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); } YY_BREAK case 6: diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index f6ca1a65f..b757b01e2 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -116,7 +116,7 @@ static char *lb_steal(lex_buf *lb) \n { std::ostringstream msgbuf; msgbuf << "Unterminated string found: " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); BEGIN(INITIAL); } @@ -130,7 +130,7 @@ static char *lb_steal(lex_buf *lb) /* error, constant is out-of-bounds */ std::ostringstream msgbuf; msgbuf << "Constant is out-of-bounds: " << yytext << " " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); } lb_append_char(&string_buf, result); @@ -142,7 +142,7 @@ static char *lb_steal(lex_buf *lb) */ std::ostringstream msgbuf; msgbuf << "Bad escape sequence found: " << yytext << " " << *yylloc; - ConfigCompilerContext::GetInstance()->AddError(false, msgbuf.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, msgbuf.str()); } \\n { lb_append_char(&string_buf, '\n'); } diff --git a/lib/config/config_parser.cc b/lib/config/config_parser.cc index 3b88ea5cf..f734bdbcc 100644 --- a/lib/config/config_parser.cc +++ b/lib/config/config_parser.cc @@ -267,7 +267,7 @@ void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err) { std::ostringstream message; message << *locp << ": " << err; - ConfigCompilerContext::GetInstance()->AddError(false, message.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, message.str()); } int yyparse(ConfigCompiler *context); @@ -283,7 +283,7 @@ void ConfigCompiler::Compile(void) try { yyparse(this); } catch (const std::exception& ex) { - ConfigCompilerContext::GetInstance()->AddError(false, boost::diagnostic_information(ex)); + ConfigCompilerContext::GetInstance()->AddMessage(true, boost::diagnostic_information(ex)); } } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 55722013f..c1fc98ff6 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -124,7 +124,7 @@ void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err) { std::ostringstream message; message << *locp << ": " << err; - ConfigCompilerContext::GetInstance()->AddError(false, message.str()); + ConfigCompilerContext::GetInstance()->AddMessage(true, message.str()); } int yyparse(ConfigCompiler *context); @@ -140,7 +140,7 @@ void ConfigCompiler::Compile(void) try { yyparse(this); } catch (const std::exception& ex) { - ConfigCompilerContext::GetInstance()->AddError(false, boost::diagnostic_information(ex)); + ConfigCompilerContext::GetInstance()->AddMessage(true, boost::diagnostic_information(ex)); } } diff --git a/lib/config/configcompilercontext.cpp b/lib/config/configcompilercontext.cpp index 953ab2af5..2f1093c54 100644 --- a/lib/config/configcompilercontext.cpp +++ b/lib/config/configcompilercontext.cpp @@ -25,19 +25,29 @@ using namespace icinga; -void ConfigCompilerContext::AddError(bool warning, const String& message) +void ConfigCompilerContext::AddMessage(bool error, const String& message) { - m_Errors.push_back(ConfigCompilerError(warning, message)); + m_Messages.push_back(ConfigCompilerMessage(error, message)); } -std::vector ConfigCompilerContext::GetErrors(void) const +std::vector ConfigCompilerContext::GetMessages(void) const { - return m_Errors; + return m_Messages; +} + +bool ConfigCompilerContext::HasErrors(void) const +{ + BOOST_FOREACH(const ConfigCompilerMessage& message, m_Messages) { + if (message.Error) + return true; + } + + return false; } void ConfigCompilerContext::Reset(void) { - m_Errors.clear(); + m_Messages.clear(); } ConfigCompilerContext *ConfigCompilerContext::GetInstance(void) diff --git a/lib/config/configcompilercontext.h b/lib/config/configcompilercontext.h index 8c9adecfa..1ebe5e968 100644 --- a/lib/config/configcompilercontext.h +++ b/lib/config/configcompilercontext.h @@ -27,13 +27,13 @@ namespace icinga { -struct I2_CONFIG_API ConfigCompilerError +struct I2_CONFIG_API ConfigCompilerMessage { - bool Warning; - String Message; + bool Error; + String Text; - ConfigCompilerError(bool warning, const String& message) - : Warning(warning), Message(message) + ConfigCompilerMessage(bool error, const String& text) + : Error(error), Text(text) { } }; @@ -43,15 +43,16 @@ struct I2_CONFIG_API ConfigCompilerError class I2_CONFIG_API ConfigCompilerContext { public: - void AddError(bool warning, const String& message); - std::vector GetErrors(void) const; + void AddMessage(bool error, const String& message); + std::vector GetMessages(void) const; + bool HasErrors(void) const; void Reset(void); static ConfigCompilerContext *GetInstance(void); private: - std::vector m_Errors; + std::vector m_Messages; }; } diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index cfba85cc7..0f42ab91b 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -116,13 +116,13 @@ void ConfigItem::Link(void) std::ostringstream message; message << "Parent object '" << name << "' does not" " exist (" << m_DebugInfo << ")"; - BOOST_THROW_EXCEPTION(std::invalid_argument(message.str())); + ConfigCompilerContext::GetInstance()->AddMessage(true, message.str()); + } else { + parent->Link(); + + ExpressionList::Ptr pexprl = parent->GetLinkedExpressionList(); + m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo)); } - - parent->Link(); - - ExpressionList::Ptr pexprl = parent->GetLinkedExpressionList(); - m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo)); } m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, m_ExpressionList, m_DebugInfo)); @@ -233,41 +233,38 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name) return ConfigItem::Ptr(); } -void ConfigItem::LinkItems(void) +void ConfigItem::ValidateItem(void) { + ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); + + if (!ctype) { + ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'"); + + return; + } + + ctype->ValidateItem(GetSelf()); +} + +bool ConfigItem::ActivateItems(bool validateOnly) +{ + if (ConfigCompilerContext::GetInstance()->HasErrors()) + return false; + Log(LogInformation, "config", "Linking config items..."); ConfigItem::Ptr item; BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) { item->Link(); } -} -void ConfigItem::ValidateItems(void) -{ - Log(LogInformation, "config", "Validating config items..."); + if (ConfigCompilerContext::GetInstance()->HasErrors()) + return false; - ConfigItem::Ptr item; - BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) { - ConfigType::Ptr ctype = ConfigType::GetByName(item->GetType()); - - if (!ctype) { - ConfigCompilerContext::GetInstance()->AddError(true, "No validation type found for object '" + item->GetName() + "' of type '" + item->GetType() + "'"); - - continue; - } - - ctype->ValidateItem(item); - } -} - -void ConfigItem::ActivateItems(void) -{ Log(LogInformation, "config", "Activating config items"); std::vector objects; - ConfigItem::Ptr item; BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) { DynamicObject::Ptr object = item->Commit(); @@ -279,6 +276,16 @@ void ConfigItem::ActivateItems(void) object->OnConfigLoaded(); } + BOOST_FOREACH(boost::tie(boost::tuples::ignore, item), m_Items) { + item->ValidateItem(); + } + + if (ConfigCompilerContext::GetInstance()->HasErrors()) + return false; + + if (validateOnly) + return true; + /* restore the previous program state */ DynamicObject::RestoreObjects(Application::GetStatePath()); @@ -293,6 +300,8 @@ void ConfigItem::ActivateItems(void) ASSERT(object->IsActive()); } } + + return true; } void ConfigItem::DiscardItems(void) diff --git a/lib/config/configitem.h b/lib/config/configitem.h index e85cb91a6..f6de74ce1 100644 --- a/lib/config/configitem.h +++ b/lib/config/configitem.h @@ -62,9 +62,9 @@ public: static ConfigItem::Ptr GetObject(const String& type, const String& name); - static void LinkItems(void); - static void ValidateItems(void); - static void ActivateItems(void); + void ValidateItem(void); + + static bool ActivateItems(bool validateOnly); static void DiscardItems(void); private: diff --git a/lib/config/configtype.cpp b/lib/config/configtype.cpp index 9c7f3966a..5baa17a41 100644 --- a/lib/config/configtype.cpp +++ b/lib/config/configtype.cpp @@ -121,7 +121,7 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, Value value = dictionary->Get(require); if (value.IsEmpty()) { - ConfigCompilerContext::GetInstance()->AddError(false, + ConfigCompilerContext::GetInstance()->AddMessage(true, "Required attribute is missing: " + LocationToString(locations)); } @@ -175,14 +175,14 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, } if (overallResult == ValidationUnknownField) - ConfigCompilerContext::GetInstance()->AddError(true, "Unknown attribute: " + LocationToString(locations)); + ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations)); else if (overallResult == ValidationInvalidType) { String message = "Invalid value for attribute: " + LocationToString(locations); if (!hint.IsEmpty()) message += ": " + hint; - ConfigCompilerContext::GetInstance()->AddError(false, message); + ConfigCompilerContext::GetInstance()->AddMessage(true, message); } if (!subRuleLists.empty() && value.IsObjectType()) @@ -204,7 +204,7 @@ void ConfigType::ValidateArray(const Array::Ptr& array, locations.push_back("Attribute '" + require + "'"); if (array->GetLength() < index) { - ConfigCompilerContext::GetInstance()->AddError(false, + ConfigCompilerContext::GetInstance()->AddMessage(true, "Required array index is missing: " + LocationToString(locations)); } @@ -261,14 +261,14 @@ void ConfigType::ValidateArray(const Array::Ptr& array, } if (overallResult == ValidationUnknownField) - ConfigCompilerContext::GetInstance()->AddError(true, "Unknown attribute: " + LocationToString(locations)); + ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations)); else if (overallResult == ValidationInvalidType) { String message = "Invalid value for array index: " + LocationToString(locations); if (!hint.IsEmpty()) message += ": " + hint; - ConfigCompilerContext::GetInstance()->AddError(false, message); + ConfigCompilerContext::GetInstance()->AddMessage(true, message); } if (!subRuleLists.empty() && value.IsObjectType()) diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 1e42fbcd2..964267c6c 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -58,6 +58,11 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const Array::Ptr array; switch (m_Operator) { + case OperatorNop: + /* Nothing to do here. */ + + return; + case OperatorExecute: if (!valueExprl) BOOST_THROW_EXCEPTION(std::invalid_argument("Operand for OperatorExecute must be an ExpressionList.")); @@ -165,3 +170,41 @@ void Expression::ExtractFiltered(const std::set& keys, con exprl->ExtractFiltered(keys, result); } } + +void Expression::ErasePath(const std::vector& path) +{ + ASSERT(!path.empty()); + + if (path[0] == m_Key) { + if (path.size() == 1) { + m_Operator = OperatorNop; + } else if (m_Value.IsObjectType()) { + ExpressionList::Ptr exprl = m_Value; + + std::vector sub_path(path.begin() + 1, path.end()); + exprl->ErasePath(sub_path); + } + } else if (m_Operator == OperatorExecute) { + ExpressionList::Ptr exprl = m_Value; + exprl->ErasePath(path); + } +} + +void Expression::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const +{ + ASSERT(!path.empty()); + + if (path[0] == m_Key) { + if (path.size() == 1) { + result = m_DebugInfo; + } else if (m_Value.IsObjectType()) { + ExpressionList::Ptr exprl = m_Value; + + std::vector sub_path(path.begin() + 1, path.end()); + exprl->FindDebugInfoPath(sub_path, result); + } + } else if (m_Operator == OperatorExecute) { + ExpressionList::Ptr exprl = m_Value; + exprl->FindDebugInfoPath(path, result); + } +} diff --git a/lib/config/expression.h b/lib/config/expression.h index b9cd012dc..1e60f66c8 100644 --- a/lib/config/expression.h +++ b/lib/config/expression.h @@ -37,6 +37,7 @@ namespace icinga */ enum ExpressionOperator { + OperatorNop, OperatorExecute, OperatorSet, OperatorPlus, @@ -63,6 +64,10 @@ public: void ExtractPath(const std::vector& path, const shared_ptr& result) const; void ExtractFiltered(const std::set& keys, const shared_ptr& result) const; + void ErasePath(const std::vector& path); + + void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; + private: String m_Key; ExpressionOperator m_Operator; diff --git a/lib/config/expressionlist.cpp b/lib/config/expressionlist.cpp index feebaaff7..edab1fdb3 100644 --- a/lib/config/expressionlist.cpp +++ b/lib/config/expressionlist.cpp @@ -68,3 +68,17 @@ void ExpressionList::ExtractFiltered(const std::set& keys, expression.ExtractFiltered(keys, result); } } + +void ExpressionList::ErasePath(const std::vector& path) +{ + BOOST_FOREACH(Expression& expression, m_Expressions) { + expression.ErasePath(path); + } +} + +void ExpressionList::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const +{ + BOOST_FOREACH(const Expression& expression, m_Expressions) { + expression.FindDebugInfoPath(path, result); + } +} diff --git a/lib/config/expressionlist.h b/lib/config/expressionlist.h index 51e77aa4a..ec0e63e4c 100644 --- a/lib/config/expressionlist.h +++ b/lib/config/expressionlist.h @@ -47,6 +47,10 @@ public: void ExtractPath(const std::vector& path, const ExpressionList::Ptr& result) const; void ExtractFiltered(const std::set& keys, const ExpressionList::Ptr& result) const; + void ErasePath(const std::vector& path); + + void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; + private: std::vector m_Expressions; }; diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 6f9a765c9..5afadccb6 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -36,8 +36,6 @@ using namespace icinga; -REGISTER_SCRIPTFUNCTION(ValidateServiceDictionary, &Host::ValidateServiceDictionary); - REGISTER_TYPE(Host); void Host::Start(void) @@ -197,7 +195,17 @@ void Host::UpdateSlaveServices(void) namebuf << GetName() << ":" << svcname; String name = namebuf.str(); - ConfigItemBuilder::Ptr builder = boost::make_shared(item->GetDebugInfo()); + std::vector path; + path.push_back("services"); + path.push_back(svcname); + + DebugInfo di; + item->GetLinkedExpressionList()->FindDebugInfoPath(path, di); + + if (di.Path.IsEmpty()) + di = item->GetDebugInfo(); + + ConfigItemBuilder::Ptr builder = boost::make_shared(di); builder->SetType("Service"); builder->SetName(name); builder->AddExpression("host_name", OperatorSet, GetName()); @@ -238,12 +246,13 @@ void Host::UpdateSlaveServices(void) builder->AddExpressionList(host_exprl); /* Clone attributes from the service expression list. */ - std::vector path; - path.push_back("services"); - path.push_back(svcname); - ExpressionList::Ptr svc_exprl = boost::make_shared(); item->GetLinkedExpressionList()->ExtractPath(path, svc_exprl); + + std::vector dpath; + dpath.push_back("templates"); + svc_exprl->ErasePath(dpath); + builder->AddExpressionList(svc_exprl); ConfigItem::Ptr serviceItem = builder->Compile(); @@ -290,42 +299,6 @@ int Host::GetTotalServices(void) const return GetServices().size(); } -Value Host::ValidateServiceDictionary(const String& location, const Dictionary::Ptr& attrs) -{ - ObjectLock olock(attrs); - - String key; - Value value; - BOOST_FOREACH(boost::tie(key, value), attrs) { - std::vector templates; - - if (!value.IsObjectType()) - BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be a dictionary.")); - - Dictionary::Ptr serviceDesc = value; - - Array::Ptr templatesArray = serviceDesc->Get("templates"); - - if (templatesArray) { - ObjectLock tlock(templatesArray); - - BOOST_FOREACH(const Value& tmpl, templatesArray) { - templates.push_back(tmpl); - } - } - - BOOST_FOREACH(const String& name, templates) { - ConfigItem::Ptr item = ConfigItem::GetObject("Service", name); - - if (!item) - ConfigCompilerContext::GetInstance()->AddError(false, "Validation failed for " + - location + ": Template '" + name + "' not found."); - } - } - - return Empty; -} - Service::Ptr Host::GetServiceByShortName(const Value& name) const { if (name.IsScalar()) { diff --git a/lib/icinga/host.h b/lib/icinga/host.h index 68011d1f5..c4d1fce8b 100644 --- a/lib/icinga/host.h +++ b/lib/icinga/host.h @@ -104,8 +104,6 @@ public: int GetTotalServices(void) const; - static Value ValidateServiceDictionary(const String& location, const Dictionary::Ptr& attrs); - static HostState CalculateState(ServiceState state, bool reachable); HostState GetState(void) const; diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index ade463095..33c67e03d 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -36,14 +36,12 @@ type Host { } }, %attribute dictionary "services" { - %validator "ValidateServiceDictionary", - %attribute dictionary "*" { %attribute array "templates" { %attribute name(Service) "*" }, - %attribute string "short_name", +/* %attribute string "short_name", %attribute string "display_name", %attribute dictionary "macros" { @@ -112,11 +110,11 @@ type Host { %attribute number "notification_state_filter", %attribute name(TimePeriod) "notification_period" } - }, + },*/ } }, - %attribute dictionary "notifications" { +/* %attribute dictionary "notifications" { %attribute dictionary "*" { %attribute array "templates" { %attribute name(Notification) "*" @@ -142,7 +140,7 @@ type Host { %attribute number "notification_state_filter", %attribute name(TimePeriod) "notification_period" } - }, + },*/ /* service attributes */ %attribute number "max_check_attempts", @@ -244,7 +242,7 @@ type Service { %attribute name(Notification) "*" }, - %attribute dictionary "macros" { +/* %attribute dictionary "macros" { %attribute string "*" }, @@ -262,7 +260,7 @@ type Service { %attribute number "notification_type_filter", %attribute number "notification_state_filter", - %attribute name(TimePeriod) "notification_period" + %attribute name(TimePeriod) "notification_period"*/ } } } diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 5ccfe28a2..05e656e99 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -147,7 +147,17 @@ void Service::UpdateSlaveNotifications(void) namebuf << GetName() << ":" << nfcname; String name = namebuf.str(); - ConfigItemBuilder::Ptr builder = boost::make_shared(item->GetDebugInfo()); + std::vector path; + path.push_back("notifications"); + path.push_back(nfcname); + + DebugInfo di; + item->GetLinkedExpressionList()->FindDebugInfoPath(path, di); + + if (di.Path.IsEmpty()) + di = item->GetDebugInfo(); + + ConfigItemBuilder::Ptr builder = boost::make_shared(di); builder->SetType("Notification"); builder->SetName(name); builder->AddExpression("host_name", OperatorSet, host->GetName()); @@ -183,12 +193,13 @@ void Service::UpdateSlaveNotifications(void) builder->AddExpressionList(svc_exprl); /* Clone attributes from the notification expression list. */ - std::vector path; - path.push_back("notifications"); - path.push_back(nfcname); - ExpressionList::Ptr nfc_exprl = boost::make_shared(); item->GetLinkedExpressionList()->ExtractPath(path, nfc_exprl); + + std::vector dpath; + dpath.push_back("templates"); + nfc_exprl->ErasePath(dpath); + builder->AddExpressionList(nfc_exprl); ConfigItem::Ptr notificationItem = builder->Compile();