Notification#BeginExecuteNotification(): on recovery clear last_notified_state_per_user

This commit is contained in:
Alexander A. Klimov 2023-12-12 15:55:04 +01:00
parent 44e9c6f40d
commit 97cd05db7a
7 changed files with 125 additions and 11 deletions

View File

@ -1550,6 +1550,40 @@ Message updates will be dropped when:
* Notification does not exist. * Notification does not exist.
* Origin endpoint is not within the local zone. * Origin endpoint is not within the local zone.
#### event::ClearLastNotifiedStatePerUser <a id="technical-concepts-json-rpc-messages-event-clearlastnotifiedstateperuser"></a>
> Location: `clusterevents.cpp`
##### Message Body
Key | Value
----------|---------
jsonrpc | 2.0
method | event::ClearLastNotifiedStatePerUser
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::OnLastNotifiedStatePerUserCleared`
Event Receiver: `LastNotifiedStatePerUserClearedAPIHandler`
##### 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> #### event::SetForceNextCheck <a id="technical-concepts-json-rpc-messages-event-setforcenextcheck"></a>
> Location: `clusterevents.cpp` > Location: `clusterevents.cpp`

View File

@ -30,6 +30,7 @@ REGISTER_APIFUNCTION(SetSuppressedNotifications, event, &ClusterEvents::Suppress
REGISTER_APIFUNCTION(SetSuppressedNotificationTypes, event, &ClusterEvents::SuppressedNotificationTypesChangedAPIHandler); REGISTER_APIFUNCTION(SetSuppressedNotificationTypes, event, &ClusterEvents::SuppressedNotificationTypesChangedAPIHandler);
REGISTER_APIFUNCTION(SetNextNotification, event, &ClusterEvents::NextNotificationChangedAPIHandler); REGISTER_APIFUNCTION(SetNextNotification, event, &ClusterEvents::NextNotificationChangedAPIHandler);
REGISTER_APIFUNCTION(UpdateLastNotifiedStatePerUser, event, &ClusterEvents::LastNotifiedStatePerUserUpdatedAPIHandler); REGISTER_APIFUNCTION(UpdateLastNotifiedStatePerUser, event, &ClusterEvents::LastNotifiedStatePerUserUpdatedAPIHandler);
REGISTER_APIFUNCTION(ClearLastNotifiedStatePerUser, event, &ClusterEvents::LastNotifiedStatePerUserClearedAPIHandler);
REGISTER_APIFUNCTION(SetForceNextCheck, event, &ClusterEvents::ForceNextCheckChangedAPIHandler); REGISTER_APIFUNCTION(SetForceNextCheck, event, &ClusterEvents::ForceNextCheckChangedAPIHandler);
REGISTER_APIFUNCTION(SetForceNextNotification, event, &ClusterEvents::ForceNextNotificationChangedAPIHandler); REGISTER_APIFUNCTION(SetForceNextNotification, event, &ClusterEvents::ForceNextNotificationChangedAPIHandler);
REGISTER_APIFUNCTION(SetAcknowledgement, event, &ClusterEvents::AcknowledgementSetAPIHandler); REGISTER_APIFUNCTION(SetAcknowledgement, event, &ClusterEvents::AcknowledgementSetAPIHandler);
@ -52,6 +53,7 @@ void ClusterEvents::StaticInitialize()
Notification::OnSuppressedNotificationsChanged.connect(&ClusterEvents::SuppressedNotificationTypesChangedHandler); Notification::OnSuppressedNotificationsChanged.connect(&ClusterEvents::SuppressedNotificationTypesChangedHandler);
Notification::OnNextNotificationChanged.connect(&ClusterEvents::NextNotificationChangedHandler); Notification::OnNextNotificationChanged.connect(&ClusterEvents::NextNotificationChangedHandler);
Notification::OnLastNotifiedStatePerUserUpdated.connect(&ClusterEvents::LastNotifiedStatePerUserUpdatedHandler); Notification::OnLastNotifiedStatePerUserUpdated.connect(&ClusterEvents::LastNotifiedStatePerUserUpdatedHandler);
Notification::OnLastNotifiedStatePerUserCleared.connect(&ClusterEvents::LastNotifiedStatePerUserClearedHandler);
Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler); Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler);
Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler); Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler);
Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler); Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler);
@ -589,6 +591,57 @@ Value ClusterEvents::LastNotifiedStatePerUserUpdatedAPIHandler(const MessageOrig
return Empty; return Empty;
} }
void ClusterEvents::LastNotifiedStatePerUserClearedHandler(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::ClearLastNotifiedStatePerUser");
message->Set("params", params);
listener->RelayMessage(origin, notification, message, true);
}
Value ClusterEvents::LastNotifiedStatePerUserClearedAPIHandler(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::OnLastNotifiedStatePerUserCleared(notification, origin);
return Empty;
}
void ClusterEvents::ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin) void ClusterEvents::ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin)
{ {
ApiListener::Ptr listener = ApiListener::GetInstance(); ApiListener::Ptr listener = ApiListener::GetInstance();

View File

@ -44,6 +44,9 @@ public:
static void LastNotifiedStatePerUserUpdatedHandler(const Notification::Ptr& notification, const String& user, uint_fast8_t state, const MessageOrigin::Ptr& origin); static void LastNotifiedStatePerUserUpdatedHandler(const Notification::Ptr& notification, const String& user, uint_fast8_t state, const MessageOrigin::Ptr& origin);
static Value LastNotifiedStatePerUserUpdatedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Value LastNotifiedStatePerUserUpdatedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
static void LastNotifiedStatePerUserClearedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin);
static Value LastNotifiedStatePerUserClearedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
static void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin); static void ForceNextCheckChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin);
static Value ForceNextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); static Value ForceNextCheckChangedAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);

View File

@ -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 MessageOrigin::Ptr&)> Notification::OnNextNotificationChanged;
boost::signals2::signal<void (const Notification::Ptr&, const String&, uint_fast8_t, const MessageOrigin::Ptr&)> Notification::OnLastNotifiedStatePerUserUpdated; boost::signals2::signal<void (const Notification::Ptr&, const String&, uint_fast8_t, const MessageOrigin::Ptr&)> Notification::OnLastNotifiedStatePerUserUpdated;
boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> Notification::OnLastNotifiedStatePerUserCleared;
String NotificationNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const String NotificationNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
{ {
@ -232,6 +233,13 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
<< "notifications of type '" << notificationTypeName << "notifications of type '" << notificationTypeName
<< "' for notification object '" << notificationName << "'."; << "' for notification object '" << notificationName << "'.";
if (type == NotificationRecovery) {
auto states (GetLastNotifiedStatePerUser());
states->Clear();
OnLastNotifiedStatePerUserCleared(this, nullptr);
}
Checkable::Ptr checkable = GetCheckable(); Checkable::Ptr checkable = GetCheckable();
if (!force) { if (!force) {
@ -469,19 +477,14 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
/* collect all notified users */ /* collect all notified users */
allNotifiedUsers.insert(user); allNotifiedUsers.insert(user);
switch (type) { if (type == NotificationProblem) {
case NotificationProblem: auto [host, service] = GetHostService(checkable);
case NotificationRecovery: { uint_fast8_t state = service ? service->GetState() : host->GetState();
auto [host, service] = GetHostService(checkable);
uint_fast8_t state = service ? service->GetState() : host->GetState();
if (state != (uint_fast8_t)GetLastNotifiedStatePerUser()->Get(userName)) { if (state != (uint_fast8_t)GetLastNotifiedStatePerUser()->Get(userName)) {
GetLastNotifiedStatePerUser()->Set(userName, state); GetLastNotifiedStatePerUser()->Set(userName, state);
OnLastNotifiedStatePerUserUpdated(this, userName, state, nullptr); OnLastNotifiedStatePerUserUpdated(this, userName, state, nullptr);
}
} }
default:
;
} }
/* store all notified users for later recovery checks */ /* store all notified users for later recovery checks */

View File

@ -94,6 +94,7 @@ public:
static boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> OnNextNotificationChanged; 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&)> OnLastNotifiedStatePerUserUpdated; static boost::signals2::signal<void (const Notification::Ptr&, const String&, uint_fast8_t, const MessageOrigin::Ptr&)> OnLastNotifiedStatePerUserUpdated;
static boost::signals2::signal<void (const Notification::Ptr&, const MessageOrigin::Ptr&)> OnLastNotifiedStatePerUserCleared;
void Validate(int types, const ValidationUtils& utils) override; void Validate(int types, const ValidationUtils& utils) override;

View File

@ -141,6 +141,8 @@ add_boost_test(base
icinga_notification/no_filter_problem_no_duplicate icinga_notification/no_filter_problem_no_duplicate
icinga_notification/filter_problem_no_duplicate icinga_notification/filter_problem_no_duplicate
icinga_notification/volatile_filter_problem_duplicate icinga_notification/volatile_filter_problem_duplicate
icinga_notification/no_recovery_filter_no_duplicate
icinga_notification/recovery_filter_duplicate
icinga_macros/simple icinga_macros/simple
icinga_legacytimeperiod/simple icinga_legacytimeperiod/simple
icinga_legacytimeperiod/advanced icinga_legacytimeperiod/advanced

View File

@ -194,4 +194,22 @@ BOOST_AUTO_TEST_CASE(volatile_filter_problem_duplicate)
helper.SendStateNotification(ServiceCritical, true); helper.SendStateNotification(ServiceCritical, true);
} }
BOOST_AUTO_TEST_CASE(no_recovery_filter_no_duplicate)
{
DuplicateDueToFilterHelper helper (~0, ~0);
helper.SendStateNotification(ServiceCritical, true);
helper.SendStateNotification(ServiceOK, true);
helper.SendStateNotification(ServiceCritical, true);
}
BOOST_AUTO_TEST_CASE(recovery_filter_duplicate)
{
DuplicateDueToFilterHelper helper (~NotificationRecovery, ~0);
helper.SendStateNotification(ServiceCritical, true);
helper.SendStateNotification(ServiceOK, false);
helper.SendStateNotification(ServiceCritical, true);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()