From 9c4a3aed1bce9897289a9bce1c74a8ed92a3e957 Mon Sep 17 00:00:00 2001
From: Mattia Codato <mattia.codato@wuerth-phoenix.com>
Date: Fri, 31 Jul 2020 17:28:33 +0200
Subject: [PATCH] Use ExecuteOverride to override the command

---
 lib/icinga/apiactions.cpp              | 19 +++++++++++++++++--
 lib/icinga/checkcommand.cpp            |  2 ++
 lib/icinga/checkcommand.hpp            |  2 ++
 lib/icinga/eventcommand.cpp            |  2 ++
 lib/icinga/eventcommand.hpp            |  2 ++
 lib/icinga/notificationcommand.cpp     |  2 ++
 lib/icinga/notificationcommand.hpp     |  2 ++
 lib/methods/clusterchecktask.cpp       |  6 +++++-
 lib/methods/clusterzonechecktask.cpp   |  6 +++++-
 lib/methods/dummychecktask.cpp         |  6 +++++-
 lib/methods/icingachecktask.cpp        |  6 +++++-
 lib/methods/pluginchecktask.cpp        |  6 +++++-
 lib/methods/plugineventtask.cpp        |  6 +++++-
 lib/methods/pluginnotificationtask.cpp |  6 +++++-
 lib/methods/randomchecktask.cpp        |  6 +++++-
 lib/methods/sleepchecktask.cpp         |  6 +++++-
 16 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp
