From 56ae875861ab260b80a030f50c4aff9f9dc8fff0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:32:39 +0200 Subject: Adding upstream version 2.14.2. Signed-off-by: Daniel Baumann --- lib/icinga/checkable-dependency.cpp | 176 ++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 lib/icinga/checkable-dependency.cpp (limited to 'lib/icinga/checkable-dependency.cpp') diff --git a/lib/icinga/checkable-dependency.cpp b/lib/icinga/checkable-dependency.cpp new file mode 100644 index 0000000..58d6b57 --- /dev/null +++ b/lib/icinga/checkable-dependency.cpp @@ -0,0 +1,176 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "icinga/service.hpp" +#include "icinga/dependency.hpp" +#include "base/logger.hpp" +#include + +using namespace icinga; + +void Checkable::AddDependency(const Dependency::Ptr& dep) +{ + std::unique_lock lock(m_DependencyMutex); + m_Dependencies.insert(dep); +} + +void Checkable::RemoveDependency(const Dependency::Ptr& dep) +{ + std::unique_lock lock(m_DependencyMutex); + m_Dependencies.erase(dep); +} + +std::vector Checkable::GetDependencies() const +{ + std::unique_lock lock(m_DependencyMutex); + return std::vector(m_Dependencies.begin(), m_Dependencies.end()); +} + +void Checkable::AddReverseDependency(const Dependency::Ptr& dep) +{ + std::unique_lock lock(m_DependencyMutex); + m_ReverseDependencies.insert(dep); +} + +void Checkable::RemoveReverseDependency(const Dependency::Ptr& dep) +{ + std::unique_lock lock(m_DependencyMutex); + m_ReverseDependencies.erase(dep); +} + +std::vector Checkable::GetReverseDependencies() const +{ + std::unique_lock lock(m_DependencyMutex); + return std::vector(m_ReverseDependencies.begin(), m_ReverseDependencies.end()); +} + +bool Checkable::IsReachable(DependencyType dt, Dependency::Ptr *failedDependency, int rstack) const +{ + /* Anything greater than 256 causes recursion bus errors. */ + int limit = 256; + + if (rstack > limit) { + Log(LogWarning, "Checkable") + << "Too many nested dependencies (>" << limit << ") for checkable '" << GetName() << "': Dependency failed."; + + return false; + } + + for (const Checkable::Ptr& checkable : GetParents()) { + if (!checkable->IsReachable(dt, failedDependency, rstack + 1)) + return false; + } + + /* implicit dependency on host if this is a service */ + const auto *service = dynamic_cast(this); + if (service && (dt == DependencyState || dt == DependencyNotification)) { + Host::Ptr host = service->GetHost(); + + if (host && host->GetState() != HostUp && host->GetStateType() == StateTypeHard) { + if (failedDependency) + *failedDependency = nullptr; + + return false; + } + } + + auto deps = GetDependencies(); + + std::unordered_map violated; // key: redundancy group, value: nullptr if satisfied, violating dependency otherwise + + for (const Dependency::Ptr& dep : deps) { + std::string redundancy_group = dep->GetRedundancyGroup(); + + if (!dep->IsAvailable(dt)) { + if (redundancy_group.empty()) { + Log(LogDebug, "Checkable") + << "Non-redundant dependency '" << dep->GetName() << "' failed for checkable '" << GetName() << "': Marking as unreachable."; + + if (failedDependency) + *failedDependency = dep; + + return false; + } + + // tentatively mark this dependency group as failed unless it is already marked; + // so it either passed before (don't overwrite) or already failed (so don't care) + // note that std::unordered_map::insert() will not overwrite an existing entry + violated.insert(std::make_pair(redundancy_group, dep)); + } else if (!redundancy_group.empty()) { + violated[redundancy_group] = nullptr; + } + } + + auto violator = std::find_if(violated.begin(), violated.end(), [](auto& v) { return v.second != nullptr; }); + if (violator != violated.end()) { + Log(LogDebug, "Checkable") + << "All dependencies in redundancy group '" << violator->first << "' have failed for checkable '" << GetName() << "': Marking as unreachable."; + + if (failedDependency) + *failedDependency = violator->second; + + return false; + } + + if (failedDependency) + *failedDependency = nullptr; + + return true; +} + +std::set Checkable::GetParents() const +{ + std::set parents; + + for (const Dependency::Ptr& dep : GetDependencies()) { + Checkable::Ptr parent = dep->GetParent(); + + if (parent && parent.get() != this) + parents.insert(parent); + } + + return parents; +} + +std::set Checkable::GetChildren() const +{ + std::set parents; + + for (const Dependency::Ptr& dep : GetReverseDependencies()) { + Checkable::Ptr service = dep->GetChild(); + + if (service && service.get() != this) + parents.insert(service); + } + + return parents; +} + +std::set Checkable::GetAllChildren() const +{ + std::set children = GetChildren(); + + GetAllChildrenInternal(children, 0); + + return children; +} + +void Checkable::GetAllChildrenInternal(std::set& children, int level) const +{ + if (level > 32) + return; + + std::set localChildren; + + for (const Checkable::Ptr& checkable : children) { + std::set cChildren = checkable->GetChildren(); + + if (!cChildren.empty()) { + GetAllChildrenInternal(cChildren, level + 1); + localChildren.insert(cChildren.begin(), cChildren.end()); + } + + localChildren.insert(checkable); + } + + children.insert(localChildren.begin(), localChildren.end()); +} -- cgit v1.2.3