From 208d035db4d04d32f613e9f3c120b9058a7bda14 Mon Sep 17 00:00:00 2001
From: Gunnar Beutner <gunnar.beutner@netways.de>
Date: Wed, 11 May 2016 12:50:08 +0200
Subject: [PATCH] Only activate HARunOnce objects once there's a cluster
 connection

fixes #11765
---
 lib/base/application.cpp   | 13 +++++++++
 lib/base/application.hpp   |  4 +++
 lib/base/configobject.cpp  |  3 ++-
 lib/cli/daemoncommand.cpp  |  4 +++
 lib/remote/apilistener.hpp |  3 +++
 lib/remote/authority.cpp   | 54 +++++++++++++++++++++++++-------------
 6 files changed, 62 insertions(+), 19 deletions(-)

diff --git a/lib/base/application.cpp b/lib/base/application.cpp
index b0cdc1286..c9e2c7c33 100644
--- a/lib/base/application.cpp
+++ b/lib/base/application.cpp
@@ -60,6 +60,7 @@ static bool l_InExceptionHandler = false;
 int Application::m_ArgC;
 char **Application::m_ArgV;
 double Application::m_StartTime;
+double Application::m_MainTime;
 bool Application::m_ScriptDebuggerEnabled = false;
 
 /**
@@ -885,6 +886,8 @@ int Application::Run(void)
 		return EXIT_FAILURE;
 	}
 
+	SetMainTime(Utility::GetTime());
+
 	return Main();
 }
 
@@ -1364,6 +1367,16 @@ void Application::SetStartTime(double ts)
 	m_StartTime = ts;
 }
 
+double Application::GetMainTime(void)
+{
+	return m_MainTime;
+}
+
+void Application::SetMainTime(double ts)
+{
+	m_MainTime = ts;
+}
+
 bool Application::GetScriptDebuggerEnabled(void)
 {
 	return m_ScriptDebuggerEnabled;
diff --git a/lib/base/application.hpp b/lib/base/application.hpp
index d030eb2a7..2174d3e03 100644
--- a/lib/base/application.hpp
+++ b/lib/base/application.hpp
@@ -134,6 +134,9 @@ public:
 	static double GetStartTime(void);
 	static void SetStartTime(double ts);
 
+	static double GetMainTime(void);
+	static void SetMainTime(double ts);
+
 	static bool GetScriptDebuggerEnabled(void);
 	static void SetScriptDebuggerEnabled(bool enabled);
 
@@ -167,6 +170,7 @@ private:
 	static bool m_Debugging; /**< Whether debugging is enabled. */
 	static LogSeverity m_DebuggingSeverity; /**< Whether debugging severity is set. */
 	static double m_StartTime;
+	static double m_MainTime;
 	static bool m_ScriptDebuggerEnabled;
 
 #ifndef _WIN32
diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp
index cfb099480..1cb6e3f3c 100644
--- a/lib/base/configobject.cpp
+++ b/lib/base/configobject.cpp
@@ -396,7 +396,8 @@ void ConfigObject::Activate(bool runtimeCreated)
 		SetActive(true, true);
 	}
 
-	SetAuthority(true);
+	if (GetHAMode() == HARunEverywhere)
+		SetAuthority(true);
 
 	NotifyActive();
 }
diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp
index f650af3a4..be32b22d6 100644
--- a/lib/cli/daemoncommand.cpp
+++ b/lib/cli/daemoncommand.cpp
@@ -19,6 +19,7 @@
 
 #include "cli/daemoncommand.hpp"
 #include "cli/daemonutility.hpp"
+#include "remote/apilistener.hpp"
 #include "config/configcompiler.hpp"
 #include "config/configcompilercontext.hpp"
 #include "config/configitembuilder.hpp"
@@ -302,5 +303,8 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 	sigaction(SIGHUP, &sa, NULL);
 #endif /* _WIN32 */
 
+	/* update object authority */
+	ApiListener::UpdateObjectAuthorityAsync();
+
 	return Application::GetInstance()->Run();
 }
diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp
index 4c860f89b..d4cb5e540 100644
--- a/lib/remote/apilistener.hpp
+++ b/lib/remote/apilistener.hpp
@@ -97,6 +97,9 @@ public:
 	static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
 	
 	static Value HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+
+	static void UpdateObjectAuthorityAsync(void);
+
 protected:
 	virtual void OnConfigLoaded(void) override;
 	virtual void OnAllConfigLoaded(void) override;
diff --git a/lib/remote/authority.cpp b/lib/remote/authority.cpp
index 37a244ee4..cb81fa927 100644
--- a/lib/remote/authority.cpp
+++ b/lib/remote/authority.cpp
@@ -36,42 +36,60 @@ static bool ObjectNameLessComparer(const ConfigObject::Ptr& a, const ConfigObjec
 
 static void AuthorityTimerHandler(void)
 {
-	ApiListener::Ptr listener = ApiListener::GetInstance();
+	Zone::Ptr my_zone = Zone::GetLocalZone();
 
-	if (!listener || !listener->IsActive())
-		return;
+	std::vector<Endpoint::Ptr> endpoints;
+	Endpoint::Ptr my_endpoint;
 
-	Zone::Ptr my_zone = Zone::GetLocalZone();
-	if (!my_zone)
-		return;
+	if (my_zone) {
+		my_endpoint = Endpoint::GetLocalEndpoint();
 
-	Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint();
+		int num_total = 0;
 
-	std::vector<Endpoint::Ptr> endpoints;
-	BOOST_FOREACH(const Endpoint::Ptr& endpoint, my_zone->GetEndpoints()) {
-		if (!endpoint->GetConnected() && endpoint != my_endpoint)
-			continue;
+		BOOST_FOREACH(const Endpoint::Ptr& endpoint, my_zone->GetEndpoints()) {
+			num_total++;
 
-		endpoints.push_back(endpoint);
-	}
+			if (endpoint != my_endpoint && !endpoint->GetConnected())
+				continue;
+
+			endpoints.push_back(endpoint);
+		}
+
+		double mainTime = Application::GetMainTime();
 
-	std::sort(endpoints.begin(), endpoints.end(), ObjectNameLessComparer);
+		if (num_total > 1 && endpoints.size() <= 1 && (mainTime == 0 || Utility::GetTime() - mainTime < 60))
+			return;
+
+		std::sort(endpoints.begin(), endpoints.end(), ObjectNameLessComparer);
+	}
 
 	BOOST_FOREACH(const ConfigType::Ptr& type, ConfigType::GetTypes()) {
 		BOOST_FOREACH(const ConfigObject::Ptr& object, type->GetObjects()) {
-			Endpoint::Ptr endpoint = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()];
+			if (object->GetHAMode() != HARunOnce)
+				continue;
+
+			bool authority;
+
+			if (!my_zone)
+				authority = true;
+			else
+				authority = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()] == my_endpoint;
 
-			if (object->GetHAMode() == HARunOnce)
-				object->SetAuthority(endpoint == my_endpoint);
+			object->SetAuthority(authority);
 		}
 	}
 }
 
+void ApiListener::UpdateObjectAuthorityAsync(void)
+{
+	l_AuthorityTimer->Reschedule(0);
+}
+
 static void StaticInitialize(void)
 {
 	l_AuthorityTimer = new Timer();
 	l_AuthorityTimer->OnTimerExpired.connect(boost::bind(&AuthorityTimerHandler));
-	l_AuthorityTimer->SetInterval(30);
+	l_AuthorityTimer->SetInterval(15);
 	l_AuthorityTimer->Start();
 }
 
-- 
2.40.0