diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index dbe73fe55..3cde81537 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -328,3 +328,12 @@ String Checkable::StateTypeToString(StateType type) return type == StateTypeSoft ? "SOFT" : "HARD"; } +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 2ccc87073..6c1add9ce 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -216,12 +216,18 @@ public: static int GetPendingChecks(); static void AquirePendingCheckSlot(int maxPendingChecks); + 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 64a700d7e..62f09e7fe 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -68,16 +68,20 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR CONTEXT("Evaluating 'apply' rule (" << di << ")"); - 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 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)) @@ -115,8 +119,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 35fb25537..fb7b2300c 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -307,3 +307,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 7cacd160f..2a432b23d 100644 --- a/lib/icinga/host.hpp +++ b/lib/icinga/host.hpp @@ -54,6 +54,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 24e6f5fbf..78c8acd17 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -67,16 +67,20 @@ bool Notification::EvaluateApplyRule(const Checkable::Ptr& checkable, const Appl CONTEXT("Evaluating 'apply' rule (" << di << ")"); - 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; @@ -100,7 +104,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)) @@ -114,8 +118,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 558dcfd86..0442158ec 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -66,16 +66,20 @@ bool ScheduledDowntime::EvaluateApplyRule(const Checkable::Ptr& checkable, const CONTEXT("Evaluating 'apply' rule (" << di << ")"); - 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; @@ -99,7 +103,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)) @@ -113,8 +117,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 ab472a47a..2de40e14c 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -61,10 +61,20 @@ bool Service::EvaluateApplyRule(const Host::Ptr& host, const ApplyRule& rule, bo CONTEXT("Evaluating 'apply' rule (" << di << ")"); - 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; @@ -89,7 +99,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; } @@ -104,8 +114,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 acc6c89e1..4cc8eeef8 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -260,3 +260,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 558f73c03..a9827a3e4 100644 --- a/lib/icinga/service.hpp +++ b/lib/icinga/service.hpp @@ -48,6 +48,8 @@ public: protected: void CreateChildObjects(const Type::Ptr& childType) override; + Dictionary::Ptr MakeLocalsForApply() override; + private: Host::Ptr m_Host;