This commit is contained in:
Alexander Aleksandrovič Klimov 2026-02-16 09:55:55 +01:00 committed by GitHub
commit 71f67fec39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 230 additions and 161 deletions

View file

@ -329,3 +329,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;
}

View file

@ -217,12 +217,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;

View file

@ -69,63 +69,66 @@ 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();
Value vinstances;
if (rule.GetScope()) {
rule.GetScope()->CopyTo(frame.Locals);
}
checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals);
frame.Locals->Freeze();
} else {
frame.Locals = checkable->GetFrozenLocalsForApply();
}
bool match = false;
if (rule.GetFTerm()) {
Value vinstances;
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
vinstances = new Array({ "" });
}
bool match = false;
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
Array::Ptr arr = vinstances;
Array::Ptr arr = vinstances;
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance);
frame.Locals->Set(rule.GetFKVar(), instance, true);
name += instance;
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
Dictionary::Ptr dict = vinstances;
for (const String& key : dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));
if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule, skipFilter))
match = true;
Dictionary::Ptr dict = vinstances;
ObjectLock olock (dict);
for (auto& kv : dict) {
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;
}
}
} else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) {
match = true;
}
return match;

View file

@ -308,3 +308,8 @@ bool Host::ResolveMacro(const String& macro, const CheckResult::Ptr&, Value *res
return false;
}
Dictionary::Ptr Host::MakeLocalsForApply()
{
return new Dictionary({{ "host", this }});
}

View file

@ -55,6 +55,8 @@ protected:
void CreateChildObjects(const Type::Ptr& childType) override;
Dictionary::Ptr MakeLocalsForApply() override;
private:
mutable std::mutex m_ServicesMutex;
std::map<String, intrusive_ptr<Service> > m_Services;

View file

@ -25,10 +25,20 @@ bool HostGroup::EvaluateObjectRule(const Host::Ptr& host, const ConfigItem::Ptr&
CONTEXT("Evaluating rule for group '" << groupName << "'");
ScriptFrame frame(true);
if (group->GetScope())
group->GetScope()->CopyTo(frame.Locals);
frame.Locals->Set("host", host);
ScriptFrame frame (false);
if (group->GetScope()) {
frame.Locals = new Dictionary();
if (group->GetScope()) {
group->GetScope()->CopyTo(frame.Locals);
}
host->GetFrozenLocalsForApply()->CopyTo(frame.Locals);
frame.Locals->Freeze();
} else {
frame.Locals = host->GetFrozenLocalsForApply();
}
if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool())
return false;

View file

@ -68,63 +68,66 @@ 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();
Value vinstances;
if (rule.GetScope()) {
rule.GetScope()->CopyTo(frame.Locals);
}
checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals);
frame.Locals->Freeze();
} else {
frame.Locals = checkable->GetFrozenLocalsForApply();
}
bool match = false;
if (rule.GetFTerm()) {
Value vinstances;
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
vinstances = new Array({ "" });
}
bool match = false;
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
Array::Ptr arr = vinstances;
Array::Ptr arr = vinstances;
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance);
frame.Locals->Set(rule.GetFKVar(), instance, true);
name += instance;
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
Dictionary::Ptr dict = vinstances;
for (const String& key : dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));
if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule, skipFilter))
match = true;
Dictionary::Ptr dict = vinstances;
ObjectLock olock (dict);
for (auto& kv : dict) {
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;
}
}
} else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) {
match = true;
}
return match;

View file

@ -67,63 +67,66 @@ 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();
Value vinstances;
if (rule.GetScope()) {
rule.GetScope()->CopyTo(frame.Locals);
}
checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals);
frame.Locals->Freeze();
} else {
frame.Locals = checkable->GetFrozenLocalsForApply();
}
bool match = false;
if (rule.GetFTerm()) {
Value vinstances;
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
vinstances = new Array({ "" });
}
bool match = false;
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
Array::Ptr arr = vinstances;
Array::Ptr arr = vinstances;
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance);
frame.Locals->Set(rule.GetFKVar(), instance, true);
name += instance;
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
Dictionary::Ptr dict = vinstances;
for (const String& key : dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));
if (EvaluateApplyRuleInstance(checkable, rule.GetName() + key, frame, rule, skipFilter))
match = true;
Dictionary::Ptr dict = vinstances;
ObjectLock olock (dict);
for (auto& kv : dict) {
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;
}
}
} else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) {
match = true;
}
return match;

View file

@ -62,57 +62,68 @@ 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);
Value vinstances;
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;
if (rule.GetFTerm()) {
Value vinstances;
try {
vinstances = rule.GetFTerm()->Evaluate(frame);
} catch (const std::exception&) {
/* Silently ignore errors here and assume there are no instances. */
return false;
}
} else {
vinstances = new Array({ "" });
}
bool match = false;
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
if (vinstances.IsObjectType<Array>()) {
if (!rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di));
Array::Ptr arr = vinstances;
Array::Ptr arr = vinstances;
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
ObjectLock olock(arr);
for (const Value& instance : arr) {
String name = rule.GetName();
if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance, true);
name += instance;
}
if (!rule.GetFKVar().IsEmpty()) {
frame.Locals->Set(rule.GetFKVar(), instance);
name += instance;
if (EvaluateApplyRuleInstance(host, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
if (EvaluateApplyRuleInstance(host, name, frame, rule, skipFilter))
match = true;
}
} else if (vinstances.IsObjectType<Dictionary>()) {
if (rule.GetFVVar().IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di));
Dictionary::Ptr dict = vinstances;
for (const String& key : dict->GetKeys()) {
frame.Locals->Set(rule.GetFKVar(), key);
frame.Locals->Set(rule.GetFVVar(), dict->Get(key));
if (EvaluateApplyRuleInstance(host, rule.GetName() + key, frame, rule, skipFilter))
match = true;
Dictionary::Ptr dict = vinstances;
ObjectLock olock (dict);
for (auto& kv : dict) {
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;
}
}
} else if (EvaluateApplyRuleInstance(host, rule.GetName(), frame, rule, skipFilter)) {
match = true;
}
return match;

View file

@ -261,3 +261,11 @@ std::pair<Host::Ptr, Service::Ptr> icinga::GetHostService(const Checkable::Ptr&
else
return std::make_pair(static_pointer_cast<Host>(checkable), nullptr);
}
Dictionary::Ptr Service::MakeLocalsForApply()
{
return new Dictionary({
{ "host", m_Host },
{ "service", this }
});
}

View file

@ -49,6 +49,8 @@ public:
protected:
void CreateChildObjects(const Type::Ptr& childType) override;
Dictionary::Ptr MakeLocalsForApply() override;
private:
Host::Ptr m_Host;

View file

@ -25,13 +25,20 @@ bool ServiceGroup::EvaluateObjectRule(const Service::Ptr& service, const ConfigI
CONTEXT("Evaluating rule for group '" << groupName << "'");
Host::Ptr host = service->GetHost();
ScriptFrame frame (false);
ScriptFrame frame(true);
if (group->GetScope())
group->GetScope()->CopyTo(frame.Locals);
frame.Locals->Set("host", host);
frame.Locals->Set("service", service);
if (group->GetScope()) {
frame.Locals = new Dictionary();
if (group->GetScope()) {
group->GetScope()->CopyTo(frame.Locals);
}
service->GetFrozenLocalsForApply()->CopyTo(frame.Locals);
frame.Locals->Freeze();
} else {
frame.Locals = service->GetFrozenLocalsForApply();
}
if (!group->GetFilter()->Evaluate(frame).GetValue().ToBool())
return false;