]> granicus.if.org Git - icinga2/commitdiff
Ensure that sent notifications are synced between Icinga instances
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 15 Jun 2016 09:27:01 +0000 (11:27 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 15 Jun 2016 09:27:01 +0000 (11:27 +0200)
fixes #11562

lib/icinga/apievents.cpp
lib/icinga/apievents.hpp
lib/icinga/checkable-notification.cpp
lib/icinga/checkable.hpp
lib/icinga/clusterevents.cpp
lib/icinga/clusterevents.hpp
lib/icinga/notification.cpp
lib/icinga/notification.ti

index e2844a78f4b08e37b174d3b603dcc9ac7d61162b..d04032c7c5e6212ba55477b0b5fe72119c5983db 100644 (file)
@@ -107,7 +107,7 @@ void ApiEvents::StateChangeHandler(const Checkable::Ptr& checkable, const CheckR
 
 void ApiEvents::NotificationSentToAllUsersHandler(const Notification::Ptr& notification,
     const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
-    const CheckResult::Ptr& cr, const String& author, const String& text)
+    const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin)
 {
        std::vector<EventQueue::Ptr> queues = EventQueue::GetQueuesForType("Notification");
 
index a60e777ac7da04b43dad6e0c413617f4df4ed910..dfbd64c3d7d0d56cedc5279108e0f1ad636b81ad 100644 (file)
@@ -40,7 +40,7 @@ public:
 
        static void NotificationSentToAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable,
            const std::set<User::Ptr>& users, NotificationType type, const CheckResult::Ptr& cr, const String& author,
-           const String& text);
+           const String& text, const MessageOrigin::Ptr& origin);
 
        static void FlappingChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin);
 
index b0d3f8e81884703264243ae21f272137f57c1080..5dc22f1d72ab01c136f7d7de637840c2ac723b10 100644 (file)
 using namespace icinga;
 
 boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
-    const NotificationType&, const CheckResult::Ptr&, const String&, const String&)> Checkable::OnNotificationSentToAllUsers;
-boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
-    const NotificationType&, const CheckResult::Ptr&, const String&, const String&)> Checkable::OnNotificationSendStart;
+    const NotificationType&, const CheckResult::Ptr&, const String&, const String&,
+    const MessageOrigin::Ptr&)> Checkable::OnNotificationSentToAllUsers;
 boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const User::Ptr&,
-    const NotificationType&, const CheckResult::Ptr&, const String&, const String&, const String&)> Checkable::OnNotificationSentToUser;
+    const NotificationType&, const CheckResult::Ptr&, const String&, const String&, const String&,
+    const MessageOrigin::Ptr&)> Checkable::OnNotificationSentToUser;
 
 void Checkable::ResetNotificationNumbers(void)
 {
index 21e55bc25e1ee3dc1fbbfe9fde0f5f1a827876b0..89dcefe76f200fa66d80947c41ce4345e11f2d6b 100644 (file)
@@ -111,15 +111,12 @@ public:
        static boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, std::set<Checkable::Ptr>, const MessageOrigin::Ptr&)> OnReachabilityChanged;
        static boost::signals2::signal<void (const Checkable::Ptr&, NotificationType, const CheckResult::Ptr&,
            const String&, const String&, const MessageOrigin::Ptr&)> OnNotificationsRequested;
-       static boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
-           const NotificationType&, const CheckResult::Ptr&, const String&,
-           const String&)> OnNotificationSendStart;
        static boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const User::Ptr&,
-           const NotificationType&, const CheckResult::Ptr&, const String&,
-           const String&, const String&)> OnNotificationSentToUser;
+           const NotificationType&, const CheckResult::Ptr&, const String&, const String&, const String&,
+           const MessageOrigin::Ptr&)> OnNotificationSentToUser;
        static boost::signals2::signal<void (const Notification::Ptr&, const Checkable::Ptr&, const std::set<User::Ptr>&,
            const NotificationType&, const CheckResult::Ptr&, const String&,
-           const String&)> OnNotificationSentToAllUsers;
+           const String&, const MessageOrigin::Ptr&)> OnNotificationSentToAllUsers;
        static boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType,
                                             bool, double, const MessageOrigin::Ptr&)> OnAcknowledgementSet;
        static boost::signals2::signal<void (const Checkable::Ptr&, const MessageOrigin::Ptr&)> OnAcknowledgementCleared;
