Skip to content

Commit

Permalink
Ensure that sent notifications are synced between Icinga instances
Browse files Browse the repository at this point in the history
fixes #11562
  • Loading branch information
gunnarbeutner committed Jun 15, 2016
1 parent 45919b4 commit 8a714d6
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 22 deletions.
2 changes: 1 addition & 1 deletion lib/icinga/apievents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
2 changes: 1 addition & 1 deletion lib/icinga/apievents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class I2_ICINGA_API ApiEvents

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

Expand Down
8 changes: 4 additions & 4 deletions lib/icinga/checkable-notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
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)
{
Expand Down
9 changes: 3 additions & 6 deletions lib/icinga/checkable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,12 @@ class I2_ICINGA_API Checkable : public ObjectImpl<Checkable>
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;
Expand Down
222 changes: 222 additions & 0 deletions lib/icinga/clusterevents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
8 changes: 8 additions & 0 deletions lib/icinga/clusterevents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ class I2_ICINGA_API ClusterEvents
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);
};

}
Expand Down
16 changes: 7 additions & 9 deletions lib/icinga/notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion lib/icinga/notification.ti
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 8a714d6

Please sign in to comment.