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);
}