diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index b212389b3..b350b4d6c 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -320,3 +320,13 @@ void Checkable::CleanDeadlinedExecutions(const Timer * const&) } } } + +Dictionary::Ptr Checkable::GetFrozenLocalsForApply() +{ + if (!m_FrozenLocalsForApply) { + m_FrozenLocalsForApply = MakeLocalsForApply(); + m_FrozenLocalsForApply->Freeze(); + } + + return m_FrozenLocalsForApply; +} diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 6a46425a9..913c3579b 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -207,12 +207,18 @@ public: static Object::Ptr GetPrototype(); + Dictionary::Ptr GetFrozenLocalsForApply(); + protected: void Start(bool runtimeCreated) override; void OnConfigLoaded() override; void OnAllConfigLoaded() override; + virtual Dictionary::Ptr MakeLocalsForApply() = 0; + private: + Dictionary::Ptr m_FrozenLocalsForApply; + mutable std::mutex m_CheckableMutex; bool m_CheckRunning{false}; long m_SchedulingOffset; diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index c37746abe..7e39c0ccc 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -70,16 +70,20 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); - Host::Ptr host; - Service::Ptr service; - tie(host, service) = GetHostService(checkable); + ScriptFrame frame (false); - ScriptFrame frame(true); - if (rule.GetScope()) - rule.GetScope()->CopyTo(frame.Locals); - frame.Locals->Set("host", host); - if (service) - frame.Locals->Set("service", service); + if (rule.GetScope() || rule.GetFTerm()) { + frame.Locals = new Dictionary(); + + if (rule.GetScope()) { + rule.GetScope()->CopyTo(frame.Locals); + } + + checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); + frame.Locals->Freeze(); + } else { + frame.Locals = checkable->GetFrozenLocalsForApply(); + } bool match = false; @@ -103,7 +107,7 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR for (const Value& instance : arr) { String name = rule.GetName(); - frame.Locals->Set(rule.GetFKVar(), instance); + frame.Locals->Set(rule.GetFKVar(), instance, true); name += instance; if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) @@ -117,8 +121,8 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first); - frame.Locals->Set(rule.GetFVVar(), kv.second); + frame.Locals->Set(rule.GetFKVar(), kv.first, true); + frame.Locals->Set(rule.GetFVVar(), kv.second, true); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) match = true; diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 36149d3dc..bc4ee4402 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -328,3 +328,8 @@ bool Host::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *res return false; } + +Dictionary::Ptr Host::MakeLocalsForApply() +{ + return new Dictionary({{ "host", this }}); +} diff --git a/lib/icinga/host.hpp b/lib/icinga/host.hpp index d0d6c1aa4..16eed5470 100644 --- a/lib/icinga/host.hpp +++ b/lib/icinga/host.hpp @@ -57,6 +57,8 @@ protected: void CreateChildObjects(const Type::Ptr& childType) override; + Dictionary::Ptr MakeLocalsForApply() override; + private: mutable std::mutex m_ServicesMutex; std::map > m_Services; diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index 1aee13961..de986a2cd 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -69,16 +69,20 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); - Host::Ptr host; - Service::Ptr service; - tie(host, service) = GetHostService(checkable); + ScriptFrame frame (false); - ScriptFrame frame(true); - if (rule.GetScope()) - rule.GetScope()->CopyTo(frame.Locals); - frame.Locals->Set("host", host); - if (service) - frame.Locals->Set("service", service); + if (rule.GetScope() || rule.GetFTerm()) { + frame.Locals = new Dictionary(); + + if (rule.GetScope()) { + rule.GetScope()->CopyTo(frame.Locals); + } + + checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); + frame.Locals->Freeze(); + } else { + frame.Locals = checkable->GetFrozenLocalsForApply(); + } bool match = false; @@ -102,7 +106,7 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl for (const Value& instance : arr) { String name = rule.GetName(); - frame.Locals->Set(rule.GetFKVar(), instance); + frame.Locals->Set(rule.GetFKVar(), instance, true); name += instance; if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) @@ -116,8 +120,8 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first); - frame.Locals->Set(rule.GetFVVar(), kv.second); + frame.Locals->Set(rule.GetFKVar(), kv.first, true); + frame.Locals->Set(rule.GetFVVar(), kv.second, true); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) match = true; diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 601b301e5..be1b25cba 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -68,16 +68,20 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); - Host::Ptr host; - Service::Ptr service; - tie(host, service) = GetHostService(checkable); + ScriptFrame frame (false); - ScriptFrame frame(true); - if (rule.GetScope()) - rule.GetScope()->CopyTo(frame.Locals); - frame.Locals->Set("host", host); - if (service) - frame.Locals->Set("service", service); + if (rule.GetScope() || rule.GetFTerm()) { + frame.Locals = new Dictionary(); + + if (rule.GetScope()) { + rule.GetScope()->CopyTo(frame.Locals); + } + + checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); + frame.Locals->Freeze(); + } else { + frame.Locals = checkable->GetFrozenLocalsForApply(); + } bool match = false; @@ -101,7 +105,7 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const for (const Value& instance : arr) { String name = rule.GetName(); - frame.Locals->Set(rule.GetFKVar(), instance); + frame.Locals->Set(rule.GetFKVar(), instance, true); name += instance; if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) @@ -115,8 +119,8 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first); - frame.Locals->Set(rule.GetFVVar(), kv.second); + frame.Locals->Set(rule.GetFKVar(), kv.first, true); + frame.Locals->Set(rule.GetFVVar(), kv.second, true); if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) match = true; diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index d7f367271..648d6d04f 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -63,10 +63,20 @@ bool Service::EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule, bo msgbuf << "Evaluating 'apply' rule (" << di << ")"; CONTEXT(msgbuf.str()); - ScriptFrame frame(true); - if (rule.GetScope()) - rule.GetScope()->CopyTo(frame.Locals); - frame.Locals->Set("host", host); + ScriptFrame frame (false); + + if (rule.GetScope() || rule.GetFTerm()) { + frame.Locals = new Dictionary(); + + if (rule.GetScope()) { + rule.GetScope()->CopyTo(frame.Locals); + } + + host->GetFrozenLocalsForApply()->CopyTo(frame.Locals); + frame.Locals->Freeze(); + } else { + frame.Locals = host->GetFrozenLocalsForApply(); + } bool match = false; @@ -91,7 +101,7 @@ bool Service::EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule, bo String name = rule.GetName(); if (!rule.GetFKVar().IsEmpty()) { - frame.Locals->Set(rule.GetFKVar(), instance); + frame.Locals->Set(rule.GetFKVar(), instance, true); name += instance; } @@ -106,8 +116,8 @@ bool Service::EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule, bo ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first); - frame.Locals->Set(rule.GetFVVar(), kv.second); + frame.Locals->Set(rule.GetFKVar(), kv.first, true); + frame.Locals->Set(rule.GetFVVar(), kv.second, true); if (EvaluateApplyRuleInstance(host, rule.GetName() + kv.first, frame, rule, skipFilter)) match = true; diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index d831136bb..1e105fab9 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -285,3 +285,11 @@ std::pair icinga::GetHostService(const Checkable::Ptr& else return std::make_pair(static_pointer_cast(checkable), nullptr); } + +Dictionary::Ptr Service::MakeLocalsForApply() +{ + return new Dictionary({ + { "host", m_Host }, + { "service", this } + }); +} diff --git a/lib/icinga/service.hpp b/lib/icinga/service.hpp index ac27c3d93..9e430985f 100644 --- a/lib/icinga/service.hpp +++ b/lib/icinga/service.hpp @@ -51,6 +51,8 @@ public: protected: void CreateChildObjects(const Type::Ptr& childType) override; + Dictionary::Ptr MakeLocalsForApply() override; + private: Host::Ptr m_Host;