From 18fb93fc114163e15b841db1cae32622c2daab15 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 May 2025 17:11:23 +0200 Subject: [PATCH 1/4] Introduce WaitGroup and StoppableWaitGroup --- lib/base/CMakeLists.txt | 1 + lib/base/wait-group.cpp | 38 +++++++++++++++++++++++++++++ lib/base/wait-group.hpp | 54 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 lib/base/wait-group.cpp create mode 100644 lib/base/wait-group.hpp diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 59e83644394..d44254a35e2 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -87,6 +87,7 @@ set(base_SOURCES unixsocket.cpp unixsocket.hpp utility.cpp utility.hpp value.cpp value.hpp value-operators.cpp + wait-group.cpp wait-group.hpp win32.hpp workqueue.cpp workqueue.hpp ) diff --git a/lib/base/wait-group.cpp b/lib/base/wait-group.cpp new file mode 100644 index 00000000000..1e1ad00eefc --- /dev/null +++ b/lib/base/wait-group.cpp @@ -0,0 +1,38 @@ +/* Icinga 2 | (c) 2025 Icinga GmbH | GPLv2+ */ + +#include "base/wait-group.hpp" + +using namespace icinga; + +bool StoppableWaitGroup::try_lock_shared() +{ + std::unique_lock lock (m_Mutex); + + if (m_Stopped) { + return false; + } + + ++m_SharedLocks; + return true; +} + +void StoppableWaitGroup::unlock_shared() +{ + std::unique_lock lock (m_Mutex); + + if (!--m_SharedLocks && m_Stopped) { + lock.unlock(); + m_CV.notify_all(); + } +} + +/** + * Disallow new shared locks, wait for all existing ones. + */ +void StoppableWaitGroup::Join() +{ + std::unique_lock lock (m_Mutex); + + m_Stopped = true; + m_CV.wait(lock, [this] { return !m_SharedLocks; }); +} diff --git a/lib/base/wait-group.hpp b/lib/base/wait-group.hpp new file mode 100644 index 00000000000..5b452701167 --- /dev/null +++ b/lib/base/wait-group.hpp @@ -0,0 +1,54 @@ +/* Icinga 2 | (c) 2025 Icinga GmbH | GPLv2+ */ + +#pragma once + +#include "base/object.hpp" +#include +#include +#include + +namespace icinga +{ + +/** + * A synchronization interface that allows concurrent shared locking. + * + * @ingroup base + */ +class WaitGroup : public Object +{ +public: + DECLARE_PTR_TYPEDEFS(WaitGroup); + + virtual bool try_lock_shared() = 0; + virtual void unlock_shared() = 0; +}; + +/** + * A thread-safe wait group that can be stopped to prevent further shared locking. + * + * @ingroup base + */ +class StoppableWaitGroup : public WaitGroup +{ +public: + DECLARE_PTR_TYPEDEFS(StoppableWaitGroup); + + StoppableWaitGroup() = default; + StoppableWaitGroup(const StoppableWaitGroup&) = delete; + StoppableWaitGroup(StoppableWaitGroup&&) = delete; + StoppableWaitGroup& operator=(const StoppableWaitGroup&) = delete; + StoppableWaitGroup& operator=(StoppableWaitGroup&&) = delete; + + bool try_lock_shared() override; + void unlock_shared() override; + void Join(); + +private: + std::mutex m_Mutex; + std::condition_variable m_CV; + uint_fast32_t m_SharedLocks = 0; + bool m_Stopped = false; +}; + +} From c7cca7b460162d713dbf26a1d09219501eb52fa1 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 May 2025 17:34:37 +0200 Subject: [PATCH 2/4] Add a StoppableWaitGroup, and join it on #Stop(), to: ApiListener CheckerComponent ExternalCommandListener LivestatusListener --- lib/checker/checkercomponent.cpp | 1 + lib/checker/checkercomponent.hpp | 2 ++ lib/compat/externalcommandlistener.cpp | 2 ++ lib/compat/externalcommandlistener.hpp | 3 +++ lib/livestatus/livestatuslistener.cpp | 1 + lib/livestatus/livestatuslistener.hpp | 2 ++ lib/remote/apilistener.cpp | 1 + lib/remote/apilistener.hpp | 2 ++ 8 files changed, 14 insertions(+) diff --git a/lib/checker/checkercomponent.cpp b/lib/checker/checkercomponent.cpp index 06ebb7bbaf3..db3833963d2 100644 --- a/lib/checker/checkercomponent.cpp +++ b/lib/checker/checkercomponent.cpp @@ -81,6 +81,7 @@ void CheckerComponent::Stop(bool runtimeRemoved) m_CV.notify_all(); } + m_WaitGroup->Join(); m_ResultTimer->Stop(true); m_Thread.join(); diff --git a/lib/checker/checkercomponent.hpp b/lib/checker/checkercomponent.hpp index 5ace7571c6e..edd3775e585 100644 --- a/lib/checker/checkercomponent.hpp +++ b/lib/checker/checkercomponent.hpp @@ -8,6 +8,7 @@ #include "base/configobject.hpp" #include "base/timer.hpp" #include "base/utility.hpp" +#include "base/wait-group.hpp" #include #include #include @@ -77,6 +78,7 @@ class CheckerComponent final : public ObjectImpl CheckableSet m_IdleCheckables; CheckableSet m_PendingCheckables; + StoppableWaitGroup::Ptr m_WaitGroup = new StoppableWaitGroup(); Timer::Ptr m_ResultTimer; void CheckThreadProc(); diff --git a/lib/compat/externalcommandlistener.cpp b/lib/compat/externalcommandlistener.cpp index b61813beb81..5f5362db6f8 100644 --- a/lib/compat/externalcommandlistener.cpp +++ b/lib/compat/externalcommandlistener.cpp @@ -50,6 +50,8 @@ void ExternalCommandListener::Start(bool runtimeCreated) */ void ExternalCommandListener::Stop(bool runtimeRemoved) { + m_WaitGroup->Join(); + Log(LogInformation, "ExternalCommandListener") << "'" << GetName() << "' stopped."; diff --git a/lib/compat/externalcommandlistener.hpp b/lib/compat/externalcommandlistener.hpp index 895531f782e..62d4f8134ee 100644 --- a/lib/compat/externalcommandlistener.hpp +++ b/lib/compat/externalcommandlistener.hpp @@ -5,6 +5,7 @@ #include "compat/externalcommandlistener-ti.hpp" #include "base/objectlock.hpp" +#include "base/wait-group.hpp" #include "base/timer.hpp" #include "base/utility.hpp" #include @@ -29,6 +30,8 @@ class ExternalCommandListener final : public ObjectImpl void Stop(bool runtimeRemoved) override; private: + StoppableWaitGroup::Ptr m_WaitGroup = new StoppableWaitGroup(); + #ifndef _WIN32 std::thread m_CommandThread; diff --git a/lib/livestatus/livestatuslistener.cpp b/lib/livestatus/livestatuslistener.cpp index e44650bfe58..fe524dcdb3a 100644 --- a/lib/livestatus/livestatuslistener.cpp +++ b/lib/livestatus/livestatuslistener.cpp @@ -112,6 +112,7 @@ void LivestatusListener::Stop(bool runtimeRemoved) << "'" << GetName() << "' stopped."; m_Listener->Close(); + m_WaitGroup->Join(); if (m_Thread.joinable()) m_Thread.join(); diff --git a/lib/livestatus/livestatuslistener.hpp b/lib/livestatus/livestatuslistener.hpp index dc739f6f1c7..60aaed9306c 100644 --- a/lib/livestatus/livestatuslistener.hpp +++ b/lib/livestatus/livestatuslistener.hpp @@ -7,6 +7,7 @@ #include "livestatus/livestatuslistener-ti.hpp" #include "livestatus/livestatusquery.hpp" #include "base/socket.hpp" +#include "base/wait-group.hpp" #include using namespace icinga; @@ -40,6 +41,7 @@ class LivestatusListener final : public ObjectImpl Socket::Ptr m_Listener; std::thread m_Thread; + StoppableWaitGroup::Ptr m_WaitGroup = new StoppableWaitGroup(); }; } diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index db024c98729..8d5a04e9f6b 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -368,6 +368,7 @@ void ApiListener::Stop(bool runtimeDeleted) m_Timer->Stop(true); m_RenewOwnCertTimer->Stop(true); + m_WaitGroup->Join(); ObjectImpl::Stop(runtimeDeleted); Log(LogInformation, "ApiListener") diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index eae1fa03e61..3aa4f40db0d 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -16,6 +16,7 @@ #include "base/tcpsocket.hpp" #include "base/tlsstream.hpp" #include "base/threadpool.hpp" +#include "base/wait-group.hpp" #include #include #include @@ -177,6 +178,7 @@ class ApiListener final : public ObjectImpl Timer::Ptr m_RenewOwnCertTimer; Endpoint::Ptr m_LocalEndpoint; + StoppableWaitGroup::Ptr m_WaitGroup = new StoppableWaitGroup(); static ApiListener::Ptr m_Instance; static std::atomic m_UpdatedObjectAuthority; From f4691dd05400465e17d9c465dc022005d9aa4376 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 22 May 2025 17:56:16 +0200 Subject: [PATCH 3/4] Require to pass WaitGroup::Ptr to several methods Namely: Checkable#ProcessCheckResult() ClusterCheckTask::ScriptFunc() ClusterZoneCheckTask::ScriptFunc() DummyCheckTask::ScriptFunc() ExceptionCheckTask::ScriptFunc() IcingaCheckTask::ScriptFunc() IfwApiCheckTask::ScriptFunc() NullCheckTask::ScriptFunc() PluginCheckTask::ScriptFunc() RandomCheckTask::ScriptFunc() SleepCheckTask::ScriptFunc() IdoCheckTask::ScriptFunc() IcingadbCheck::ScriptFunc() CheckCommand#Execute() Checkable#ExecuteCheck() ClusterEvents::ExecuteCheckFromQueue() ExternalCommandProcessor::Process*CheckResult() ExternalCommandCallback ExternalCommandProcessor::Execute() ExternalCommandProcessor::ExecuteFromFile() ExternalCommandProcessor::ProcessFile() LivestatusQuery#ExecuteCommandHelper() LivestatusQuery#Execute() --- lib/checker/checkercomponent.cpp | 4 +- lib/compat/externalcommandlistener.cpp | 2 +- lib/db_ido/idochecktask.cpp | 26 +++--- lib/db_ido/idochecktask.hpp | 2 +- lib/icinga/apiactions.cpp | 5 +- lib/icinga/checkable-check.cpp | 14 +-- lib/icinga/checkable-script.cpp | 5 +- lib/icinga/checkable.hpp | 9 +- lib/icinga/checkcommand.cpp | 3 +- lib/icinga/checkcommand.hpp | 1 + lib/icinga/clusterevents-check.cpp | 2 +- lib/icinga/clusterevents.cpp | 4 +- lib/icinga/externalcommandprocessor.cpp | 34 +++++--- lib/icinga/externalcommandprocessor.hpp | 17 ++-- lib/icingadb/icingadbchecktask.cpp | 20 ++--- lib/icingadb/icingadbchecktask.hpp | 2 +- lib/livestatus/livestatuslistener.cpp | 2 +- lib/livestatus/livestatusquery.cpp | 8 +- lib/livestatus/livestatusquery.hpp | 5 +- lib/methods/clusterchecktask.cpp | 8 +- lib/methods/clusterchecktask.hpp | 2 +- lib/methods/clusterzonechecktask.cpp | 12 +-- lib/methods/clusterzonechecktask.hpp | 2 +- lib/methods/dummychecktask.cpp | 6 +- lib/methods/dummychecktask.hpp | 2 +- lib/methods/exceptionchecktask.cpp | 4 +- lib/methods/exceptionchecktask.hpp | 2 +- lib/methods/icingachecktask.cpp | 6 +- lib/methods/icingachecktask.hpp | 2 +- lib/methods/ifwapichecktask.cpp | 8 +- lib/methods/ifwapichecktask.hpp | 2 +- lib/methods/nullchecktask.cpp | 6 +- lib/methods/nullchecktask.hpp | 2 +- lib/methods/pluginchecktask.cpp | 13 +-- lib/methods/pluginchecktask.hpp | 6 +- lib/methods/randomchecktask.cpp | 6 +- lib/methods/randomchecktask.hpp | 2 +- lib/methods/sleepchecktask.cpp | 6 +- lib/methods/sleepchecktask.hpp | 2 +- lib/remote/apilistener.hpp | 5 ++ test/icinga-checkable-flapping.cpp | 76 ++++++++-------- test/icinga-checkresult.cpp | 110 ++++++++++++------------ test/livestatus.cpp | 2 +- 43 files changed, 243 insertions(+), 214 deletions(-) diff --git a/lib/checker/checkercomponent.cpp b/lib/checker/checkercomponent.cpp index db3833963d2..1ebdf5fa12e 100644 --- a/lib/checker/checkercomponent.cpp +++ b/lib/checker/checkercomponent.cpp @@ -232,7 +232,7 @@ void CheckerComponent::CheckThreadProc() void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable) { try { - checkable->ExecuteCheck(); + checkable->ExecuteCheck(m_WaitGroup); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); @@ -246,7 +246,7 @@ void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable) cr->SetExecutionStart(now); cr->SetExecutionEnd(now); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, m_WaitGroup); Log(LogCritical, "checker", output); } diff --git a/lib/compat/externalcommandlistener.cpp b/lib/compat/externalcommandlistener.cpp index 5f5362db6f8..6ca4e3c0969 100644 --- a/lib/compat/externalcommandlistener.cpp +++ b/lib/compat/externalcommandlistener.cpp @@ -138,7 +138,7 @@ void ExternalCommandListener::CommandPipeThread(const String& commandPath) Log(LogInformation, "ExternalCommandListener") << "Executing external command: " << command; - ExternalCommandProcessor::Execute(command); + ExternalCommandProcessor::Execute(m_WaitGroup, command); } catch (const std::exception& ex) { Log(LogWarning, "ExternalCommandListener") << "External command failed: " << DiagnosticInformation(ex, false); diff --git a/lib/db_ido/idochecktask.cpp b/lib/db_ido/idochecktask.cpp index 3b5856a6598..d3b93e37b7d 100644 --- a/lib/db_ido/idochecktask.cpp +++ b/lib/db_ido/idochecktask.cpp @@ -16,11 +16,11 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); static void ReportIdoCheck( - const Checkable::Ptr& checkable, const CheckCommand::Ptr& commandObj, - const CheckResult::Ptr& cr, String output, ServiceState state = ServiceUnknown + const Checkable::Ptr& checkable, const CheckCommand::Ptr& commandObj, const CheckResult::Ptr& cr, + const WaitGroup::Ptr& producer, String output, ServiceState state = ServiceUnknown ) { if (Checkable::ExecuteCommandProcessFinishedHandler) { @@ -36,12 +36,12 @@ static void ReportIdoCheck( } else { cr->SetState(state); cr->SetOutput(output); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { ServiceState state; CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); @@ -88,19 +88,19 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult return; if (idoType.IsEmpty()) { - ReportIdoCheck(checkable, commandObj, cr, "Attribute 'ido_type' must be set."); + ReportIdoCheck(checkable, commandObj, cr, producer, "Attribute 'ido_type' must be set."); return; } if (idoName.IsEmpty()) { - ReportIdoCheck(checkable, commandObj, cr, "Attribute 'ido_name' must be set."); + ReportIdoCheck(checkable, commandObj, cr, producer, "Attribute 'ido_name' must be set."); return; } Type::Ptr type = Type::GetByName(idoType); if (!type || !DbConnection::TypeInstance->IsAssignableFrom(type)) { - ReportIdoCheck(checkable, commandObj, cr, "DB IDO type '" + idoType + "' is invalid."); + ReportIdoCheck(checkable, commandObj, cr, producer, "DB IDO type '" + idoType + "' is invalid."); return; } @@ -110,14 +110,14 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult DbConnection::Ptr conn = static_pointer_cast(dtype->GetObject(idoName)); if (!conn) { - ReportIdoCheck(checkable, commandObj, cr, "DB IDO connection '" + idoName + "' does not exist."); + ReportIdoCheck(checkable, commandObj, cr, producer, "DB IDO connection '" + idoName + "' does not exist."); return; } double qps = conn->GetQueryCount(60) / 60.0; if (conn->IsPaused()) { - ReportIdoCheck(checkable, commandObj, cr, "DB IDO connection is temporarily disabled on this cluster instance.", ServiceOK); + ReportIdoCheck(checkable, commandObj, cr, producer, "DB IDO connection is temporarily disabled on this cluster instance.", ServiceOK); return; } @@ -125,10 +125,10 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult if (!conn->GetConnected()) { if (conn->GetShouldConnect()) { - ReportIdoCheck(checkable, commandObj, cr, "Could not connect to the database server.", ServiceCritical); + ReportIdoCheck(checkable, commandObj, cr, producer, "Could not connect to the database server.", ServiceCritical); } else { ReportIdoCheck( - checkable, commandObj, cr, + checkable, commandObj, cr, producer, "Not currently enabled: Another cluster instance is responsible for the IDO database.", ServiceOK ); } @@ -193,5 +193,5 @@ void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult { new PerfdataValue("pending_queries", pendingQueries, false, "", pendingQueriesWarning, pendingQueriesCritical) } })); - ReportIdoCheck(checkable, commandObj, cr, msgbuf.str(), state); + ReportIdoCheck(checkable, commandObj, cr, producer, msgbuf.str(), state); } diff --git a/lib/db_ido/idochecktask.hpp b/lib/db_ido/idochecktask.hpp index 5868c38671b..1377d676589 100644 --- a/lib/db_ido/idochecktask.hpp +++ b/lib/db_ido/idochecktask.hpp @@ -18,7 +18,7 @@ class IdoCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IdoCheckTask(); diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 0f7e5cff1ae..3a30993fb91 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -126,7 +126,8 @@ Dictionary::Ptr ApiActions::ProcessCheckResult(const ConfigObject::Ptr& object, if (params->Contains("ttl")) cr->SetTtl(HttpUtility::GetLastParameter(params, "ttl")); - Result result = checkable->ProcessCheckResult(cr); + Result result = checkable->ProcessCheckResult(cr, ApiListener::GetInstance()->GetWaitGroup()); + switch (result) { case Result::Ok: return ApiActions::CreateResult(200, "Successfully processed check result for object '" + checkable->GetName() + "'."); @@ -787,7 +788,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons Defer resetCheckCommandOverride([]() { CheckCommand::ExecuteOverride = nullptr; }); - cmd->Execute(checkable, cr, execMacros, false); + cmd->Execute(checkable, cr, listener->GetWaitGroup(), execMacros, false); } } else if (command_type == "EventCommand") { EventCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(EventCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser); diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 868921dc976..b2b5ca45ee8 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -96,7 +96,7 @@ double Checkable::GetLastCheck() const return schedule_end; } -Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin) +Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const WaitGroup::Ptr& producer, const MessageOrigin::Ptr& origin) { using Result = Checkable::ProcessingResult; @@ -544,7 +544,7 @@ Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr return Result::Ok; } -void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) +void Checkable::ExecuteRemoteCheck(const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros) { CONTEXT("Executing remote check for object '" << GetName() << "'"); @@ -555,10 +555,10 @@ void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) cr->SetScheduleStart(scheduled_start); cr->SetExecutionStart(before_check); - GetCheckCommand()->Execute(this, cr, resolvedMacros, true); + GetCheckCommand()->Execute(this, cr, producer, resolvedMacros, true); } -void Checkable::ExecuteCheck() +void Checkable::ExecuteCheck(const WaitGroup::Ptr& producer) { CONTEXT("Executing check for object '" << GetName() << "'"); @@ -599,10 +599,10 @@ void Checkable::ExecuteCheck() bool local = !endpoint || endpoint == Endpoint::GetLocalEndpoint(); if (local) { - GetCheckCommand()->Execute(this, cr, nullptr, false); + GetCheckCommand()->Execute(this, cr, producer, nullptr, false); } else { Dictionary::Ptr macros = new Dictionary(); - GetCheckCommand()->Execute(this, cr, macros, false); + GetCheckCommand()->Execute(this, cr, producer, macros, false); if (endpoint->GetConnected()) { /* perform check on remote endpoint */ @@ -663,7 +663,7 @@ void Checkable::ExecuteCheck() cr->SetOutput(output); - ProcessCheckResult(cr); + ProcessCheckResult(cr, producer); } { diff --git a/lib/icinga/checkable-script.cpp b/lib/icinga/checkable-script.cpp index 764a9f851fd..a455440caf5 100644 --- a/lib/icinga/checkable-script.cpp +++ b/lib/icinga/checkable-script.cpp @@ -6,6 +6,7 @@ #include "base/function.hpp" #include "base/functionwrapper.hpp" #include "base/scriptframe.hpp" +#include "remote/apilistener.hpp" using namespace icinga; @@ -16,7 +17,9 @@ static void CheckableProcessCheckResult(const CheckResult::Ptr& cr) REQUIRE_NOT_NULL(self); if (cr) { - self->ProcessCheckResult(cr); + auto api (ApiListener::GetInstance()); + + self->ProcessCheckResult(cr, api ? api->GetWaitGroup() : new StoppableWaitGroup()); } } diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index da6be56309d..310923ec8f8 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -12,6 +12,7 @@ #include "icinga/notification.hpp" #include "icinga/comment.hpp" #include "icinga/downtime.hpp" +#include "base/wait-group.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include @@ -114,15 +115,17 @@ class Checkable : public ObjectImpl static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); - void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = nullptr); - void ExecuteCheck(); + void ExecuteRemoteCheck(const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros = nullptr); + void ExecuteCheck(const WaitGroup::Ptr& producer); + enum class ProcessingResult { Ok, CheckableInactive, NewerCheckResultPresent, }; - ProcessingResult ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin = nullptr); + + ProcessingResult ProcessCheckResult(const CheckResult::Ptr& cr, const WaitGroup::Ptr& producer, const MessageOrigin::Ptr& origin = nullptr); Endpoint::Ptr GetCommandEndpoint() const; diff --git a/lib/icinga/checkcommand.cpp b/lib/icinga/checkcommand.cpp index fb8032a199e..e1aed1718b1 100644 --- a/lib/icinga/checkcommand.cpp +++ b/lib/icinga/checkcommand.cpp @@ -11,11 +11,12 @@ 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) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { GetExecute()->Invoke({ checkable, cr, + producer, resolvedMacros, useResolvedMacros }); diff --git a/lib/icinga/checkcommand.hpp b/lib/icinga/checkcommand.hpp index c654cf93e87..1ed3b9ae707 100644 --- a/lib/icinga/checkcommand.hpp +++ b/lib/icinga/checkcommand.hpp @@ -23,6 +23,7 @@ class CheckCommand final : public ObjectImpl static thread_local CheckCommand::Ptr ExecuteOverride; void Execute(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros = nullptr, bool useResolvedMacros = false); }; diff --git a/lib/icinga/clusterevents-check.cpp b/lib/icinga/clusterevents-check.cpp index 40325b4c0e4..205c4c79daa 100644 --- a/lib/icinga/clusterevents-check.cpp +++ b/lib/icinga/clusterevents-check.cpp @@ -279,7 +279,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons if (command_type == "check_command") { try { - host->ExecuteRemoteCheck(macros); + host->ExecuteRemoteCheck(ApiListener::GetInstance()->GetWaitGroup(), macros); } catch (const std::exception& ex) { String output = "Exception occurred while checking '" + host->GetName() + "': " + DiagnosticInformation(ex); ServiceState state = ServiceUnknown; diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index b49d2071d0d..a45ac458b64 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -176,9 +176,9 @@ Value ClusterEvents::CheckResultAPIHandler(const MessageOrigin::Ptr& origin, con } if (!checkable->IsPaused() && Zone::GetLocalZone() == checkable->GetZone() && endpoint == checkable->GetCommandEndpoint()) - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, ApiListener::GetInstance()->GetWaitGroup()); else - checkable->ProcessCheckResult(cr, origin); + checkable->ProcessCheckResult(cr, ApiListener::GetInstance()->GetWaitGroup(), origin); return Empty; } diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index 0560947aaac..fbc0432a465 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -27,7 +27,7 @@ using namespace icinga; boost::signals2::signal&)> ExternalCommandProcessor::OnNewExternalCommand; -void ExternalCommandProcessor::Execute(const String& line) +void ExternalCommandProcessor::Execute(const WaitGroup::Ptr& producer, const String& line) { if (line.IsEmpty()) return; @@ -54,10 +54,10 @@ void ExternalCommandProcessor::Execute(const String& line) BOOST_THROW_EXCEPTION(std::invalid_argument("Missing arguments in command: " + line)); std::vector argvExtra(argv.begin() + 1, argv.end()); - Execute(ts, argv[0], argvExtra); + Execute(producer, ts, argv[0], argvExtra); } -void ExternalCommandProcessor::Execute(double time, const String& command, const std::vector& arguments) +void ExternalCommandProcessor::Execute(const WaitGroup::Ptr& producer, double time, const String& command, const std::vector& arguments) { ExternalCommandInfo eci; @@ -102,7 +102,7 @@ void ExternalCommandProcessor::Execute(double time, const String& command, const OnNewExternalCommand(time, command, realArguments); - eci.Callback(time, realArguments); + eci.Callback(producer, time, realArguments); } void ExternalCommandProcessor::RegisterCommand(const String& command, const ExternalCommandCallback& callback, size_t minArgs, size_t maxArgs) @@ -115,6 +115,16 @@ void ExternalCommandProcessor::RegisterCommand(const String& command, const Exte GetCommands()[command] = eci; } +void ExternalCommandProcessor::RegisterCommand(const String& command, const ExternalCommandCallbackLite& callback, size_t minArgs, size_t maxArgs) +{ + RegisterCommand( + command, + [callback](const WaitGroup::Ptr&, double time, const std::vector& args) { callback(time, args); }, + minArgs, + maxArgs + ); +} + void ExternalCommandProcessor::RegisterCommands() { RegisterCommand("PROCESS_HOST_CHECK_RESULT", &ExternalCommandProcessor::ProcessHostCheckResult, 3); @@ -237,7 +247,7 @@ void ExternalCommandProcessor::RegisterCommands() RegisterCommand("DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS", &ExternalCommandProcessor::DisableServicegroupSvcNotifications, 1); } -void ExternalCommandProcessor::ExecuteFromFile(const String& line, std::deque< std::vector >& file_queue) +void ExternalCommandProcessor::ExecuteFromFile(const WaitGroup::Ptr& producer, const String& line, std::deque>& file_queue) { if (line.IsEmpty()) return; @@ -270,11 +280,11 @@ void ExternalCommandProcessor::ExecuteFromFile(const String& line, std::deque< s << "Enqueing external command file " << argvExtra[0]; file_queue.push_back(argvExtra); } else { - Execute(ts, argv[0], argvExtra); + Execute(producer, ts, argv[0], argvExtra); } } -void ExternalCommandProcessor::ProcessHostCheckResult(double time, const std::vector& arguments) +void ExternalCommandProcessor::ProcessHostCheckResult(const WaitGroup::Ptr& producer, double time, const std::vector& arguments) { Host::Ptr host = Host::GetByName(arguments[0]); @@ -318,10 +328,10 @@ void ExternalCommandProcessor::ProcessHostCheckResult(double time, const std::ve Log(LogNotice, "ExternalCommandProcessor") << "Processing passive check result for host '" << arguments[0] << "'"; - host->ProcessCheckResult(result); + host->ProcessCheckResult(result, producer); } -void ExternalCommandProcessor::ProcessServiceCheckResult(double time, const std::vector& arguments) +void ExternalCommandProcessor::ProcessServiceCheckResult(const WaitGroup::Ptr& producer, double time, const std::vector& arguments) { Service::Ptr service = Service::GetByNamePair(arguments[0], arguments[1]); @@ -356,7 +366,7 @@ void ExternalCommandProcessor::ProcessServiceCheckResult(double time, const std: Log(LogNotice, "ExternalCommandProcessor") << "Processing passive check result for service '" << arguments[1] << "'"; - service->ProcessCheckResult(result); + service->ProcessCheckResult(result, producer); } void ExternalCommandProcessor::ScheduleHostCheck(double, const std::vector& arguments) @@ -921,7 +931,7 @@ void ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks(double, const st } } -void ExternalCommandProcessor::ProcessFile(double, const std::vector& arguments) +void ExternalCommandProcessor::ProcessFile(const WaitGroup::Ptr& producer, double, const std::vector& arguments) { std::deque< std::vector > file_queue; file_queue.push_back(arguments); @@ -946,7 +956,7 @@ void ExternalCommandProcessor::ProcessFile(double, const std::vector& ar Log(LogNotice, "compat") << "Executing external command: " << line; - ExecuteFromFile(line, file_queue); + ExecuteFromFile(producer, line, file_queue); } catch (const std::exception& ex) { Log(LogWarning, "ExternalCommandProcessor") << "External command failed: " << DiagnosticInformation(ex); diff --git a/lib/icinga/externalcommandprocessor.hpp b/lib/icinga/externalcommandprocessor.hpp index a7c5a306873..38db883d245 100644 --- a/lib/icinga/externalcommandprocessor.hpp +++ b/lib/icinga/externalcommandprocessor.hpp @@ -5,6 +5,7 @@ #include "icinga/i2-icinga.hpp" #include "icinga/command.hpp" +#include "base/wait-group.hpp" #include "base/string.hpp" #include #include @@ -12,7 +13,8 @@ namespace icinga { -typedef std::function& arguments)> ExternalCommandCallback; +typedef std::function& arguments)> ExternalCommandCallback; +typedef std::function& arguments)> ExternalCommandCallbackLite; struct ExternalCommandInfo { @@ -23,18 +25,18 @@ struct ExternalCommandInfo class ExternalCommandProcessor { public: - static void Execute(const String& line); - static void Execute(double time, const String& command, const std::vector& arguments); + static void Execute(const WaitGroup::Ptr& producer, const String& line); + static void Execute(const WaitGroup::Ptr& producer, double time, const String& command, const std::vector& arguments); static boost::signals2::signal&)> OnNewExternalCommand; private: ExternalCommandProcessor(); - static void ExecuteFromFile(const String& line, std::deque< std::vector >& file_queue); + static void ExecuteFromFile(const WaitGroup::Ptr& producer, const String& line, std::deque>& file_queue); - static void ProcessHostCheckResult(double time, const std::vector& arguments); - static void ProcessServiceCheckResult(double time, const std::vector& arguments); + static void ProcessHostCheckResult(const WaitGroup::Ptr& producer, double time, const std::vector& arguments); + static void ProcessServiceCheckResult(const WaitGroup::Ptr& producer, double time, const std::vector& arguments); static void ScheduleHostCheck(double time, const std::vector& arguments); static void ScheduleForcedHostCheck(double time, const std::vector& arguments); static void ScheduleSvcCheck(double time, const std::vector& arguments); @@ -67,7 +69,7 @@ class ExternalCommandProcessor { static void DisableServicegroupPassiveSvcChecks(double time, const std::vector& arguments); static void EnableHostgroupPassiveSvcChecks(double time, const std::vector& arguments); static void DisableHostgroupPassiveSvcChecks(double time, const std::vector& arguments); - static void ProcessFile(double time, const std::vector& arguments); + static void ProcessFile(const WaitGroup::Ptr& producer, double time, const std::vector& arguments); static void ScheduleSvcDowntime(double time, const std::vector& arguments); static void DelSvcDowntime(double time, const std::vector& arguments); static void ScheduleHostDowntime(double time, const std::vector& arguments); @@ -157,6 +159,7 @@ class ExternalCommandProcessor { static void ChangeCustomCommandVarInternal(const Command::Ptr& command, const String& name, const Value& value); static void RegisterCommand(const String& command, const ExternalCommandCallback& callback, size_t minArgs = 0, size_t maxArgs = UINT_MAX); + static void RegisterCommand(const String& command, const ExternalCommandCallbackLite& callback, size_t minArgs = 0, size_t maxArgs = UINT_MAX); static void RegisterCommands(); static std::mutex& GetMutex(); diff --git a/lib/icingadb/icingadbchecktask.cpp b/lib/icingadb/icingadbchecktask.cpp index cee93cd3384..54e76e8941e 100644 --- a/lib/icingadb/icingadbchecktask.cpp +++ b/lib/icingadb/icingadbchecktask.cpp @@ -13,11 +13,11 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, IcingadbCheck, &IcingadbCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, IcingadbCheck, &IcingadbCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); static void ReportIcingadbCheck( const Checkable::Ptr& checkable, const CheckCommand::Ptr& commandObj, - const CheckResult::Ptr& cr, String output, ServiceState state) + const CheckResult::Ptr& cr, const WaitGroup::Ptr& producer, String output, ServiceState state) { if (Checkable::ExecuteCommandProcessFinishedHandler) { double now = Utility::GetTime(); @@ -32,7 +32,7 @@ static void ReportIcingadbCheck( } else { cr->SetState(state); cr->SetOutput(output); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } @@ -43,7 +43,7 @@ double GetXMessageTs(const Array::Ptr& xMessage) } void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { CheckCommand::Ptr commandObj = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand(); @@ -87,21 +87,21 @@ void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckR return; if (icingadbName.IsEmpty()) { - ReportIcingadbCheck(checkable, commandObj, cr, "Icinga DB UNKNOWN: Attribute 'icingadb_name' must be set.", ServiceUnknown); + ReportIcingadbCheck(checkable, commandObj, cr, producer, "Icinga DB UNKNOWN: Attribute 'icingadb_name' must be set.", ServiceUnknown); return; } auto conn (IcingaDB::GetByName(icingadbName)); if (!conn) { - ReportIcingadbCheck(checkable, commandObj, cr, "Icinga DB UNKNOWN: Icinga DB connection '" + icingadbName + "' does not exist.", ServiceUnknown); + ReportIcingadbCheck(checkable, commandObj, cr, producer, "Icinga DB UNKNOWN: Icinga DB connection '" + icingadbName + "' does not exist.", ServiceUnknown); return; } auto redis (conn->GetConnection()); if (!redis || !redis->GetConnected()) { - ReportIcingadbCheck(checkable, commandObj, cr, "Icinga DB CRITICAL: Not connected to Redis.", ServiceCritical); + ReportIcingadbCheck(checkable, commandObj, cr, producer, "Icinga DB CRITICAL: Not connected to Redis.", ServiceCritical); return; } @@ -136,7 +136,7 @@ void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckR xReadHistoryBacklog = std::move(replies.at(4)); } catch (const std::exception& ex) { ReportIcingadbCheck( - checkable, commandObj, cr, + checkable, commandObj, cr, producer, String("Icinga DB CRITICAL: Could not query Redis: ") + ex.what(), ServiceCritical ); return; @@ -144,7 +144,7 @@ void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckR if (!xReadHeartbeat) { ReportIcingadbCheck( - checkable, commandObj, cr, + checkable, commandObj, cr, producer, "Icinga DB CRITICAL: The Icinga DB daemon seems to have never run. (Missing heartbeat)", ServiceCritical ); @@ -511,5 +511,5 @@ void IcingadbCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckR } cr->SetPerformanceData(perfdata); - ReportIcingadbCheck(checkable, commandObj, cr, msgbuf.str(), state); + ReportIcingadbCheck(checkable, commandObj, cr, producer, msgbuf.str(), state); } diff --git a/lib/icingadb/icingadbchecktask.hpp b/lib/icingadb/icingadbchecktask.hpp index ba7d61b1edf..5fffff4f1e3 100644 --- a/lib/icingadb/icingadbchecktask.hpp +++ b/lib/icingadb/icingadbchecktask.hpp @@ -18,7 +18,7 @@ class IcingadbCheckTask { public: static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IcingadbCheckTask(); diff --git a/lib/livestatus/livestatuslistener.cpp b/lib/livestatus/livestatuslistener.cpp index fe524dcdb3a..9f48bcdbeba 100644 --- a/lib/livestatus/livestatuslistener.cpp +++ b/lib/livestatus/livestatuslistener.cpp @@ -192,7 +192,7 @@ void LivestatusListener::ClientHandler(const Socket::Ptr& client) break; LivestatusQuery::Ptr query = new LivestatusQuery(lines, GetCompatLogPath()); - if (!query->Execute(stream)) + if (!query->Execute(m_WaitGroup, stream)) break; } diff --git a/lib/livestatus/livestatusquery.cpp b/lib/livestatus/livestatusquery.cpp index 0f9b3dac9ce..c152eaf27d5 100644 --- a/lib/livestatus/livestatusquery.cpp +++ b/lib/livestatus/livestatusquery.cpp @@ -570,7 +570,7 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream) SendResponse(stream, LivestatusErrorOK, result.str()); } -void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream) +void LivestatusQuery::ExecuteCommandHelper(const WaitGroup::Ptr& producer, const Stream::Ptr& stream) { { std::unique_lock lock(l_QueryMutex); @@ -580,7 +580,7 @@ void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream) Log(LogNotice, "LivestatusQuery") << "Executing command: " << m_Command; - ExternalCommandProcessor::Execute(m_Command); + ExternalCommandProcessor::Execute(producer, m_Command); SendResponse(stream, LivestatusErrorOK, ""); } @@ -621,7 +621,7 @@ void LivestatusQuery::PrintFixed16(const Stream::Ptr& stream, int code, const St } } -bool LivestatusQuery::Execute(const Stream::Ptr& stream) +bool LivestatusQuery::Execute(const WaitGroup::Ptr& producer, const Stream::Ptr& stream) { try { Log(LogNotice, "LivestatusQuery") @@ -630,7 +630,7 @@ bool LivestatusQuery::Execute(const Stream::Ptr& stream) if (m_Verb == "GET") ExecuteGetHelper(stream); else if (m_Verb == "COMMAND") - ExecuteCommandHelper(stream); + ExecuteCommandHelper(producer, stream); else if (m_Verb == "ERROR") ExecuteErrorHelper(stream); else diff --git a/lib/livestatus/livestatusquery.hpp b/lib/livestatus/livestatusquery.hpp index 910cc162e79..838a9a8f5e8 100644 --- a/lib/livestatus/livestatusquery.hpp +++ b/lib/livestatus/livestatusquery.hpp @@ -5,6 +5,7 @@ #include "livestatus/filter.hpp" #include "livestatus/aggregator.hpp" +#include "base/wait-group.hpp" #include "base/object.hpp" #include "base/array.hpp" #include "base/stream.hpp" @@ -33,7 +34,7 @@ class LivestatusQuery final : public Object LivestatusQuery(const std::vector& lines, const String& compat_log_path); - bool Execute(const Stream::Ptr& stream); + bool Execute(const WaitGroup::Ptr& producer, const Stream::Ptr& stream); static int GetExternalCommands(); @@ -76,7 +77,7 @@ class LivestatusQuery final : public Object static String QuoteStringPython(const String& str); void ExecuteGetHelper(const Stream::Ptr& stream); - void ExecuteCommandHelper(const Stream::Ptr& stream); + void ExecuteCommandHelper(const WaitGroup::Ptr& producer, const Stream::Ptr& stream); void ExecuteErrorHelper(const Stream::Ptr& stream); void SendResponse(const Stream::Ptr& stream, int code, const String& data); diff --git a/lib/methods/clusterchecktask.cpp b/lib/methods/clusterchecktask.cpp index 6ce28cac440..c629225c39c 100644 --- a/lib/methods/clusterchecktask.cpp +++ b/lib/methods/clusterchecktask.cpp @@ -17,10 +17,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -47,7 +47,7 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe } else { cr->SetOutput(output); cr->SetState(ServiceUnknown); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } return; @@ -92,7 +92,7 @@ void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRe cr->SetState(state); cr->SetOutput(output); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/clusterchecktask.hpp b/lib/methods/clusterchecktask.hpp index 16ee8a53c80..39e544c1be5 100644 --- a/lib/methods/clusterchecktask.hpp +++ b/lib/methods/clusterchecktask.hpp @@ -17,7 +17,7 @@ class ClusterCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterCheckTask(); diff --git a/lib/methods/clusterzonechecktask.cpp b/lib/methods/clusterzonechecktask.cpp index fd52534c308..d7c99138c60 100644 --- a/lib/methods/clusterzonechecktask.cpp +++ b/lib/methods/clusterzonechecktask.cpp @@ -12,10 +12,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -42,7 +42,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che cr->SetCommand(commandName); cr->SetOutput(output); cr->SetState(state); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } return; @@ -97,7 +97,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che cr->SetCommand(commandName); cr->SetOutput(output); cr->SetState(state); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } return; @@ -123,7 +123,7 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che cr->SetCommand(commandName); cr->SetOutput(output); cr->SetState(state); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } return; } @@ -213,6 +213,6 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond) })); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/clusterzonechecktask.hpp b/lib/methods/clusterzonechecktask.hpp index 2af442c4c75..2bf3e10656a 100644 --- a/lib/methods/clusterzonechecktask.hpp +++ b/lib/methods/clusterzonechecktask.hpp @@ -17,7 +17,7 @@ class ClusterZoneCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ClusterZoneCheckTask(); diff --git a/lib/methods/dummychecktask.cpp b/lib/methods/dummychecktask.cpp index 905a022c341..85ef33d9a74 100644 --- a/lib/methods/dummychecktask.cpp +++ b/lib/methods/dummychecktask.cpp @@ -13,10 +13,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, DummyCheck, &DummyCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, DummyCheck, &DummyCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -70,6 +70,6 @@ void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu cr->SetExecutionEnd(now); cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/dummychecktask.hpp b/lib/methods/dummychecktask.hpp index 621bbfb9f02..9c32a19ad6e 100644 --- a/lib/methods/dummychecktask.hpp +++ b/lib/methods/dummychecktask.hpp @@ -19,7 +19,7 @@ class DummyCheckTask { public: static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: DummyCheckTask(); diff --git a/lib/methods/exceptionchecktask.cpp b/lib/methods/exceptionchecktask.cpp index 47707f26ff8..645a751bd8b 100644 --- a/lib/methods/exceptionchecktask.cpp +++ b/lib/methods/exceptionchecktask.cpp @@ -12,10 +12,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr&, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); diff --git a/lib/methods/exceptionchecktask.hpp b/lib/methods/exceptionchecktask.hpp index 09db1045f4a..6d8c8c4e063 100644 --- a/lib/methods/exceptionchecktask.hpp +++ b/lib/methods/exceptionchecktask.hpp @@ -18,7 +18,7 @@ class ExceptionCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: ExceptionCheckTask(); diff --git a/lib/methods/icingachecktask.cpp b/lib/methods/icingachecktask.cpp index d3eae1f33f2..3a8e9fbce93 100644 --- a/lib/methods/icingachecktask.cpp +++ b/lib/methods/icingachecktask.cpp @@ -17,10 +17,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -204,6 +204,6 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes cr->SetOutput(output); cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/icingachecktask.hpp b/lib/methods/icingachecktask.hpp index 93def628d76..94e4c6e76a7 100644 --- a/lib/methods/icingachecktask.hpp +++ b/lib/methods/icingachecktask.hpp @@ -18,7 +18,7 @@ class IcingaCheckTask { public: static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IcingaCheckTask(); diff --git a/lib/methods/ifwapichecktask.cpp b/lib/methods/ifwapichecktask.cpp index ce48deefc3a..fd3cc21c883 100644 --- a/lib/methods/ifwapichecktask.cpp +++ b/lib/methods/ifwapichecktask.cpp @@ -31,7 +31,7 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, IfwApiCheck, &IfwApiCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, IfwApiCheck, &IfwApiCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); static const char* GetUnderstandableError(const std::exception& ex) { @@ -194,7 +194,7 @@ static void DoIfwNetIo( } void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { namespace asio = boost::asio; namespace http = boost::beast::http; @@ -213,7 +213,7 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes if (!(commandEndpoint->GetCapabilities() & (uint_fast64_t)ApiCapabilities::IfwApiCheckCommand)) { // Assume "ifw-api-check-command" has been imported into a check command which can also work // based on "plugin-check-command", delegate respectively and hope for the best - PluginCheckTask::ScriptFunc(checkable, cr, resolvedMacros, useResolvedMacros); + PluginCheckTask::ScriptFunc(checkable, cr, producer, resolvedMacros, useResolvedMacros); return; } } @@ -275,7 +275,7 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes callback(cr->GetCommand(), pr); }; } else { - reportResult = [checkable, cr]() { checkable->ProcessCheckResult(cr); }; + reportResult = [checkable, cr, producer] { checkable->ProcessCheckResult(cr, producer); }; } // Set the default check result state and exit code to unknown for the moment! diff --git a/lib/methods/ifwapichecktask.hpp b/lib/methods/ifwapichecktask.hpp index 39327336b0b..0c2b3bac2c8 100644 --- a/lib/methods/ifwapichecktask.hpp +++ b/lib/methods/ifwapichecktask.hpp @@ -18,7 +18,7 @@ class IfwApiCheckTask { public: static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: IfwApiCheckTask(); diff --git a/lib/methods/nullchecktask.cpp b/lib/methods/nullchecktask.cpp index ee660294ee4..07479c366b2 100644 --- a/lib/methods/nullchecktask.cpp +++ b/lib/methods/nullchecktask.cpp @@ -13,10 +13,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void NullCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -45,6 +45,6 @@ void NullCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResul })); cr->SetState(state); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/nullchecktask.hpp b/lib/methods/nullchecktask.hpp index 954cf8d618b..1b991f13256 100644 --- a/lib/methods/nullchecktask.hpp +++ b/lib/methods/nullchecktask.hpp @@ -19,7 +19,7 @@ class NullCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: NullCheckTask(); diff --git a/lib/methods/pluginchecktask.cpp b/lib/methods/pluginchecktask.cpp index 1a3df810528..f5600bd14a7 100644 --- a/lib/methods/pluginchecktask.cpp +++ b/lib/methods/pluginchecktask.cpp @@ -14,10 +14,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -48,8 +48,8 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes if (Checkable::ExecuteCommandProcessFinishedHandler) { callback = Checkable::ExecuteCommandProcessFinishedHandler; } else { - callback = [checkable, cr](const Value& commandLine, const ProcessResult& pr) { - ProcessFinishedHandler(checkable, cr, commandLine, pr); + callback = [checkable, cr, producer](const Value& commandLine, const ProcessResult& pr) { + ProcessFinishedHandler(checkable, cr, producer, commandLine, pr); }; } @@ -62,7 +62,8 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes } } -void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr) +void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, + const WaitGroup::Ptr& producer, const Value& commandLine, const ProcessResult& pr) { Checkable::CurrentConcurrentChecks.fetch_sub(1); Checkable::DecreasePendingChecks(); @@ -93,5 +94,5 @@ void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, co cr->SetExecutionStart(pr.ExecutionStart); cr->SetExecutionEnd(pr.ExecutionEnd); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } diff --git a/lib/methods/pluginchecktask.hpp b/lib/methods/pluginchecktask.hpp index a4fc3a3850d..3491c65f940 100644 --- a/lib/methods/pluginchecktask.hpp +++ b/lib/methods/pluginchecktask.hpp @@ -19,13 +19,13 @@ class PluginCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: PluginCheckTask(); - static void ProcessFinishedHandler(const Checkable::Ptr& service, - const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr); + static void ProcessFinishedHandler(const Checkable::Ptr& service, const CheckResult::Ptr& cr, + const WaitGroup::Ptr& producer, const Value& commandLine, const ProcessResult& pr); }; } diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 9b133ef0ee5..ae7547ee515 100644 --- a/lib/methods/randomchecktask.cpp +++ b/lib/methods/randomchecktask.cpp @@ -13,10 +13,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -60,6 +60,6 @@ void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes cr->SetState(state); cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/randomchecktask.hpp b/lib/methods/randomchecktask.hpp index 00ce663dc9a..82a0c48a7bd 100644 --- a/lib/methods/randomchecktask.hpp +++ b/lib/methods/randomchecktask.hpp @@ -18,7 +18,7 @@ class RandomCheckTask { public: static void ScriptFunc(const Checkable::Ptr& service, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: RandomCheckTask(); diff --git a/lib/methods/sleepchecktask.cpp b/lib/methods/sleepchecktask.cpp index 05ed2675a03..975fde697b1 100644 --- a/lib/methods/sleepchecktask.cpp +++ b/lib/methods/sleepchecktask.cpp @@ -9,10 +9,10 @@ using namespace icinga; -REGISTER_FUNCTION_NONCONST(Internal, SleepCheck, &SleepCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros"); +REGISTER_FUNCTION_NONCONST(Internal, SleepCheck, &SleepCheckTask::ScriptFunc, "checkable:cr:producer:resolvedMacros:useResolvedMacros"); void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) { REQUIRE_NOT_NULL(checkable); REQUIRE_NOT_NULL(cr); @@ -62,6 +62,6 @@ void SleepCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResu cr->SetExecutionEnd(now); cr->SetCommand(commandName); - checkable->ProcessCheckResult(cr); + checkable->ProcessCheckResult(cr, producer); } } diff --git a/lib/methods/sleepchecktask.hpp b/lib/methods/sleepchecktask.hpp index ed8d59089ab..38019a5bc62 100644 --- a/lib/methods/sleepchecktask.hpp +++ b/lib/methods/sleepchecktask.hpp @@ -19,7 +19,7 @@ class SleepCheckTask { public: static void ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); + const WaitGroup::Ptr& producer, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros); private: SleepCheckTask(); diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index 3aa4f40db0d..d7965508dd3 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -152,6 +152,11 @@ class ApiListener final : public ObjectImpl double GetTlsHandshakeTimeout() const override; void SetTlsHandshakeTimeout(double value, bool suppress_events, const Value& cookie) override; + WaitGroup::Ptr GetWaitGroup() const + { + return m_WaitGroup; + } + protected: void OnConfigLoaded() override; void OnAllConfigLoaded() override; diff --git a/test/icinga-checkable-flapping.cpp b/test/icinga-checkable-flapping.cpp index bc305642590..a63c78fc42d 100644 --- a/test/icinga-checkable-flapping.cpp +++ b/test/icinga-checkable-flapping.cpp @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(host_not_flapping) int i = 0; while (i++ < 10) { // For some reason, elusive to me, the first check is a state change - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); @@ -107,9 +107,9 @@ BOOST_AUTO_TEST_CASE(host_flapping) int i = 0; while (i++ < 25) { if (i % 2) - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); else - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); @@ -144,18 +144,18 @@ BOOST_AUTO_TEST_CASE(host_flapping_recover) Utility::SetTime(0); // A few warning - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); for (int i = 0; i <= 7; i++) { if (i % 2) - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); else - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); } LogFlapping(host); @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(host_flapping_recover) BOOST_CHECK(host->GetFlappingCurrent() > 25.0); BOOST_CHECK(host->IsFlapping()); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); count++; @@ -203,40 +203,40 @@ BOOST_AUTO_TEST_CASE(host_flapping_docs_example) Utility::SetTime(0); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceWarning)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceWarning), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); BOOST_CHECK(host->GetFlappingCurrent() == 39.1); BOOST_CHECK(host->IsFlapping()); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); LogFlapping(host); LogHostStatus(host); diff --git a/test/icinga-checkresult.cpp b/test/icinga-checkresult.cpp index fdc78915ede..438dee87d7c 100644 --- a/test/icinga-checkresult.cpp +++ b/test/icinga-checkresult.cpp @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(host_1attempt) CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + host->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(host_1attempt) CheckNotification(host, true, NotificationProblem); std::cout << "Second check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(host_1attempt) CheckNotification(host, true, NotificationRecovery); std::cout << "Third check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(host_1attempt) CheckNotification(host, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(host_2attempts) CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + host->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(host_2attempts) CheckNotification(host, false); std::cout << "Second check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(host_2attempts) CheckNotification(host, true, NotificationProblem); std::cout << "Third check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(host_2attempts) CheckNotification(host, true, NotificationRecovery); std::cout << "Fourth check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(host_2attempts) CheckNotification(host, false); std::cout << "Fifth check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, false); std::cout << "First check result (unknown)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + host->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, false); std::cout << "Second check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 2); @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, false); std::cout << "Third check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, true, NotificationRecovery); std::cout << "Fifth check result (critical)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + host->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostDown); BOOST_CHECK(host->GetStateType() == StateTypeSoft); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(host_3attempts) CheckNotification(host, false); std::cout << "Sixth check result (ok)" << std::endl; - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(host->GetState() == HostUp); BOOST_CHECK(host->GetStateType() == StateTypeHard); BOOST_CHECK(host->GetCheckAttempt() == 1); @@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(service_1attempt) CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + service->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(service_1attempt) CheckNotification(service, true, NotificationProblem); std::cout << "Second check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -280,7 +280,7 @@ BOOST_AUTO_TEST_CASE(service_1attempt) CheckNotification(service, true, NotificationRecovery); std::cout << "Third check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -288,7 +288,7 @@ BOOST_AUTO_TEST_CASE(service_1attempt) CheckNotification(service, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(service_2attempts) CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + service->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(service_2attempts) CheckNotification(service, false); std::cout << "Second check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(service_2attempts) CheckNotification(service, true, NotificationProblem); std::cout << "Third check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -345,7 +345,7 @@ BOOST_AUTO_TEST_CASE(service_2attempts) CheckNotification(service, true, NotificationRecovery); std::cout << "Fourth check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -353,7 +353,7 @@ BOOST_AUTO_TEST_CASE(service_2attempts) CheckNotification(service, false); std::cout << "Fifth check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -386,7 +386,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, false); std::cout << "First check result (unknown)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceUnknown)); + service->ProcessCheckResult(MakeCheckResult(ServiceUnknown), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceUnknown); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -394,7 +394,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, false); std::cout << "Second check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 2); @@ -402,7 +402,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, false); std::cout << "Third check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, true, NotificationProblem); std::cout << "Fourth check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -418,7 +418,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, true, NotificationRecovery); std::cout << "Fifth check result (critical)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceCritical); BOOST_CHECK(service->GetStateType() == StateTypeSoft); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -426,7 +426,7 @@ BOOST_AUTO_TEST_CASE(service_3attempts) CheckNotification(service, false); std::cout << "Sixth check result (ok)" << std::endl; - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == ServiceOK); BOOST_CHECK(service->GetStateType() == StateTypeHard); BOOST_CHECK(service->GetCheckAttempt() == 1); @@ -470,7 +470,7 @@ BOOST_AUTO_TEST_CASE(host_flapping_notification) for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); - host->ProcessCheckResult(MakeCheckResult(state)); + host->ProcessCheckResult(MakeCheckResult(state), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -481,7 +481,7 @@ BOOST_AUTO_TEST_CASE(host_flapping_notification) std::cout << "Now calm down..." << std::endl; for (int i = 0; i < 20; i++) { - host->ProcessCheckResult(MakeCheckResult(ServiceOK)); + host->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -527,7 +527,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_notification) for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); - service->ProcessCheckResult(MakeCheckResult(state)); + service->ProcessCheckResult(MakeCheckResult(state), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -540,7 +540,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_notification) std::cout << "Now calm down..." << std::endl; for (int i = 0; i < 20; i++) { - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -585,7 +585,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_problem_notifications) for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); - service->ProcessCheckResult(MakeCheckResult(state)); + service->ProcessCheckResult(MakeCheckResult(state), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -595,11 +595,11 @@ BOOST_AUTO_TEST_CASE(service_flapping_problem_notifications) //Insert enough check results to get into hard problem state but staying flapping - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); @@ -611,7 +611,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_problem_notifications) // Calm down while (service->IsFlapping()) { - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -641,7 +641,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_problem_notifications) // Known failure, see #5713 // CheckNotification(service, true, NotificationProblem); - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); // Known failure, see #5713 @@ -686,7 +686,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_into_bad) for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); - service->ProcessCheckResult(MakeCheckResult(state)); + service->ProcessCheckResult(MakeCheckResult(state), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -696,11 +696,11 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_into_bad) //Insert enough check results to get into hard problem state but staying flapping - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); @@ -712,13 +712,13 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_into_bad) // Calm down while (service->IsFlapping()) { - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == false); @@ -767,7 +767,7 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_over_bad_into_ok) for (int i = 0; i < 10; i++) { ServiceState state = (i % 2 == 0 ? ServiceOK : ServiceCritical); - service->ProcessCheckResult(MakeCheckResult(state)); + service->ProcessCheckResult(MakeCheckResult(state), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } @@ -777,11 +777,11 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_over_bad_into_ok) //Insert enough check results to get into hard problem state but staying flapping - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); @@ -793,13 +793,13 @@ BOOST_AUTO_TEST_CASE(service_flapping_ok_over_bad_into_ok) // Calm down while (service->IsFlapping()) { - service->ProcessCheckResult(MakeCheckResult(ServiceCritical)); + service->ProcessCheckResult(MakeCheckResult(ServiceCritical), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); } CheckNotification(service, true, NotificationFlappingEnd); - service->ProcessCheckResult(MakeCheckResult(ServiceOK)); + service->ProcessCheckResult(MakeCheckResult(ServiceOK), new StoppableWaitGroup()); Utility::IncrementTime(timeStepInterval); BOOST_CHECK(service->IsFlapping() == false); @@ -894,7 +894,7 @@ BOOST_AUTO_TEST_CASE(suppressed_notification) for (int i = 0; i < checkAttempts; i++) { std::cout << " ProcessCheckResult(" << Service::StateToString(initialState) << ")" << std::endl; - service->ProcessCheckResult(MakeCheckResult(initialState)); + service->ProcessCheckResult(MakeCheckResult(initialState), new StoppableWaitGroup()); } BOOST_CHECK(service->GetState() == initialState); @@ -972,7 +972,7 @@ BOOST_AUTO_TEST_CASE(suppressed_notification) // Process check results for the state sequence. for (ServiceState s : sequence) { std::cout << " ProcessCheckResult(" << Service::StateToString(s) << ")" << std::endl; - service->ProcessCheckResult(MakeCheckResult(s)); + service->ProcessCheckResult(MakeCheckResult(s), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == s); if (checkAttempts == 1) { BOOST_CHECK(service->GetStateType() == StateTypeHard); @@ -1002,7 +1002,7 @@ BOOST_AUTO_TEST_CASE(suppressed_notification) for (int i = 0; i < checkAttempts && service->GetStateType() == StateTypeSoft; i++) { std::cout << " ProcessCheckResult(" << Service::StateToString(sequence.back()) << ")" << std::endl; - service->ProcessCheckResult(MakeCheckResult(sequence.back())); + service->ProcessCheckResult(MakeCheckResult(sequence.back()), new StoppableWaitGroup()); BOOST_CHECK(service->GetState() == sequence.back()); } } diff --git a/test/livestatus.cpp b/test/livestatus.cpp index 6aafa3be3e2..a989eedca99 100644 --- a/test/livestatus.cpp +++ b/test/livestatus.cpp @@ -15,7 +15,7 @@ String LivestatusQueryHelper(const std::vector& lines) std::stringstream stream; StdioStream::Ptr sstream = new StdioStream(&stream, false); - query->Execute(sstream); + query->Execute(new StoppableWaitGroup(), sstream); String output; String result; From 36743f3100ad5f76dacb6077878ef6b9cfa20999 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 20 May 2025 13:02:26 +0200 Subject: [PATCH 4/4] Checkable#ProcessCheckResult(): discard CR or delay its producers shutdown --- lib/icinga/checkable-check.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index b2b5ca45ee8..2d34ec644d9 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -14,6 +14,7 @@ #include "base/convert.hpp" #include "base/utility.hpp" #include "base/context.hpp" +#include using namespace icinga; @@ -101,6 +102,7 @@ Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr using Result = Checkable::ProcessingResult; VERIFY(cr); + VERIFY(producer); { ObjectLock olock(this); @@ -135,6 +137,14 @@ Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr cr->SetCheckSource(command_endpoint->GetName()); } + std::shared_lock producerLock (*producer, std::try_to_lock); + + if (!producerLock) { + // Discard the check result to not delay the current reload. + // We'll re-run the check immediately after the reload. + return Result::CheckableInactive; + } + /* agent checks go through the api */ if (command_endpoint && GetExtension("agent_check")) { ApiListener::Ptr listener = ApiListener::GetInstance();