index 9772109408c06e2b013266f36cb3fa7eac440e9d..6dbfe10487e8c40e6e52a9c4e46c42bf28d0cbd9 100644 (file)
@@ -49,6 +49,8 @@ REGISTER_APIFUNCTION(ClearAcknowledgement, event, &ClusterEvents::Acknowledgemen
 REGISTER_APIFUNCTION(UpdateRepository, event, &ClusterEvents::UpdateRepositoryAPIHandler);
 REGISTER_APIFUNCTION(ExecuteCommand, event, &ClusterEvents::ExecuteCommandAPIHandler);
 REGISTER_APIFUNCTION(SendNotifications, event, &ClusterEvents::SendNotificationsAPIHandler);
+REGISTER_APIFUNCTION(NotificationSentUser, event, &ClusterEvents::NotificationSentUserAPIHandler);
+REGISTER_APIFUNCTION(NotificationSentAllUsers, event, &ClusterEvents::NotificationSentAllUsersAPIHandler);
 
 static Timer::Ptr l_RepositoryTimer;
 
@@ -60,6 +62,8 @@ void ClusterEvents::StaticInitialize(void)
        Checkable::OnForceNextCheckChanged.connect(&ClusterEvents::ForceNextCheckChangedHandler);
        Checkable::OnForceNextNotificationChanged.connect(&ClusterEvents::ForceNextNotificationChangedHandler);
        Checkable::OnNotificationsRequested.connect(&ClusterEvents::SendNotificationsHandler);
+       Checkable::OnNotificationSentToUser.connect(&ClusterEvents::NotificationSentUserHandler);
+       Checkable::OnNotificationSentToAllUsers.connect(&ClusterEvents::NotificationSentAllUsersHandler);
 
        Checkable::OnAcknowledgementSet.connect(&ClusterEvents::AcknowledgementSetHandler);
        Checkable::OnAcknowledgementCleared.connect(&ClusterEvents::AcknowledgementClearedHandler);
@@ -828,3 +832,221 @@ Value ClusterEvents::SendNotificationsAPIHandler(const MessageOrigin::Ptr& origi
 
        return Empty;
 }
+
+void ClusterEvents::NotificationSentUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
+    NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const String& command,
+    const MessageOrigin::Ptr& origin)
+{
+       ApiListener::Ptr listener = ApiListener::GetInstance();
+
+       if (!listener)
+               return;
+
+       Host::Ptr host;
+       Service::Ptr service;
+       tie(host, service) = GetHostService(checkable);
+
+       Dictionary::Ptr params = new Dictionary();
+       params->Set("host", host->GetName());
+       if (service)
+               params->Set("service", service->GetShortName());
+       params->Set("notification", notification->GetName());
+       params->Set("user", user->GetName());
+       params->Set("type", notificationType);
+       params->Set("cr", Serialize(cr));
+       params->Set("author", author);
+       params->Set("text", commentText);
+       params->Set("command", command);
+
+       Dictionary::Ptr message = new Dictionary();
+       message->Set("jsonrpc", "2.0");
+       message->Set("method", "event::NotificationSentUser");
+       message->Set("params", params);
+
+       listener->RelayMessage(origin, ConfigObject::Ptr(), message, true);
+}
+
+Value ClusterEvents::NotificationSentUserAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+       Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint();
+
+       if (!endpoint) {
+               Log(LogNotice, "ClusterEvents")
+                   << "Discarding 'sent notification to user' 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 != Zone::GetLocalZone()) {
+               Log(LogNotice, "ClusterEvents")
+                   << "Discarding 'sent notification to user' 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<NotificationType>(static_cast<int>(params->Get("type")));
+       String author = params->Get("author");
+       String text = params->Get("text");
+
+       Notification::Ptr notification = Notification::GetByName(params->Get("notification"));
+
+       if (!notification)
+               return Empty;
+
+       User::Ptr user = User::GetByName(params->Get("user"));
+
+       if (!user)
+               return Empty;
+
+       String command = params->Get("command");
+
+       Checkable::OnNotificationSentToUser(notification, checkable, user, type, cr, author, text, command, origin);
+
+       return Empty;
+}
+
+void ClusterEvents::NotificationSentAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users,
+    NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const MessageOrigin::Ptr& origin)
+{
+       ApiListener::Ptr listener = ApiListener::GetInstance();
+
+       if (!listener)
+               return;
+
+       Host::Ptr host;
+       Service::Ptr service;
+       tie(host, service) = GetHostService(checkable);
+
+       Dictionary::Ptr params = new Dictionary();
+       params->Set("host", host->GetName());
+       if (service)
+               params->Set("service", service->GetShortName());
+       params->Set("notification", notification->GetName());
+
+       Array::Ptr ausers = new Array();
+       BOOST_FOREACH(const User::Ptr& user, users) {
+               ausers->Add(user->GetName());
+       }
+       params->Set("users", ausers);
+
+       params->Set("type", notificationType);
+       params->Set("cr", Serialize(cr));
+       params->Set("author", author);
+       params->Set("text", commentText);
+
+       params->Set("last_notification", notification->GetLastNotification());
+       params->Set("next_notifications", notification->GetNextNotification());
+       params->Set("notification_number", notification->GetNotificationNumber());
+       params->Set("last_problem_notification", notification->GetLastProblemNotification());
+
+       Dictionary::Ptr message = new Dictionary();
+       message->Set("jsonrpc", "2.0");
+       message->Set("method", "event::NotificationSentAllUsers");
+       message->Set("params", params);
+
+       listener->RelayMessage(origin, ConfigObject::Ptr(), message, true);
+}
+
+Value ClusterEvents::NotificationSentAllUsersAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+       Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint();
+
+       if (!endpoint) {
+               Log(LogNotice, "ClusterEvents")
+                   << "Discarding 'sent notification to all users' 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 != Zone::GetLocalZone()) {
+               Log(LogNotice, "ClusterEvents")
+                   << "Discarding 'sent notification to all users' 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<NotificationType>(static_cast<int>(params->Get("type")));
+       String author = params->Get("author");
+       String text = params->Get("text");
+
+       Notification::Ptr notification = Notification::GetByName(params->Get("notification"));
+
+       if (!notification)
+               return Empty;
+
+       Array::Ptr ausers = params->Get("users");
+
+       if (!ausers)
+               return Empty;
+
+       std::set<User::Ptr> users;
+
+       {
+               ObjectLock olock(ausers);
+               BOOST_FOREACH(const String& auser, ausers) {
+                       User::Ptr user = User::GetByName(auser);
+
+                       if (!user)
+                               continue;
+
+                       users.insert(user);
+               }
+       }
+
+       notification->SetLastNotification(params->Get("last_notification"));
+       notification->SetNextNotification(params->Get("next_notification"));
+       notification->SetNotificationNumber(params->Get("notification_number"));
+       notification->SetLastProblemNotification(params->Get("last_problem_notification"));
+
+       Checkable::OnNotificationSentToAllUsers(notification, checkable, users, type, cr, author, text, origin);
+
+       return Empty;
+}
index 56a8bd49f155defa5ec5f31928cab8884376daa8..3b9b7c4be286e7af690f8e5beb5d99cd9e4d7a60 100644 (file)
@@ -70,6 +70,14 @@ public:
        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);
