From bbe0f2d8c48510998bfaebe3f241d2926165d6ab Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 10 Mar 2020 13:19:56 +0100 Subject: [PATCH 01/67] mkclass: make .ti class members atomic if possible ... not to have to lock the objects while setting attributes. --- lib/base/atomic.hpp | 76 +++++++++++++++++++++++++++++++++ lib/base/configobject.ti | 4 +- lib/icinga/host.ti | 4 +- lib/icinga/hostgroup.ti | 4 +- lib/icinga/service.ti | 4 +- lib/icinga/servicegroup.ti | 4 +- lib/icinga/timeperiod.ti | 4 +- lib/icinga/user.ti | 4 +- lib/icinga/usergroup.ti | 4 +- tools/mkclass/classcompiler.cpp | 7 +-- 10 files changed, 96 insertions(+), 19 deletions(-) diff --git a/lib/base/atomic.hpp b/lib/base/atomic.hpp index 0ebcddefb19..62fa376387d 100644 --- a/lib/base/atomic.hpp +++ b/lib/base/atomic.hpp @@ -4,6 +4,8 @@ #define ATOMIC_H #include +#include +#include namespace icinga { @@ -38,6 +40,80 @@ class Atomic : public std::atomic { } }; +/** + * Wraps T into a std::atomic-like interface. + * + * @ingroup base + */ +template +class NotAtomic +{ +public: + inline T load() const + { + return m_Value; + } + + inline void store(T desired) + { + m_Value = std::move(desired); + } + + T m_Value; +}; + +/** + * Tells whether to use std::atomic or NotAtomic. + * + * @ingroup base + */ +template +struct Atomicable +{ + // Doesn't work with too old compilers. + //static constexpr bool value = std::is_trivially_copyable::value && sizeof(T) <= sizeof(void*); + static constexpr bool value = (std::is_fundamental::value || std::is_pointer::value) && sizeof(T) <= sizeof(void*); +}; + +/** + * Uses either std::atomic or NotAtomic depending on atomicable. + * + * @ingroup base + */ +template +struct AtomicTemplate; + +template<> +struct AtomicTemplate +{ + template + struct tmplt + { + typedef NotAtomic type; + }; +}; + +template<> +struct AtomicTemplate +{ + template + struct tmplt + { + typedef std::atomic type; + }; +}; + +/** + * Uses either std::atomic or NotAtomic depending on T. + * + * @ingroup base + */ +template +struct EventuallyAtomic +{ + typedef typename AtomicTemplate::value>::template tmplt::type type; +}; + } #endif /* ATOMIC_H */ diff --git a/lib/base/configobject.ti b/lib/base/configobject.ti index fcfcb022365..3e5859c814a 100644 --- a/lib/base/configobject.ti +++ b/lib/base/configobject.ti @@ -59,10 +59,10 @@ abstract class ConfigObject : ConfigObjectBase < ConfigType [config, no_user_modify] String __name (Name); [config, no_user_modify] String "name" (ShortName) { get {{{ - if (m_ShortName.IsEmpty()) + if (m_ShortName.m_Value.IsEmpty()) return GetName(); else - return m_ShortName; + return m_ShortName.m_Value; }}} }; [config, no_user_modify] name(Zone) zone (ZoneName); diff --git a/lib/icinga/host.ti b/lib/icinga/host.ti index 03c606228f8..1c8a6c9fea9 100644 --- a/lib/icinga/host.ti +++ b/lib/icinga/host.ti @@ -21,10 +21,10 @@ class Host : Checkable [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; diff --git a/lib/icinga/hostgroup.ti b/lib/icinga/hostgroup.ti index a4404eafe3c..efcb45e543a 100644 --- a/lib/icinga/hostgroup.ti +++ b/lib/icinga/hostgroup.ti @@ -11,10 +11,10 @@ class HostGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; diff --git a/lib/icinga/service.ti b/lib/icinga/service.ti index bab1ebc8f23..f76750ef420 100644 --- a/lib/icinga/service.ti +++ b/lib/icinga/service.ti @@ -33,10 +33,10 @@ class Service : Checkable < ServiceNameComposer [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetShortName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; [config, required] name(Host) host_name; diff --git a/lib/icinga/servicegroup.ti b/lib/icinga/servicegroup.ti index 69f30050826..69a0887b94d 100644 --- a/lib/icinga/servicegroup.ti +++ b/lib/icinga/servicegroup.ti @@ -11,10 +11,10 @@ class ServiceGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; diff --git a/lib/icinga/timeperiod.ti b/lib/icinga/timeperiod.ti index 27365988e04..ccfbcc3d470 100644 --- a/lib/icinga/timeperiod.ti +++ b/lib/icinga/timeperiod.ti @@ -12,10 +12,10 @@ class TimePeriod : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; [config] Dictionary::Ptr ranges; diff --git a/lib/icinga/user.ti b/lib/icinga/user.ti index 450d9535849..5de35b523df 100644 --- a/lib/icinga/user.ti +++ b/lib/icinga/user.ti @@ -13,10 +13,10 @@ class User : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; [config, no_user_modify, required] array(name(UserGroup)) groups { diff --git a/lib/icinga/usergroup.ti b/lib/icinga/usergroup.ti index 31193217118..35c7ccff491 100644 --- a/lib/icinga/usergroup.ti +++ b/lib/icinga/usergroup.ti @@ -11,10 +11,10 @@ class UserGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + if (m_DisplayName.m_Value.IsEmpty()) return GetName(); else - return m_DisplayName; + return m_DisplayName.m_Value; }}} }; diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index fd30df8e191..f6793da501b 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -797,7 +797,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) << "{" << std::endl; if (field.GetAccessor.empty() && !(field.Attributes & FANoStorage)) - m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ";" << std::endl; + m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ".load();" << std::endl; else m_Impl << field.GetAccessor << std::endl; @@ -835,7 +835,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage)) - m_Impl << "\t" << "m_" << field.GetFriendlyName() << " = value;" << std::endl; + m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl; else m_Impl << field.SetAccessor << std::endl << std::endl; @@ -1044,7 +1044,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) if (field.Attributes & FANoStorage) continue; - m_Header << "\t" << field.Type.GetRealType() << " m_" << field.GetFriendlyName() << ";" << std::endl; + m_Header << "\tEventuallyAtomic<" << field.Type.GetRealType() << ">::type m_" << field.GetFriendlyName() << ";" << std::endl; } /* signal */ @@ -1431,6 +1431,7 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream& input, << "#include \"base/type.hpp\"" << std::endl << "#include \"base/value.hpp\"" << std::endl << "#include \"base/array.hpp\"" << std::endl + << "#include \"base/atomic.hpp\"" << std::endl << "#include \"base/dictionary.hpp\"" << std::endl << "#include " << std::endl << std::endl; From 645dcbdc9e205c9880b4e723447598f16385582b Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 3 Apr 2020 11:10:08 +0200 Subject: [PATCH 02/67] Introduce Endpoint#icinga_version ... and set it to e.g. 21200 via icinga::Hello. --- lib/remote/apilistener.cpp | 42 +++++++++++++++++++++++++++++++++++++- lib/remote/endpoint.ti | 3 +++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index cb024e1fdf1..49ed2919886 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -506,6 +508,20 @@ void ApiListener::NewClientHandler( } } +static const auto l_AppVersionInt (([]() -> unsigned long { + auto appVersion (Application::GetAppVersion()); + boost::regex rgx (R"EOF(^v?(\d+)\.(\d+)\.(\d+))EOF"); + boost::smatch match; + + if (!boost::regex_search(appVersion.GetData(), match, rgx)) { + return 0; + } + + return 100u * 100u * boost::lexical_cast(match[1].str()) + + 100u * boost::lexical_cast(match[2].str()) + + boost::lexical_cast(match[3].str()); +})()); + /** * Processes a new client connection. * @@ -650,7 +666,9 @@ void ApiListener::NewClientHandlerInternal( JsonRpc::SendMessage(client, new Dictionary({ { "jsonrpc", "2.0" }, { "method", "icinga::Hello" }, - { "params", new Dictionary() } + { "params", new Dictionary({ + { "version", (double)l_AppVersionInt } + }) } }), yc); client->async_flush(yc); @@ -683,6 +701,16 @@ void ApiListener::NewClientHandlerInternal( } if (firstByte >= '0' && firstByte <= '9') { + JsonRpc::SendMessage(client, new Dictionary({ + { "jsonrpc", "2.0" }, + { "method", "icinga::Hello" }, + { "params", new Dictionary({ + { "version", (double)l_AppVersionInt } + }) } + }), yc); + + client->async_flush(yc); + ctype = ClientJsonRpc; } else { ctype = ClientHttp; @@ -1607,6 +1635,18 @@ std::set ApiListener::GetHttpClients() const Value ApiListener::HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { + if (origin) { + auto client (origin->FromClient); + + if (client) { + auto endpoint (client->GetEndpoint()); + + if (endpoint) { + endpoint->SetIcingaVersion((double)params->Get("version")); + } + } + } + return Empty; } diff --git a/lib/remote/endpoint.ti b/lib/remote/endpoint.ti index 1c3b654d1c1..31a00b89d1c 100644 --- a/lib/remote/endpoint.ti +++ b/lib/remote/endpoint.ti @@ -21,6 +21,9 @@ class Endpoint : ConfigObject [state] Timestamp local_log_position; [state] Timestamp remote_log_position; + [state] "unsigned long" icinga_version { + default {{{ return 0; }}} + }; [no_user_modify] bool connecting; [no_user_modify] bool syncing; From 93711542a708cd0c3a24fcf5afd5ab645a59dbc4 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 10:05:38 +0200 Subject: [PATCH 03/67] Get UUID from params --- lib/icinga/clusterevents-check.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 515003661f7..5db8c009b7b 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -99,6 +99,9 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { Log(LogCritical, "ApiListener", "Not implemented."); + + String uuid = params->Get("source"); + return; } From 39479b666fdf05dba4cc60225106b1f878321e51 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 11:21:13 +0200 Subject: [PATCH 04/67] Implement ClusterEvents::ExecutedCommandAPIHandler --- lib/icinga/clusterevents.cpp | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 4146d285239..46a60fec27d 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -944,6 +944,92 @@ Value ClusterEvents::NotificationSentToAllUsersAPIHandler(const MessageOrigin::P Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { + ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) + BOOST_THROW_EXCEPTION(std::invalid_argument("No ApiListener instance configured.")); + + Endpoint::Ptr endpoint; + if (origin->FromClient) { + endpoint = origin->FromClient->GetEndpoint(); + } else if (origin->IsLocal()){ + endpoint = Endpoint::GetLocalEndpoint(); + } + + if (!endpoint) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message from '" << origin->FromClient->GetIdentity() + << "': Invalid endpoint origin (client not allowed)."; + + return Empty; + } + + Host::Ptr host = Host::GetByName(params->Get("host")); + if (!host) + return Empty; + + Checkable::Ptr checkable; + + if (params->Contains("service")) + checkable = host->GetServiceByShortName(params->Get("service")); + else + checkable = host; + + if (!checkable) + return Empty; + + ObjectLock oLock (checkable); + + if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; + return Empty; + } + + if (!params->Contains("execution")) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID not found."; + return Empty; + } + String uuid = params->Get("execution"); + + Dictionary::Ptr executions = checkable->GetExecutions(); + if (!executions) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': No executions available."; + return Empty; + } + + Dictionary::Ptr execution = executions->Get(uuid); + if (!execution) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; + return Empty; + } + + execution->Set("pending", false); + + /* TODO update execution with the command result */ + + /* Broadcast the update */ + Dictionary::Ptr executionsToBroadcast = new Dictionary(); + executionsToBroadcast->Set(uuid, execution); + Dictionary::Ptr updateParams = new Dictionary(); + updateParams->Set("host", host->GetName()); + if (params->Contains("service")) + updateParams->Set("service", params->Get("service")); + updateParams->Set("executions", executionsToBroadcast); + + Dictionary::Ptr updateMessage = new Dictionary(); + updateMessage->Set("jsonrpc", "2.0"); + updateMessage->Set("method", "event::UpdateExecutions"); + updateMessage->Set("params", updateParams); + + listener->RelayMessage(origin, checkable, updateMessage, true); + return "Not implemented"; } From b6c84982f2bb14498d263228948e050cc022bd36 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 16:51:13 +0200 Subject: [PATCH 05/67] Uniform command_type strings --- lib/icinga/apiactions.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index e1d25cefd83..454c50f0794 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -588,12 +588,12 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, BOOST_THROW_EXCEPTION(std::invalid_argument("No ApiListener instance configured.")); /* Get command_type */ - String command_type = "EventCommand"; + String command_type = "event_command"; if (params->Contains("command_type")) command_type = HttpUtility::GetLastParameter(params, "command_type"); /* Validate command_type */ - if (command_type != "EventCommand" && command_type != "CheckCommand" && command_type != "NotificationCommand") + if (command_type != "event_command" && command_type != "check_command" && command_type != "notification_command") return ApiActions::CreateResult(400, "Invalid command_type '" + command_type + "'."); Checkable::Ptr checkable = dynamic_pointer_cast(object); @@ -649,11 +649,11 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Get command */ String command; if (!params->Contains("command")) { - if (command_type == "CheckCommand" ) { + if (command_type == "check_command" ) { command = "$check_command$"; - } else if (command_type == "EventCommand") { + } else if (command_type == "event_command") { command = "$event_command$"; - } else if (command_type == "NotificationCommand") { + } else if (command_type == "notification_command") { command = "$notification_command$"; } } else { @@ -676,19 +676,19 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, MacroResolver::OverrideMacros = nullptr; }); - if (command_type == "CheckCommand") { + if (command_type == "check_command") { 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 cmd->Execute(checkable, cr, execMacros, false); - } else if (command_type == "EventCommand") { + } else if (command_type == "event_command") { 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 cmd->Execute(checkable, execMacros, false); - } else if (command_type == "NotificationCommand") { + } else if (command_type == "notification_command") { NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); if (!cmd) return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); From c3d9f6c17b9113a64f6892e8fde127bf8654f70b Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 16:51:45 +0200 Subject: [PATCH 06/67] Add ExecuteActionTask --- lib/methods/CMakeLists.txt | 1 + lib/methods/executeactiontask.cpp | 77 +++++++++++++++++++++++++++++++ lib/methods/executeactiontask.hpp | 32 +++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 lib/methods/executeactiontask.cpp create mode 100644 lib/methods/executeactiontask.hpp diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt index 9fde9fddb35..7bb2fbf6a79 100644 --- a/lib/methods/CMakeLists.txt +++ b/lib/methods/CMakeLists.txt @@ -17,6 +17,7 @@ set(methods_SOURCES randomchecktask.cpp randomchecktask.hpp timeperiodtask.cpp timeperiodtask.hpp sleepchecktask.cpp sleepchecktask.hpp + executeactiontask.cpp exceptionchecktask.hpp ) if(ICINGA2_UNITY_BUILD) diff --git a/lib/methods/executeactiontask.cpp b/lib/methods/executeactiontask.cpp new file mode 100644 index 00000000000..c40a7ba24fa --- /dev/null +++ b/lib/methods/executeactiontask.cpp @@ -0,0 +1,77 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "methods/executeactiontask.hpp" +#include "icinga/pluginutility.hpp" +#include "icinga/checkcommand.hpp" +#include "icinga/clusterevents.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/icingaapplication.hpp" +#include "remote/apilistener.hpp" +#include "base/configtype.hpp" +#include "base/logger.hpp" +#include "base/function.hpp" +#include "base/utility.hpp" +#include "base/process.hpp" +#include "base/convert.hpp" + +using namespace icinga; + +void ExecuteActionTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) +{ + Checkable::CurrentConcurrentChecks.fetch_sub(1); + Checkable::DecreasePendingChecks(); + + if (pr.ExitStatus > 3) { + Process::Arguments parguments = Process::PrepareCommand(commandLine); + Log(LogWarning, "PluginCheckTask") + << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " + << pr.ExitStatus << ", output: " << pr.Output; + } + + String output = pr.Output.Trim(); + + std::pair co = PluginUtility::ParseCheckOutput(output); + cr->SetCommand(commandLine); + cr->SetOutput(co.first); + cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); + cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); + cr->SetExitStatus(pr.ExitStatus); + cr->SetExecutionStart(pr.ExecutionStart); + cr->SetExecutionEnd(pr.ExecutionEnd); + + Host::Ptr host; + Service::Ptr service; + tie(host, service) = GetHostService(checkable); + + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("host", host->GetName()); + if (service) + executedParams->Set("service", service->GetShortName()); + + /* TODO set the execution UUID */ + /*executedParams->Set("execution", uuid);*/ + + executedParams->Set("check_result", cr); + + /* FIXME command endpoint was overwrite by macro? */ + Endpoint::Ptr commandEndpoint = checkable->GetCommandEndpoint(); + bool local = !commandEndpoint || commandEndpoint == Endpoint::GetLocalEndpoint(); + if (local) { + MessageOrigin::Ptr origin = new MessageOrigin(); + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (listener) { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(commandEndpoint, executedMessage); + } else { + Log(LogCritical, "ExecuteActionTask") << "Api listener not found"; + } + } +} diff --git a/lib/methods/executeactiontask.hpp b/lib/methods/executeactiontask.hpp new file mode 100644 index 00000000000..6717bef3113 --- /dev/null +++ b/lib/methods/executeactiontask.hpp @@ -0,0 +1,32 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#ifndef EXECUTEACTIONTASK_H +#define EXECUTEACTIONTASK_H + +#include "methods/i2-methods.hpp" +#include "base/process.hpp" +#include "icinga/service.hpp" + +namespace icinga +{ + +/** + * Implements service checks based on external plugins. + * + * @ingroup methods + */ +class ExecuteActionTask +{ +public: + + static void ProcessFinishedHandler(const Checkable::Ptr& service, + const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr); + static thread_local String ExecutionUUID; +private: + + ExecuteActionTask(); +}; + +} + +#endif /* EXECUTEACTIONTASK_H */ From 15159b1632d52fac18b7ed98ae09f7a9afe83ecb Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 16:56:07 +0200 Subject: [PATCH 07/67] Add ExecuteCommandProcessFinishedHandler and checkable param to ExecuteRemoteCheck --- lib/icinga/checkable-check.cpp | 8 +++++-- lib/icinga/checkable.cpp | 1 + lib/icinga/checkable.hpp | 5 ++++- lib/icinga/clusterevents-check.cpp | 35 ++++++++++++++++++++++++++---- lib/methods/executeactiontask.cpp | 2 +- lib/methods/pluginchecktask.cpp | 13 ++++++++--- 6 files changed, 53 insertions(+), 11 deletions(-) diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 68361fe17c3..cc32f09ee36 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -492,7 +492,7 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig } } -void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) +void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros, const Checkable::Ptr& checkable) { CONTEXT("Executing remote check for object '" + GetName() + "'"); @@ -503,7 +503,11 @@ void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) cr->SetScheduleStart(scheduled_start); cr->SetExecutionStart(before_check); - GetCheckCommand()->Execute(this, cr, resolvedMacros, true); + if (!checkable) { + GetCheckCommand()->Execute(this, cr, resolvedMacros, true); + } else { + GetCheckCommand()->Execute(checkable, cr, resolvedMacros, true); + } } void Checkable::ExecuteCheck() diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index 0f4d1399beb..3f31d56676e 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -20,6 +20,7 @@ boost::signals2::signal Checkable::OnFlappingChange; static Timer::Ptr l_CheckablesFireSuppressedNotifications; +thread_local std::function Checkable::ExecuteCommandProcessFinishedHandler; void Checkable::StaticInitialize() { diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 0eb1c59506a..38ecf0106ab 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -5,6 +5,7 @@ #include "base/atomic.hpp" #include "base/timer.hpp" +#include "base/process.hpp" #include "icinga/i2-icinga.hpp" #include "icinga/checkable-ti.hpp" #include "icinga/timeperiod.hpp" @@ -14,6 +15,7 @@ #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include +#include namespace icinga { @@ -55,6 +57,7 @@ class Checkable : public ObjectImpl DECLARE_OBJECTNAME(Checkable); static void StaticInitialize(); + static thread_local std::function ExecuteCommandProcessFinishedHandler; Checkable(); @@ -94,7 +97,7 @@ class Checkable : public ObjectImpl static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); - void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = nullptr); + void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = nullptr, const Checkable::Ptr& checkbale = nullptr); void ExecuteCheck(); void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin = nullptr); diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 5db8c009b7b..8ab03f6551f 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -6,6 +6,7 @@ #include "base/configuration.hpp" #include "base/serializer.hpp" #include "base/exception.hpp" +#include "methods/executeactiontask.hpp" #include #include @@ -97,12 +98,38 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } + Checkable::Ptr checkable = nullptr; if (params->Contains("source")) { - Log(LogCritical, "ApiListener", "Not implemented."); - String uuid = params->Get("source"); - return; + Host::Ptr host = Host::GetByName(params->Get("host")); + if (!host) { + Log(LogCritical, "ApiListener", "Host not found."); + return; + } + + if (params->Contains("service")) + checkable = host->GetServiceByShortName(params->Get("service")); + else + checkable = host; + + if (!checkable) { + Log(LogCritical, "ApiListener", "Checkable not found."); + return; + } + + ObjectLock oLock (checkable); + + if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { + Log(LogNotice, "ApiListener") + << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; + return; + } + + Checkable::ExecuteCommandProcessFinishedHandler = ExecuteActionTask::ProcessFinishedHandler; + } else { + Checkable::ExecuteCommandProcessFinishedHandler = nullptr; } if (!listener->GetAcceptCommands()) { @@ -182,7 +209,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (command_type == "check_command") { try { - host->ExecuteRemoteCheck(macros); + host->ExecuteRemoteCheck(macros, checkable); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); diff --git a/lib/methods/executeactiontask.cpp b/lib/methods/executeactiontask.cpp index c40a7ba24fa..305bc3213cf 100644 --- a/lib/methods/executeactiontask.cpp +++ b/lib/methods/executeactiontask.cpp @@ -54,7 +54,7 @@ void ExecuteActionTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, executedParams->Set("check_result", cr); - /* FIXME command endpoint was overwrite by macro? */ + /* FIXME command endpoint overwritten by macro? */ Endpoint::Ptr commandEndpoint = checkable->GetCommandEndpoint(); bool local = !commandEndpoint || commandEndpoint == Endpoint::GetLocalEndpoint(); if (local) { diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index 70523b49f92..43851f31d14 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -43,9 +43,16 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes if (!checkable->GetCheckTimeout().IsEmpty()) timeout = checkable->GetCheckTimeout(); - PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), - resolvers, resolvedMacros, useResolvedMacros, timeout, - std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, timeout, + std::bind(Checkable::ExecuteCommandProcessFinishedHandler, checkable, cr, _1, _2)); + } else { + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, timeout, + std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); + } if (!resolvedMacros || useResolvedMacros) { Checkable::CurrentConcurrentChecks.fetch_add(1); From fa4aebbfd2d10d8d02c07b52f8118f5ae3810f6e Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 10 Jul 2020 16:56:35 +0200 Subject: [PATCH 08/67] Set CheckResult to execeution --- lib/icinga/clusterevents.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 46a60fec27d..65d1134bbbc 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1002,6 +1002,14 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, return Empty; } + if (!params->Contains("check_result")) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': No check result available."; + return Empty; + } + CheckResult::Ptr cr = params->Get("check_result"); + Dictionary::Ptr execution = executions->Get(uuid); if (!execution) { Log(LogNotice, "ClusterEvents") @@ -1011,8 +1019,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, } execution->Set("pending", false); - - /* TODO update execution with the command result */ + execution->Set("check_result", cr); /* Broadcast the update */ Dictionary::Ptr executionsToBroadcast = new Dictionary(); @@ -1030,7 +1037,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, listener->RelayMessage(origin, checkable, updateMessage, true); - return "Not implemented"; + return Empty; } Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) From 6bad8bbc0fd4ce5a9fabb82b770631d2449dcc1a Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 09:47:19 +0200 Subject: [PATCH 09/67] Replace executeactiontask with a lambda function --- lib/icinga/clusterevents-check.cpp | 45 +++++++++++++++-- lib/icinga/clusterevents.cpp | 13 +++-- lib/methods/CMakeLists.txt | 1 - lib/methods/executeactiontask.cpp | 77 ------------------------------ lib/methods/executeactiontask.hpp | 32 ------------- 5 files changed, 47 insertions(+), 121 deletions(-) delete mode 100644 lib/methods/executeactiontask.cpp delete mode 100644 lib/methods/executeactiontask.hpp diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 8ab03f6551f..7d86a17ec17 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -6,7 +6,6 @@ #include "base/configuration.hpp" #include "base/serializer.hpp" #include "base/exception.hpp" -#include "methods/executeactiontask.hpp" #include #include @@ -122,12 +121,50 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ApiListener") - << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; + << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return; } - Checkable::ExecuteCommandProcessFinishedHandler = ExecuteActionTask::ProcessFinishedHandler; + Checkable::ExecuteCommandProcessFinishedHandler = [listener, sourceEndpoint, origin, params] (const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) -> void { + Checkable::CurrentConcurrentChecks.fetch_sub(1); + Checkable::DecreasePendingChecks(); + + if (pr.ExitStatus > 3) { + Process::Arguments parguments = Process::PrepareCommand(commandLine); + Log(LogWarning, "ApiListener") + << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " + << pr.ExitStatus << ", output: " << pr.Output; + } + + String output = pr.Output.Trim(); + + std::pair co = PluginUtility::ParseCheckOutput(output); + cr->SetCommand(commandLine); + cr->SetOutput(co.first); + cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); + cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); + cr->SetExitStatus(pr.ExitStatus); + cr->SetExecutionStart(pr.ExecutionStart); + cr->SetExecutionEnd(pr.ExecutionEnd); + + Dictionary::Ptr executedParams = new Dictionary(); + params->CopyTo(executedParams); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("check_result", Serialize(cr)); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + }; } else { Checkable::ExecuteCommandProcessFinishedHandler = nullptr; } diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 65d1134bbbc..83b14d5d447 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1002,24 +1002,23 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, return Empty; } - if (!params->Contains("check_result")) { + Dictionary::Ptr execution = executions->Get(uuid); + if (!execution) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': No check result available."; + << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; return Empty; } - CheckResult::Ptr cr = params->Get("check_result"); - Dictionary::Ptr execution = executions->Get(uuid); - if (!execution) { + if (!params->Contains("check_result")) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; + << "' from '" << origin->FromClient->GetIdentity() << "': No check result available."; return Empty; } + execution->Set("check_result", params->Get("check_result")); execution->Set("pending", false); - execution->Set("check_result", cr); /* Broadcast the update */ Dictionary::Ptr executionsToBroadcast = new Dictionary(); diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt index 7bb2fbf6a79..9fde9fddb35 100644 --- a/lib/methods/CMakeLists.txt +++ b/lib/methods/CMakeLists.txt @@ -17,7 +17,6 @@ set(methods_SOURCES randomchecktask.cpp randomchecktask.hpp timeperiodtask.cpp timeperiodtask.hpp sleepchecktask.cpp sleepchecktask.hpp - executeactiontask.cpp exceptionchecktask.hpp ) if(ICINGA2_UNITY_BUILD) diff --git a/lib/methods/executeactiontask.cpp b/lib/methods/executeactiontask.cpp deleted file mode 100644 index 305bc3213cf..00000000000 --- a/lib/methods/executeactiontask.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ - -#include "methods/executeactiontask.hpp" -#include "icinga/pluginutility.hpp" -#include "icinga/checkcommand.hpp" -#include "icinga/clusterevents.hpp" -#include "icinga/macroprocessor.hpp" -#include "icinga/icingaapplication.hpp" -#include "remote/apilistener.hpp" -#include "base/configtype.hpp" -#include "base/logger.hpp" -#include "base/function.hpp" -#include "base/utility.hpp" -#include "base/process.hpp" -#include "base/convert.hpp" - -using namespace icinga; - -void ExecuteActionTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) -{ - Checkable::CurrentConcurrentChecks.fetch_sub(1); - Checkable::DecreasePendingChecks(); - - if (pr.ExitStatus > 3) { - Process::Arguments parguments = Process::PrepareCommand(commandLine); - Log(LogWarning, "PluginCheckTask") - << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID - << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " - << pr.ExitStatus << ", output: " << pr.Output; - } - - String output = pr.Output.Trim(); - - std::pair co = PluginUtility::ParseCheckOutput(output); - cr->SetCommand(commandLine); - cr->SetOutput(co.first); - cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); - cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); - cr->SetExitStatus(pr.ExitStatus); - cr->SetExecutionStart(pr.ExecutionStart); - cr->SetExecutionEnd(pr.ExecutionEnd); - - Host::Ptr host; - Service::Ptr service; - tie(host, service) = GetHostService(checkable); - - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("host", host->GetName()); - if (service) - executedParams->Set("service", service->GetShortName()); - - /* TODO set the execution UUID */ - /*executedParams->Set("execution", uuid);*/ - - executedParams->Set("check_result", cr); - - /* FIXME command endpoint overwritten by macro? */ - Endpoint::Ptr commandEndpoint = checkable->GetCommandEndpoint(); - bool local = !commandEndpoint || commandEndpoint == Endpoint::GetLocalEndpoint(); - if (local) { - MessageOrigin::Ptr origin = new MessageOrigin(); - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - ApiListener::Ptr listener = ApiListener::GetInstance(); - - if (listener) { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(commandEndpoint, executedMessage); - } else { - Log(LogCritical, "ExecuteActionTask") << "Api listener not found"; - } - } -} diff --git a/lib/methods/executeactiontask.hpp b/lib/methods/executeactiontask.hpp deleted file mode 100644 index 6717bef3113..00000000000 --- a/lib/methods/executeactiontask.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ - -#ifndef EXECUTEACTIONTASK_H -#define EXECUTEACTIONTASK_H - -#include "methods/i2-methods.hpp" -#include "base/process.hpp" -#include "icinga/service.hpp" - -namespace icinga -{ - -/** - * Implements service checks based on external plugins. - * - * @ingroup methods - */ -class ExecuteActionTask -{ -public: - - static void ProcessFinishedHandler(const Checkable::Ptr& service, - const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr); - static thread_local String ExecutionUUID; -private: - - ExecuteActionTask(); -}; - -} - -#endif /* EXECUTEACTIONTASK_H */ From 3414acbec184770f609bb3c77f6a5bfecf214413 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 10:14:30 +0200 Subject: [PATCH 10/67] Remove unuseful parameter from ExecuteRemoteCheck --- lib/icinga/checkable-check.cpp | 8 ++------ lib/icinga/checkable.hpp | 2 +- lib/icinga/clusterevents-check.cpp | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index cc32f09ee36..68361fe17c3 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -492,7 +492,7 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig } } -void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros, const Checkable::Ptr& checkable) +void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) { CONTEXT("Executing remote check for object '" + GetName() + "'"); @@ -503,11 +503,7 @@ void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros, const cr->SetScheduleStart(scheduled_start); cr->SetExecutionStart(before_check); - if (!checkable) { - GetCheckCommand()->Execute(this, cr, resolvedMacros, true); - } else { - GetCheckCommand()->Execute(checkable, cr, resolvedMacros, true); - } + GetCheckCommand()->Execute(this, cr, resolvedMacros, true); } void Checkable::ExecuteCheck() diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 38ecf0106ab..dd74b85db9a 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -97,7 +97,7 @@ class Checkable : public ObjectImpl static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); - void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = nullptr, const Checkable::Ptr& checkbale = nullptr); + void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = nullptr); void ExecuteCheck(); void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin = nullptr); diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 7d86a17ec17..ffa0b6a3ae3 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -97,7 +97,6 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } - Checkable::Ptr checkable = nullptr; if (params->Contains("source")) { String uuid = params->Get("source"); @@ -107,6 +106,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } + Checkable::Ptr checkable; if (params->Contains("service")) checkable = host->GetServiceByShortName(params->Get("service")); else @@ -246,7 +246,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (command_type == "check_command") { try { - host->ExecuteRemoteCheck(macros, checkable); + host->ExecuteRemoteCheck(macros); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); From b9510e72ddcf141c4031bc0915e368224503d3de Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 10:20:23 +0200 Subject: [PATCH 11/67] Check deadline --- lib/icinga/clusterevents-check.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index ffa0b6a3ae3..3564c99b752 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -126,6 +126,15 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } + /* Check deadline */ + double deadline = params->Get("deadline"); + if (Utility::GetTime() > deadline) { + Log(LogNotice, "ApiListener") + << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Deadline has expired."; + return; + } + Checkable::ExecuteCommandProcessFinishedHandler = [listener, sourceEndpoint, origin, params] (const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) -> void { Checkable::CurrentConcurrentChecks.fetch_sub(1); Checkable::DecreasePendingChecks(); From a3027d717730dca65121930b95a408f71a0aa50e Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 16:54:37 +0200 Subject: [PATCH 12/67] Fix ExecuteCommandProcessFinishedHandler parameters --- lib/icinga/checkable.cpp | 2 +- lib/icinga/checkable.hpp | 2 +- lib/icinga/clusterevents-check.cpp | 7 +++---- lib/methods/pluginchecktask.cpp | 11 +++++------ 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index 3f31d56676e..22d1d0cf43e 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -20,7 +20,7 @@ boost::signals2::signal Checkable::OnFlappingChange; static Timer::Ptr l_CheckablesFireSuppressedNotifications; -thread_local std::function Checkable::ExecuteCommandProcessFinishedHandler; +thread_local std::function Checkable::ExecuteCommandProcessFinishedHandler; void Checkable::StaticInitialize() { diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index dd74b85db9a..cfa04339a49 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -57,7 +57,7 @@ class Checkable : public ObjectImpl DECLARE_OBJECTNAME(Checkable); static void StaticInitialize(); - static thread_local std::function ExecuteCommandProcessFinishedHandler; + static thread_local std::function ExecuteCommandProcessFinishedHandler; Checkable(); diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 3564c99b752..b6f0e17aeed 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -135,7 +135,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } - Checkable::ExecuteCommandProcessFinishedHandler = [listener, sourceEndpoint, origin, params] (const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) -> void { + Checkable::ExecuteCommandProcessFinishedHandler = [checkable, listener, sourceEndpoint, origin, params] (const Value& commandLine, const ProcessResult& pr) { Checkable::CurrentConcurrentChecks.fetch_sub(1); Checkable::DecreasePendingChecks(); @@ -150,6 +150,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons String output = pr.Output.Trim(); std::pair co = PluginUtility::ParseCheckOutput(output); + CheckResult::Ptr cr = new CheckResult(); cr->SetCommand(commandLine); cr->SetOutput(co.first); cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); @@ -174,10 +175,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons listener->SyncSendMessage(sourceEndpoint, executedMessage); } }; - } else { - Checkable::ExecuteCommandProcessFinishedHandler = nullptr; } - + if (!listener->GetAcceptCommands()) { Log(LogWarning, "ApiListener") << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index 43851f31d14..9dcbd79362f 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -44,15 +44,14 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes timeout = checkable->GetCheckTimeout(); + std::function callback; if (Checkable::ExecuteCommandProcessFinishedHandler) { - PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), - resolvers, resolvedMacros, useResolvedMacros, timeout, - std::bind(Checkable::ExecuteCommandProcessFinishedHandler, checkable, cr, _1, _2)); + callback = Checkable::ExecuteCommandProcessFinishedHandler; } else { - PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), - resolvers, resolvedMacros, useResolvedMacros, timeout, - std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2)); + callback = std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2); } + PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), + resolvers, resolvedMacros, useResolvedMacros, timeout, callback); if (!resolvedMacros || useResolvedMacros) { Checkable::CurrentConcurrentChecks.fetch_add(1); From 134a43d48a586ad27297f277d9e6d88a23499899 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 17:06:08 +0200 Subject: [PATCH 13/67] Improve logs --- lib/icinga/clusterevents-check.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index b6f0e17aeed..a1b2f89ee47 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -102,7 +102,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons Host::Ptr host = Host::GetByName(params->Get("host")); if (!host) { - Log(LogCritical, "ApiListener", "Host not found."); + Log(LogCritical, "ApiListener") << "Host '" << params->Get("host") << "' not found."; return; } @@ -113,7 +113,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons checkable = host; if (!checkable) { - Log(LogCritical, "ApiListener", "Checkable not found."); + Log(LogCritical, "ApiListener") << "Checkable '" << params->Get("host") + << " " << params->Get("service") << "' not found."; return; } @@ -176,7 +177,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons } }; } - + if (!listener->GetAcceptCommands()) { Log(LogWarning, "ApiListener") << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; From 2db7b10ff0d724adabfe2ba5674859c29f205082 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 13 Jul 2020 17:49:38 +0200 Subject: [PATCH 14/67] Defer ExecuteCommandProcessFinishedHandler --- lib/icinga/clusterevents-check.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index a1b2f89ee47..e513f1fef87 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -97,6 +97,14 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons return; } + bool executeCommandProcessFinishedHandlerToBeReset = false; + Defer resetExecuteCommandProcessFinishedHandler ([&executeCommandProcessFinishedHandlerToBeReset]() { + if (executeCommandProcessFinishedHandlerToBeReset) { + Checkable::ExecuteCommandProcessFinishedHandler = nullptr; + executeCommandProcessFinishedHandlerToBeReset = false; + } + }); + if (params->Contains("source")) { String uuid = params->Get("source"); @@ -176,6 +184,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons listener->SyncSendMessage(sourceEndpoint, executedMessage); } }; + executeCommandProcessFinishedHandlerToBeReset = true; } if (!listener->GetAcceptCommands()) { From 59dfe6ad415c27e231074f38262c8acc56da2ca9 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 14 Jul 2020 11:23:39 +0200 Subject: [PATCH 15/67] Fix log --- lib/icinga/clusterevents-check.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index e513f1fef87..85b52ebf41f 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -122,7 +122,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (!checkable) { Log(LogCritical, "ApiListener") << "Checkable '" << params->Get("host") - << " " << params->Get("service") << "' not found."; + << "!" << params->Get("service") << "' not found."; return; } From 26685a93609fa238c7ea0bd974e2adcf2f8d3cc3 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 14 Jul 2020 11:57:12 +0200 Subject: [PATCH 16/67] Remove unuseful variable. Fix log --- lib/icinga/clusterevents-check.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 85b52ebf41f..0980a0c2caa 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -93,16 +93,12 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) { - Log(LogCritical, "ApiListener", "No instance available."); + Log(LogCritical, "ApiListener") << "No instance available."; return; } - bool executeCommandProcessFinishedHandlerToBeReset = false; - Defer resetExecuteCommandProcessFinishedHandler ([&executeCommandProcessFinishedHandlerToBeReset]() { - if (executeCommandProcessFinishedHandlerToBeReset) { - Checkable::ExecuteCommandProcessFinishedHandler = nullptr; - executeCommandProcessFinishedHandlerToBeReset = false; - } + Defer resetExecuteCommandProcessFinishedHandler ([]() { + Checkable::ExecuteCommandProcessFinishedHandler = nullptr; }); if (params->Contains("source")) { @@ -184,7 +180,6 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons listener->SyncSendMessage(sourceEndpoint, executedMessage); } }; - executeCommandProcessFinishedHandlerToBeReset = true; } if (!listener->GetAcceptCommands()) { From 96c34528a0782e2f168e309650c998599a92d8fe Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 14 Jul 2020 12:01:12 +0200 Subject: [PATCH 17/67] Change command type 'notification_command' with 'NotificationCommand' --- lib/icinga/apiactions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 454c50f0794..cddadb488c1 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -593,7 +593,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, command_type = HttpUtility::GetLastParameter(params, "command_type"); /* Validate command_type */ - if (command_type != "event_command" && command_type != "check_command" && command_type != "notification_command") + if (command_type != "event_command" && command_type != "check_command" && command_type != "NotificationCommand") return ApiActions::CreateResult(400, "Invalid command_type '" + command_type + "'."); Checkable::Ptr checkable = dynamic_pointer_cast(object); @@ -653,7 +653,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, command = "$check_command$"; } else if (command_type == "event_command") { command = "$event_command$"; - } else if (command_type == "notification_command") { + } else if (command_type == "NotificationCommand") { command = "$notification_command$"; } } else { @@ -688,7 +688,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); else cmd->Execute(checkable, execMacros, false); - } else if (command_type == "notification_command") { + } else if (command_type == "NotificationCommand") { NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); if (!cmd) return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'."); From 12da369ee188eae12ad1a2fc1dc6289bbb20bf6d Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 14 Jul 2020 17:23:03 +0200 Subject: [PATCH 18/67] Change check_command and event_command strings to CheckCommand and EventCommand --- lib/icinga/apiactions.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index cddadb488c1..2cfd8f8273e 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -588,12 +588,12 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, BOOST_THROW_EXCEPTION(std::invalid_argument("No ApiListener instance configured.")); /* Get command_type */ - String command_type = "event_command"; + String command_type = "EventCommand"; if (params->Contains("command_type")) command_type = HttpUtility::GetLastParameter(params, "command_type"); /* Validate command_type */ - if (command_type != "event_command" && command_type != "check_command" && command_type != "NotificationCommand") + if (command_type != "EventCommand" && command_type != "CheckCommand" && command_type != "NotificationCommand") return ApiActions::CreateResult(400, "Invalid command_type '" + command_type + "'."); Checkable::Ptr checkable = dynamic_pointer_cast(object); @@ -649,9 +649,9 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Get command */ String command; if (!params->Contains("command")) { - if (command_type == "check_command" ) { + if (command_type == "CheckCommand" ) { command = "$check_command$"; - } else if (command_type == "event_command") { + } else if (command_type == "EventCommand") { command = "$event_command$"; } else if (command_type == "NotificationCommand") { command = "$notification_command$"; @@ -676,13 +676,13 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, MacroResolver::OverrideMacros = nullptr; }); - if (command_type == "check_command") { + if (command_type == "CheckCommand") { 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 cmd->Execute(checkable, cr, execMacros, false); - } else if (command_type == "event_command") { + } 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 + "'."); @@ -763,7 +763,12 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Create execution parameters */ Dictionary::Ptr execParams = new Dictionary(); - execParams->Set("command_type", command_type); + if (command_type == "CheckCommand") + execParams->Set("command_type", "check_command"); + else if (command_type == "EventCommand") + execParams->Set("command_type", "event_command"); + else if (command_type == "NotificationCommand") + execParams->Set("command_type", "notification_command"); execParams->Set("command", resolved_command); execParams->Set("host", host->GetName()); if (service) From 3f490ac0e28191cf22baf64c8700c7abb8c2b8c6 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 15 Jul 2020 08:37:28 +0200 Subject: [PATCH 19/67] Set the right prams to send to ExecutedCommand --- lib/icinga/clusterevents-check.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 0980a0c2caa..555037d1788 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -165,8 +165,10 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons cr->SetExecutionEnd(pr.ExecutionEnd); Dictionary::Ptr executedParams = new Dictionary(); - params->CopyTo(executedParams); executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); executedParams->Set("check_result", Serialize(cr)); if (origin->IsLocal()) { From 300bc89cb62a1da4e1117016e201c97f94644170 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 15 Jul 2020 08:53:28 +0200 Subject: [PATCH 20/67] Handle when listener doesn't accept commands --- lib/icinga/clusterevents-check.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 555037d1788..5e514c19eb0 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -203,8 +203,29 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); cr->SetOutput("Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."); - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("check_result", Serialize(cr)); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + } else { + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + } return; } From 27f8bc5920eebefefa5bcc0827efbe2c77e27348 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 15 Jul 2020 09:14:01 +0200 Subject: [PATCH 21/67] Call ExecuteCommandProcessFinishedHandler for notification and event commands --- lib/methods/plugineventtask.cpp | 9 +++++++-- lib/methods/pluginnotificationtask.cpp | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp index b2bb466b825..9296df0f199 100644 --- a/lib/methods/plugineventtask.cpp +++ b/lib/methods/plugineventtask.cpp @@ -36,9 +36,14 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, int timeout = commandObj->GetTimeout(); + std::function callback; + if (Checkable::ExecuteCommandProcessFinishedHandler) { + callback = Checkable::ExecuteCommandProcessFinishedHandler; + } else { + callback = std::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2); + } PluginUtility::ExecuteCommand(commandObj, checkable, checkable->GetLastCheckResult(), - resolvers, resolvedMacros, useResolvedMacros, timeout, - std::bind(&PluginEventTask::ProcessFinishedHandler, checkable, _1, _2)); + resolvers, resolvedMacros, useResolvedMacros, timeout, callback); } void PluginEventTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp index 0fcc95dc234..b81708cf329 100644 --- a/lib/methods/pluginnotificationtask.cpp +++ b/lib/methods/pluginnotificationtask.cpp @@ -53,9 +53,14 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, int timeout = commandObj->GetTimeout(); + std::function callback; + if (Checkable::ExecuteCommandProcessFinishedHandler) { + callback = Checkable::ExecuteCommandProcessFinishedHandler; + } else { + callback = std::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2); + } PluginUtility::ExecuteCommand(commandObj, checkable, cr, resolvers, - resolvedMacros, useResolvedMacros, timeout, - std::bind(&PluginNotificationTask::ProcessFinishedHandler, checkable, _1, _2)); + resolvedMacros, useResolvedMacros, timeout, callback); } void PluginNotificationTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const Value& commandLine, const ProcessResult& pr) From 4255fd9494e9b1c421875657a7ba4cca991fe029 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 15 Jul 2020 13:50:49 +0200 Subject: [PATCH 22/67] Get host by Deserialize --- lib/icinga/clusterevents-check.cpp | 34 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 5e514c19eb0..e294d224bc7 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -104,24 +104,30 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { String uuid = params->Get("source"); - Host::Ptr host = Host::GetByName(params->Get("host")); - if (!host) { - Log(LogCritical, "ApiListener") << "Host '" << params->Get("host") << "' not found."; - return; - } + Host::Ptr host = new Host(); + Dictionary::Ptr attrs = new Dictionary(); + + attrs->Set("__name", params->Get("host")); + attrs->Set("type", "Host"); + + /* + * Override the check timeout if the parent caller provided the value. Compatible with older versions not + * passing this inside the cluster message. + * This happens with host/service command_endpoint agents and the 'check_timeout' attribute being specified. + */ + if (params->Contains("check_timeout")) + attrs->Set("check_timeout", params->Get("check_timeout")); + + Deserialize(host, attrs, false, FAConfig); - Checkable::Ptr checkable; if (params->Contains("service")) - checkable = host->GetServiceByShortName(params->Get("service")); - else - checkable = host; + host->SetExtension("agent_service_name", params->Get("service")); - if (!checkable) { - Log(LogCritical, "ApiListener") << "Checkable '" << params->Get("host") - << "!" << params->Get("service") << "' not found."; - return; - } + attrs->Set(params->Get("command_type"), params->Get("command")); + attrs->Set("command_endpoint", sourceEndpoint->GetName()); + Deserialize(host, attrs, false, FAConfig); + Checkable::Ptr checkable = host; ObjectLock oLock (checkable); if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { From 50f803c0422c1b4ef14f4c20f9c5a4400e94592f Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 15 Jul 2020 18:40:37 +0200 Subject: [PATCH 23/67] Return the process result parameters instead of the check result --- lib/icinga/clusterevents-check.cpp | 22 ++++++++-------------- lib/icinga/clusterevents.cpp | 21 ++++++++++++++------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index e294d224bc7..3c826144696 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -158,24 +158,15 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons << pr.ExitStatus << ", output: " << pr.Output; } - String output = pr.Output.Trim(); - - std::pair co = PluginUtility::ParseCheckOutput(output); - CheckResult::Ptr cr = new CheckResult(); - cr->SetCommand(commandLine); - cr->SetOutput(co.first); - cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); - cr->SetState(PluginUtility::ExitStatusToState(pr.ExitStatus)); - cr->SetExitStatus(pr.ExitStatus); - cr->SetExecutionStart(pr.ExecutionStart); - cr->SetExecutionEnd(pr.ExecutionEnd); - Dictionary::Ptr executedParams = new Dictionary(); executedParams->Set("execution", params->Get("source")); executedParams->Set("host", params->Get("host")); if (params->Contains("service")) executedParams->Set("service", params->Get("service")); - executedParams->Set("check_result", Serialize(cr)); + executedParams->Set("exit", pr.ExitStatus); + executedParams->Set("output", pr.Output); + executedParams->Set("start", pr.ExecutionStart); + executedParams->Set("end", pr.ExecutionEnd); if (origin->IsLocal()) { ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); @@ -216,7 +207,10 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons executedParams->Set("host", params->Get("host")); if (params->Contains("service")) executedParams->Set("service", params->Get("service")); - executedParams->Set("check_result", Serialize(cr)); + double now = Utility::GetTime(); + executedParams->Set("error", cr->GetOutput()); + executedParams->Set("start", now); + executedParams->Set("end", now); if (origin->IsLocal()) { ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 83b14d5d447..8bca1f1b42f 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1010,14 +1010,21 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, return Empty; } - if (!params->Contains("check_result")) { - Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': No check result available."; - return Empty; - } + if (params->Contains("error")) + execution->Set("error", params->Get("error")); + + if (params->Contains("exit")) + execution->Set("exit", params->Get("exit")); + + if (params->Contains("output")) + execution->Set("output", params->Get("output")); + + if (params->Contains("start")) + execution->Set("start", params->Get("start")); + + if (params->Contains("end")) + execution->Set("end", params->Get("end")); - execution->Set("check_result", params->Get("check_result")); execution->Set("pending", false); /* Broadcast the update */ From d4fb5a0656edee0f80eb265baa77d518375d76d2 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 16 Jul 2020 16:41:47 +0200 Subject: [PATCH 24/67] Remove unuseful check --- lib/icinga/clusterevents-check.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 3c826144696..6805fe351d8 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -130,13 +130,6 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons Checkable::Ptr checkable = host; ObjectLock oLock (checkable); - if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { - Log(LogNotice, "ApiListener") - << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; - return; - } - /* Check deadline */ double deadline = params->Get("deadline"); if (Utility::GetTime() > deadline) { From 461b4e21763354a058e40c96cccfa811b4c3690d Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 16 Jul 2020 16:52:48 +0200 Subject: [PATCH 25/67] Do CurrentConcurrentChecks and DecreasePendingChecks only for check_command --- lib/icinga/clusterevents-check.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 6805fe351d8..4579b28789a 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -140,13 +140,15 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons } Checkable::ExecuteCommandProcessFinishedHandler = [checkable, listener, sourceEndpoint, origin, params] (const Value& commandLine, const ProcessResult& pr) { - Checkable::CurrentConcurrentChecks.fetch_sub(1); - Checkable::DecreasePendingChecks(); + if (params->Get("command_type") == "check_command") { + Checkable::CurrentConcurrentChecks.fetch_sub(1); + Checkable::DecreasePendingChecks(); + } if (pr.ExitStatus > 3) { Process::Arguments parguments = Process::PrepareCommand(commandLine); Log(LogWarning, "ApiListener") - << "Check command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << "Command for object '" << checkable->GetName() << "' (PID: " << pr.PID << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " << pr.ExitStatus << ", output: " << pr.Output; } From f59c60f85f9c14196d73f6e61691e06248fbb9c5 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 20 Jul 2020 08:18:53 +0200 Subject: [PATCH 26/67] Send error as command execution result --- lib/icinga/clusterevents-check.cpp | 35 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 4579b28789a..2fa75af1157 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -180,21 +180,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons Log(LogWarning, "ApiListener") << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; - Host::Ptr host = new Host(); - Dictionary::Ptr attrs = new Dictionary(); - - attrs->Set("__name", params->Get("host")); - attrs->Set("type", "Host"); - attrs->Set("enable_active_checks", false); - - Deserialize(host, attrs, false, FAConfig); - - if (params->Contains("service")) - host->SetExtension("agent_service_name", params->Get("service")); - - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(ServiceUnknown); - cr->SetOutput("Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."); + String output = "Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."; if (params->Contains("source")) { Dictionary::Ptr executedParams = new Dictionary(); @@ -203,7 +189,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("service")) executedParams->Set("service", params->Get("service")); double now = Utility::GetTime(); - executedParams->Set("error", cr->GetOutput()); + executedParams->Set("exit", 126); + executedParams->Set("output", output); executedParams->Set("start", now); executedParams->Set("end", now); @@ -218,6 +205,22 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons listener->SyncSendMessage(sourceEndpoint, executedMessage); } } else { + Host::Ptr host = new Host(); + Dictionary::Ptr attrs = new Dictionary(); + + attrs->Set("__name", params->Get("host")); + attrs->Set("type", "Host"); + attrs->Set("enable_active_checks", false); + + Deserialize(host, attrs, false, FAConfig); + + if (params->Contains("service")) + host->SetExtension("agent_service_name", params->Get("service")); + + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(ServiceUnknown); + cr->SetOutput(output); + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); } From c6d4a9ac478ffe1a410394349baada6c14e4f69e Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 20 Jul 2020 12:46:22 +0200 Subject: [PATCH 27/67] Get checakble name from params --- lib/icinga/clusterevents-check.cpp | 34 ++++++------------------------ 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 2fa75af1157..6d437ef60f4 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -104,42 +104,20 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { String uuid = params->Get("source"); - Host::Ptr host = new Host(); - Dictionary::Ptr attrs = new Dictionary(); - - attrs->Set("__name", params->Get("host")); - attrs->Set("type", "Host"); - - /* - * Override the check timeout if the parent caller provided the value. Compatible with older versions not - * passing this inside the cluster message. - * This happens with host/service command_endpoint agents and the 'check_timeout' attribute being specified. - */ - if (params->Contains("check_timeout")) - attrs->Set("check_timeout", params->Get("check_timeout")); - - Deserialize(host, attrs, false, FAConfig); - + String checkableName = params->Get("host"); if (params->Contains("service")) - host->SetExtension("agent_service_name", params->Get("service")); - - attrs->Set(params->Get("command_type"), params->Get("command")); - attrs->Set("command_endpoint", sourceEndpoint->GetName()); - - Deserialize(host, attrs, false, FAConfig); - Checkable::Ptr checkable = host; - ObjectLock oLock (checkable); + checkableName += "!" + params->Get("service"); /* Check deadline */ double deadline = params->Get("deadline"); - if (Utility::GetTime() > deadline) { + if (Utility::GetTime() > deadline) {\ Log(LogNotice, "ApiListener") - << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkable->GetName() + << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkableName << "' from '" << origin->FromClient->GetIdentity() << "': Deadline has expired."; return; } - Checkable::ExecuteCommandProcessFinishedHandler = [checkable, listener, sourceEndpoint, origin, params] (const Value& commandLine, const ProcessResult& pr) { + Checkable::ExecuteCommandProcessFinishedHandler = [checkableName, listener, sourceEndpoint, origin, params] (const Value& commandLine, const ProcessResult& pr) { if (params->Get("command_type") == "check_command") { Checkable::CurrentConcurrentChecks.fetch_sub(1); Checkable::DecreasePendingChecks(); @@ -148,7 +126,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (pr.ExitStatus > 3) { Process::Arguments parguments = Process::PrepareCommand(commandLine); Log(LogWarning, "ApiListener") - << "Command for object '" << checkable->GetName() << "' (PID: " << pr.PID + << "Command for object '" << checkableName << "' (PID: " << pr.PID << ", arguments: " << Process::PrettyPrintArguments(parguments) << ") terminated with exit code " << pr.ExitStatus << ", output: " << pr.Output; } From acc986afd0da3a7640634598b1b4b0cc4cf02133 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 20 Jul 2020 13:15:12 +0200 Subject: [PATCH 28/67] Remove extra char --- lib/icinga/clusterevents-check.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 6d437ef60f4..70c647371a8 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -110,7 +110,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons /* Check deadline */ double deadline = params->Get("deadline"); - if (Utility::GetTime() > deadline) {\ + if (Utility::GetTime() > deadline) { Log(LogNotice, "ApiListener") << "Discarding 'ExecuteCheckFromQueue' event for checkable '" << checkableName << "' from '" << origin->FromClient->GetIdentity() << "': Deadline has expired."; From 8758e58b926df4834b3b362e72d5283376f0485b Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 20 Jul 2020 16:29:26 +0200 Subject: [PATCH 29/67] Use ExecuteCommandProcessFinishedHandler for all lib/methods/*task.cpp --- lib/methods/clusterchecktask.cpp | 54 +++++++---- lib/methods/clusterzonechecktask.cpp | 130 ++++++++++++++++++++------- lib/methods/dummychecktask.cpp | 28 ++++-- lib/methods/exceptionchecktask.cpp | 16 +++- lib/methods/icingachecktask.cpp | 30 +++++-- lib/methods/nullchecktask.cpp | 29 ++++-- lib/methods/randomchecktask.cpp | 39 +++++--- lib/methods/sleepchecktask.cpp | 23 +++-- 8 files changed, 257 insertions(+), 92 deletions(-) diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp index a9be0414dcf..ddefa9f8497 100644 --- a/lib/methods/clusterchecktask.cpp +++ b/lib/methods/clusterchecktask.cpp @@ -29,45 +29,69 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe return; CheckCommand::Ptr command = checkable->GetCheckCommand(); - cr->SetCommand(command->GetName()); + String commandName = command->GetName(); ApiListener::Ptr listener = ApiListener::GetInstance(); - if (!listener) { - cr->SetOutput("No API listener is configured for this instance."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "No API listener is configured for this instance."; + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 126; + pr.Output = output; + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(output); + cr->SetState(ServiceUnknown); + checkable->ProcessCheckResult(cr); + } return; } std::pair stats = listener->GetStatus(); - Dictionary::Ptr status = stats.first; - - /* use feature stats perfdata */ - std::pair feature_stats = CIB::GetFeatureStats(); - cr->SetPerformanceData(feature_stats.second); - int numConnEndpoints = status->Get("num_conn_endpoints"); int numNotConnEndpoints = status->Get("num_not_conn_endpoints"); + ServiceState state; String output = "Icinga 2 Cluster"; if (numNotConnEndpoints > 0) { output += " Problem: " + Convert::ToString(numNotConnEndpoints) + " endpoints are not connected."; output += "\n(" + FormatArray(status->Get("not_conn_endpoints")) + ")"; - cr->SetState(ServiceCritical); + state = ServiceCritical; } else { output += " OK: " + Convert::ToString(numConnEndpoints) + " endpoints are connected."; output += "\n(" + FormatArray(status->Get("conn_endpoints")) + ")"; - cr->SetState(ServiceOK); + state = ServiceOK; } - cr->SetOutput(output); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; - checkable->ProcessCheckResult(cr); + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + /* use feature stats perfdata */ + std::pair feature_stats = CIB::GetFeatureStats(); + cr->SetPerformanceData(feature_stats.second); + + cr->SetCommand(commandName); + cr->SetState(state); + cr->SetOutput(output); + + checkable->ProcessCheckResult(cr); + } } String ClusterCheckTask::FormatArray(const Array::Ptr& arr) diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index c955b7dd9ca..af0c660530c 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -21,15 +21,32 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che REQUIRE_NOT_NULL(cr); ApiListener::Ptr listener = ApiListener::GetInstance(); + CheckCommand::Ptr command = checkable->GetCheckCommand(); + String commandName = command->GetName(); if (!listener) { - cr->SetOutput("No API listener is configured for this instance."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "No API listener is configured for this instance."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } return; } - CheckCommand::Ptr command = checkable->GetCheckCommand(); Value raw_command = command->GetCommandLine(); Host::Ptr host; @@ -58,21 +75,51 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che if (resolvedMacros && !useResolvedMacros) return; - cr->SetCommand(command->GetName()); - if (zoneName.IsEmpty()) { - cr->SetOutput("Macro 'cluster_zone' must be set."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "Macro 'cluster_zone' must be set."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } return; } Zone::Ptr zone = Zone::GetByName(zoneName); if (!zone) { - cr->SetOutput("Zone '" + zoneName + "' does not exist."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "Zone '" + zoneName + "' does not exist."; + ServiceState state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetOutput(output); + cr->SetState(state); + checkable->ProcessCheckResult(cr); + } return; } @@ -107,34 +154,51 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che bytesReceivedPerSecond += endpoint->GetBytesReceivedPerSecond(); } + ServiceState state; + String output; if (connected) { - cr->SetState(ServiceOK); - cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag)); + state = ServiceOK; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag); /* Check whether the thresholds have been resolved and compare them */ if (missingLagCritical.IsEmpty() && zoneLag > lagCritical) { - cr->SetState(ServiceCritical); - cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) - + " greater than critical threshold: " + Utility::FormatDuration(lagCritical)); + state = ServiceCritical; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + + " greater than critical threshold: " + Utility::FormatDuration(lagCritical); } else if (missingLagWarning.IsEmpty() && zoneLag > lagWarning) { - cr->SetState(ServiceWarning); - cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) - + " greater than warning threshold: " + Utility::FormatDuration(lagWarning)); + state = ServiceWarning; + output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag) + + " greater than warning threshold: " + Utility::FormatDuration(lagWarning); } } else { - cr->SetState(ServiceCritical); - cr->SetOutput("Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag)); + state = ServiceCritical; + output = "Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag); } - cr->SetPerformanceData(new Array({ - new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical), - new PerfdataValue("last_messages_sent", lastMessageSent), - new PerfdataValue("last_messages_received", lastMessageReceived), - new PerfdataValue("sum_messages_sent_per_second", messagesSentPerSecond), - new PerfdataValue("sum_messages_received_per_second", messagesReceivedPerSecond), - new PerfdataValue("sum_bytes_sent_per_second", bytesSentPerSecond), - new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond) - })); - - checkable->ProcessCheckResult(cr); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetCommand(commandName); + cr->SetState(state); + cr->SetOutput(output); + cr->SetPerformanceData(new Array({ + new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical), + new PerfdataValue("last_messages_sent", lastMessageSent), + new PerfdataValue("last_messages_received", lastMessageReceived), + new PerfdataValue("sum_messages_sent_per_second", messagesSentPerSecond), + new PerfdataValue("sum_messages_received_per_second", messagesReceivedPerSecond), + new PerfdataValue("sum_bytes_sent_per_second", bytesSentPerSecond), + new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond) + })); + + checkable->ProcessCheckResult(cr); + } } diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index e42754f3143..09398debe55 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -48,14 +48,26 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu std::pair co = PluginUtility::ParseCheckOutput(dummyText); double now = Utility::GetTime(); + String commandName = command->GetName(); - cr->SetOutput(co.first); - cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); - cr->SetState(PluginUtility::ExitStatusToState(dummyState)); - cr->SetExitStatus(dummyState); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - cr->SetCommand(command->GetName()); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + ProcessResult pr; + pr.PID = -1; + pr.Output = co.first; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = dummyState; - checkable->ProcessCheckResult(cr); + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(co.first); + cr->SetPerformanceData(PluginUtility::SplitPerfdata(co.second)); + cr->SetState(PluginUtility::ExitStatusToState(dummyState)); + cr->SetExitStatus(dummyState); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } } diff --git a/lib/methods/exceptionchecktask.cpp b/lib/methods/exceptionchecktask.cpp index 5ce3a926263..6efbd51b3d6 100644 --- a/lib/methods/exceptionchecktask.cpp +++ b/lib/methods/exceptionchecktask.cpp @@ -23,5 +23,19 @@ void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Check if (resolvedMacros && !useResolvedMacros) return; - BOOST_THROW_EXCEPTION(ScriptError("Test") << boost::errinfo_api_function("Test")); + ScriptError scriptError = ScriptError("Test") << boost::errinfo_api_function("Test"); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = scriptError.what(); + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + BOOST_THROW_EXCEPTION(ScriptError("Test") << boost::errinfo_api_function("Test")); + } } diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index 2c2c5c5929e..a5da4c80186 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -148,7 +148,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes perfdata->Add(new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond)); cr->SetPerformanceData(perfdata); - cr->SetState(ServiceOK); + ServiceState state = ServiceOK; String appVersion = Application::GetAppVersion(); @@ -160,7 +160,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes if (lastReloadFailed > 0) { output += "; Last reload attempt failed at " + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", lastReloadFailed); - cr->SetState(ServiceWarning); + state =ServiceWarning; } /* Indicate a warning when the last synced config caused a stage validation error. */ @@ -173,7 +173,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes output += "; Last zone sync stage validation failed at " + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", validationResult->Get("ts")); - cr->SetState(ServiceWarning); + state = ServiceWarning; } } @@ -182,11 +182,25 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes /* Return an error if the version is less than specified (optional). */ if (missingIcingaMinVersion.IsEmpty() && !icingaMinVersion.IsEmpty() && Utility::CompareVersion(icingaMinVersion, parsedAppVersion) < 0) { output += "; Minimum version " + icingaMinVersion + " is not installed."; - cr->SetState(ServiceCritical); + state = ServiceCritical; } - cr->SetOutput(output); - cr->SetCommand(command->GetName()); - - checkable->ProcessCheckResult(cr); + String commandName = command->GetName(); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + cr->SetCommand(commandName); + + checkable->ProcessCheckResult(cr); + } } diff --git a/lib/methods/nullchecktask.cpp b/lib/methods/nullchecktask.cpp index b56087b2ed4..ee660294ee4 100644 --- a/lib/methods/nullchecktask.cpp +++ b/lib/methods/nullchecktask.cpp @@ -26,12 +26,25 @@ void NullCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResul String output = "Hello from "; output += IcingaApplication::GetInstance()->GetNodeName(); - - cr->SetOutput(output); - cr->SetPerformanceData(new Array({ - new PerfdataValue("time", Convert::ToDouble(Utility::GetTime())) - })); - cr->SetState(ServiceOK); - - checkable->ProcessCheckResult(cr); + ServiceState state = ServiceOK; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + cr->SetOutput(output); + cr->SetPerformanceData(new Array({ + new PerfdataValue("time", Convert::ToDouble(Utility::GetTime())) + })); + cr->SetState(state); + + checkable->ProcessCheckResult(cr); + } } diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 35e10d2a635..0e138ffa55c 100644 --- a/lib/methods/randomchecktask.cpp +++ b/lib/methods/randomchecktask.cpp @@ -31,22 +31,35 @@ void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes + ". Icinga 2 has been running for " + Utility::FormatDuration(uptime) + ". Version: " + Application::GetAppVersion(); - cr->SetOutput(output); + CheckCommand::Ptr command = checkable->GetCheckCommand(); + String commandName = command->GetName(); + ServiceState state = static_cast(Utility::Random() % 4); - double random = Utility::Random() % 1000; + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; - cr->SetPerformanceData(new Array({ - new PerfdataValue("time", now), - new PerfdataValue("value", random), - new PerfdataValue("value_1m", random * 0.9), - new PerfdataValue("value_5m", random * 0.8), - new PerfdataValue("uptime", uptime), - })); + Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr); + } else { + cr->SetOutput(output); - cr->SetState(static_cast(Utility::Random() % 4)); + double random = Utility::Random() % 1000; + cr->SetPerformanceData(new Array({ + new PerfdataValue("time", now), + new PerfdataValue("value", random), + new PerfdataValue("value_1m", random * 0.9), + new PerfdataValue("value_5m", random * 0.8), + new PerfdataValue("uptime", uptime), + })); - CheckCommand::Ptr command = checkable->GetCheckCommand(); - cr->SetCommand(command->GetName()); + cr->SetState(state); + cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr); + } } diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index 47f735c3699..b5f3d88914a 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -42,13 +42,24 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu String output = "Slept for " + Convert::ToString(sleepTime) + " seconds."; double now = Utility::GetTime(); + CheckCommand::Ptr command = checkable->GetCheckCommand(); + String commandName = command->GetName(); - cr->SetOutput(output); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; - CheckCommand::Ptr command = checkable->GetCheckCommand(); - cr->SetCommand(command->GetName()); + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } else { + cr->SetOutput(output); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr); + } } \ No newline at end of file From 986c07fd7dcec44037fe3e8360a7ceaf8119ea30 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 08:33:43 +0200 Subject: [PATCH 30/67] Use ExecuteCommandProcessFinishedHandler in NullEventTask --- lib/methods/nulleventtask.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/methods/nulleventtask.cpp b/lib/methods/nulleventtask.cpp index 0755a4d0195..3c02f234f8e 100644 --- a/lib/methods/nulleventtask.cpp +++ b/lib/methods/nulleventtask.cpp @@ -11,4 +11,16 @@ REGISTER_FUNCTION_NONCONST(Internal, NullEvent, &NullEventTask::ScriptFunc, "che void NullEventTask::ScriptFunc(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = ""; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } } From abf164bceb1c8c3480537411cbc9d54dc27087d4 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 09:57:59 +0200 Subject: [PATCH 31/67] Use ExecuteCommandProcessFinishedHandler in TimePeriodTask --- lib/methods/timeperiodtask.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/methods/timeperiodtask.cpp b/lib/methods/timeperiodtask.cpp index bb3f1bb0059..8d014d5b654 100644 --- a/lib/methods/timeperiodtask.cpp +++ b/lib/methods/timeperiodtask.cpp @@ -12,6 +12,18 @@ Array::Ptr TimePeriodTask::EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, doub { REQUIRE_NOT_NULL(tp); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = ""; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } + Array::Ptr segments = new Array(); return segments; } @@ -31,5 +43,17 @@ Array::Ptr TimePeriodTask::EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr& tp } } + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = ""; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = 0; + + Checkable::ExecuteCommandProcessFinishedHandler("", pr); + } + return new Array(std::move(segments)); } From 867da09fb495643a585e73659d58b9dea4dddec6 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 10:52:59 +0200 Subject: [PATCH 32/67] Revert "Use ExecuteCommandProcessFinishedHandler in TimePeriodTask" This reverts commit abf164bceb1c8c3480537411cbc9d54dc27087d4. --- lib/methods/timeperiodtask.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/lib/methods/timeperiodtask.cpp b/lib/methods/timeperiodtask.cpp index 8d014d5b654..bb3f1bb0059 100644 --- a/lib/methods/timeperiodtask.cpp +++ b/lib/methods/timeperiodtask.cpp @@ -12,18 +12,6 @@ Array::Ptr TimePeriodTask::EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, doub { REQUIRE_NOT_NULL(tp); - if (Checkable::ExecuteCommandProcessFinishedHandler) { - double now = Utility::GetTime(); - ProcessResult pr; - pr.PID = -1; - pr.Output = ""; - pr.ExecutionStart = now; - pr.ExecutionEnd = now; - pr.ExitStatus = 0; - - Checkable::ExecuteCommandProcessFinishedHandler("", pr); - } - Array::Ptr segments = new Array(); return segments; } @@ -43,17 +31,5 @@ Array::Ptr TimePeriodTask::EvenMinutesTimePeriodUpdate(const TimePeriod::Ptr& tp } } - if (Checkable::ExecuteCommandProcessFinishedHandler) { - double now = Utility::GetTime(); - ProcessResult pr; - pr.PID = -1; - pr.Output = ""; - pr.ExecutionStart = now; - pr.ExecutionEnd = now; - pr.ExitStatus = 0; - - Checkable::ExecuteCommandProcessFinishedHandler("", pr); - } - return new Array(std::move(segments)); } From 2e8b492f2945643664b0ee42dab892ecc93aec88 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 13:27:03 +0200 Subject: [PATCH 33/67] Implement notification execution --- lib/icinga/apiactions.cpp | 8 +++-- lib/icinga/clusterevents-check.cpp | 56 ++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 2cfd8f8273e..65f462499c8 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -676,6 +676,9 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, MacroResolver::OverrideMacros = nullptr; }); + /* Create execution parameters */ + Dictionary::Ptr execParams = new Dictionary(); + if (command_type == "CheckCommand") { CheckCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(CheckCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); if (!cmd) @@ -707,6 +710,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, User::Ptr user = GetSingleObjectByNameUsingPermissions(User::GetTypeName(), resolved_user, ActionsHandler::AuthenticatedApiUser); if (!user) return ApiActions::CreateResult(404, "Can't find a valid user for '" + resolved_user + "'."); + execParams->Set("user", user->GetName()); /* Get notification */ String notification_string = ""; @@ -722,6 +726,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, Notification::Ptr notification = GetSingleObjectByNameUsingPermissions(Notification::GetTypeName(), resolved_notification, ActionsHandler::AuthenticatedApiUser); if (!notification) return ApiActions::CreateResult(404, "Can't find a valid notification for '" + resolved_notification + "'."); + execParams->Set("notification", notification->GetName()); cmd->Execute(notification, user, cr, NotificationType::NotificationCustom, ActionsHandler::AuthenticatedApiUser->GetName(), "", execMacros, false); @@ -761,8 +766,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, MessageOrigin::Ptr origin = new MessageOrigin(); listener->RelayMessage(origin, checkable, updateMessage, true); - /* Create execution parameters */ - Dictionary::Ptr execParams = new Dictionary(); + /* Populate execution parameters */ if (command_type == "CheckCommand") execParams->Set("command_type", "check_command"); else if (command_type == "EventCommand") diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 70c647371a8..9e7381ffd54 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -241,11 +241,16 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons } else if (command_type == "event_command") { if (!EventCommand::GetByName(command)) { Log(LogWarning, "ClusterEvents") - << "Event command '" << command << "' does not exist."; + << "Event command '" << command << "' does not exist."; return; } - } else - return; + } else if (command_type == "notification_command") { + if (!NotificationCommand::GetByName(command)) { + Log(LogWarning, "ClusterEvents") + << "Notification command '" << command << "' does not exist."; + return; + } + } attrs->Set(command_type, params->Get("command")); attrs->Set("command_endpoint", sourceEndpoint->GetName()); @@ -279,6 +284,51 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons } } else if (command_type == "event_command") { host->ExecuteEventHandler(macros, true); + } else if (command_type == "notification_command") { + /* Get user */ + User::Ptr user = new User(); + Dictionary::Ptr attrs = new Dictionary(); + attrs->Set("__name", params->Get("user")); + attrs->Set("type", User::GetTypeName()); + + Deserialize(user, attrs, false, FAConfig); + + /* Get notification */ + Notification::Ptr notification = new Notification(); + attrs->Clear(); + attrs->Set("__name", params->Get("notification")); + attrs->Set("type", Notification::GetTypeName()); + attrs->Set("command", command); + + Deserialize(notification, attrs, false, FAConfig); + + try { + CheckResult::Ptr cr = new CheckResult(); + String author = macros->Get("notification_author"); + NotificationCommand::Ptr notificationCommand = NotificationCommand::GetByName(command); + + notificationCommand->Execute(notification, user, cr, NotificationType::NotificationCustom, + author, ""); + } catch (const std::exception& ex) { + String output = "Exception occurred during notification '" + notification->GetName() + + "' for checkable '" + notification->GetCheckable()->GetName() + + "' and user '" + user->GetName() + "' using command '" + command + "': " + + DiagnosticInformation(ex, false); + double now = Utility::GetTime(); + + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(ServiceUnknown); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + + Log(LogCritical, "checker", output); + } } } From 05b1beb2ff772b2596a37a915b1b65ce225da233 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 15:51:57 +0200 Subject: [PATCH 34/67] Send event::ExecutedCommand where necessary --- lib/icinga/clusterevents-check.cpp | 132 +++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 9e7381ffd54..83d73c48771 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -231,11 +231,42 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (command_type == "check_command") { if (!CheckCommand::GetByName(command)) { - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(ServiceUnknown); - cr->SetOutput("Check command '" + command + "' does not exist."); - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + ServiceState state = ServiceUnknown; + String output = "Check command '" + command + "' does not exist."; + double now = Utility::GetTime(); + + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + } else { + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(state); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + } return; } } else if (command_type == "event_command") { @@ -265,20 +296,43 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons try { host->ExecuteRemoteCheck(macros); } catch (const std::exception& ex) { - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(ServiceUnknown); - String output = "Exception occurred while checking '" + host->GetName() + "': " + DiagnosticInformation(ex); - cr->SetOutput(output); - + ServiceState state = ServiceUnknown; double now = Utility::GetTime(); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + } else { + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(state); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + } Log(LogCritical, "checker", output); } @@ -315,17 +369,41 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons + "' and user '" + user->GetName() + "' using command '" + command + "': " + DiagnosticInformation(ex, false); double now = Utility::GetTime(); - - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(ServiceUnknown); - cr->SetOutput(output); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + ServiceState state = ServiceUnknown; + + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + } else { + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(state); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + } Log(LogCritical, "checker", output); } From b4d6fe2c8dc7c97477b870abd060023cc8210428 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 21 Jul 2020 16:33:52 +0200 Subject: [PATCH 35/67] Check if the node accept commands only if the origin is not local --- lib/icinga/clusterevents-check.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 83d73c48771..69cdf7636a6 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -154,7 +154,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons }; } - if (!listener->GetAcceptCommands()) { + if (!listener->GetAcceptCommands() && !origin->IsLocal()) { Log(LogWarning, "ApiListener") << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; @@ -172,16 +172,12 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons executedParams->Set("start", now); executedParams->Set("end", now); - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + listener->SyncSendMessage(sourceEndpoint, executedMessage); } else { Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); From 96dc3492404279a2f5897e743ce422b7bd2f70d5 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 22 Jul 2020 11:38:41 +0200 Subject: [PATCH 36/67] Fix scriptfunc for dummychecktask, exceptionchecktask and sleepchecktask --- lib/methods/dummychecktask.cpp | 2 +- lib/methods/exceptionchecktask.cpp | 2 +- lib/methods/sleepchecktask.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index 09398debe55..ce72ca233e3 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -53,7 +53,7 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu if (Checkable::ExecuteCommandProcessFinishedHandler) { ProcessResult pr; pr.PID = -1; - pr.Output = co.first; + pr.Output = dummyText; pr.ExecutionStart = now; pr.ExecutionEnd = now; pr.ExitStatus = dummyState; diff --git a/lib/methods/exceptionchecktask.cpp b/lib/methods/exceptionchecktask.cpp index 6efbd51b3d6..47707f26ff8 100644 --- a/lib/methods/exceptionchecktask.cpp +++ b/lib/methods/exceptionchecktask.cpp @@ -32,7 +32,7 @@ void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Check pr.Output = scriptError.what(); pr.ExecutionStart = now; pr.ExecutionEnd = now; - pr.ExitStatus = 0; + pr.ExitStatus = 3; Checkable::ExecuteCommandProcessFinishedHandler("", pr); } else { diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index b5f3d88914a..55f9f8fa133 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -49,7 +49,7 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu ProcessResult pr; pr.PID = -1; pr.Output = output; - pr.ExecutionStart = now; + pr.ExecutionStart = now - sleepTime; pr.ExecutionEnd = now; pr.ExitStatus = 0; From 4e3a38f3201c84ecbc42a7cd1415d7e20d39dd6f Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 22 Jul 2020 14:16:41 +0200 Subject: [PATCH 37/67] Unify code to check if command exists --- lib/icinga/clusterevents-check.cpp | 84 +++++++++++++----------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 69cdf7636a6..737af21f3d5 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -225,61 +225,49 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons String command = params->Get("command"); String command_type = params->Get("command_type"); - if (command_type == "check_command") { - if (!CheckCommand::GetByName(command)) { - ServiceState state = ServiceUnknown; - String output = "Check command '" + command + "' does not exist."; - double now = Utility::GetTime(); - - if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); + if (command_type == "check_command" && !CheckCommand::GetByName(command) || + command_type == "event_command" && !EventCommand::GetByName(command) || + command_type == "notification_command" && !NotificationCommand::GetByName(command)) { + ServiceState state = ServiceUnknown; + String output = command_type + " '" + command + "' does not exist."; + double now = Utility::GetTime(); - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); } else { - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(state); - cr->SetOutput(output); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); } - return; - } - } else if (command_type == "event_command") { - if (!EventCommand::GetByName(command)) { - Log(LogWarning, "ClusterEvents") - << "Event command '" << command << "' does not exist."; - return; - } - } else if (command_type == "notification_command") { - if (!NotificationCommand::GetByName(command)) { - Log(LogWarning, "ClusterEvents") - << "Notification command '" << command << "' does not exist."; - return; + } else { + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(state); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); } + return; } - attrs->Set(command_type, params->Get("command")); + attrs->Set(command_type, command); attrs->Set("command_endpoint", sourceEndpoint->GetName()); Deserialize(host, attrs, false, FAConfig); From e690eaf3c43954de1cfd3adb0c4fa7a38927c069 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 22 Jul 2020 17:22:50 +0200 Subject: [PATCH 38/67] Run ExecutedCommandAPIHandler in case of command not found and if source is set --- lib/icinga/clusterevents-check.cpp | 134 +++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 35 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 737af21f3d5..2242b3964b0 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -225,49 +225,113 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons String command = params->Get("command"); String command_type = params->Get("command_type"); - if (command_type == "check_command" && !CheckCommand::GetByName(command) || - command_type == "event_command" && !EventCommand::GetByName(command) || - command_type == "notification_command" && !NotificationCommand::GetByName(command)) { - ServiceState state = ServiceUnknown; - String output = command_type + " '" + command + "' does not exist."; - double now = Utility::GetTime(); + if (command_type == "check_command") { + if (!CheckCommand::GetByName(command)) { + ServiceState state = ServiceUnknown; + String output = "Check command '" + command + "' does not exist."; + double now = Utility::GetTime(); + + if (params->Contains("source")) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); - if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); + CheckResult::Ptr cr = new CheckResult(); + cr->SetState(state); + cr->SetOutput(output); + cr->SetScheduleStart(now); + cr->SetScheduleEnd(now); + cr->SetExecutionStart(now); + cr->SetExecutionEnd(now); + Dictionary::Ptr message = MakeCheckResultMessage(host, cr); + listener->SyncSendMessage(sourceEndpoint, message); + } + return; + } + } else if (command_type == "event_command") { + if (!EventCommand::GetByName(command)) { + String output = "Event command '" + command + "' does not exist."; + Log(LogWarning, "ClusterEvents") << output; - listener->SyncSendMessage(sourceEndpoint, executedMessage); + if (params->Contains("source")) { + double now = Utility::GetTime(); + ServiceState state = ServiceUnknown; + + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } } - } else { - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(state); - cr->SetOutput(output); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); + return; + } + } else if (command_type == "notification_command") { + if (!NotificationCommand::GetByName(command)) { + String output = "Notification command '" + command + "' does not exist."; + Log(LogWarning, "ClusterEvents") << output; + + if (params->Contains("source")) { + double now = Utility::GetTime(); + ServiceState state = ServiceUnknown; + + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", state); + executedParams->Set("output", output); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } + } + return; } - return; } - attrs->Set(command_type, command); + attrs->Set(command_type, params->Get("command")); attrs->Set("command_endpoint", sourceEndpoint->GetName()); Deserialize(host, attrs, false, FAConfig); From 6656afb259faf02ca9d81e28c2220e2ee7ab1ab8 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 08:26:31 +0200 Subject: [PATCH 39/67] Code refactoring: create sendEventExecuteCommand function --- lib/icinga/clusterevents-check.cpp | 174 ++++++----------------------- 1 file changed, 32 insertions(+), 142 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 2242b3964b0..42e04d6022f 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -75,6 +75,31 @@ void ClusterEvents::EnqueueCheck(const MessageOrigin::Ptr& origin, const Diction } } +static void sendEventExecuteCommand(const Dictionary::Ptr& params, const long& exit, const String& output, + const double& start, const double& end, const ApiListener::Ptr& listener, const MessageOrigin::Ptr& origin, + const Endpoint::Ptr& sourceEndpoint) { + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", exit); + executedParams->Set("output", output); + executedParams->Set("start", start); + executedParams->Set("end", end); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->SyncSendMessage(sourceEndpoint, executedMessage); + } +} + void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { Endpoint::Ptr sourceEndpoint; @@ -131,26 +156,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons << pr.ExitStatus << ", output: " << pr.Output; } - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", pr.ExitStatus); - executedParams->Set("output", pr.Output); - executedParams->Set("start", pr.ExecutionStart); - executedParams->Set("end", pr.ExecutionEnd); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, pr.ExitStatus, pr.Output, pr.ExecutionStart, pr.ExecutionEnd, listener, origin, sourceEndpoint); }; } @@ -161,23 +167,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons String output = "Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."; if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); double now = Utility::GetTime(); - executedParams->Set("exit", 126); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); + sendEventExecuteCommand(params, 126, output, now, now, listener, origin, sourceEndpoint); } else { Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); @@ -232,34 +223,11 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); cr->SetOutput(output); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); listener->SyncSendMessage(sourceEndpoint, message); } @@ -273,27 +241,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); ServiceState state = ServiceUnknown; - - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -305,27 +253,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); ServiceState state = ServiceUnknown; - - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -349,26 +277,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); @@ -420,26 +329,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons ServiceState state = ServiceUnknown; if (params->Contains("source")) { - Dictionary::Ptr executedParams = new Dictionary(); - executedParams->Set("execution", params->Get("source")); - executedParams->Set("host", params->Get("host")); - if (params->Contains("service")) - executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", state); - executedParams->Set("output", output); - executedParams->Set("start", now); - executedParams->Set("end", now); - - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->SyncSendMessage(sourceEndpoint, executedMessage); - } + sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); From 9940aaf90c0752f745c80e62369c02bac61c0438 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 11:31:44 +0200 Subject: [PATCH 40/67] Refactor SendEventExecuteCommand function --- lib/icinga/clusterevents-check.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 42e04d6022f..17e8e964965 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -75,15 +75,15 @@ void ClusterEvents::EnqueueCheck(const MessageOrigin::Ptr& origin, const Diction } } -static void sendEventExecuteCommand(const Dictionary::Ptr& params, const long& exit, const String& output, - const double& start, const double& end, const ApiListener::Ptr& listener, const MessageOrigin::Ptr& origin, - const Endpoint::Ptr& sourceEndpoint) { +static void SendEventExecuteCommand(const Dictionary::Ptr& params, long exitStatus, const String& output, + double start, double end, const ApiListener::Ptr& listener, const MessageOrigin::Ptr& origin, + const Endpoint::Ptr& sourceEndpoint) { Dictionary::Ptr executedParams = new Dictionary(); executedParams->Set("execution", params->Get("source")); executedParams->Set("host", params->Get("host")); if (params->Contains("service")) executedParams->Set("service", params->Get("service")); - executedParams->Set("exit", exit); + executedParams->Set("exit", exitStatus); executedParams->Set("output", output); executedParams->Set("start", start); executedParams->Set("end", end); @@ -156,7 +156,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons << pr.ExitStatus << ", output: " << pr.Output; } - sendEventExecuteCommand(params, pr.ExitStatus, pr.Output, pr.ExecutionStart, pr.ExecutionEnd, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, pr.ExitStatus, pr.Output, pr.ExecutionStart, pr.ExecutionEnd, listener, + origin, sourceEndpoint); }; } @@ -168,7 +169,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); - sendEventExecuteCommand(params, 126, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, 126, output, now, now, listener, origin, sourceEndpoint); } else { Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); @@ -223,7 +224,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); if (params->Contains("source")) { - sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); @@ -241,7 +242,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); ServiceState state = ServiceUnknown; - sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -253,7 +254,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); ServiceState state = ServiceUnknown; - sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -277,7 +278,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); if (params->Contains("source")) { - sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); @@ -329,7 +330,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons ServiceState state = ServiceUnknown; if (params->Contains("source")) { - sendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); } else { CheckResult::Ptr cr = new CheckResult(); cr->SetState(state); From 14c02ec654f006d386e60c30d819667c454e5f6f Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 12:58:50 +0200 Subject: [PATCH 41/67] Remove unuseful check result for notification command --- lib/icinga/clusterevents-check.cpp | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 17e8e964965..af124cb3217 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -322,29 +322,15 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons notificationCommand->Execute(notification, user, cr, NotificationType::NotificationCustom, author, ""); } catch (const std::exception& ex) { - String output = "Exception occurred during notification '" + notification->GetName() - + "' for checkable '" + notification->GetCheckable()->GetName() - + "' and user '" + user->GetName() + "' using command '" + command + "': " - + DiagnosticInformation(ex, false); - double now = Utility::GetTime(); - ServiceState state = ServiceUnknown; - if (params->Contains("source")) { + String output = "Exception occurred during notification '" + notification->GetName() + + "' for checkable '" + notification->GetCheckable()->GetName() + + "' and user '" + user->GetName() + "' using command '" + command + "': " + + DiagnosticInformation(ex, false); + double now = Utility::GetTime(); + ServiceState state = ServiceUnknown; SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); - } else { - CheckResult::Ptr cr = new CheckResult(); - cr->SetState(state); - cr->SetOutput(output); - cr->SetScheduleStart(now); - cr->SetScheduleEnd(now); - cr->SetExecutionStart(now); - cr->SetExecutionEnd(now); - - Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(sourceEndpoint, message); } - - Log(LogCritical, "checker", output); } } } From b30960fda5d1245a997a81a35100adea8f2ac4d3 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 13:03:30 +0200 Subject: [PATCH 42/67] Add try catch for ExecuteEventHandler --- lib/icinga/clusterevents-check.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index af124cb3217..646a7bd3918 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -295,7 +295,18 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons Log(LogCritical, "checker", output); } } else if (command_type == "event_command") { - host->ExecuteEventHandler(macros, true); + try { + host->ExecuteEventHandler(macros, true); + } catch (const std::exception& ex) { + if (params->Contains("source")) { + String output = "Exception occurred while executing event command '" + command + "' for '" + + host->GetName() + "': " + DiagnosticInformation(ex); + + double now = Utility::GetTime(); + ServiceState state = ServiceUnknown; + SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + } + } } else if (command_type == "notification_command") { /* Get user */ User::Ptr user = new User(); From 53659066f2e56075f413755f3833d89ead3d2742 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 13:20:31 +0200 Subject: [PATCH 43/67] Remove unuseful variables --- lib/icinga/clusterevents-check.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 646a7bd3918..7058a68f66d 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -241,8 +241,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); - ServiceState state = ServiceUnknown; - SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -253,8 +252,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (params->Contains("source")) { double now = Utility::GetTime(); - ServiceState state = ServiceUnknown; - SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } return; } @@ -303,8 +301,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons host->GetName() + "': " + DiagnosticInformation(ex); double now = Utility::GetTime(); - ServiceState state = ServiceUnknown; - SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } } } else if (command_type == "notification_command") { @@ -339,8 +336,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons + "' and user '" + user->GetName() + "' using command '" + command + "': " + DiagnosticInformation(ex, false); double now = Utility::GetTime(); - ServiceState state = ServiceUnknown; - SendEventExecuteCommand(params, state, output, now, now, listener, origin, sourceEndpoint); + SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } } } From aadedc0d1ce21152c9c90040ac4541304deba637 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 13:23:13 +0200 Subject: [PATCH 44/67] Throw an exception in case of error during ExecuteEventHandler if source is not set --- lib/icinga/clusterevents-check.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 7058a68f66d..13bf02dacce 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -302,6 +302,8 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); + } else { + throw ex; } } } else if (command_type == "notification_command") { From bf07ada3df1081d5c9c12ae8c46d98456e56709c Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 23 Jul 2020 13:34:26 +0200 Subject: [PATCH 45/67] Remove arguments from 'throw' inc case of ExecuteEventHandler error --- lib/icinga/clusterevents-check.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 13bf02dacce..ac5aed79732 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -303,7 +303,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons double now = Utility::GetTime(); SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } else { - throw ex; + throw; } } } else if (command_type == "notification_command") { From 1e59810dddfc0bef70b25fb92770197decf0e654 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:38:49 +0200 Subject: [PATCH 46/67] Fix indentation --- lib/icinga/clusterevents.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 8bca1f1b42f..4e453257f37 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -957,8 +957,8 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (!endpoint) { Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message from '" << origin->FromClient->GetIdentity() - << "': Invalid endpoint origin (client not allowed)."; + << "Discarding 'update executions API handler' message from '" << origin->FromClient->GetIdentity() + << "': Invalid endpoint origin (client not allowed)."; return Empty; } @@ -981,15 +981,15 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; return Empty; } if (!params->Contains("execution")) { Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID not found."; + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID not found."; return Empty; } String uuid = params->Get("execution"); @@ -997,16 +997,16 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, Dictionary::Ptr executions = checkable->GetExecutions(); if (!executions) { Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': No executions available."; + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': No executions available."; return Empty; } Dictionary::Ptr execution = executions->Get(uuid); if (!execution) { Log(LogNotice, "ClusterEvents") - << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; + << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() + << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; return Empty; } From 5a4fa6965031332e91f1c73ed2b3826547f725fe Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:43:30 +0200 Subject: [PATCH 47/67] Fix logs --- lib/icinga/clusterevents.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 4e453257f37..4d8783a39eb 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -989,7 +989,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (!params->Contains("execution")) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID not found."; + << "' from '" << origin->FromClient->GetIdentity() << "': Execution UUID missing."; return Empty; } String uuid = params->Get("execution"); @@ -998,7 +998,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (!executions) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': No executions available."; + << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' missing."; return Empty; } @@ -1006,7 +1006,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (!execution) { Log(LogNotice, "ClusterEvents") << "Discarding 'update executions API handler' message for checkable '" << checkable->GetName() - << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' not found."; + << "' from '" << origin->FromClient->GetIdentity() << "': Execution '" << uuid << "' missing."; return Empty; } From 2cda17a99bb09ea86808fa3b7c50f616928d5d09 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:45:19 +0200 Subject: [PATCH 48/67] Remove pending key when the execution is completed --- lib/icinga/clusterevents.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 4d8783a39eb..44bb6bc6a75 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1025,7 +1025,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, if (params->Contains("end")) execution->Set("end", params->Get("end")); - execution->Set("pending", false); + execution->Remove("pending"); /* Broadcast the update */ Dictionary::Ptr executionsToBroadcast = new Dictionary(); From a834b5cecd7026f209a1b2905e9394a6cb75ce33 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:46:09 +0200 Subject: [PATCH 49/67] Remove unused key in the execution --- lib/icinga/clusterevents.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 44bb6bc6a75..66eec6da1df 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1010,9 +1010,6 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, return Empty; } - if (params->Contains("error")) - execution->Set("error", params->Get("error")); - if (params->Contains("exit")) execution->Set("exit", params->Get("exit")); From edb5c47a9dbb337891cc4d7b2c676facc5ed157b Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:52:15 +0200 Subject: [PATCH 50/67] Execute notification command only if there is a source param --- lib/icinga/clusterevents-check.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index ac5aed79732..5be2b43bbfb 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -306,7 +306,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons throw; } } - } else if (command_type == "notification_command") { + } else if (command_type == "notification_command" && params->Contains("source")) { /* Get user */ User::Ptr user = new User(); Dictionary::Ptr attrs = new Dictionary(); @@ -332,14 +332,12 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons notificationCommand->Execute(notification, user, cr, NotificationType::NotificationCustom, author, ""); } catch (const std::exception& ex) { - if (params->Contains("source")) { - String output = "Exception occurred during notification '" + notification->GetName() - + "' for checkable '" + notification->GetCheckable()->GetName() - + "' and user '" + user->GetName() + "' using command '" + command + "': " - + DiagnosticInformation(ex, false); - double now = Utility::GetTime(); - SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); - } + String output = "Exception occurred during notification '" + notification->GetName() + + "' for checkable '" + notification->GetCheckable()->GetName() + + "' and user '" + user->GetName() + "' using command '" + command + "': " + + DiagnosticInformation(ex, false); + double now = Utility::GetTime(); + SendEventExecuteCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); } } } From 064d5e91947c7d24883595337a94a6bc172d3881 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 08:57:22 +0200 Subject: [PATCH 51/67] Keep consistency with other methods in case of missing API listener --- lib/icinga/clusterevents.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 66eec6da1df..70aca976567 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -946,7 +946,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, { ApiListener::Ptr listener = ApiListener::GetInstance(); if (!listener) - BOOST_THROW_EXCEPTION(std::invalid_argument("No ApiListener instance configured.")); + return Empty; Endpoint::Ptr endpoint; if (origin->FromClient) { From 75e0e164e4d7fc22f004f11cab7316ce0a9b24cf Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 29 Jul 2020 09:54:18 +0200 Subject: [PATCH 52/67] Fix indentation --- lib/icinga/clusterevents-check.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 5be2b43bbfb..0ca53030c7a 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -111,7 +111,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (!sourceEndpoint || (origin->FromZone && !Zone::GetLocalZone()->IsChildOf(origin->FromZone))) { Log(LogNotice, "ClusterEvents") - << "Discarding 'execute command' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; + << "Discarding 'execute command' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; return; } @@ -163,7 +163,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (!listener->GetAcceptCommands() && !origin->IsLocal()) { Log(LogWarning, "ApiListener") - << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; + << "Ignoring command. '" << listener->GetName() << "' does not accept commands."; String output = "Endpoint '" + Endpoint::GetLocalEndpoint()->GetName() + "' does not accept commands."; From a5698d5fdee6079a09022a9d891d8cfcc3b68e12 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 08:53:10 +0200 Subject: [PATCH 53/67] Check if last check result is null before executing the command --- lib/icinga/apiactions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 65f462499c8..fa5fdf7a29f 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -667,6 +667,8 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, ); CheckResult::Ptr cr = checkable->GetLastCheckResult(); + if (!cr) + cr = new CheckResult(); /* Check if resolved_command exists and it is of type command_type */ Dictionary::Ptr execMacros = new Dictionary(); From 44fc841ee1c9a64b4eaa38d1e93b8e867b06fbd0 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 10:42:01 +0200 Subject: [PATCH 54/67] Notify to all nodes that execution has completed --- lib/icinga/clusterevents-check.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 0ca53030c7a..63b2478f9d9 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -88,9 +88,9 @@ static void SendEventExecuteCommand(const Dictionary::Ptr& params, long exitStat executedParams->Set("start", start); executedParams->Set("end", end); - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + + if (!origin->IsLocal()) { Dictionary::Ptr executedMessage = new Dictionary(); executedMessage->Set("jsonrpc", "2.0"); executedMessage->Set("method", "event::ExecutedCommand"); From 604b938ade23e3cbd1cd8c29b37a21768510e2b7 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 11:15:17 +0200 Subject: [PATCH 55/67] Fix macros substitutions --- lib/icinga/apiactions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index fa5fdf7a29f..97561397ed7 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -619,8 +619,9 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, endpoint = HttpUtility::GetLastParameter(params, "endpoint"); MacroProcessor::ResolverList resolvers; + Value macros; if (params->Contains("macros")) { - Value macros = HttpUtility::GetLastParameter(params, "macros"); + macros = HttpUtility::GetLastParameter(params, "macros"); if (macros.IsObjectType()) { resolvers.emplace_back("override", macros); } @@ -673,7 +674,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, /* Check if resolved_command exists and it is of type command_type */ Dictionary::Ptr execMacros = new Dictionary(); - MacroResolver::OverrideMacros = execMacros; + MacroResolver::OverrideMacros = macros; Defer o ([]() { MacroResolver::OverrideMacros = nullptr; }); From cf1430c40978fa89fe1a48ef44e8ba3d4d3966fc Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 14:07:48 +0200 Subject: [PATCH 56/67] Fix update execution --- lib/icinga/clusterevents-check.cpp | 6 +++--- lib/icinga/clusterevents.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 63b2478f9d9..0ca53030c7a 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -88,9 +88,9 @@ static void SendEventExecuteCommand(const Dictionary::Ptr& params, long exitStat executedParams->Set("start", start); executedParams->Set("end", end); - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - - if (!origin->IsLocal()) { + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { Dictionary::Ptr executedMessage = new Dictionary(); executedMessage->Set("jsonrpc", "2.0"); executedMessage->Set("method", "event::ExecutedCommand"); diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 70aca976567..5817d8cc849 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1038,7 +1038,7 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin, updateMessage->Set("method", "event::UpdateExecutions"); updateMessage->Set("params", updateParams); - listener->RelayMessage(origin, checkable, updateMessage, true); + listener->RelayMessage(nullptr, checkable, updateMessage, true); return Empty; } From d7dadbfc661b80b00c4c71a721943e186f8f1eda Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 14:21:09 +0200 Subject: [PATCH 57/67] Use MacroResolver::OverrideMacros on *task files --- lib/methods/clusterzonechecktask.cpp | 3 +++ lib/methods/dummychecktask.cpp | 3 +++ lib/methods/icingachecktask.cpp | 3 +++ lib/methods/plugineventtask.cpp | 3 +++ lib/methods/pluginnotificationtask.cpp | 3 +++ lib/methods/sleepchecktask.cpp | 5 ++++- 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index af0c660530c..8b9d771e4aa 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -54,6 +54,9 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index ce72ca233e3..56bdb790ab1 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -29,6 +29,9 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index a5da4c80186..9901ebd3a56 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -33,6 +33,9 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp index 9296df0f199..f511480f743 100644 --- a/lib/methods/plugineventtask.cpp +++ b/lib/methods/plugineventtask.cpp @@ -28,6 +28,9 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp index b81708cf329..c1eb2e3d448 100644 --- a/lib/methods/pluginnotificationtask.cpp +++ b/lib/methods/pluginnotificationtask.cpp @@ -42,6 +42,9 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + resolvers.emplace_back("user", user); resolvers.emplace_back("notification", notificationExtra); resolvers.emplace_back("notification", notification); diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index 55f9f8fa133..30a395c00b7 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -24,7 +24,10 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu Service::Ptr service; tie(host, service) = GetHostService(checkable); - MacroProcessor::ResolverList resolvers; + MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); From 9c4a3aed1bce9897289a9bce1c74a8ed92a3e957 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Fri, 31 Jul 2020 17:28:33 +0200 Subject: [PATCH 58/67] 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 97561397ed7..e7d8acd88ef 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 e0da4154723..fb8032a199e 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 6eb6119a3c8..eb8f5a0122b 100644 --- a/lib/icinga/checkcommand.hpp +++ b/lib/icinga/checkcommand.hpp @@ -20,6 +20,8 @@ class CheckCommand final : public ObjectImpl 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 f9ab3be19be..39f2d3126c0 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 95bd1095a23..064cb5ad012 100644 --- a/lib/icinga/eventcommand.hpp +++ b/lib/icinga/eventcommand.hpp @@ -20,6 +20,8 @@ class EventCommand final : public ObjectImpl 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 8ae3e82a574..d4a5fd6ab82 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 210c91e86ee..f0f6899e37a 100644 --- a/lib/icinga/notificationcommand.hpp +++ b/lib/icinga/notificationcommand.hpp @@ -22,6 +22,8 @@ class NotificationCommand final : public ObjectImpl DECLARE_OBJECT(NotificationCommand); DECLARE_OBJECTNAME(NotificationCommand); + static thread_local NotificationCommand::Ptr ExecuteOverride; + virtual Dictionary::Ptr Execute(const intrusive_ptr& 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 ddefa9f8497..1fb02633d12 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 8b9d771e4aa..024288ed761 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 56bdb790ab1..ae44a1d63ba 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 9901ebd3a56..efbdcc3c91b 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 9dcbd79362f..0825bf1b4fc 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 f511480f743..7a7932a9d8a 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 c1eb2e3d448..79485bab2c7 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(itype); diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 0e138ffa55c..083d075167e 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(Utility::Random() % 4); diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index 30a395c00b7..a3e62d13360 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; From c2f8d6df4486843c2c4b54b6e7125cb61c0842d5 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 3 Aug 2020 08:07:32 +0200 Subject: [PATCH 59/67] Use ternary operator to get ExecuteOverride or checkable command --- 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 +----- 9 files changed, 9 insertions(+), 45 deletions(-) diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp index 1fb02633d12..eef3900ea94 100644 --- a/lib/methods/clusterchecktask.cpp +++ b/lib/methods/clusterchecktask.cpp @@ -28,11 +28,7 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe if (resolvedMacros && !useResolvedMacros) return; - CheckCommand::Ptr command; - if (CheckCommand::ExecuteOverride) - command = CheckCommand::ExecuteOverride; - else - command = checkable->GetCheckCommand(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); String commandName = command->GetName(); ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index 024288ed761..0d5889a408b 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -21,11 +21,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che REQUIRE_NOT_NULL(cr); ApiListener::Ptr listener = ApiListener::GetInstance(); - CheckCommand::Ptr command; - if (CheckCommand::ExecuteOverride) - command = CheckCommand::ExecuteOverride; - else - command = checkable->GetCheckCommand(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); String commandName = command->GetName(); if (!listener) { diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index ae44a1d63ba..45c773fcbf8 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -22,11 +22,7 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); - CheckCommand::Ptr command; - if (CheckCommand::ExecuteOverride) - command = CheckCommand::ExecuteOverride; - else - command = checkable->GetCheckCommand(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); Host::Ptr host; Service::Ptr service; diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index efbdcc3c91b..d697b6925ed 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -26,11 +26,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); - CheckCommand::Ptr command; - if (CheckCommand::ExecuteOverride) - command = CheckCommand::ExecuteOverride; - else - command = checkable->GetCheckCommand(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); Host::Ptr host; Service::Ptr service; diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index 0825bf1b4fc..83d36c96d87 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -22,11 +22,7 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); - CheckCommand::Ptr commandObj; - if (CheckCommand::ExecuteOverride) - commandObj = CheckCommand::ExecuteOverride; - else - commandObj = checkable->GetCheckCommand(); + CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); Host::Ptr host; Service::Ptr service; diff --git a/lib/methods/plugineventtask.cpp b/lib/methods/plugineventtask.cpp index 7a7932a9d8a..9c4401303f8 100644 --- a/lib/methods/plugineventtask.cpp +++ b/lib/methods/plugineventtask.cpp @@ -21,11 +21,7 @@ void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable, { REQUIRE_NOT_NULL(checkable); - EventCommand::Ptr commandObj; - if (EventCommand::ExecuteOverride) - commandObj = EventCommand::ExecuteOverride; - else - commandObj = checkable->GetEventCommand(); + EventCommand::Ptr commandObj = EventCommand::ExecuteOverride ? EventCommand::ExecuteOverride : checkable->GetEventCommand(); Host::Ptr host; Service::Ptr service; diff --git a/lib/methods/pluginnotificationtask.cpp b/lib/methods/pluginnotificationtask.cpp index 79485bab2c7..ae89cc24555 100644 --- a/lib/methods/pluginnotificationtask.cpp +++ b/lib/methods/pluginnotificationtask.cpp @@ -25,11 +25,7 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, REQUIRE_NOT_NULL(notification); REQUIRE_NOT_NULL(user); - NotificationCommand::Ptr commandObj; - if (NotificationCommand::ExecuteOverride) - commandObj = NotificationCommand::ExecuteOverride; - else - commandObj = notification->GetCommand(); + NotificationCommand::Ptr commandObj = NotificationCommand::ExecuteOverride ? NotificationCommand::ExecuteOverride : notification->GetCommand(); auto type = static_cast(itype); diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 083d075167e..9b133ef0ee5 100644 --- a/lib/methods/randomchecktask.cpp +++ b/lib/methods/randomchecktask.cpp @@ -31,11 +31,7 @@ void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes + ". Icinga 2 has been running for " + Utility::FormatDuration(uptime) + ". Version: " + Application::GetAppVersion(); - CheckCommand::Ptr command; - if (CheckCommand::ExecuteOverride) - command = CheckCommand::ExecuteOverride; - else - command = checkable->GetCheckCommand(); + CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); String commandName = command->GetName(); ServiceState state = static_cast(Utility::Random() % 4); diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index a3e62d13360..ed3a5b6eeb0 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -18,11 +18,7 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); - CheckCommand::Ptr commandObj; - if (CheckCommand::ExecuteOverride) - commandObj = CheckCommand::ExecuteOverride; - else - commandObj = checkable->GetCheckCommand(); + CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); Host::Ptr host; Service::Ptr service; From 951388797a00b7144c2ec1fb29d093212006e29a Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Mon, 3 Aug 2020 21:09:57 +0200 Subject: [PATCH 60/67] Forward the execute command through the zones --- lib/icinga/apiactions.cpp | 3 ++- lib/icinga/clusterevents.cpp | 40 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index e7d8acd88ef..977d0ee3ef2 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -806,6 +806,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, execParams->Set("source", uuid); execParams->Set("deadline", deadline); execParams->Set("macros", execMacros); + execParams->Set("endpoint", resolved_endpoint); /* Execute command */ bool local = endpointPtr == Endpoint::GetLocalEndpoint(); @@ -817,7 +818,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, execMessage->Set("method", "event::ExecuteCommand"); execMessage->Set("params", execParams); - listener->SyncSendMessage(endpointPtr, execMessage); + listener->RelayMessage(origin, checkable, execMessage, true); } Dictionary::Ptr result = new Dictionary(); diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 5817d8cc849..bc1d2d12692 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -619,7 +619,29 @@ Value ClusterEvents::AcknowledgementClearedAPIHandler(const MessageOrigin::Ptr& Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) { - EnqueueCheck(origin, params); + ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) + return Empty; + + Endpoint::Ptr execEndpoint = Endpoint::GetByName(params->Get("endpoint")); + if (execEndpoint != Endpoint::GetLocalEndpoint()) { + + Zone::Ptr endpointZone = execEndpoint->GetZone(); + Zone::Ptr localZone = Zone::GetLocalZone(); + + if (!endpointZone->IsChildOf(localZone)) { + return Empty; + } + + Dictionary::Ptr execMessage = new Dictionary(); + execMessage->Set("jsonrpc", "2.0"); + execMessage->Set("method", "event::ExecuteCommand"); + execMessage->Set("params", params); + + listener->RelayMessage(origin, endpointZone, execMessage, true); + } else { + EnqueueCheck(origin, params); + } return Empty; } @@ -1084,5 +1106,21 @@ Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin newExecutions->CopyTo(executions); checkable->SetExecutions(executions); + ApiListener::Ptr listener = ApiListener::GetInstance(); + if (!listener) + return Empty; + + Dictionary::Ptr updateMessage = new Dictionary(); + updateMessage->Set("jsonrpc", "2.0"); + updateMessage->Set("method", "event::UpdateExecutions"); + updateMessage->Set("params", params); + + Zone::Ptr localZone = Zone::GetLocalZone(); + Zone::Ptr parentZone = localZone->GetParent(); + + if (localZone != parentZone) { + listener->RelayMessage(origin, parentZone, updateMessage, true); + } + return Empty; } From c6c18491067d04d35148a513c486397e9d078671 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 4 Aug 2020 14:32:36 +0200 Subject: [PATCH 61/67] Change checkable with the endpoint zone for execute command relay message --- lib/icinga/apiactions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 977d0ee3ef2..9f139e5403d 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -818,7 +818,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, execMessage->Set("method", "event::ExecuteCommand"); execMessage->Set("params", execParams); - listener->RelayMessage(origin, checkable, execMessage, true); + listener->RelayMessage(origin, endpointPtr->GetZone(), execMessage, true); } Dictionary::Ptr result = new Dictionary(); From ac71cc67f8cfde9e178bf3853ff51ce2a0c0648f Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Tue, 4 Aug 2020 16:09:21 +0200 Subject: [PATCH 62/67] Use local zone for update executions --- lib/icinga/clusterevents.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index bc1d2d12692..93d2a762e22 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -1115,12 +1115,7 @@ Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin updateMessage->Set("method", "event::UpdateExecutions"); updateMessage->Set("params", params); - Zone::Ptr localZone = Zone::GetLocalZone(); - Zone::Ptr parentZone = localZone->GetParent(); - - if (localZone != parentZone) { - listener->RelayMessage(origin, parentZone, updateMessage, true); - } + listener->RelayMessage(origin, Zone::GetLocalZone(), updateMessage, true); return Empty; } From a90068cc783dd19db28543492f84acf742ce64a2 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 5 Aug 2020 10:01:29 +0200 Subject: [PATCH 63/67] Check satellites Icinga version before relay the execute command message --- lib/icinga/apiactions.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 9f139e5403d..86c8616d221 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -813,6 +813,21 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, if (local) { ClusterEvents::ExecuteCommandAPIHandler(origin, execParams); } else { + /* Check if the child endpoints have Icinga version >= 2.13 */ + Zone::Ptr localZone = Zone::GetLocalZone(); + for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { + /* Fetch immediate child zone members */ + if (zone->GetParent() == localZone) { + std::set endpoints = zone->GetEndpoints(); + + for (const Endpoint::Ptr& childEndpoint : endpoints) { + if (childEndpoint->GetIcingaVersion() < 21300) { + return ApiActions::CreateResult(400, "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); + } + } + } + } + Dictionary::Ptr execMessage = new Dictionary(); execMessage->Set("jsonrpc", "2.0"); execMessage->Set("method", "event::ExecuteCommand"); From 7c004af6beb34e66a153dc3fa0c6bde2309d8092 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 5 Aug 2020 14:08:54 +0200 Subject: [PATCH 64/67] Check child endpoint versions and check child zone can access to the target endpoint --- lib/icinga/apiactions.cpp | 18 +++++++++++++++-- lib/icinga/clusterevents.cpp | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 86c8616d221..cf77aea4b84 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -817,12 +817,26 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, Zone::Ptr localZone = Zone::GetLocalZone(); for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { /* Fetch immediate child zone members */ - if (zone->GetParent() == localZone) { + if (zone->GetParent() == localZone && zone->CanAccessObject(endpointPtr->GetZone())) { std::set endpoints = zone->GetEndpoints(); for (const Endpoint::Ptr& childEndpoint : endpoints) { if (childEndpoint->GetIcingaVersion() < 21300) { - return ApiActions::CreateResult(400, "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); + /* Update execution */ + double now = Utility::GetTime(); + pending_execution->Set("exit", 2); + pending_execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); + pending_execution->Set("start", now); + pending_execution->Set("end", now); + pending_execution->Remove("pending"); + + checkable->SetExecutions(executions); + listener->RelayMessage(origin, checkable, updateMessage, true); + + Dictionary::Ptr result = new Dictionary(); + result->Set("checkable", checkable->GetName()); + result->Set("execution", uuid); + return ApiActions::CreateResult(202, "Accepted", result); } } } diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 93d2a762e22..b1426ae762e 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -633,6 +633,44 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, return Empty; } + /* Check if the child endpoints have Icinga version >= 2.13 */ + for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { + /* Fetch immediate child zone members */ + if (zone->GetParent() == localZone && zone->CanAccessObject(endpointZone)) { + std::set endpoints = zone->GetEndpoints(); + + for (const Endpoint::Ptr& childEndpoint : endpoints) { + if (childEndpoint->GetIcingaVersion() < 21300) { + /* Update execution */ + double now = Utility::GetTime(); + Dictionary::Ptr execution = new Dictionary(); + execution->Set("exit", 2); + execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); + execution->Set("start", now); + execution->Set("end", now); + + Dictionary::Ptr executionsToBroadcast = new Dictionary(); + executionsToBroadcast->Set(params->Get("source"), execution); + + Dictionary::Ptr updateParams = new Dictionary(); + updateParams->Set("host", params->Get("host")); + if (params->Contains("service")) + updateParams->Set("service", params->Get("service")); + updateParams->Set("executions", executionsToBroadcast); + + Dictionary::Ptr updateMessage = new Dictionary(); + updateMessage->Set("jsonrpc", "2.0"); + updateMessage->Set("method", "event::UpdateExecutions"); + updateMessage->Set("params", executionsToBroadcast); + + listener->RelayMessage(nullptr, nullptr, updateMessage, true); + + return Empty; + } + } + } + } + Dictionary::Ptr execMessage = new Dictionary(); execMessage->Set("jsonrpc", "2.0"); execMessage->Set("method", "event::ExecuteCommand"); From 7474ab6de570cb5bdd44acfe26716fe95ad6d3b7 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 5 Aug 2020 15:53:34 +0200 Subject: [PATCH 65/67] Set exit code 126 if endpoint doens't support the new executeCommand API --- lib/icinga/apiactions.cpp | 3 +- lib/icinga/clusterevents.cpp | 98 ++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index cf77aea4b84..67c3990c068 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -824,13 +824,12 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, if (childEndpoint->GetIcingaVersion() < 21300) { /* Update execution */ double now = Utility::GetTime(); - pending_execution->Set("exit", 2); + pending_execution->Set("exit", 126); pending_execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); pending_execution->Set("start", now); pending_execution->Set("end", now); pending_execution->Remove("pending"); - checkable->SetExecutions(executions); listener->RelayMessage(origin, checkable, updateMessage, true); Dictionary::Ptr result = new Dictionary(); diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index b1426ae762e..4e3b3aa5f71 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -623,64 +623,66 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, if (!listener) return Empty; - Endpoint::Ptr execEndpoint = Endpoint::GetByName(params->Get("endpoint")); - if (execEndpoint != Endpoint::GetLocalEndpoint()) { + if (params->Contains("endpoint")) { + Endpoint::Ptr execEndpoint = Endpoint::GetByName(params->Get("endpoint")); + if (execEndpoint != Endpoint::GetLocalEndpoint()) { - Zone::Ptr endpointZone = execEndpoint->GetZone(); - Zone::Ptr localZone = Zone::GetLocalZone(); + Zone::Ptr endpointZone = execEndpoint->GetZone(); + Zone::Ptr localZone = Zone::GetLocalZone(); - if (!endpointZone->IsChildOf(localZone)) { - return Empty; - } + if (!endpointZone->IsChildOf(localZone)) { + return Empty; + } - /* Check if the child endpoints have Icinga version >= 2.13 */ - for (const Zone::Ptr& zone : ConfigType::GetObjectsByType()) { - /* Fetch immediate child zone members */ - if (zone->GetParent() == localZone && zone->CanAccessObject(endpointZone)) { - std::set endpoints = zone->GetEndpoints(); - - for (const Endpoint::Ptr& childEndpoint : endpoints) { - if (childEndpoint->GetIcingaVersion() < 21300) { - /* Update execution */ - double now = Utility::GetTime(); - Dictionary::Ptr execution = new Dictionary(); - execution->Set("exit", 2); - execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); - execution->Set("start", now); - execution->Set("end", now); - - Dictionary::Ptr executionsToBroadcast = new Dictionary(); - executionsToBroadcast->Set(params->Get("source"), execution); - - Dictionary::Ptr updateParams = new Dictionary(); - updateParams->Set("host", params->Get("host")); - if (params->Contains("service")) - updateParams->Set("service", params->Get("service")); - updateParams->Set("executions", executionsToBroadcast); - - Dictionary::Ptr updateMessage = new Dictionary(); - updateMessage->Set("jsonrpc", "2.0"); - updateMessage->Set("method", "event::UpdateExecutions"); - updateMessage->Set("params", executionsToBroadcast); - - listener->RelayMessage(nullptr, nullptr, updateMessage, true); - - return Empty; + /* Check if the child endpoints have Icinga version >= 2.13 */ + for (const Zone::Ptr &zone : ConfigType::GetObjectsByType()) { + /* Fetch immediate child zone members */ + if (zone->GetParent() == localZone && zone->CanAccessObject(endpointZone)) { + std::set endpoints = zone->GetEndpoints(); + + for (const Endpoint::Ptr &childEndpoint : endpoints) { + if (childEndpoint->GetIcingaVersion() < 21300) { + double now = Utility::GetTime(); + Dictionary::Ptr executedParams = new Dictionary(); + executedParams->Set("execution", params->Get("source")); + executedParams->Set("host", params->Get("host")); + if (params->Contains("service")) + executedParams->Set("service", params->Get("service")); + executedParams->Set("exit", 126); + executedParams->Set("output", + "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13."); + executedParams->Set("start", now); + executedParams->Set("end", now); + + if (origin->IsLocal()) { + ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); + } else { + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + + listener->RelayMessage(nullptr, nullptr, executedMessage, true); + } + + return Empty; + } } } } - } - Dictionary::Ptr execMessage = new Dictionary(); - execMessage->Set("jsonrpc", "2.0"); - execMessage->Set("method", "event::ExecuteCommand"); - execMessage->Set("params", params); + Dictionary::Ptr execMessage = new Dictionary(); + execMessage->Set("jsonrpc", "2.0"); + execMessage->Set("method", "event::ExecuteCommand"); + execMessage->Set("params", params); - listener->RelayMessage(origin, endpointZone, execMessage, true); - } else { - EnqueueCheck(origin, params); + listener->RelayMessage(origin, endpointZone, execMessage, true); + return Empty; + } } + EnqueueCheck(origin, params); + return Empty; } From df2b82f7fe791b98f03acd766ce15db245dba6e9 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Wed, 5 Aug 2020 16:14:57 +0200 Subject: [PATCH 66/67] Remove an useless check --- lib/icinga/clusterevents.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 4e3b3aa5f71..56e8ef976d4 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -654,17 +654,12 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin, executedParams->Set("start", now); executedParams->Set("end", now); - if (origin->IsLocal()) { - ClusterEvents::ExecutedCommandAPIHandler(origin, executedParams); - } else { - Dictionary::Ptr executedMessage = new Dictionary(); - executedMessage->Set("jsonrpc", "2.0"); - executedMessage->Set("method", "event::ExecutedCommand"); - executedMessage->Set("params", executedParams); - - listener->RelayMessage(nullptr, nullptr, executedMessage, true); - } + Dictionary::Ptr executedMessage = new Dictionary(); + executedMessage->Set("jsonrpc", "2.0"); + executedMessage->Set("method", "event::ExecutedCommand"); + executedMessage->Set("params", executedParams); + listener->RelayMessage(nullptr, nullptr, executedMessage, true); return Empty; } } From 80dc908fcac4e77bcc7a212c6e6e37c9f57ec257 Mon Sep 17 00:00:00 2001 From: Mattia Codato Date: Thu, 13 Aug 2020 09:26:19 +0200 Subject: [PATCH 67/67] Use ExecuteCommand::ExecuteOverride also for ido check --- lib/db_ido/idochecktask.cpp | 180 ++++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 36 deletions(-) diff --git a/lib/db_ido/idochecktask.cpp b/lib/db_ido/idochecktask.cpp index 8a9536dc3a8..22febdaf5f5 100644 --- a/lib/db_ido/idochecktask.cpp +++ b/lib/db_ido/idochecktask.cpp @@ -20,7 +20,8 @@ REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "check void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { - CheckCommand::Ptr commandObj = checkable->GetCheckCommand(); + ServiceState state; + CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); Value raw_command = commandObj->GetCommandLine(); Host::Ptr host; @@ -28,6 +29,9 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult tie(host, service) = GetHostService(checkable); MacroProcessor::ResolverList resolvers; + if (MacroResolver::OverrideMacros) + resolvers.emplace_back("override", MacroResolver::OverrideMacros); + if (service) resolvers.emplace_back("service", service); resolvers.emplace_back("host", host); @@ -61,25 +65,70 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult return; if (idoType.IsEmpty()) { - cr->SetOutput("Attribute 'ido_type' must be set."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "Attribute 'ido_type' must be set."; + state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } if (idoName.IsEmpty()) { - cr->SetOutput("Attribute 'ido_name' must be set."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "Attribute 'ido_name' must be set."; + state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } Type::Ptr type = Type::GetByName(idoType); if (!type || !DbConnection::TypeInstance->IsAssignableFrom(type)) { - cr->SetOutput("DB IDO type '" + idoType + "' is invalid."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "DB IDO type '" + idoType + "' is invalid."; + state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } @@ -89,34 +138,78 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult DbConnection::Ptr conn = static_pointer_cast(dtype->GetObject(idoName)); if (!conn) { - cr->SetOutput("DB IDO connection '" + idoName + "' does not exist."); - cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + String output = "DB IDO connection '" + idoName + "' does not exist."; + state = ServiceUnknown; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } double qps = conn->GetQueryCount(60) / 60.0; if (conn->IsPaused()) { - cr->SetOutput("DB IDO connection is temporarily disabled on this cluster instance."); - cr->SetState(ServiceOK); - checkable->ProcessCheckResult(cr); + String output = "DB IDO connection is temporarily disabled on this cluster instance."; + state = ServiceOK; + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } double pendingQueries = conn->GetPendingQueryCount(); if (!conn->GetConnected()) { + String output; if (conn->GetShouldConnect()) { - cr->SetOutput("Could not connect to the database server."); - cr->SetState(ServiceCritical); + output ="Could not connect to the database server."; + state = ServiceCritical; } else { - cr->SetOutput("Not currently enabled: Another cluster instance is responsible for the IDO database."); - cr->SetState(ServiceOK); + output = "Not currently enabled: Another cluster instance is responsible for the IDO database."; + state = ServiceOK; } - checkable->ProcessCheckResult(cr); + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); + checkable->ProcessCheckResult(cr); + } return; } @@ -130,13 +223,13 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult << " Queries per second: " << std::fixed << std::setprecision(3) << qps << " Pending queries: " << std::fixed << std::setprecision(3) << pendingQueries << "."; - cr->SetState(ServiceWarning); + state = ServiceWarning; } else { msgbuf << "Connected to the database server (Schema version: '" << schema_version << "')." << " Queries per second: " << std::fixed << std::setprecision(3) << qps << " Pending queries: " << std::fixed << std::setprecision(3) << pendingQueries << "."; - cr->SetState(ServiceOK); + state = ServiceOK; } if (conn->GetEnableHa()) { @@ -149,34 +242,49 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult if (missingQueriesCritical.IsEmpty() && qps < queriesCritical) { msgbuf << " " << qps << " queries/s lower than critical threshold (" << queriesCritical << " queries/s)."; - cr->SetState(ServiceCritical); + state= ServiceCritical; } else if (missingQueriesWarning.IsEmpty() && qps < queriesWarning) { msgbuf << " " << qps << " queries/s lower than warning threshold (" << queriesWarning << " queries/s)."; - cr->SetState(ServiceWarning); + state = ServiceWarning; } if (missingPendingQueriesCritical.IsEmpty() && pendingQueries > pendingQueriesCritical) { msgbuf << " " << pendingQueries << " pending queries greater than critical threshold (" << pendingQueriesCritical << " queries)."; - cr->SetState(ServiceCritical); + state = ServiceCritical; } else if (missingPendingQueriesWarning.IsEmpty() && pendingQueries > pendingQueriesWarning) { msgbuf << " " << pendingQueries << " pending queries greater than warning threshold (" << pendingQueriesWarning << " queries)."; - cr->SetState(ServiceWarning); + state = ServiceWarning; } - cr->SetOutput(msgbuf.str()); + String output = msgbuf.str(); + + if (Checkable::ExecuteCommandProcessFinishedHandler) { + double now = Utility::GetTime(); + ProcessResult pr; + pr.PID = -1; + pr.Output = output; + pr.ExecutionStart = now; + pr.ExecutionEnd = now; + pr.ExitStatus = state; + + Checkable::ExecuteCommandProcessFinishedHandler(commandObj->GetName(), pr); + } else { + cr->SetState(state); + cr->SetOutput(output); - cr->SetPerformanceData(new Array({ - { new PerfdataValue("queries", qps, false, "", queriesWarning, queriesCritical) }, - { new PerfdataValue("queries_1min", conn->GetQueryCount(60)) }, - { new PerfdataValue("queries_5mins", conn->GetQueryCount(5 * 60)) }, - { new PerfdataValue("queries_15mins", conn->GetQueryCount(15 * 60)) }, - { new PerfdataValue("pending_queries", pendingQueries, false, "", pendingQueriesWarning, pendingQueriesCritical) } - })); + cr->SetPerformanceData(new Array({ + { new PerfdataValue("queries", qps, false, "", queriesWarning, queriesCritical) }, + { new PerfdataValue("queries_1min", conn->GetQueryCount(60)) }, + { new PerfdataValue("queries_5mins", conn->GetQueryCount(5 * 60)) }, + { new PerfdataValue("queries_15mins", conn->GetQueryCount(15 * 60)) }, + { new PerfdataValue("pending_queries", pendingQueries, false, "", pendingQueriesWarning, pendingQueriesCritical) } + })); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr); + } }