Introduce Notification#command_endpoint

for delegating notification execution to a specific endpoint.
This commit is contained in:
Alexander A. Klimov 2020-10-29 13:30:02 +01:00
parent a13751d972
commit 3e714e19be
4 changed files with 80 additions and 11 deletions

View File

@ -480,6 +480,7 @@ Configuration Attributes:
user\_groups | Array of object names | **Required.** A list of user group names who should be notified. **Optional.** if the `users` attribute is set. user\_groups | Array of object names | **Required.** A list of user group names who should be notified. **Optional.** if the `users` attribute is set.
times | Dictionary | **Optional.** A dictionary containing `begin` and `end` attributes for the notification. If `end` is set to 0, `Notifications` are disabled permanently. Please read the [notification delay](03-monitoring-basics.md#notification-delay) chapter for details. times | Dictionary | **Optional.** A dictionary containing `begin` and `end` attributes for the notification. If `end` is set to 0, `Notifications` are disabled permanently. Please read the [notification delay](03-monitoring-basics.md#notification-delay) chapter for details.
command | Object name | **Required.** The name of the notification command which should be executed when the notification is triggered. command | Object name | **Required.** The name of the notification command which should be executed when the notification is triggered.
command\_endpoint | Object name | **Optional.** The endpoint where commands are executed on.
interval | Duration | **Optional.** The notification interval (in seconds). This interval is used for active notifications. Defaults to 30 minutes. If set to 0, [re-notifications](03-monitoring-basics.md#disable-renotification) are disabled. interval | Duration | **Optional.** The notification interval (in seconds). This interval is used for active notifications. Defaults to 30 minutes. If set to 0, [re-notifications](03-monitoring-basics.md#disable-renotification) are disabled.
period | Object name | **Optional.** The name of a time period which determines when this notification should be triggered. Not set by default (effectively 24x7). period | Object name | **Optional.** The name of a time period which determines when this notification should be triggered. Not set by default (effectively 24x7).
zone | Object name | **Optional.** The zone this object is a member of. Please read the [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) chapter for details. zone | Object name | **Optional.** The zone this object is a member of. Please read the [distributed monitoring](06-distributed-monitoring.md#distributed-monitoring) chapter for details.

View File

@ -316,7 +316,7 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons
throw; throw;
} }
} }
} else if (command_type == "notification_command" && params->Contains("source")) { } else if (command_type == "notification_command") {
/* Get user */ /* Get user */
User::Ptr user = new User(); User::Ptr user = new User();
Dictionary::Ptr attrs = new Dictionary(); Dictionary::Ptr attrs = new Dictionary();
@ -340,14 +340,18 @@ void ClusterEvents::ExecuteCheckFromQueue(const MessageOrigin::Ptr& origin, cons
NotificationCommand::Ptr notificationCommand = NotificationCommand::GetByName(command); NotificationCommand::Ptr notificationCommand = NotificationCommand::GetByName(command);
notificationCommand->Execute(notification, user, cr, NotificationType::NotificationCustom, notificationCommand->Execute(notification, user, cr, NotificationType::NotificationCustom,
author, ""); author, "", macros, true);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
String output = "Exception occurred during notification '" + notification->GetName() if (params->Contains("source")) {
+ "' for checkable '" + notification->GetCheckable()->GetName() String output = "Exception occurred during notification '" + notification->GetName()
+ "' and user '" + user->GetName() + "' using command '" + command + "': " + "' for checkable '" + notification->GetCheckable()->GetName()
+ DiagnosticInformation(ex, false); + "' and user '" + user->GetName() + "' using command '" + command + "': "
double now = Utility::GetTime(); + DiagnosticInformation(ex, false);
SendEventExecutedCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint); double now = Utility::GetTime();
SendEventExecutedCommand(params, ServiceUnknown, output, now, now, listener, origin, sourceEndpoint);
} else {
throw;
}
} }
} }
} }

View File