+
+       static void NotificationSentUserHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
+           NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const String& command, const MessageOrigin::Ptr& origin);
+       static Value NotificationSentUserAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+
+       static void NotificationSentAllUsersHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users,
+           NotificationType notificationType, const CheckResult::Ptr& cr, const String& author, const String& commentText, const MessageOrigin::Ptr& origin);
+       static Value NotificationSentAllUsersAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
 };
 
 }
index 7d1f7247d22363ae3ccb6e938601e8fc8c473ef2..98b67676eec03ded487a30786d2158b1b2ab3674 100644 (file)
@@ -345,7 +345,11 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
                std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
        }
 
-       Service::OnNotificationSendStart(this, checkable, allUsers, type, cr, author, text);
+       {
+               ObjectLock olock(this);
+               UpdateNotificationNumber();
+               SetLastNotification(Utility::GetTime());
+       }
 
        std::set<User::Ptr> allNotifiedUsers;
        Array::Ptr notifiedUsers = GetNotifiedUsers();
@@ -392,7 +396,7 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
                notifiedUsers->Clear();
 
        /* used in db_ido for notification history */
-       Service::OnNotificationSentToAllUsers(this, checkable, allNotifiedUsers, type, cr, author, text);
+       Service::OnNotificationSentToAllUsers(this, checkable, allNotifiedUsers, type, cr, author, text, MessageOrigin::Ptr());
 }
 
 bool Notification::CheckNotificationUserFilters(NotificationType type, const User::Ptr& user, bool force)
@@ -474,14 +478,8 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
 
                command->Execute(this, user, cr, type, author, text);
 
-               {
-                       ObjectLock olock(this);
-                       UpdateNotificationNumber();
-                       SetLastNotification(Utility::GetTime());
-               }
-
                /* required by compatlogger */
-               Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, command->GetName());
+               Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, command->GetName(), MessageOrigin::Ptr());
 
                Log(LogInformation, "Notification")
                    << "Completed sending notification '" << GetName()
index 18604e2e9d557be7840c461b8bb53c252a90cb53..0d234c99a7cd8fc7f5a83855feb834563f2a27ab 100644 (file)
@@ -92,7 +92,7 @@ class Notification : CustomVarObject < NotificationNameComposer
 
        [state] double last_notification;
        [state] double next_notification;
-       [state, set_protected] Value notification_number;
+       [state] int notification_number;
        [state] double last_problem_notification;
 
        [config, navigation] name(Endpoint) command_endpoint (CommandEndpointRaw) {