Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public enum SpServerError {
SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED(
"hawkbit.server.error.repo.tenantConfigurationValueChangeNotAllowed",
"The requested tenant configuration value modification is not allowed."),
SP_MULTIASSIGNMENT_NOT_ENABLED(
SP_MULTIASSIGNMENT(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this now removed ?
"The requested operation requires multi assignment to be enabled" is not valid error anymore ?

"hawkbit.server.error.multiAssignmentNotEnabled",
"The requested operation requires multi assignments to be enabled."),
SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -687,23 +687,6 @@ void downloadAndUpdateStatusDuringMaintenanceWindow() throws Exception {
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available")));
}

/**
* Assign multiple DS in multi-assignment mode. The earliest active Action is exposed to the controller.
*/
@Test
void earliestActionIsExposedToControllerInMultiAssignMode() throws Exception {
enableMultiAssignments();
final Target target = testdataFactory.createTarget();
final DistributionSet ds1 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final DistributionSet ds2 = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final Action action1 = getFirstAssignedAction(assignDistributionSet(ds1.getId(), target.getControllerId(), 56));
final Long action2Id = getFirstAssignedActionId(assignDistributionSet(ds2.getId(), target.getControllerId(), 34));

assertDeploymentActionIsExposedToTarget(target.getControllerId(), action1.getId());
sendDeploymentActionFeedback(target, action1, "closed", "success");
assertDeploymentActionIsExposedToTarget(target.getControllerId(), action2Id);
}

/**
* The system should not create a new target because of a too long controller id.
*/
Expand Down Expand Up @@ -759,16 +742,6 @@ private ResultActions sendDeploymentActionFeedback(final Target target, final Ac
return sendDeploymentActionFeedback(target, action, execution, finished, null);
}

private void assertDeploymentActionIsExposedToTarget(final String controllerId, final long expectedActionId) throws Exception {
final String expectedDeploymentBaseLink = String.format(
"/%s/controller/v1/%s/deploymentBase/%d",
AccessContext.tenant(), controllerId, expectedActionId);
mvc.perform(get(CONTROLLER_BASE, AccessContext.tenant(), controllerId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.deploymentBase.href", containsString(expectedDeploymentBaseLink)));
}

private void withPollingTime(final String pollingTime, final Callable<Void> runnable) throws Exception {
getAs(withUser("tenantadmin", TENANT_CONFIGURATION),
() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -43,7 +42,6 @@
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;
Expand All @@ -53,14 +51,10 @@
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;
Expand Down Expand Up @@ -142,30 +136,6 @@ protected void targetAssignDistributionSet(final TargetAssignDistributionSetServ
}
}

/**
* 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) {
Expand Down Expand Up @@ -247,39 +217,6 @@ protected DmfConfirmRequest createConfirmRequest(
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,
Expand All @@ -297,19 +234,6 @@ private static EventTopic getEventTypeForTarget(final ActionProperties action) {
: 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
Expand Down Expand Up @@ -412,40 +336,6 @@ private void sendUpdateMessageToTargets(
}
}

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,7 +39,6 @@
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;
Expand All @@ -52,7 +48,6 @@
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;
Expand Down Expand Up @@ -315,29 +310,7 @@ private void registerTarget(final Message message, final String virtualHost) {
}

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
Expand Down Expand Up @@ -112,10 +111,6 @@ void before() {
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement);
messageConverter = new Jackson2JsonMessageConverter();
lenient().when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
final TenantConfigurationValue multiAssignmentConfig = TenantConfigurationValue.builder().value(Boolean.FALSE)
.global(Boolean.FALSE).build();
lenient().when(tenantConfigurationManagement.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class))
.thenReturn(multiAssignmentConfig);

amqpMessageHandlerService = new AmqpMessageHandlerService(
rabbitTemplate, amqpMessageDispatcherServiceMock, controllerManagementMock, confirmationManagementMock);
Expand Down
Loading
Loading