Multi-Asssignments feature removal (#2893)

* Multi-Asssignments feature removal

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fix some sonar findings

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fixes after review

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

---------

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>
This commit is contained in:
Stanislav Trailov
2026-02-04 16:59:09 +02:00
committed by GitHub
parent 2bf443661d
commit c33156b134
43 changed files with 123 additions and 1610 deletions

View File

@@ -10,7 +10,6 @@
package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.context.AccessContext.asSystem;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
import java.net.URI;
@@ -43,24 +42,18 @@ import org.eclipse.hawkbit.dmf.json.model.DmfBatchDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfConfirmRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
@@ -99,7 +92,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement;
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
private final DeploymentManagement deploymentManagement;
private final RepositoryProperties repositoryProperties;
@SuppressWarnings("java:S107")
protected AmqpMessageDispatcherService(
@@ -109,8 +101,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
final TargetManagement<? extends Target> targetManagement,
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final DeploymentManagement deploymentManagement,
final RepositoryProperties repositoryProperties) {
final DeploymentManagement deploymentManagement) {
super(rabbitTemplate);
this.artifactUrlHandler = artifactUrlHandler;
this.amqpSenderService = amqpSenderService;
@@ -119,7 +110,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
this.softwareModuleManagement = softwareModuleManagement;
this.distributionSetManagement = distributionSetManagement;
this.deploymentManagement = deploymentManagement;
this.repositoryProperties = repositoryProperties;
}
public boolean isBatchAssignmentsEnabled() {
@@ -142,30 +132,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
}
/**
* Listener for Multi-Action events.
*
* @param multiActionAssignServiceEvent the Multi-Action event to be processed
*/
@EventListener(classes = MultiActionAssignServiceEvent.class)
protected void onMultiActionAssign(final MultiActionAssignServiceEvent multiActionAssignServiceEvent) {
final MultiActionAssignEvent multiActionAssignEvent = multiActionAssignServiceEvent.getRemoteEvent();
log.debug("MultiActionAssignEvent received for {}", multiActionAssignEvent.getControllerIds());
sendMultiActionRequestMessages(multiActionAssignEvent.getControllerIds());
}
/**
* Listener for Multi-Action events.
*
* @param multiActionCancelServiceEvent the Multi-Action event to be processed
*/
@EventListener(classes = MultiActionCancelServiceEvent.class)
protected void onMultiActionCancel(final MultiActionCancelServiceEvent multiActionCancelServiceEvent) {
final MultiActionCancelEvent multiActionCancelEvent = multiActionCancelServiceEvent.getRemoteEvent();
log.debug("MultiActionCancelEvent received for {}", multiActionCancelEvent.getControllerIds());
sendMultiActionRequestMessages(multiActionCancelEvent.getControllerIds());
}
protected void sendUpdateMessageToTarget(
final ActionProperties actionsProps, final Target target,
final Map<SoftwareModule, Map<String, String>> softwareModules) {
@@ -247,39 +213,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
return new DmfConfirmRequest(actionId, asSystem(target::getSecurityToken), convertToAmqpSoftwareModules(target, softwareModules));
}
void sendMultiActionRequestToTarget(
final Target target, final List<Action> actions,
final Function<SoftwareModule, Map<String, String>> getSoftwareModuleMetaData) {
final URI targetAddress = IpUtil.addressToUri(target.getAddress());
if (!IpUtil.isAmqpUri(targetAddress) || CollectionUtils.isEmpty(actions)) {
return;
}
final DmfMultiActionRequest multiActionRequest = new DmfMultiActionRequest(
actions.stream()
.map(action -> {
final DmfActionRequest actionRequest = createDmfActionRequest(
target, action,
action.getDistributionSet().getModules().stream()
.collect(Collectors.toMap(Function.identity(), module -> {
final Map<String, String> softwareModuleMetadata = getSoftwareModuleMetaData.apply(module);
return softwareModuleMetadata == null ? Collections.emptyMap() : softwareModuleMetadata;
})));
final int weight = getWeightConsideringDefault(action);
return new DmfMultiActionRequest.DmfMultiActionElement(getEventTypeForAction(action), actionRequest, weight);
})
.toList());
final Message message = getMessageConverter().toMessage(
multiActionRequest,
createConnectorMessagePropertiesEvent(target.getTenant(), target.getControllerId(), EventTopic.MULTI_ACTION));
amqpSenderService.sendMessage(message, targetAddress);
}
private int getWeightConsideringDefault(final Action action) {
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
}
/**
* Method to get the type of event depending on whether the action is a DOWNLOAD_ONLY action or if it has a valid maintenance window
* available or not based on defined maintenance schedule. In case of no maintenance schedule or if there is a valid window available,
@@ -297,19 +230,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
: EventTopic.DOWNLOAD_AND_INSTALL;
}
/**
* Determines the {@link EventTopic} for the given {@link Action}, depending on its action type.
*
* @param action to obtain the corresponding {@link EventTopic} for
* @return the {@link EventTopic} for this action
*/
private static EventTopic getEventTypeForAction(final Action action) {
if (action.isCancelingOrCanceled()) {
return EventTopic.CANCEL_DOWNLOAD;
}
return getEventTypeForTarget(new ActionProperties(action));
}
private static <T, R> List<R> partitionedParallelExecution(
final Collection<T> controllerIds, final Function<Collection<T>, List<R>> loadingFunction) {
// Ensure not exceeding the max value of MAX_PROCESSING_SIZE
@@ -412,40 +332,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
}
private void sendMultiActionRequestMessages(final List<String> controllerIds) {
final Map<String, List<Action>> controllerIdToActions = controllerIds.stream()
.collect(Collectors.toMap(
Function.identity(),
controllerId -> deploymentManagement.findActiveActionsWithHighestWeight(controllerId, MAX_ACTION_COUNT)));
// gets all software modules for all action at once
final Set<Long> allSmIds = controllerIdToActions.values().stream()
.flatMap(actions -> actions.stream()
.map(Action::getDistributionSet)
.flatMap(ds -> ds.getModules().stream())
.map(SoftwareModule::getId))
.collect(Collectors.toSet());
final Map<Long, ? extends Map<String, String>> getSoftwareModuleMetadata =
allSmIds.isEmpty()
? Collections.emptyMap()
: softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(allSmIds);
targetManagement.findByControllerId(controllerIds).forEach(target ->
sendMultiActionRequestToTarget(
target, controllerIdToActions.get(target.getControllerId()), module -> getSoftwareModuleMetadata.get(module.getId())));
}
private DmfActionRequest createDmfActionRequest(
final Target target, final Action action,
final Map<SoftwareModule, Map<String, String>> softwareModules) {
if (action.isCancelingOrCanceled()) {
return new DmfActionRequest(action.getId());
} else if (action.isWaitingConfirmation()) {
return createConfirmRequest(target, action.getId(), softwareModules);
}
return createDownloadAndUpdateRequest(target, action.getId(), softwareModules);
}
private void sendSingleUpdateMessage(
final ActionProperties action, final Target target, final Map<SoftwareModule, Map<String, String>> modules) {
final String tenant = action.getTenant();

View File

@@ -9,15 +9,12 @@
*/
package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -42,7 +39,6 @@ import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.helper.TenantConfigHelper;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
@@ -52,7 +48,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.eclipse.hawkbit.utils.IpUtil;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message;
@@ -315,29 +310,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
private void sendUpdateCommandToTarget(final Target target) {
if (TenantConfigHelper.getAsSystem(TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class)) {
sendCurrentActionsAsMultiActionToTarget(target);
} else {
sendOldestActionToTarget(target);
}
}
private void sendCurrentActionsAsMultiActionToTarget(final Target target) {
final List<Action> actions = controllerManagement.findActiveActionsWithHighestWeight(target.getControllerId(), MAX_ACTION_COUNT);
// gets all software modules for all action at once
final Set<Long> allSmIds = actions.stream()
.map(Action::getDistributionSet)
.flatMap(ds -> ds.getModules().stream())
.map(SoftwareModule::getId)
.collect(Collectors.toSet());
final Map<Long, Map<String, String>> getSoftwareModuleMetadata =
allSmIds.isEmpty() ? Collections.emptyMap() : controllerManagement.findTargetVisibleMetaDataBySoftwareModuleId(allSmIds);
amqpMessageDispatcherService.sendMultiActionRequestToTarget(target, actions, module -> getSoftwareModuleMetadata.get(module.getId()));
}
private void sendOldestActionToTarget(final Target target) {
// send oldest action to Target
final Optional<Action> actionOptional = controllerManagement.findActiveActionWithHighestWeight(target.getControllerId());
if (actionOptional.isEmpty()) {
return;

View File

@@ -265,11 +265,10 @@ public class DmfApiConfiguration {
final SystemManagement systemManagement,
final TargetManagement<? extends Target> targetManagement,
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement,
final RepositoryProperties repositoryProperties) {
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement,
deploymentManagement, repositoryProperties);
deploymentManagement);
}
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {