diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:32:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:32:39 +0000 |
commit | 56ae875861ab260b80a030f50c4aff9f9dc8fff0 (patch) | |
tree | 531412110fc901a5918c7f7442202804a83cada9 /lib/icinga/checkable-dependency.cpp | |
parent | Initial commit. (diff) | |
download | icinga2-56ae875861ab260b80a030f50c4aff9f9dc8fff0.tar.xz icinga2-56ae875861ab260b80a030f50c4aff9f9dc8fff0.zip |
Adding upstream version 2.14.2.upstream/2.14.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/icinga/checkable-dependency.cpp')
-rw-r--r-- | lib/icinga/checkable-dependency.cpp | 176 |
1 files changed, 176 insertions, 0 deletions
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 <unordered_map> + +using namespace icinga; + +void Checkable::AddDependency(const Dependency::Ptr& dep) +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + m_Dependencies.insert(dep); +} + +void Checkable::RemoveDependency(const Dependency::Ptr& dep) +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + m_Dependencies.erase(dep); +} + +std::vector<Dependency::Ptr> Checkable::GetDependencies() const +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + return std::vector<Dependency::Ptr>(m_Dependencies.begin(), m_Dependencies.end()); +} + +void Checkable::AddReverseDependency(const Dependency::Ptr& dep) +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + m_ReverseDependencies.insert(dep); +} + +void Checkable::RemoveReverseDependency(const Dependency::Ptr& dep) +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + m_ReverseDependencies.erase(dep); +} + +std::vector<Dependency::Ptr> Checkable::GetReverseDependencies() const +{ + std::unique_lock<std::mutex> lock(m_DependencyMutex); + return std::vector<Dependency::Ptr>(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<const Service *>(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<std::string, Dependency::Ptr> 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::Ptr> Checkable::GetParents() const +{ + std::set<Checkable::Ptr> 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::Ptr> Checkable::GetChildren() const +{ + std::set<Checkable::Ptr> 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::Ptr> Checkable::GetAllChildren() const +{ + std::set<Checkable::Ptr> children = GetChildren(); + + GetAllChildrenInternal(children, 0); + + return children; +} + +void Checkable::GetAllChildrenInternal(std::set<Checkable::Ptr>& children, int level) const +{ + if (level > 32) + return; + + std::set<Checkable::Ptr> localChildren; + + for (const Checkable::Ptr& checkable : children) { + std::set<Checkable::Ptr> 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()); +} |