From: Alexander A. Klimov <alexander.klimov@icinga.com>
Date: Fri, 30 Aug 2019 16:05:25 +0000 (+0200)
Subject: Actually make use of Dependency#parents
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=refs%2Fheads%2Ffeature%2Fmulti-parent-dependencies-1869;p=icinga2

Actually make use of Dependency#parents

refs #1869
---

diff --git a/lib/icinga/dependency.cpp b/lib/icinga/dependency.cpp
index d05f633c7..f33ade9e1 100644
--- a/lib/icinga/dependency.cpp
+++ b/lib/icinga/dependency.cpp
@@ -191,7 +191,7 @@ std::unique_ptr<Dependency::ParentsTree> Dependency::RequireParents(const Value&
 			auto service (Service::GetByName(checkableName));
 
 			if (service) {
-				return std::unique_ptr<ParentsTree>(new ParentsLeaf(std::move(service)));
+				return std::unique_ptr<ParentsTree>(new ParentsLeaf(this, std::move(service)));
 			}
 		}
 
@@ -199,7 +199,7 @@ std::unique_ptr<Dependency::ParentsTree> Dependency::RequireParents(const Value&
 			auto host (Host::GetByName(checkableName));
 
 			if (host) {
-				return std::unique_ptr<ParentsTree>(new ParentsLeaf(std::move(host)));
+				return std::unique_ptr<ParentsTree>(new ParentsLeaf(this, std::move(host)));
 			}
 		}
 
@@ -227,9 +227,9 @@ std::unique_ptr<Dependency::ParentsTree> Dependency::RequireParents(const Value&
 					BlameBadParents(std::move(hostName) + "!" + std::move(serviceName));
 				}
 
