From 8136cda3675bca06ef2b512e57dc69017d2b1f45 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Mon, 5 Oct 2015 12:44:11 +0200 Subject: [PATCH] Implement the ignore_on_error keyword fixes #9960 --- lib/config/applyrule.cpp | 13 ++++++--- lib/config/applyrule.hpp | 7 +++-- lib/config/config_lexer.ll | 1 + lib/config/config_parser.yy | 24 ++++++++++++---- lib/config/configitem.cpp | 39 ++++++++++++++++++++------ lib/config/configitem.hpp | 4 ++- lib/config/configitembuilder.cpp | 7 ++++- lib/config/configitembuilder.hpp | 2 ++ lib/config/expression.cpp | 4 +-- lib/config/expression.hpp | 12 +++++--- lib/config/vmops.hpp | 7 +++-- lib/icinga/dependency-apply.cpp | 1 + lib/icinga/notification-apply.cpp | 1 + lib/icinga/scheduleddowntime-apply.cpp | 1 + lib/icinga/service-apply.cpp | 1 + 15 files changed, 93 insertions(+), 31 deletions(-) diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index ad408e298..cc3f972bd 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -29,9 +29,9 @@ ApplyRule::TypeMap ApplyRule::m_Types; ApplyRule::ApplyRule(const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, - const DebugInfo& di, const Dictionary::Ptr& scope) + bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope) : m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_Package(package), m_FKVar(fkvar), - m_FVVar(fvvar), m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope), m_HasMatches(false) + m_FVVar(fvvar), m_FTerm(fterm), m_IgnoreOnError(ignoreOnError), m_DebugInfo(di), m_Scope(scope), m_HasMatches(false) { } String ApplyRule::GetTargetType(void) const @@ -74,6 +74,11 @@ boost::shared_ptr ApplyRule::GetFTerm(void) const return m_FTerm; } +bool ApplyRule::GetIgnoreOnError(void) const +{ + return m_IgnoreOnError; +} + DebugInfo ApplyRule::GetDebugInfo(void) const { return m_DebugInfo; @@ -86,9 +91,9 @@ Dictionary::Ptr ApplyRule::GetScope(void) const void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, - const String& fvvar, const boost::shared_ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope) + const String& fvvar, const boost::shared_ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope) { - m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, package, fkvar, fvvar, fterm, di, scope)); + m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, package, fkvar, fvvar, fterm, ignoreOnError, di, scope)); } bool ApplyRule::EvaluateFilter(ScriptFrame& frame) const diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index 83f0842a4..223593ea2 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -45,6 +45,7 @@ public: String GetFKVar(void) const; String GetFVVar(void) const; boost::shared_ptr GetFTerm(void) const; + bool GetIgnoreOnError(void) const; DebugInfo GetDebugInfo(void) const; Dictionary::Ptr GetScope(void) const; void AddMatch(void); @@ -53,7 +54,8 @@ public: bool EvaluateFilter(ScriptFrame& frame) const; static void AddRule(const String& sourceType, const String& targetType, const String& name, const boost::shared_ptr& expression, - const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope); + const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, + bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope); static std::vector& GetRules(const String& type); static void RegisterType(const String& sourceType, const std::vector& targetTypes); @@ -73,6 +75,7 @@ private: String m_FKVar; String m_FVVar; boost::shared_ptr m_FTerm; + bool m_IgnoreOnError; DebugInfo m_DebugInfo; Dictionary::Ptr m_Scope; bool m_HasMatches; @@ -82,7 +85,7 @@ private: ApplyRule(const String& targetType, const String& name, const boost::shared_ptr& expression, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, - const DebugInfo& di, const Dictionary::Ptr& scope); + bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope); }; } diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index dff59929a..075dfa932 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -195,6 +195,7 @@ if return T_IF; else return T_ELSE; while return T_WHILE; throw return T_THROW; +ignore_on_error return T_IGNORE_ON_ERROR; =\> return T_FOLLOWS; \<\< return T_SHIFT_LEFT; \>\> return T_SHIFT_RIGHT; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 186f07aed..8c81efcd6 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -143,6 +143,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %token T_GLOBALS "globals (T_GLOBALS)" %token T_LOCALS "locals (T_LOCALS)" %token T_CONST "const (T_CONST)" +%token T_IGNORE_ON_ERROR "ignore_on_error (T_IGNORE_ON_ERROR)" %token T_USE "use (T_USE)" %token T_OBJECT "object (T_OBJECT)" %token T_TEMPLATE "template (T_TEMPLATE)" @@ -192,6 +193,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %type apply %type optional_rterm %type target_type_specifier +%type ignore_specifier %type use_specifier %type use_specifier_items %type use_specifier_item @@ -340,7 +342,7 @@ object: context->m_Assign.push(NULL); context->m_Ignore.push(NULL); } - object_declaration identifier optional_rterm use_specifier rterm_scope_require_side_effect + object_declaration identifier optional_rterm use_specifier ignore_specifier rterm_scope_require_side_effect { context->m_ObjectAssign.pop(); @@ -349,7 +351,7 @@ object: String type = *$3; delete $3; - $6->MakeInline(); + $7->MakeInline(); bool seen_assign = context->m_SeenAssign.top(); context->m_SeenAssign.pop(); @@ -382,7 +384,7 @@ object: BOOST_THROW_EXCEPTION(ScriptError("object rule 'ignore' is missing 'assign' for type '" + type + "'", DebugInfoRange(@2, @4))); } - $$ = new ObjectExpression(abstract, type, $4, filter, context->GetZone(), context->GetPackage(), $5, $6, DebugInfoRange(@2, @5)); + $$ = new ObjectExpression(abstract, type, $4, filter, context->GetZone(), context->GetPackage(), $5, $6, $7, DebugInfoRange(@2, @6)); } ; @@ -882,6 +884,16 @@ target_type_specifier: /* empty */ } ; +ignore_specifier: /* empty */ + { + $$ = false; + } + | T_IGNORE_ON_ERROR + { + $$ = true; + } + ; + use_specifier: /* empty */ { $$ = NULL; @@ -958,7 +970,7 @@ apply: context->m_FVVar.push(""); context->m_FTerm.push(NULL); } - T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier rterm_scope_require_side_effect + T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier ignore_specifier rterm_scope_require_side_effect { context->m_Apply.pop(); @@ -991,7 +1003,7 @@ apply: BOOST_THROW_EXCEPTION(ScriptError("'apply' target type '" + target + "' is invalid", DebugInfoRange(@2, @5))); } - $8->MakeInline(); + $9->MakeInline(); bool seen_assign = context->m_SeenAssign.top(); context->m_SeenAssign.pop(); @@ -1030,7 +1042,7 @@ apply: Expression *fterm = context->m_FTerm.top(); context->m_FTerm.pop(); - $$ = new ApplyExpression(type, target, $4, filter, context->GetPackage(), fkvar, fvvar, fterm, $7, $8, DebugInfoRange(@2, @7)); + $$ = new ApplyExpression(type, target, $4, filter, context->GetPackage(), fkvar, fvvar, fterm, $7, $8, $9, DebugInfoRange(@2, @8)); } ; diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 3016752d7..91bfbf164 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -60,11 +60,11 @@ REGISTER_SCRIPTFUNCTION(commit_objects, &ConfigItem::CommitAndActivate); */ ConfigItem::ConfigItem(const String& type, const String& name, bool abstract, const boost::shared_ptr& exprl, - const boost::shared_ptr& filter, + const boost::shared_ptr& filter, bool ignoreOnError, const DebugInfo& debuginfo, const Dictionary::Ptr& scope, const String& zone, const String& package) : m_Type(type), m_Name(name), m_Abstract(abstract), - m_Expression(exprl), m_Filter(filter), + m_Expression(exprl), m_Filter(filter), m_IgnoreOnError(ignoreOnError), m_DebugInfo(debuginfo), m_Scope(scope), m_Zone(zone), m_Package(package) { @@ -184,7 +184,18 @@ ConfigObject::Ptr ConfigItem::Commit(bool discard) ScriptFrame frame(dobj); if (m_Scope) m_Scope->CopyTo(frame.Locals); - m_Expression->Evaluate(frame, &debugHints); + try { + m_Expression->Evaluate(frame, &debugHints); + } catch (const std::exception& ex) { + if (m_IgnoreOnError) { + Log(LogWarning, "ConfigObject") + << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex); + + return ConfigObject::Ptr(); + } + + throw; + } if (discard) m_Expression.reset(); @@ -237,17 +248,24 @@ ConfigObject::Ptr ConfigItem::Commit(bool discard) di->Add(m_DebugInfo.LastColumn); persistentItem->Set("debug_info", di); - ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); - persistentItem.reset(); - try { DefaultValidationUtils utils; dobj->Validate(FAConfig, utils); } catch (ValidationError& ex) { + if (m_IgnoreOnError) { + Log(LogWarning, "ConfigObject") + << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex); + + return ConfigObject::Ptr(); + } + ex.SetDebugHint(dhint); throw; } + ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); + persistentItem.reset(); + dhint.reset(); dobj->Register(); @@ -407,7 +425,8 @@ bool ConfigItem::CommitNewItems(WorkQueue& upq, std::vector& ne continue; BOOST_FOREACH(const ConfigItem::Ptr& item, new_items) { - ASSERT(item->m_Object); + if (!item->m_Object) + continue; if (item->m_Type == type) upq.Enqueue(boost::bind(&ConfigObject::OnAllConfigLoaded, item->m_Object)); @@ -422,7 +441,8 @@ bool ConfigItem::CommitNewItems(WorkQueue& upq, std::vector& ne BOOST_FOREACH(const String& loadDep, ptype->GetLoadDependencies()) { BOOST_FOREACH(const ConfigItem::Ptr& item, new_items) { - ASSERT(item->m_Object); + if (!item->m_Object) + continue; if (item->m_Type == loadDep) upq.Enqueue(boost::bind(&ConfigObject::CreateChildObjects, item->m_Object, ptype)); @@ -464,6 +484,9 @@ bool ConfigItem::CommitItems(WorkQueue& upq) typedef std::map ItemCountMap; ItemCountMap itemCounts; BOOST_FOREACH(const ConfigItem::Ptr& item, newItems) { + if (!item->m_Object) + continue; + itemCounts[item->m_Object->GetReflectionType()]++; } diff --git a/lib/config/configitem.hpp b/lib/config/configitem.hpp index 36b6264df..6439d428e 100644 --- a/lib/config/configitem.hpp +++ b/lib/config/configitem.hpp @@ -41,13 +41,14 @@ public: ConfigItem(const String& type, const String& name, bool abstract, const boost::shared_ptr& exprl, const boost::shared_ptr& filter, - const DebugInfo& debuginfo, + bool ignoreOnError, const DebugInfo& debuginfo, const Dictionary::Ptr& scope, const String& zone, const String& package); String GetType(void) const; String GetName(void) const; bool IsAbstract(void) const; + bool GetIgnoreOnError(void) const; std::vector GetParents(void) const; @@ -80,6 +81,7 @@ private: boost::shared_ptr m_Expression; boost::shared_ptr m_Filter; + bool m_IgnoreOnError; DebugInfo m_DebugInfo; /**< Debug information. */ Dictionary::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 00405b382..2350bef25 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -80,6 +80,11 @@ void ConfigItemBuilder::SetFilter(const boost::shared_ptr& filter) m_Filter = filter; } +void ConfigItemBuilder::SetIgnoreOnError(bool ignoreOnError) +{ + m_IgnoreOnError = ignoreOnError; +} + ConfigItem::Ptr ConfigItemBuilder::Compile(void) { if (m_Type.IsEmpty()) { @@ -116,6 +121,6 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) exprl->MakeInline(); return new ConfigItem(m_Type, m_Name, m_Abstract, exprl, m_Filter, - m_DebugInfo, m_Scope, m_Zone, m_Package); + m_IgnoreOnError, m_DebugInfo, m_Scope, m_Zone, m_Package); } diff --git a/lib/config/configitembuilder.hpp b/lib/config/configitembuilder.hpp index 318bcaa31..a4d59fb12 100644 --- a/lib/config/configitembuilder.hpp +++ b/lib/config/configitembuilder.hpp @@ -48,6 +48,7 @@ public: void SetScope(const Dictionary::Ptr& scope); void SetZone(const String& zone); void SetPackage(const String& package); + void SetIgnoreOnError(bool ignoreOnError); void AddExpression(Expression *expr); void SetFilter(const boost::shared_ptr& filter); @@ -64,6 +65,7 @@ private: Dictionary::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ String m_Package; /**< The package name. */ + bool m_IgnoreOnError; /**< Whether the object should be ignored when an error occurs in one of the expressions. */ }; } diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 5f2832f91..f1679a84c 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -738,7 +738,7 @@ ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin CHECK_RESULT(nameres); return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter, - m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_Expression, m_DebugInfo); + m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo); } ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const @@ -756,7 +756,7 @@ ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhi } return VMOps::NewObject(frame, m_Abstract, m_Type, name, m_Filter, m_Zone, - m_Package, m_ClosedVars, m_Expression, m_DebugInfo); + m_Package, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo); } ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index adb96bc1a..dba2db3ae 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -804,11 +804,12 @@ class I2_CONFIG_API ApplyExpression : public DebuggableExpression public: ApplyExpression(const String& type, const String& target, Expression *name, Expression *filter, const String& package, const String& fkvar, const String& fvvar, - Expression *fterm, std::map *closedVars, + Expression *fterm, std::map *closedVars, bool ignoreOnError, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Type(type), m_Target(target), m_Name(name), m_Filter(filter), m_Package(package), m_FKVar(fkvar), m_FVVar(fvvar), - m_FTerm(fterm), m_ClosedVars(closedVars), m_Expression(expression) + m_FTerm(fterm), m_IgnoreOnError(ignoreOnError), m_ClosedVars(closedVars), + m_Expression(expression) { } ~ApplyExpression(void) @@ -828,6 +829,7 @@ private: String m_FKVar; String m_FVVar; boost::shared_ptr m_FTerm; + bool m_IgnoreOnError; std::map *m_ClosedVars; boost::shared_ptr m_Expression; }; @@ -837,9 +839,10 @@ class I2_CONFIG_API ObjectExpression : public DebuggableExpression public: ObjectExpression(bool abstract, const String& type, Expression *name, Expression *filter, const String& zone, const String& package, std::map *closedVars, - Expression *expression, const DebugInfo& debugInfo = DebugInfo()) + bool ignoreOnError, Expression *expression, const DebugInfo& debugInfo = DebugInfo()) : DebuggableExpression(debugInfo), m_Abstract(abstract), m_Type(type), - m_Name(name), m_Filter(filter), m_Zone(zone), m_Package(package), m_ClosedVars(closedVars), m_Expression(expression) + m_Name(name), m_Filter(filter), m_Zone(zone), m_Package(package), + m_IgnoreOnError(ignoreOnError), m_ClosedVars(closedVars), m_Expression(expression) { } ~ObjectExpression(void) @@ -857,6 +860,7 @@ private: boost::shared_ptr m_Filter; String m_Zone; String m_Package; + bool m_IgnoreOnError; std::map *m_ClosedVars; boost::shared_ptr m_Expression; }; diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 8160dad8c..0027a12d2 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -106,16 +106,16 @@ public: static inline Value NewApply(ScriptFrame& frame, const String& type, const String& target, const String& name, const boost::shared_ptr& filter, const String& package, const String& fkvar, const String& fvvar, const boost::shared_ptr& fterm, std::map *closedVars, - const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) + bool ignoreOnError, const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) { ApplyRule::AddRule(type, target, name, expression, filter, package, fkvar, - fvvar, fterm, debugInfo, EvaluateClosedVars(frame, closedVars)); + fvvar, fterm, ignoreOnError, debugInfo, EvaluateClosedVars(frame, closedVars)); return Empty; } static inline Value NewObject(ScriptFrame& frame, bool abstract, const String& type, const String& name, const boost::shared_ptr& filter, - const String& zone, const String& package, std::map *closedVars, const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) + const String& zone, const String& package, bool ignoreOnError, std::map *closedVars, const boost::shared_ptr& expression, const DebugInfo& debugInfo = DebugInfo()) { ConfigItemBuilder::Ptr item = new ConfigItemBuilder(debugInfo); @@ -149,6 +149,7 @@ public: item->SetZone(zone); item->SetPackage(package); item->SetFilter(filter); + item->SetIgnoreOnError(ignoreOnError); item->Compile()->Register(); return Empty; diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 44913cd79..1eb3eb121 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -55,6 +55,7 @@ bool Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, cons builder->SetType("Dependency"); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); + builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index e298cb0fc..fb36e4bb4 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -55,6 +55,7 @@ bool Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, co builder->SetType("Notification"); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); + builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 59fd4f90e..654a26bfa 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -54,6 +54,7 @@ bool ScheduledDowntime::EvaluateApplyRuleInstance(const Checkable::Ptr& checkabl builder->SetType("ScheduledDowntime"); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); + builder->SetIgnoreOnError(rule.GetIgnoreOnError()); Host::Ptr host; Service::Ptr service; diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index 07a8a760c..69cbf6ce1 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -53,6 +53,7 @@ bool Service::EvaluateApplyRuleInstance(const Host::Ptr& host, const String& nam builder->SetType("Service"); builder->SetName(name); builder->SetScope(frame.Locals->ShallowClone()); + builder->SetIgnoreOnError(rule.GetIgnoreOnError()); builder->AddExpression(new SetExpression(MakeIndexer(ScopeThis, "host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));