index 97561397e..e7d8acd88 100644
--- a/lib/icinga/apiactions.cpp
+++ b/lib/icinga/apiactions.cpp
@@ -686,14 +686,24 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object,
 		CheckCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(CheckCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
 		if (!cmd)
 			return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'.");
-		else
+		else {
+			CheckCommand::ExecuteOverride = cmd;
+			Defer resetCheckCommandOverride([]() {
+				CheckCommand::ExecuteOverride = nullptr;
+			});
 			cmd->Execute(checkable, cr, execMacros, false);
+		}
 	} else if (command_type == "EventCommand") {
 		EventCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(EventCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
 		if (!cmd)
 			return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'.");
-		else
+		else {
+			EventCommand::ExecuteOverride = cmd;
+			Defer resetCheckCommandOverride([]() {
+				EventCommand::ExecuteOverride = nullptr;
+			});
 			cmd->Execute(checkable, execMacros, false);
+		}
 	} else if (command_type == "NotificationCommand") {
 		NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
 		if (!cmd)
@@ -731,6 +741,11 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object,
 				return ApiActions::CreateResult(404, "Can't find a valid notification for '" + resolved_notification + "'.");
 			execParams->Set("notification", notification->GetName());
 
+			NotificationCommand::ExecuteOverride = cmd;
+			Defer resetCheckCommandOverride([]() {
+				NotificationCommand::ExecuteOverride = nullptr;
+			});
+
 			cmd->Execute(notification, user, cr, NotificationType::NotificationCustom,
 				ActionsHandler::AuthenticatedApiUser->GetName(), "", execMacros, false);
 		}
diff --git a/lib/icinga/checkcommand.cpp b/lib/icinga/checkcommand.cpp
index e0da41547..fb8032a19 100644
--- a/lib/icinga/checkcommand.cpp
+++ b/lib/icinga/checkcommand.cpp
@@ -8,6 +8,8 @@ using namespace icinga;
 
 REGISTER_TYPE(CheckCommand);
 
+thread_local CheckCommand::Ptr CheckCommand::ExecuteOverride;
+
 void CheckCommand::Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
 	const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
 {
diff --git a/lib/icinga/checkcommand.hpp b/lib/icinga/checkcommand.hpp
index 6eb6119a3..eb8f5a012 100644
--- a/lib/icinga/checkcommand.hpp
+++ b/lib/icinga/checkcommand.hpp
@@ -20,6 +20,8 @@ public:
 	DECLARE_OBJECT(CheckCommand);
 	DECLARE_OBJECTNAME(CheckCommand);
 
+	static thread_local CheckCommand::Ptr ExecuteOverride;
+
 	virtual void Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
 		const Dictionary::Ptr& resolvedMacros = nullptr,
 		bool useResolvedMacros = false);
diff --git a/lib/icinga/eventcommand.cpp b/lib/icinga/eventcommand.cpp
index f9ab3be19..39f2d3126 100644
--- a/lib/icinga/eventcommand.cpp
+++ b/lib/icinga/eventcommand.cpp
@@ -7,6 +7,8 @@ using namespace icinga;
 
 REGISTER_TYPE(EventCommand);
 
+thread_local EventCommand::Ptr EventCommand::ExecuteOverride;
+
 void EventCommand::Execute(const Checkable::Ptr& checkable,
 	const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
 {
diff --git a/lib/icinga/eventcommand.hpp b/lib/icinga/eventcommand.hpp
index 95bd1095a..064cb5ad0 100644
--- a/lib/icinga/eventcommand.hpp
+++ b/lib/icinga/eventcommand.hpp
@@ -20,6 +20,8 @@ public:
 	DECLARE_OBJECT(EventCommand);
 	DECLARE_OBJECTNAME(EventCommand);
 
+	static thread_local EventCommand::Ptr ExecuteOverride;
+
 	virtual void Execute(const Checkable::Ptr& checkable,
 		const Dictionary::Ptr& resolvedMacros = nullptr,
 		bool useResolvedMacros = false);
diff --git a/lib/icinga/notificationcommand.cpp b/lib/icinga/notificationcommand.cpp
index 8ae3e82a5..d4a5fd6ab 100644
--- a/lib/icinga/notificationcommand.cpp
+++ b/lib/icinga/notificationcommand.cpp
@@ -7,6 +7,8 @@ using namespace icinga;
 
 REGISTER_TYPE(NotificationCommand);
 
+thread_local NotificationCommand::Ptr NotificationCommand::ExecuteOverride;
+
 Dictionary::Ptr NotificationCommand::Execute(const Notification::Ptr& notification,
 	const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type,
 	const String& author, const String& comment, const Dictionary::Ptr& resolvedMacros,
diff --git a/lib/icinga/notificationcommand.hpp b/lib/icinga/notificationcommand.hpp
index 210c91e86..f0f6899e3 100644
--- a/lib/icinga/notificationcommand.hpp
+++ b/lib/icinga/notificationcommand.hpp
@@ -22,6 +22,8 @@ public:
 	DECLARE_OBJECT(NotificationCommand);
 	DECLARE_OBJECTNAME(NotificationCommand);
 
+	static thread_local NotificationCommand::Ptr ExecuteOverride;
+
 	virtual Dictionary::Ptr Execute(const intrusive_ptr<Notification>& notification,
 		const User::Ptr& user, const CheckResult::Ptr& cr, const NotificationType& type,
 		const String& author, const String& comment,
diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp
index ddefa9f84..1fb02633d 100644
--- a/lib/methods/clusterchecktask.cpp
+++ b/lib/methods/clusterchecktask.cpp
@@ -28,7 +28,11 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe
 	if (resolvedMacros && !useResolvedMacros)
 		return;
 
-	CheckCommand::Ptr command = checkable->GetCheckCommand();
+	CheckCommand::Ptr command;
+	if (CheckCommand::ExecuteOverride)
+		command = CheckCommand::ExecuteOverride;
+	else
+		command = checkable->GetCheckCommand();
 	String commandName = command->GetName();
 
 	ApiListener::Ptr listener = ApiListener::GetInstance();
diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp
index 8b9d771e4..024288ed7 100644
--- a/lib/methods/clusterzonechecktask.cpp
+++ b/lib/methods/clusterzonechecktask.cpp
@@ -21,7 +21,11 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che
 	REQUIRE_NOT_NULL(cr);
 
 	ApiListener::Ptr listener = ApiListener::GetInstance();
-	CheckCommand::Ptr command = checkable->GetCheckCommand();
+	CheckCommand::Ptr command;
+	if (CheckCommand::ExecuteOverride)
+		command = CheckCommand::ExecuteOverride;
+	else
+		command = checkable->GetCheckCommand();
 	String commandName = command->GetName();
 
 	if (!listener) {
diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp
index 56bdb790a..ae44a1d63 100644
--- a/lib/methods/dummychecktask.cpp
+++ b/lib/methods/dummychecktask.cpp
@@ -22,7 +22,11 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu
 	REQUIRE_NOT_NULL(checkable);
 	REQUIRE_NOT_NULL(cr);
 
-	CheckCommand::Ptr command = checkable->GetCheckCommand();
+	CheckCommand::Ptr command;
+	if (CheckCommand::ExecuteOverride)
+		command = CheckCommand::ExecuteOverride;
+	else
+		command = checkable->GetCheckCommand();
 
 	Host::Ptr host;
 	Service::Ptr service;
diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp
index 9901ebd3a..efbdcc3c9 100644
--- a/lib/methods/icingachecktask.cpp
+++ b/lib/methods/icingachecktask.cpp
@@ -26,7 +26,11 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
 	REQUIRE_NOT_NULL(checkable);
 	REQUIRE_NOT_NULL(cr);
 
-	CheckCommand::Ptr command = checkable->GetCheckCommand();
+	CheckCommand::Ptr command;
+	if (CheckCommand::ExecuteOverride)
+		command = CheckCommand::ExecuteOverride;
+	else
+		command = checkable->GetCheckCommand();
 
 	Host::Ptr host;
 	Service::Ptr service;
diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp
index 9dcbd7936..0825bf1b4 100644
--- a/lib/methods/pluginchecktask.cpp
+++ b/lib/methods/pluginchecktask.cpp
@@ -22,7 +22,11 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
 	REQUIRE_NOT_NULL(checkable);
 	REQUIRE_NOT_NULL(cr);
 
-	CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
+	CheckCommand::Ptr commandObj;
+	if (CheckCommand::ExecuteOverride)
+		commandObj = CheckCommand::ExecuteOverride;
+	else
+		commandObj = checkable->GetCheckCommand();
 
 	Host::Ptr host;
 	Service::Ptr service;
diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp
index f511480f7..7a7932a9d 100644
--- a/lib/methods/plugineventtask.cpp
+++ b/lib/methods/plugineventtask.cpp
@@ -21,7 +21,11 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable,
 {
 	REQUIRE_NOT_NULL(checkable);
 
-	EventCommand::Ptr commandObj = checkable->GetEventCommand();
+	EventCommand::Ptr commandObj;
+	if (EventCommand::ExecuteOverride)
+		commandObj = EventCommand::ExecuteOverride;
+	else
+		commandObj = checkable->GetEventCommand();
 
 	Host::Ptr host;
 	Service::Ptr service;
diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp
index c1eb2e3d4..79485bab2 100644
--- a/lib/methods/pluginnotificationtask.cpp
+++ b/lib/methods/pluginnotificationtask.cpp
@@ -25,7 +25,11 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification,
 	REQUIRE_NOT_NULL(notification);
 	REQUIRE_NOT_NULL(user);
 
-	NotificationCommand::Ptr commandObj = notification->GetCommand();
+	NotificationCommand::Ptr commandObj;
+	if (NotificationCommand::ExecuteOverride)
+		commandObj = NotificationCommand::ExecuteOverride;
+	else
+		commandObj = notification->GetCommand();
 
 	auto type = static_cast<NotificationType>(itype);
 
diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp
index 0e138ffa5..083d07516 100644
--- a/lib/methods/randomchecktask.cpp
+++ b/lib/methods/randomchecktask.cpp
@@ -31,7 +31,11 @@ void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
 		+ ". Icinga 2 has been running for " + Utility::FormatDuration(uptime)
 		+ ". Version: " + Application::GetAppVersion();
 
-	CheckCommand::Ptr command = checkable->GetCheckCommand();
+	CheckCommand::Ptr command;
+	if (CheckCommand::ExecuteOverride)
+		command = CheckCommand::ExecuteOverride;
+	else
+		command = checkable->GetCheckCommand();
 	String commandName = command->GetName();
 	ServiceState state = static_cast<ServiceState>(Utility::Random() % 4);
 
diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp
index 30a395c00..a3e62d133 100644
--- a/lib/methods/sleepchecktask.cpp
+++ b/lib/methods/sleepchecktask.cpp
@@ -18,7 +18,11 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu
     REQUIRE_NOT_NULL(checkable);
     REQUIRE_NOT_NULL(cr);
 
-    CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
+	CheckCommand::Ptr commandObj;
+	if (CheckCommand::ExecuteOverride)
+		commandObj = CheckCommand::ExecuteOverride;
+	else
+		commandObj = checkable->GetCheckCommand();
 
     Host::Ptr host;
     Service::Ptr service;