Skip to content

Commit

Permalink
Notification#BeginExecuteNotification(): on recovery clear last_notif…
Browse files Browse the repository at this point in the history
…ied_state_per_user
  • Loading branch information
Al2Klimov committed Nov 24, 2023
1 parent 644982f commit 4b51ec9
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 11 deletions.
34 changes: 34 additions & 0 deletions doc/19-technical-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,40 @@ Message updates will be dropped when:
* Notification does not exist.
* Origin endpoint is not within the local zone.
#### event::ClearLastNotifiedStates <a id="technical-concepts-json-rpc-messages-event-clearlastnotifiedstates"></a>
> Location: `clusterevents.cpp`
##### Message Body
Key | Value
----------|---------
jsonrpc | 2.0
method | event::ClearLastNotifiedStates
params | Dictionary
##### Params
Key | Type | Description
-------------|--------|------------------
notification | String | Notification name
Used to sync the state of a notification object within the same HA zone.
##### Functions
Event Sender: `Notification::OnLastNotifiedStatesCleared`
Event Receiver: `LastNotifiedStatesClearedAPIHandler`
##### Permissions
The receiver will not process messages from not configured endpoints.
Message updates will be dropped when:
* Notification does not exist.
* Origin endpoint is not within the local zone.
#### event::SetForceNextCheck <a id="technical-concepts-json-rpc-messages-event-setforcenextcheck"></a>
> Location: `clusterevents.cpp`
Expand Down
53 changes: 53 additions & 0 deletions lib/icinga/clusterevents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ REGISTER_APIFUNCTION(SetSuppressedNotifications, event, &ClusterEvents::Suppress
REGISTER_APIFUNCTION(SetSuppressedNotificationTypes, event, &ClusterEvents::SuppressedNotificationTypesChangedAPIHandler);
REGISTER_APIFUNCTION(SetNextNotification, event, &ClusterEvents::NextNotificationChangedAPIHandler);
REGISTER_APIFUNCTION(UpdateLastNotifiedStateOfUser, event, &ClusterEvents::LastNotifiedStateOfUserUpdatedAPIHandler);
REGISTER_APIFUNCTION(ClearLastNotifiedStates, event, &ClusterEvents::LastNotifiedStatesClearedAPIHandler);
REGISTER_APIFUNCTION(SetForceNextCheck, event, &ClusterEvents::ForceNextCheckChangedAPIHandler);
REGISTER_APIFUNCTION(SetForceNextNotification, event, &ClusterEvents::ForceNextNotificationChangedAPIHandler);
REGISTER_APIFUNCTION(SetAcknowledgement, event, &ClusterEvents::AcknowledgementSetAPIHandler);
Expand All @@ -52,6 +53,7 @@ void ClusterEvents::StaticInitialize()
Notification::OnSuppressedNotificationsChanged.connect(&ClusterEvents::SuppressedNotificationTypesChangedHandler);
Notification::OnNextNotificationChanged.connect(&ClusterEvents::NextNotificationChangedHandler);
Notification::OnLastNotifiedStateOfUserUpdated.connect(&ClusterEvents::LastNotifiedStateOfUserUpdatedHandler);
Notification::OnLastNotifiedStatesCleared.connect(&ClusterEvents::LastNotifiedStatesClearedHandler);
Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler);
Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler);
Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler);
Expand Down Expand Up @@ -589,6 +591,57 @@ Value ClusterEvents::LastNotifiedStateOfUserUpdatedAPIHandler(const MessageOrigi
return Empty;
}

void ClusterEvents::LastNotifiedStatesClearedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin)
{
auto listener (ApiListener::GetInstance());

if (!listener) {
return;
}

Dictionary::Ptr params = new Dictionary();
params->Set("notification", notification->GetName());

Dictionary::Ptr message = new Dictionary();
message->Set("jsonrpc", "2.0");
message->Set("method", "event::ClearLastNotifiedStates");
message->Set("params", params);

listener->RelayMessage(origin, notification, message, true);
}

Value ClusterEvents::LastNotifiedStatesClearedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
{
auto endpoint (origin->FromClient->GetEndpoint());

if (!endpoint) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'last notified state of user cleared' message from '"
<< origin->FromClient->GetIdentity() << "': Invalid endpoint origin (client not allowed).";

return Empty;
}

if (origin->FromZone && origin->FromZone != Zone::GetLocalZone()) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'last notified state of user cleared' message from '"
<< origin->FromClient->GetIdentity() << "': Unauthorized access.";

return Empty;
}

auto notification (Notification::GetByName(params->Get("notification")));

if (!notification) {
return Empty;
}

notification->GetLastNotifiedStatePerUser()->Clear();
Notification::OnLastNotifiedStatesCleared(notification, origin);

return Empty;
}