@ -123,6 +123,24 @@ void Notification::OnAllConfigLoaded()
if (!m_Checkable) if (!m_Checkable)
BOOST_THROW_EXCEPTION(ScriptError("Notification object refers to a host/service which doesn't exist.", GetDebugInfo())); BOOST_THROW_EXCEPTION(ScriptError("Notification object refers to a host/service which doesn't exist.", GetDebugInfo()));
Endpoint::Ptr endpoint = GetCommandEndpoint();
if (endpoint) {
Zone::Ptr myZone = static_pointer_cast<Zone>(GetZone());
if (myZone) {
Zone::Ptr cmdZone = endpoint->GetZone();
if (cmdZone != myZone && cmdZone->GetParent() != myZone) {
BOOST_THROW_EXCEPTION(ValidationError(this, { "command_endpoint" },
"Command endpoint must be in zone '" + myZone->GetName() + "' or in a direct child zone thereof."));
}
} else {
BOOST_THROW_EXCEPTION(ValidationError(this, { "command_endpoint" },
"Notification with command endpoint requires a zone. Please check the troubleshooting documentation."));
}
}
GetCheckable()->RegisterNotification(this); GetCheckable()->RegisterNotification(this);
} }
@ -604,7 +622,8 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
{ {
String notificationName = GetName(); String notificationName = GetName();
String userName = user->GetName(); String userName = user->GetName();
String checkableName = GetCheckable()->GetName(); auto checkable (GetCheckable());
String checkableName = checkable->GetName();
NotificationCommand::Ptr command = GetCommand(); NotificationCommand::Ptr command = GetCommand();
@ -615,9 +634,53 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
} }
String commandName = command->GetName(); String commandName = command->GetName();
ApiListener::Ptr listener = ApiListener::GetInstance();
Endpoint::Ptr endpoint = GetCommandEndpoint();
bool local = !endpoint || endpoint == Endpoint::GetLocalEndpoint();
if (!local && !(endpoint->GetCapabilities() & (uint_fast64_t)ApiCapabilities::ExecuteNotificationCommand)) {
Log(LogWarning, "Notification")
<< "Sending notification '" << GetName() << "' locally as its command endpoint '"
<< endpoint->GetName() << "' doesn't support executing notification commands. Consider upgrading it.";
local = true;
}
if (!local && (!endpoint->GetConnected() || !listener)) {
Log(LogWarning, "Notification")
<< "Sending notification '" << GetName() << "' locally as its command endpoint '"
<< endpoint->GetName() << "' is not connected.";
local = true;
}
try { try {
command->Execute(this, user, cr, type, author, text); if (local) {
command->Execute(this, user, cr, type, author, text);
} else {
Dictionary::Ptr macros = new Dictionary();
Host::Ptr host;
Service::Ptr service;
Dictionary::Ptr params = new Dictionary();
Dictionary::Ptr message = new Dictionary();
command->Execute(this, user, cr, type, author, text, macros, false);
tie(host, service) = GetHostService(checkable);
params->Set("command_type", "notification_command");
params->Set("command", command->GetName());
params->Set("macros", macros);
params->Set("notification", GetName());
params->Set("user", user->GetName());
params->Set("host", host->GetName());
if (service)
params->Set("service", service->GetShortName());
message->Set("jsonrpc", "2.0");
message->Set("method", "event::ExecuteCommand");
message->Set("params", params);
listener->SyncSendMessage(endpoint, message);
}
/* required by compatlogger */ /* required by compatlogger */
Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, commandName, nullptr); Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, commandName, nullptr);

View File

@ -71,8 +71,9 @@ enum class ApiCapabilities : uint_fast64_t
ExecuteArbitraryCommand = 1u << 0u, ExecuteArbitraryCommand = 1u << 0u,
IfwApiCheckCommand = 1u << 1u, IfwApiCheckCommand = 1u << 1u,
HostChildrenInheritObjectAuthority = 1u << 2u, HostChildrenInheritObjectAuthority = 1u << 2u,
ExecuteNotificationCommand = 1u << 3u,
MyCapabilities = ExecuteArbitraryCommand | IfwApiCheckCommand | HostChildrenInheritObjectAuthority MyCapabilities = ExecuteArbitraryCommand | IfwApiCheckCommand | HostChildrenInheritObjectAuthority | ExecuteNotificationCommand
}; };
/** /**