Merge pull request #8627 from WuerthPhoenix/bug/agent-cannot-update-executions-8616

Fix update execution message discarded. refs #8616
This commit is contained in:
Julian Brost 2023-04-13 19:29:49 +02:00 committed by GitHub
commit 8228fae740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 9 deletions

View File

@ -719,6 +719,21 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
if (!endpointPtr)
return ApiActions::CreateResult(404, "Can't find a valid endpoint for '" + resolved_endpoint + "'.");
/* Return an error when
* the endpoint is different from the command endpoint of the checkable
* and the endpoint zone can't access the checkable.
* The endpoints are checked to allow for the case where command_endpoint is specified in the checkable
* but checkable is not actually present in the agent.
*/
Zone::Ptr endpointZone = endpointPtr->GetZone();
Endpoint::Ptr commandEndpoint = checkable->GetCommandEndpoint();
if (endpointPtr != commandEndpoint && !endpointZone->CanAccessObject(checkable)) {
return ApiActions::CreateResult(
409,
"Zone '" + endpointZone->GetName() + "' cannot access checkable '" + checkable->GetName() + "'."
);
}
/* Get command */
String command;
@ -844,6 +859,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
Dictionary::Ptr pending_execution = new Dictionary();
pending_execution->Set("pending", true);
pending_execution->Set("deadline", deadline);
pending_execution->Set("endpoint", resolved_endpoint);
Dictionary::Ptr executions = checkable->GetExecutions();
if (!executions)

View File

@ -829,9 +829,18 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin,
}
}
String executionUuid = params->Get("source");
if (params->Contains("endpoint")) {
Endpoint::Ptr execEndpoint = Endpoint::GetByName(params->Get("endpoint"));
if (!execEndpoint) {
Log(LogWarning, "ClusterEvents")
<< "Discarding 'execute command' message " << executionUuid
<< ": Endpoint " << params->Get("endpoint") << " does not exist";
return Empty;
}
if (execEndpoint != Endpoint::GetLocalEndpoint()) {
Zone::Ptr endpointZone = execEndpoint->GetZone();
Zone::Ptr localZone = Zone::GetLocalZone();
@ -850,7 +859,7 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin,
if (!(childEndpoint->GetCapabilities() & (uint_fast64_t)ApiCapabilities::ExecuteArbitraryCommand)) {
double now = Utility::GetTime();
Dictionary::Ptr executedParams = new Dictionary();
executedParams->Set("execution", params->Get("source"));
executedParams->Set("execution", executionUuid);
executedParams->Set("host", params->Get("host"));
if (params->Contains("service"))
@ -871,6 +880,62 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin,
return Empty;
}
}
Checkable::Ptr checkable;
Host::Ptr host = Host::GetByName(params->Get("host"));
if (!host) {
Log(LogWarning, "ClusterEvents")
<< "Discarding 'execute command' message " << executionUuid
<< ": host " << params->Get("host") << " does not exist";
return Empty;
}
if (params->Contains("service"))
checkable = host->GetServiceByShortName(params->Get("service"));
else
checkable = host;
if (!checkable) {
String checkableName = host->GetName();
if (params->Contains("service"))
checkableName += "!" + params->Get("service");
Log(LogWarning, "ClusterEvents")
<< "Discarding 'execute command' message " << executionUuid
<< ": " << checkableName << " does not exist";
return Empty;
}
/* Return an error when the endpointZone is different than the child zone and
* the child zone can't access the checkable.
* The zones are checked to allow for the case where command_endpoint is specified in the checkable
* but checkable is not actually present in the agent.
*/
if (!zone->CanAccessObject(checkable) && zone != endpointZone) {
double now = Utility::GetTime();
Dictionary::Ptr executedParams = new Dictionary();
executedParams->Set("execution", executionUuid);
executedParams->Set("host", params->Get("host"));
if (params->Contains("service"))
executedParams->Set("service", params->Get("service"));
executedParams->Set("exit", 126);
executedParams->Set(
"output",
"Zone '" + zone->GetName() + "' cannot access to checkable '" + checkable->GetName() + "'."
);
executedParams->Set("start", now);
executedParams->Set("end", now);
Dictionary::Ptr executedMessage = new Dictionary();
executedMessage->Set("jsonrpc", "2.0");
executedMessage->Set("method", "event::ExecutedCommand");
executedMessage->Set("params", executedParams);
listener->RelayMessage(nullptr, nullptr, executedMessage, true);
return Empty;
}
}
}
@ -1247,13 +1312,6 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin,
ObjectLock oLock (checkable);
if (origin->FromZone && !origin->FromZone->CanAccessObject(checkable)) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'update executions API handler' message for checkable '" << checkable->GetName()
<< "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access.";
return Empty;
}
if (!params->Contains("execution")) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'update executions API handler' message for checkable '" << checkable->GetName()
@ -1281,6 +1339,22 @@ Value ClusterEvents::ExecutedCommandAPIHandler(const MessageOrigin::Ptr& origin,
return Empty;
}
Endpoint::Ptr command_endpoint = Endpoint::GetByName(execution->Get("endpoint"));
if (!command_endpoint) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'update executions API handler' message from '" << origin->FromClient->GetIdentity()
<< "': Command endpoint does not exists.";
return Empty;
}
if (origin->FromZone && !command_endpoint->GetZone()->IsChildOf(origin->FromZone)) {
Log(LogNotice, "ClusterEvents")
<< "Discarding 'update executions API handler' message for checkable '" << checkable->GetName()
<< "' from '" << origin->FromClient->GetIdentity() << "': Unauthorized access.";
return Empty;
}
if (params->Contains("exit"))
execution->Set("exit", params->Get("exit"));
@ -1371,7 +1445,7 @@ Value ClusterEvents::UpdateExecutionsAPIHandler(const MessageOrigin::Ptr& origin
updateMessage->Set("method", "event::UpdateExecutions");
updateMessage->Set("params", params);
listener->RelayMessage(origin, Zone::GetLocalZone(), updateMessage, true);
listener->RelayMessage(origin, checkable, updateMessage, true);
return Empty;
}