void ClusterEvents::ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin)
{
ApiListener::Ptr listener = ApiListener::GetInstance();
Expand Down
3 changes: 3 additions & 0 deletions lib/icinga/clusterevents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class ClusterEvents
static void LastNotifiedStateOfUserUpdatedHandler(const Notification::Ptr& notification, const String& user, uint_fast8_t state, const MessageOrigin::Ptr& origin);
static Value LastNotifiedStateOfUserUpdatedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);

static void LastNotifiedStatesClearedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin);
static Value LastNotifiedStatesClearedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);

static void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin);
static Value ForceNextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);

Expand Down
25 changes: 14 additions & 11 deletions lib/icinga/notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ std::map<String, int> Notification::m_TypeFilterMap;

boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> Notification::OnNextNotificationChanged;
boost::signals2::signal<void (const Notification::Ptr&, const String&, uint_fast8_t, const MessageOrigin::Ptr&)> Notification::OnLastNotifiedStateOfUserUpdated;
boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> Notification::OnLastNotifiedStatesCleared;

String NotificationNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
{
Expand Down Expand Up @@ -232,6 +233,13 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
<< "notifications of type '" << notificationTypeName
<< "' for notification object '" << notificationName << "'.";

if (type == NotificationRecovery) {
auto states (GetLastNotifiedStatePerUser());

states->Clear();
OnLastNotifiedStatesCleared(this, nullptr);
}

Checkable::Ptr checkable = GetCheckable();

if (!force) {
Expand Down Expand Up @@ -469,19 +477,14 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
/* collect all notified users */
allNotifiedUsers.insert(user);

switch (type) {
case NotificationProblem:
case NotificationRecovery: {
auto [host, service] = GetHostService(checkable);
uint_fast8_t state = service ? service->GetState() : host->GetState();
if (type == NotificationProblem) {
auto [host, service] = GetHostService(checkable);
uint_fast8_t state = service ? service->GetState() : host->GetState();

if (state != GetLastNotifiedStatePerUser()->Get(userName)) {
GetLastNotifiedStatePerUser()->Set(userName, state);
OnLastNotifiedStateOfUserUpdated(this, userName, state, nullptr);
}
if (state != GetLastNotifiedStatePerUser()->Get(userName)) {
GetLastNotifiedStatePerUser()->Set(userName, state);
OnLastNotifiedStateOfUserUpdated(this, userName, state, nullptr);
}
default:
;
}

/* store all notified users for later recovery checks */
Expand Down
1 change: 1 addition & 0 deletions lib/icinga/notification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class Notification final : public ObjectImpl<Notification>

static boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> OnNextNotificationChanged;
static boost::signals2::signal<void (const Notification::Ptr&, const String&, uint_fast8_t, const MessageOrigin::Ptr&)> OnLastNotifiedStateOfUserUpdated;
static boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> OnLastNotifiedStatesCleared;

void Validate(int types, const ValidationUtils& utils) override;

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ add_boost_test(base
icinga_notification/state_filter
icinga_notification/type_filter
icinga_notification/duplicate_dueto_filter
icinga_notification/duplicate_dueto_filter_recovery
icinga_macros/simple
icinga_legacytimeperiod/simple
icinga_legacytimeperiod/advanced
Expand Down
35 changes: 35 additions & 0 deletions test/icinga-notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,39 @@ BOOST_AUTO_TEST_CASE(duplicate_dueto_filter)
BOOST_CHECK(helper.called == 1u);
}

BOOST_AUTO_TEST_CASE(duplicate_dueto_filter_recovery)
{
DuplicateDueToFilterHelper helper;

helper.s->SetState(ServiceCritical, true);
Application::GetTP().Start();
helper.n->BeginExecuteNotification(NotificationProblem, nullptr, false, false, "", "");
Application::GetTP().Stop();
BOOST_CHECK(helper.called == 1u);

helper.s->SetState(ServiceWarning, true);
Application::GetTP().Start();
helper.n->BeginExecuteNotification(NotificationProblem, nullptr, false, false, "", "");
Application::GetTP().Stop();
BOOST_CHECK(helper.called == 1u);

helper.s->SetState(ServiceCritical, true);
Application::GetTP().Start();
helper.n->BeginExecuteNotification(NotificationProblem, nullptr, false, false, "", "");
Application::GetTP().Stop();
BOOST_CHECK(helper.called == 1u);

helper.s->SetState(ServiceOK, true);
Application::GetTP().Start();
helper.n->BeginExecuteNotification(NotificationRecovery, nullptr, false, false, "", "");
Application::GetTP().Stop();
BOOST_CHECK(helper.called == 1u);

helper.s->SetState(ServiceCritical, true);
Application::GetTP().Start();
helper.n->BeginExecuteNotification(NotificationProblem, nullptr, false, false, "", "");
Application::GetTP().Stop();
BOOST_CHECK(helper.called == 2u);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 4b51ec9

Please sign in to comment.