diff --git a/AUTHORS b/AUTHORS index 0018eb74e..a91663a9d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,6 +12,7 @@ Gaƫl Beaudoin Gerd von Egidy Gunnar Beutner Ildar Hizbulin +James Pharaoh Jan Andres Jan Wagner Jason Young diff --git a/lib/icinga/apievents.cpp b/lib/icinga/apievents.cpp index 6e21c7f86..e3aed4c58 100644 --- a/lib/icinga/apievents.cpp +++ b/lib/icinga/apievents.cpp @@ -1511,9 +1511,9 @@ Value ApiEvents::AcknowledgementClearedAPIHandler(const MessageOrigin& origin, c Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dictionary::Ptr& params) { - Endpoint::Ptr endpoint = origin.FromClient->GetEndpoint(); + Endpoint::Ptr sourceEndpoint = origin.FromClient->GetEndpoint(); - if (!endpoint || (origin.FromZone && !Zone::GetLocalZone()->IsChildOf(origin.FromZone))) + if (!sourceEndpoint || (origin.FromZone && !Zone::GetLocalZone()->IsChildOf(origin.FromZone))) return Empty; ApiListener::Ptr listener = ApiListener::GetInstance(); @@ -1539,11 +1539,12 @@ Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dic cr->SetState(ServiceUnknown); cr->SetOutput("'" + listener->GetName() + "' does not accept commands."); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(endpoint, message); + listener->SyncSendMessage(sourceEndpoint, message); return Empty; } + /* use a virtual host object for executing the command */ Host::Ptr host = new Host(); Dictionary::Ptr attrs = new Dictionary(); @@ -1559,7 +1560,7 @@ Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dic cr->SetState(ServiceUnknown); cr->SetOutput("Check command '" + command + "' does not exist."); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(endpoint, message); + listener->SyncSendMessage(sourceEndpoint, message); return Empty; } } else if (command_type == "event_command") { @@ -1569,7 +1570,7 @@ Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dic return Empty; attrs->Set(command_type, params->Get("command")); - attrs->Set("command_endpoint", endpoint->GetName()); + attrs->Set("command_endpoint", sourceEndpoint->GetName()); Deserialize(host, attrs, false, FAConfig); @@ -1586,7 +1587,7 @@ Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dic if (command_type == "check_command") { try { - host->ExecuteCheck(macros, true); + host->ExecuteRemoteCheck(macros); } catch (const std::exception& ex) { CheckResult::Ptr cr = new CheckResult(); cr->SetState(ServiceUnknown); @@ -1601,7 +1602,7 @@ Value ApiEvents::ExecuteCommandAPIHandler(const MessageOrigin& origin, const Dic cr->SetExecutionEnd(now); Dictionary::Ptr message = MakeCheckResultMessage(host, cr); - listener->SyncSendMessage(endpoint, message); + listener->SyncSendMessage(sourceEndpoint, message); Log(LogCritical, "checker", output); } diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 8ed1dd2dd..a4da0c31d 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -260,15 +260,37 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig Endpoint::Ptr command_endpoint = GetCommandEndpoint(); - if (command_endpoint && (Endpoint::GetLocalEndpoint() != command_endpoint) && GetExtension("agent_check")) { + if (command_endpoint && GetExtension("agent_check")) { + /* agent checks go through the api */ ApiListener::Ptr listener = ApiListener::GetInstance(); if (listener) { + /* send message back to its origin */ Dictionary::Ptr message = ApiEvents::MakeCheckResultMessage(this, cr); listener->SyncSendMessage(command_endpoint, message); + + /* HA cluster zone nodes must also process the check result locally + * by fetching the real host/service object if existing + */ + Host::Ptr tempHost; + Service::Ptr tempService; + tie(tempHost, tempService) = GetHostService(this); + Host::Ptr realHost = Host::GetByName(tempHost->GetName()); + if (realHost) { + Value agent_service_name = GetExtension("agent_service_name"); + if (!agent_service_name.IsEmpty()) { + Checkable::Ptr realCheckable; + realCheckable = realHost->GetServiceByShortName(agent_service_name); + if (realCheckable) { + realCheckable->ProcessCheckResult(cr, origin); + } + } + } + } return; + } bool reachable = IsReachable(); @@ -498,7 +520,21 @@ bool Checkable::IsCheckPending(void) const return m_CheckRunning; } -void Checkable::ExecuteCheck(const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros) +void Checkable::ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros) +{ + CONTEXT("Executing remote check for object '" + GetName() + "'"); + + double scheduled_start = GetNextCheck(); + double before_check = Utility::GetTime(); + + CheckResult::Ptr cr = new CheckResult(); + cr->SetScheduleStart(scheduled_start); + cr->SetExecutionStart(before_check); + + GetCheckCommand()->Execute(this, cr, resolvedMacros, true); +} + +void Checkable::ExecuteCheck() { CONTEXT("Executing check for object '" + GetName() + "'"); @@ -526,23 +562,22 @@ void Checkable::ExecuteCheck(const Dictionary::Ptr& resolvedMacros, bool useReso double scheduled_start = GetNextCheck(); double before_check = Utility::GetTime(); - CheckResult::Ptr result = new CheckResult(); + CheckResult::Ptr cr = new CheckResult(); - result->SetScheduleStart(scheduled_start); - result->SetExecutionStart(before_check); + cr->SetScheduleStart(scheduled_start); + cr->SetExecutionStart(before_check); - Dictionary::Ptr macros; Endpoint::Ptr endpoint = GetCommandEndpoint(); + bool local = !endpoint || endpoint == Endpoint::GetLocalEndpoint(); - if (endpoint && !useResolvedMacros) - macros = new Dictionary(); - else - macros = resolvedMacros; + if (local) { + GetCheckCommand()->Execute(this, cr, NULL, false); + } else { + Dictionary::Ptr macros = new Dictionary(); + GetCheckCommand()->Execute(this, cr, macros, false); - GetCheckCommand()->Execute(this, result, macros, useResolvedMacros); - - if (endpoint && !useResolvedMacros) { if (endpoint->IsConnected()) { + /* perform check on remote endpoint */ Dictionary::Ptr message = new Dictionary(); message->Set("jsonrpc", "2.0"); message->Set("method", "event::ExecuteCommand"); @@ -566,10 +601,15 @@ void Checkable::ExecuteCheck(const Dictionary::Ptr& resolvedMacros, bool useReso if (listener) listener->SyncSendMessage(endpoint, message); + } else if (Application::GetInstance()->GetStartTime() < Utility::GetTime() - 30) { - result->SetState(ServiceUnknown); - result->SetOutput("Remote Icinga instance '" + endpoint->GetName() + "' is not connected."); - ProcessCheckResult(result); + /* fail to perform check on unconnected endpoint */ + cr->SetState(ServiceUnknown); + + cr->SetOutput("Remote Icinga instance '" + endpoint->GetName() + + "' " + "is not connected to '" + Endpoint::GetLocalEndpoint()->GetName() + "'"); + + ProcessCheckResult(cr); } { diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 1968c5d88..91b462a99 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -135,8 +135,8 @@ public: static void UpdateStatistics(const CheckResult::Ptr& cr, CheckableType type); - void ExecuteCheck(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr(), - bool useResolvedMacros = false); + void ExecuteRemoteCheck(const Dictionary::Ptr& resolvedMacros = Dictionary::Ptr()); + void ExecuteCheck(); void ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin& origin = MessageOrigin()); int GetModifiedAttributes(void) const;