-				return std::unique_ptr<ParentsTree>(new ParentsLeaf(std::move(service)));
+				return std::unique_ptr<ParentsTree>(new ParentsLeaf(this, std::move(service)));
 			} else {
-				return std::unique_ptr<ParentsTree>(new ParentsLeaf(std::move(host)));
+				return std::unique_ptr<ParentsTree>(new ParentsLeaf(this, std::move(host)));
 			}
 		} else {
 			std::vector<std::unique_ptr<ParentsTree>> subTrees;
@@ -302,23 +302,29 @@ void Dependency::OnAllConfigLoaded()
 
 	m_Child->AddDependency(this);
 
-	Host::Ptr parentHost = Host::GetByName(GetParentHostName());
+	auto parentHostName (GetParentHostName());
+	auto parentServiceName (GetParentServiceName());
+	auto parents (GetParents());
 
-	if (parentHost) {
-		if (GetParentServiceName().IsEmpty())
-			m_Parent = parentHost;
-		else
-			m_Parent = parentHost->GetServiceByShortName(GetParentServiceName());
+	if (!((!parentHostName.IsEmpty() || !parentServiceName.IsEmpty()) ^ !parents.IsEmpty())) {
+		BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' must reference a parent host/service either via parent_host_name and parent_service_name or via parents, but not via both.", GetDebugInfo()));
 	}
 
-	if (!m_Parent)
-		BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist.", GetDebugInfo()));
+	if (parents.IsEmpty()) {
+		Host::Ptr parentHost = Host::GetByName(parentHostName);
 
-	m_Parent->AddReverseDependency(this);
+		if (parentHost) {
+			if (GetParentServiceName().IsEmpty())
+				m_Parent = parentHost;
+			else
+				m_Parent = parentHost->GetServiceByShortName(parentServiceName);
+		}
 
-	auto parents (GetParents());
+		if (!m_Parent)
+			BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist.", GetDebugInfo()));
 
-	if (!parents.IsEmpty()) {
+		m_Parent->AddReverseDependency(this);
+	} else {
 		SetParentsTree(RequireParents(parents));
 	}
 
@@ -330,14 +336,23 @@ void Dependency::Stop(bool runtimeRemoved)
 	ObjectImpl<Dependency>::Stop(runtimeRemoved);
 
 	GetChild()->RemoveDependency(this);
-	GetParent()->RemoveReverseDependency(this);
+
+	auto parent (GetParent());
+
+	if (parent) {
+		parent->RemoveReverseDependency(this);
+	}
+
 	SetParentsTree(nullptr);
 }
 
 bool Dependency::IsAvailable(DependencyType dt) const
 {
-	Checkable::Ptr parent = GetParent();
+	return m_ParentsTree ? m_ParentsTree->IsAvailable(dt) : IsAvailable(GetParent(), dt);
+}
 
+bool Dependency::IsAvailable(const Checkable::Ptr& parent, DependencyType dt) const
+{
 	Host::Ptr parentHost;
 	Service::Ptr parentService;
 	tie(parentHost, parentService) = GetHostService(parent);
@@ -490,3 +505,28 @@ void Dependency::ParentsBranch::GetAllLeavesFlat(std::set<Checkable::Ptr>& out)
 		subTree->GetAllLeavesFlat(out);
 	}
 }
+
+bool Dependency::ParentsLeaf::IsAvailable(DependencyType dt) const
+{
+	return m_Dep->IsAvailable(m_Checkable, dt);
+}
+
+bool Dependency::ParentsAll::IsAvailable(DependencyType dt) const
+{
+	for (auto& subTree : m_SubTrees) {
+		if (!subTree->IsAvailable(dt))
+			return false;
+	}
+
+	return true;
+}
+
+bool Dependency::ParentsAny::IsAvailable(DependencyType dt) const
+{
+	for (auto& subTree : m_SubTrees) {
+		if (subTree->IsAvailable(dt))
+			return true;
+	}
+
+	return false;
+}
diff --git a/lib/icinga/dependency.hpp b/lib/icinga/dependency.hpp
index 10245d785..86c733812 100644
--- a/lib/icinga/dependency.hpp
+++ b/lib/icinga/dependency.hpp
@@ -35,6 +35,7 @@ public:
 	TimePeriod::Ptr GetPeriod() const;
 
 	bool IsAvailable(DependencyType dt) const;
+	bool IsAvailable(const Checkable::Ptr& parent, DependencyType dt) const;
 
 	void ValidateStates(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils) override;
 
@@ -60,6 +61,7 @@ private:
 		virtual ~ParentsTree() = default;
 
 		virtual void GetAllLeavesFlat(std::set<Checkable::Ptr>& out) const = 0;
+		virtual bool IsAvailable(DependencyType dt) const = 0;
 
 	protected:
 		ParentsTree() = default;
@@ -68,13 +70,16 @@ private:
 	class ParentsLeaf : public ParentsTree
 	{
 	public:
-		inline ParentsLeaf(Checkable::Ptr checkable) : m_Checkable(std::move(checkable))
+		inline ParentsLeaf(Dependency *dep, Checkable::Ptr checkable)
+			: m_Dep(dep), m_Checkable(std::move(checkable))
 		{
 		}
 
 		void GetAllLeavesFlat(std::set<Checkable::Ptr>& out) const override;
+		bool IsAvailable(DependencyType dt) const override;
 
 	private:
+		Dependency *m_Dep;
 		Checkable::Ptr m_Checkable;
 	};
 
@@ -87,7 +92,7 @@ private:
 
 		void GetAllLeavesFlat(std::set<Checkable::Ptr>& out) const override;
 
-	private:
+	protected:
 		std::vector<std::unique_ptr<ParentsTree>> m_SubTrees;
 	};
 
@@ -95,12 +100,16 @@ private:
 	{
 	public:
 		using ParentsBranch::ParentsBranch;
+
+		bool IsAvailable(DependencyType dt) const override;
 	};
 
 	class ParentsAny : public ParentsBranch
 	{
 	public:
 		using ParentsBranch::ParentsBranch;
+
+		bool IsAvailable(DependencyType dt) const override;
 	};
 
 	Checkable::Ptr m_Parent;
diff --git a/lib/icinga/dependency.ti b/lib/icinga/dependency.ti
index cf3694f91..50e637361 100644
--- a/lib/icinga/dependency.ti
+++ b/lib/icinga/dependency.ti
@@ -50,7 +50,7 @@ class Dependency : CustomVarObject < DependencyNameComposer
 		}}}
 	};
 
-	[config, required, navigation(parent_host)] name(Host) parent_host_name {
+	[config, navigation(parent_host)] name(Host) parent_host_name {
 		navigate {{{
 			return Host::GetByName(GetParentHostName());
 		}}}