Skip to content

Commit

Permalink
Stash notifications until object authority has been updated once
Browse files Browse the repository at this point in the history
refs #7086
  • Loading branch information
Al2Klimov committed Jul 8, 2019
1 parent 536dbbf commit 40c69b9
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 16 deletions.
52 changes: 42 additions & 10 deletions lib/icinga/checkable-notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

#include "icinga/checkable.hpp"
#include "icinga/icingaapplication.hpp"
#include "base/dictionary.hpp"
#include "base/objectlock.hpp"
#include "base/logger.hpp"
#include "base/exception.hpp"
#include "base/context.hpp"
#include "base/convert.hpp"
#include "remote/apilistener.hpp"

using namespace icinga;

Expand Down Expand Up @@ -52,17 +54,47 @@ void Checkable::SendNotifications(NotificationType type, const CheckResult::Ptr&
return;

for (const Notification::Ptr& notification : notifications) {
try {
if (!notification->IsPaused()) {
notification->BeginExecuteNotification(type, cr, force, false, author, text);
} else {
Log(LogNotice, "Notification")
<< "Notification '" << notification->GetName() << "': HA cluster active, this endpoint does not have the authority (paused=true). Skipping.";
if (ApiListener::UpdatedObjectAuthority()) {
try {
if (!notification->IsPaused()) {
auto stashedNotifications (notification->GetStashedNotifications());

if (stashedNotifications->GetLength()) {
Log(LogNotice, "Notification")
<< "Notification '" << notification->GetName() << "': there are some stashed notifications. Stashing notification to preserve order.";

stashedNotifications->Add(new Dictionary({
{"type", type},
{"cr", cr},
{"force", force},
{"reminder", false},
{"author", author},
{"text", text}
}));
} else {
notification->BeginExecuteNotification(type, cr, force, false, author, text);
}
} else {
Log(LogNotice, "Notification")
<< "Notification '" << notification->GetName() << "': HA cluster active, this endpoint does not have the authority (paused=true). Skipping.";
}
} catch (const std::exception& ex) {
Log(LogWarning, "Checkable")
<< "Exception occurred during notification '" << notification->GetName() << "' for checkable '"
<< GetName() << "': " << DiagnosticInformation(ex, false);
}
} catch (const std::exception& ex) {
Log(LogWarning, "Checkable")
<< "Exception occurred during notification '" << notification->GetName() << "' for checkable '"
<< GetName() << "': " << DiagnosticInformation(ex, false);
} else {
Log(LogNotice, "Notification")
<< "Notification '" << notification->GetName() << "': object authority hasn't been updated, yet. Stashing notification.";

notification->GetStashedNotifications()->Add(new Dictionary({
{"type", type},
{"cr", cr},
{"force", force},
{"reminder", false},
{"author", author},
{"text", text}
}));
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions lib/icinga/notification.ti
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class Notification : CustomVarObject < NotificationNameComposer
default {{{ return false; }}}
};

[state, no_user_view, no_user_modify] Array::Ptr stashed_notifications {
default {{{ return new Array(); }}}
};

[state] Timestamp last_notification;
[state] Timestamp next_notification;
[state] int notification_number;
Expand Down
62 changes: 56 additions & 6 deletions lib/notification/notificationcomponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/utility.hpp"
#include "base/exception.hpp"
#include "base/statsfunction.hpp"
#include "remote/apilistener.hpp"

using namespace icinga;

Expand Down Expand Up @@ -72,19 +73,70 @@ void NotificationComponent::NotificationTimerHandler()
continue;

String notificationName = notification->GetName();
bool updatedObjectAuthority = ApiListener::UpdatedObjectAuthority();

/* Skip notification if paused, in a cluster setup & HA feature is enabled. */
if (notification->IsPaused() && myEndpoint && GetEnableHA()) {
Log(LogNotice, "NotificationComponent")
<< "Reminder notification '" << notificationName << "': HA cluster active, this endpoint does not have the authority (paused=true). Skipping.";
continue;
if (notification->IsPaused()) {
if (updatedObjectAuthority) {
auto stashedNotifications (notification->GetStashedNotifications());
ObjectLock olock(stashedNotifications);

if (stashedNotifications->GetLength()) {
Log(LogNotice, "NotificationComponent")
<< "Notification '" << notificationName << "': HA cluster active, this endpoint does not have the authority. Dropping all stashed notifications.";

stashedNotifications->Clear();
}
}

if (myEndpoint && GetEnableHA()) {
Log(LogNotice, "NotificationComponent")
<< "Reminder notification '" << notificationName << "': HA cluster active, this endpoint does not have the authority (paused=true). Skipping.";
continue;
}
}

Checkable::Ptr checkable = notification->GetCheckable();

if (!IcingaApplication::GetInstance()->GetEnableNotifications() || !checkable->GetEnableNotifications())
continue;

bool reachable = checkable->IsReachable(DependencyNotification);

if (reachable) {
Array::Ptr unstashedNotifications = new Array();

{
auto stashedNotifications (notification->GetStashedNotifications());
ObjectLock olock(stashedNotifications);

stashedNotifications->CopyTo(unstashedNotifications);
stashedNotifications->Clear();
}

ObjectLock olock(unstashedNotifications);

for (Dictionary::Ptr unstashedNotification : unstashedNotifications) {
try {
Log(LogNotice, "NotificationComponent")
<< "Attempting to send stashed notification '" << notificationName << "'.";

notification->BeginExecuteNotification(
(NotificationType)(int)unstashedNotification->Get("type"),
(CheckResult::Ptr)unstashedNotification->Get("cr"),
(bool)unstashedNotification->Get("force"),
(bool)unstashedNotification->Get("reminder"),
(String)unstashedNotification->Get("author"),
(String)unstashedNotification->Get("text")
);
} catch (const std::exception& ex) {
Log(LogWarning, "NotificationComponent")
<< "Exception occurred during notification for object '"
<< notificationName << "': " << DiagnosticInformation(ex, false);
}
}
}

if (notification->GetInterval() <= 0 && notification->GetNoMoreNotifications()) {
Log(LogNotice, "NotificationComponent")
<< "Reminder notification '" << notificationName << "': Notification was sent out once and interval=0 disables reminder notifications.";
Expand All @@ -94,8 +146,6 @@ void NotificationComponent::NotificationTimerHandler()
if (notification->GetNextNotification() > now)
continue;

bool reachable = checkable->IsReachable(DependencyNotification);

{
ObjectLock olock(notification);
notification->SetNextNotification(Utility::GetTime() + notification->GetInterval());
Expand Down

0 comments on commit 40c69b9

Please sign in to comment.