From 0eb0992d5e2a403dfd334ca39fde31460522143e Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 7 Jun 2016 12:44:12 +0200 Subject: [PATCH] Fix custom notifications in a HA zone fixes #9242 --- doc/6-object-types.md | 2 +- lib/icinga/apiactions.cpp | 2 +- lib/icinga/checkable-check.cpp | 18 +++--- lib/icinga/checkable-notification.cpp | 3 +- lib/icinga/checkable.cpp | 4 +- lib/icinga/checkable.hpp | 2 +- lib/icinga/clusterevents.cpp | 72 ++++++++++++++++++++++ lib/icinga/clusterevents.hpp | 4 ++ lib/icinga/externalcommandprocessor.cpp | 6 +- lib/notification/notificationcomponent.cpp | 3 - 10 files changed, 98 insertions(+), 18 deletions(-) diff --git a/doc/6-object-types.md b/doc/6-object-types.md index b0779e865..9921c0608 100644 --- a/doc/6-object-types.md +++ b/doc/6-object-types.md @@ -1078,7 +1078,7 @@ Configuration Attributes: Name |Description ----------------|---------------- - enable\_ha |**Optional.** Enable the high availability functionality. Only valid in a [cluster setup](13-distributed-monitoring-ha.md#high-availability-notifications). Defaults to "true". + enable\_ha |**Optional.** Enable the high availability functionality. Only valid in a [cluster setup](13-distributed-monitoring-ha.md#high-availability-notifications). Disabling this currently only affects reminder notifications. Defaults to "true". ## OpenTsdbWriter diff --git a/lib/icinga/apiactions.cpp b/lib/icinga/apiactions.cpp index 37f22cc43..7181b27b4 100644 --- a/lib/icinga/apiactions.cpp +++ b/lib/icinga/apiactions.cpp @@ -156,7 +156,7 @@ Dictionary::Ptr ApiActions::SendCustomNotification(const ConfigObject::Ptr& obje checkable->SetForceNextNotification(true); Checkable::OnNotificationsRequested(checkable, NotificationCustom, checkable->GetLastCheckResult(), - HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment")); + HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), MessageOrigin::Ptr()); return ApiActions::CreateResult(200, "Successfully sent custom notification for object '" + checkable->GetName() + "'."); } diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 2922631aa..f912e8291 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -38,7 +38,7 @@ using namespace icinga; boost::signals2::signal Checkable::OnNewCheckResult; boost::signals2::signal Checkable::OnStateChange; boost::signals2::signal, const MessageOrigin::Ptr&)> Checkable::OnReachabilityChanged; -boost::signals2::signal Checkable::OnNotificationsRequested; +boost::signals2::signal Checkable::OnNotificationsRequested; boost::signals2::signal Checkable::OnNextCheckUpdated; boost::mutex Checkable::m_StatsMutex; @@ -368,26 +368,30 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig (is_volatile && !(IsStateOK(old_state) && IsStateOK(new_state)))) ExecuteEventHandler(); - if (send_downtime_notification) - OnNotificationsRequested(this, in_downtime ? NotificationDowntimeStart : NotificationDowntimeEnd, cr, "", ""); + if (send_downtime_notification && !origin) + OnNotificationsRequested(this, in_downtime ? NotificationDowntimeStart : NotificationDowntimeEnd, cr, "", "", MessageOrigin::Ptr()); if (send_notification) { if (!was_flapping && is_flapping) { - OnNotificationsRequested(this, NotificationFlappingStart, cr, "", ""); + if (!IsPaused()) + OnNotificationsRequested(this, NotificationFlappingStart, cr, "", "", MessageOrigin::Ptr()); Log(LogNotice, "Checkable") << "Flapping: Checkable " << GetName() << " started flapping (" << GetFlappingThreshold() << "% < " << GetFlappingCurrent() << "%)."; NotifyFlapping(origin); } else if (was_flapping && !is_flapping) { - OnNotificationsRequested(this, NotificationFlappingEnd, cr, "", ""); + if (!IsPaused()) + OnNotificationsRequested(this, NotificationFlappingEnd, cr, "", "", MessageOrigin::Ptr()); Log(LogNotice, "Checkable") << "Flapping: Checkable " << GetName() << " stopped flapping (" << GetFlappingThreshold() << "% >= " << GetFlappingCurrent() << "%)."; NotifyFlapping(origin); - } else if (!was_flapping && !is_flapping) - OnNotificationsRequested(this, recovery ? NotificationRecovery : NotificationProblem, cr, "", ""); + } else if (!was_flapping && !is_flapping) { + if (!IsPaused()) + OnNotificationsRequested(this, recovery ? NotificationRecovery : NotificationProblem, cr, "", "", MessageOrigin::Ptr()); + } } } diff --git a/lib/icinga/checkable-notification.cpp b/lib/icinga/checkable-notification.cpp index 91d9cad40..b0d3f8e81 100644 --- a/lib/icinga/checkable-notification.cpp +++ b/lib/icinga/checkable-notification.cpp @@ -73,7 +73,8 @@ void Checkable::SendNotifications(NotificationType type, const CheckResult::Ptr& BOOST_FOREACH(const Notification::Ptr& notification, notifications) { try { - notification->BeginExecuteNotification(type, cr, force, author, text); + if (!notification->IsPaused()) + notification->BeginExecuteNotification(type, cr, force, author, text); } catch (const std::exception& ex) { Log(LogWarning, "Checkable") << "Exception occured during notification for service '" diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index 53db31da3..dbf1305e1 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -97,8 +97,8 @@ void Checkable::AcknowledgeProblem(const String& author, const String& comment, SetAcknowledgementRaw(type); SetAcknowledgementExpiry(expiry); - if (notify) - OnNotificationsRequested(this, NotificationAcknowledgement, GetLastCheckResult(), author, comment); + if (notify && !IsPaused()) + OnNotificationsRequested(this, NotificationAcknowledgement, GetLastCheckResult(), author, comment, MessageOrigin::Ptr()); OnAcknowledgementSet(this, author, comment, type, notify, expiry, origin); } diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index 9abc19afe..21e55bc25 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -110,7 +110,7 @@ public: static boost::signals2::signal OnStateChange; static boost::signals2::signal, const MessageOrigin::Ptr&)> OnReachabilityChanged; static boost::signals2::signal OnNotificationsRequested; + const String&, const String&, const MessageOrigin::Ptr&)> OnNotificationsRequested; static boost::signals2::signal&, const NotificationType&, const CheckResult::Ptr&, const String&, const String&)> OnNotificationSendStart; diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 114e38cae..c97f7bbc0 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -48,6 +48,7 @@ REGISTER_APIFUNCTION(SetAcknowledgement, event, &ClusterEvents::AcknowledgementS REGISTER_APIFUNCTION(ClearAcknowledgement, event, &ClusterEvents::AcknowledgementClearedAPIHandler); REGISTER_APIFUNCTION(UpdateRepository, event, &ClusterEvents::UpdateRepositoryAPIHandler); REGISTER_APIFUNCTION(ExecuteCommand, event, &ClusterEvents::ExecuteCommandAPIHandler); +REGISTER_APIFUNCTION(SendNotifications, event, &ClusterEvents::SendNotificationsAPIHandler); static Timer::Ptr l_RepositoryTimer; @@ -58,6 +59,7 @@ void ClusterEvents::StaticInitialize(void) Notification::OnNextNotificationChanged.connect(&ClusterEvents::NextNotificationChangedHandler); Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler); Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler); + Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler); Checkable::OnAcknowledgementSet.connect(&ClusterEvents::AcknowledgementSetHandler); Checkable::OnAcknowledgementCleared.connect(&ClusterEvents::AcknowledgementClearedHandler); @@ -756,3 +758,73 @@ Value ClusterEvents::UpdateRepositoryAPIHandler(const MessageOrigin::Ptr& origin return Empty; } + +void ClusterEvents::SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, + const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin) +{ + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (!listener) + return; + + Dictionary::Ptr message = MakeCheckResultMessage(checkable, cr); + message->Set("method", "event::SendNotifications"); + + Dictionary::Ptr params = message->Get("params"); + params->Set("type", type); + params->Set("author", author); + params->Set("text", text); + + listener->RelayMessage(origin, checkable, message, true); +} + +Value ClusterEvents::SendNotificationsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params) +{ + Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint(); + + if (!endpoint) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'send notification' message from '" << origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed)."; + return Empty; + } + + if (!params) + return Empty; + + Host::Ptr host = Host::GetByName(params->Get("host")); + + if (!host) + return Empty; + + Checkable::Ptr checkable; + + if (params->Contains("service")) + checkable = host->GetServiceByShortName(params->Get("service")); + else + checkable = host; + + if (!checkable) + return Empty; + + if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) { + Log(LogNotice, "ClusterEvents") + << "Discarding 'send custom notification' message from '" << origin->FromClient->GetIdentity() << "': Unauthorized access."; + return Empty; + } + + CheckResult::Ptr cr = new CheckResult(); + + Dictionary::Ptr vcr = params->Get("cr"); + Array::Ptr vperf = vcr->Get("performance_data"); + vcr->Remove("performance_data"); + + Deserialize(cr, params->Get("cr"), true); + + NotificationType type = static_cast(static_cast(params->Get("type"))); + String author = params->Get("author"); + String text = params->Get("text"); + + Checkable::OnNotificationsRequested(checkable, type, cr, author, text, origin); + + return Empty; +} diff --git a/lib/icinga/clusterevents.hpp b/lib/icinga/clusterevents.hpp index df1faf051..56a8bd49f 100644 --- a/lib/icinga/clusterevents.hpp +++ b/lib/icinga/clusterevents.hpp @@ -66,6 +66,10 @@ public: static Value UpdateRepositoryAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Dictionary::Ptr MakeCheckResultMessage(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); + + static void SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, + const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin); + static Value SendNotificationsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); }; } diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index c9c921c41..01bba2840 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -1290,7 +1290,8 @@ void ExternalCommandProcessor::SendCustomHostNotification(double, const std::vec host->SetForceNextNotification(true); } - Checkable::OnNotificationsRequested(host, NotificationCustom, host->GetLastCheckResult(), arguments[2], arguments[3]); + Checkable::OnNotificationsRequested(host, NotificationCustom, + host->GetLastCheckResult(), arguments[2], arguments[3], MessageOrigin::Ptr()); } void ExternalCommandProcessor::SendCustomSvcNotification(double, const std::vector& arguments) @@ -1309,7 +1310,8 @@ void ExternalCommandProcessor::SendCustomSvcNotification(double, const std::vect service->SetForceNextNotification(true); } - Service::OnNotificationsRequested(service, NotificationCustom, service->GetLastCheckResult(), arguments[3], arguments[4]); + Service::OnNotificationsRequested(service, NotificationCustom, + service->GetLastCheckResult(), arguments[3], arguments[4], MessageOrigin::Ptr()); } void ExternalCommandProcessor::DelayHostNotification(double, const std::vector& arguments) diff --git a/lib/notification/notificationcomponent.cpp b/lib/notification/notificationcomponent.cpp index abf1d7d75..aafa2815d 100644 --- a/lib/notification/notificationcomponent.cpp +++ b/lib/notification/notificationcomponent.cpp @@ -131,8 +131,5 @@ void NotificationComponent::NotificationTimerHandler(void) void NotificationComponent::SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type, const CheckResult::Ptr& cr, const String& author, const String& text) { - if (checkable->IsPaused() && GetEnableHA()) - return; - checkable->SendNotifications(type, cr, author, text); } -- 2.50.0